.. include:: ../vars.rst .. _chapter-authentication: ************** Authentication ************** Authentication is the process of making sure a |DP| is who it claims to be. Loading any [#]_ security plugins will configure the |DP| to request the plugins to authenticate a newly discovered remote participant before initiating |EP_disc| with that participant. Authentication is done via a series of inter-participant challenge and response messages, which are exchanged during a 3-way handshake. These messages perform mutual authentication, so the end result is that this |DP| authenticates the remote |DP| and vice-versa. Before a |DP| is enabled, the |AuthPlugin| associated with the |DP| must be configured with three artifacts: #. The **Identity CA Certificate**, which contains the public key of the Identity CA. #. The **Private Key** of the |DP|. #. An **Identity Certificate** that chains up to the Identity CA. This certificate binds the public key of the |DP| to its subject name. If the |AuthPlugin| fails to verify any of these prerequisites, participant creation fails. To successfully authenticate a remote participant, that remote participant must present a valid |IdentityCert| (this is known as Identity Certificate Validation, which we describe in :ref:`p2_core/authentication:Identity Certificate Validation`) and prove to have access to the private key associated with the |IdentityCert|'s public key (by signing challenges during the handshake). Authentication of the remote participant takes place right after the |DP_disc| phase (see :link_connext_dds_pro_um:`Discovery in the Core Libraries User's Manual <#users_manual/Discovery.htm>`). Secure |EP_disc| will only happen between mutually authenticated participants. In other words, if a participant (let’s call it |P1|) fails to authenticate a different participant (|P2|), |P1| ignores |EP_disc| traffic from |P2|. Otherwise, |P1| initiates |EP_disc| with |P2| after mutual authentication. If a participant fails to authenticate, |CONNEXT| will try again by initiating a new handshake through the |AuthPlugin|. Each |DP| can optionally specify a certificate revocation list (CRL) to the |AuthPlugin|. The CRL is checked for revoked certificates as part of the Identity Certificate Validation (see :ref:`p2_core/authentication:Identity Certificate Validation`). Remote participants presenting a revoked certificate will not be authenticated. This way, you can prevent a compromised |DP| from joining your secure domain by revoking its |IdentityCert| and adding it to the CRL. .. [#] Either |RTI_SP| or custom security plugins. Setting :property:`.load_plugin` will tell the |CONNEXT| core to call the |AuthPlugin|. Handshake ========= To perform mutual authentication, |DPs| exchange a series of challenge and response messages in a 3-way handshake. This handshake is the mechanism by which participants verify each other's identity and establish a |SharedSecret|. After mutual authentication over an unsecure channel, a |SharedKey| is derived using the |SharedSecret|. Handshake messages are sent over the |AuthT|, which allows the messages to be directed to a specific recipient (see :ref:`p2_core/authentication:Authentication Builtin Topic (ParticipantStatelessMessage)`). The handshake establishes mutual authentication between discovered participants using the RSA or ECDSA digital signature algorithms, and determines a |SharedSecret| using Diffie-Hellman (DH) or Elliptic Curve Diffie-Hellman (ECDH) key establishment methods. Message Exchange ---------------- Let’s analyze the handshake by examining the messages that two participants (|P1| and |P2|) exchange as part of the authentication: Handshake Request ^^^^^^^^^^^^^^^^^ To initiate the handshake, |P1| sends a |HS_REQ| to |P2| that includes: * |P1|’s |IdentityCert| (*Cert1*), which includes |P1|’s public key (*PubK1*) * |P1|’s Participant data (*Pdata1*), which includes |P1|’s DomainParticipantQos and |P1|’s security attributes * |P1|’s |PermissionsDoc| (*Perm1*) * A challenge (*Challenge1*) and a Diffie-Hellman public key (*DH1*), which |P1| randomly generates right before initiating the handshake Handshake Reply ^^^^^^^^^^^^^^^ When |P2| receives the |HS_REQ|, it verifies *Cert1* and *Perm1*'s signature. At this point, |P2| knows whether |P1| has presented a valid |IdentityCert| (that chains up to the shared Identity CA) and |PermissionsDoc| (signed by the shared Permissions CA). If it did, the handshake continues and |P2| sends a |HS_REP| to |P1| that includes: * |P2|’s |IdentityCert| (*Cert2*), which includes |P2|’s public key (*PubK2*) * |P2|’s Participant data (*Pdata2*), which includes |P2|’s DomainParticipantQos and |P2|’s security attributes * |P2|’s |PermissionsDoc| (*Perm2*) * A challenge (*Challenge2*) and a Diffie-Hellman public key (*DH2*), which |P2| randomly generates upon reception of a |HS_REQ| * A signature (*Sign2*), which |P2| generates by signing some of the message contents, including *Challenge1* and *DH2*, with its private key (*PrivK2*) Handshake Final ^^^^^^^^^^^^^^^ When |P1| receives the |HS_REP|, it verifies *Cert2* and *Perm1*'s signature, thus verifying whether |P2| has presented a valid |IdentityCert| (that chains up to the shared Identity CA) and |PermissionsDoc| (signed by the shared Permissions CA). |P1| also verifies *Sign2* against *PubK2*. Hence, |P1| can verify whether *Sign2* was generated with *PrivK2*. At this point, |P1| knows whether |P2| is the legitimate holder of the private key associated with *Cert2*. If the verification succeeds, |P2| is authenticated and |P1| computes the |SharedSecret| from *DH2* and the Diffie-Hellman private key used for *DH1*. At this point, |P1| sends a |HS_FIN| to |P2| that includes: * A signature (*Sign1*), which |P1| generates by signing some of the message contents, including *Challenge2* and *DH1*, with its private key (*PrivK1*) When |P2| receives this message it verifies *Sign1* against *PubK1*. Now, |P2| knows whether |P1| is the legitimate holder of the private key associated with *Cert1*. |P1| is now authenticated and |P2| computes the |SharedSecret| from *DH1* and the Diffie-Hellman private key used for *DH2*. At this point, the handshake concludes: |P1| and |P2| are mutually authenticated and have a |SharedSecret| they can use to derive the |SharedKey| they need to communicate securely. General Considerations ---------------------- The authentication process is secure, even if the channel where the authentication happens is not secure. As we mentioned earlier, the |HS_REQ| and |HS_REP| messages include a random challenge. In both cases, the purpose of this challenge is to verify that the remote participant currently holds the private key corresponding to the exchanged certificate. For clarity, let's analyze how we achieve this using the |HS_REQ|. In the |HS_REQ|, |P1| is the challenger participant, and |P2| is the challenged participant. (Note that the mechanism used in the |HS_REP| is the same, but |P1| and |P2| swap roles.) In this first case, |P1| sends a random challenge that |P2| needs to sign (along with other information) with its private key, sending the result back to |P1|. Then |P1| verifies that the signature corresponds to the public key in |P2|'s certificate. Since the challenge is a random piece of information unique to the current authentication session, |P1| can verify that |P2| currently holds the private key corresponding to the public key claimed in the certificate. With this mechanism, it is not possible to capture a valid handshake from a previous authentication session and replay it later without it becoming invalid. Therefore, we can be sure that |P2| is the legitimate holder of the exchanged certificate. In other words, this verifies that |P2| is who it claims to be. During the authentication process, things can go wrong. For example, an unauthorized participant may present an invalid certificate, an attacker trying to impersonate one of your participants will be unable to give a valid response to the challenges, or an attacker may try to break the authentication between two legitimate participants by sending invalid responses to challenges in lieu of an authorized participant halfway through the authentication process. An invalid certificate or response to a challenge will result in a VALIDATION_FAILURE for that particular handshake message, but authentication will not fail until it times out. This is to avoid denial-of-service (DoS) attacks where a third party injects messages during an authentication. If the authentication process fails (because it times out), the participants can fall into one of the following states: Symmetric Authentication Failure ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If the authentication process is not completed and fails for both participants (|P1| does not authenticate |P2|, and |P2| does not authenticate |P1|), |P1| cleans up all the authentication state of |P2| and |P2| cleans up all the authentication state of |P1|, so the authentication can start from scratch. Asymmetric Authentication Failure ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Let’s analyze the case where |P1| successfully authenticates |P2|, but |P2| did not authenticate |P1|. This can happen if |P1| received the |HS_REP| that was correct, but it couldn’t deliver the |HS_FIN| (because of a network failure, for example). In this case, |P2| cannot start authenticating from scratch because from |P1|’s perspective, |P2| has already authenticated (in other words, |P1| has not cleaned up |P2|’s authentication state). Asymmetric authentication failure can also happen if authentication succeeds for both participants, then liveliness expires for just one of them. To solve this problem, by default, |P2| periodically sends |AuthReq| messages to |P1| after a timeout. With an |AuthReq|, |P2| asks |P1| to open a secondary authentication process so it has the opportunity to reauthenticate. If that succeeds, |P1| will replace |P2|’s old authentication state with the new one. At this point, |P1| and |P2| are mutually authenticated. For more details, see :ref:`p2_core/authentication:Re-Authentication`. Identity Certificate Validation ------------------------------- |IdentityCerts| are signed by a CA trusted by both |DPs|. Therefore, |DPs| can verify that the received certificate is legitimate. As per the DDS Security Specification, |IdentityCerts| are in PEM format and may contain a human-readable section above the mandatory section delimited by: .. code-block:: text ---BEGIN CERTIFICATE--- ---END CERTIFICATE--- The human-readable section adds no functionality and is NOT used for validating the certificate. Removing it from the |IdentityCert| before the authentication process reduces the size of the messages on the network. By default beginning in Connext DDS version 6.0.1, the human-readable part of |IdentityCerts| is stripped when the certificate is loaded. This behavior avoids additional overhead and can be controlled with the boolean property :property:`authentication.propagate_simplified_identity_certificate` (see :numref:`RTI Security Plugins Properties for Configuring Authentication`). Identity Certificate Validation is done when this participant receives the first handshake message from a remote participant, and implies multiple checks: Step 1. Verifying the certificate validity on the current date and time ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The |SP| will check the certificate's X.509 Validity fields (*Not Before* and *Not After*). If the certificate is received outside this time frame (before it becomes valid, or after it has expired), validation fails immediately. Otherwise, the certificate is considered currently valid. Step 2. Verifying that the certificate is not revoked ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ You can specify a CRL by setting the :property:`authentication.crl` property (see :numref:`RTI Security Plugins Properties for Configuring Authentication`). By doing this, your |DP| will check the certificate against the revocation list. If the certificate is found to be revoked, validation fails immediately. Note that the revocation list is immutable (it is not exchanged during discovery or handshaking) and changes in the CRL are not enforced until the |DP| using it is deleted and recreated. For further details, refer to :ref:`p2_core/elements_dds_secure_system:Multiple Certificate Revocation Lists`. Step 3. Verifying that the Identity CA issued the remote’s |IdentityCert| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The local |DP| validates the certificate against the Identity CA specified in the :property:`dds.sec.auth.identity_ca` property (see :numref:`DDS Security Properties for Configuring Authentication`). If the issuer of the |IdentityCert| is an intermediate CA, you should specify the full certificate chain in the :property:`dds.sec.auth.identity_certificate` property. In this case, the |IdentityCert| will be verified to chain up to the Identity CA, as specified in :ref:`p2_core/authentication:Identity Certificate Chaining`. If the Identity CA is not currently valid or cannot validate an |IdentityCert|, then the validation will be retried with the alternative certificates specified in the :property:`authentication.alternative_ca_files` property (see :numref:`RTI Security Plugins Properties for Configuring Authentication`). If none of the alternative CAs are currently valid and can validate the file (or if you did not set this property), the validation process will fail. Shared Key Derivation --------------------- As an additional result of the handshake, the two involved participants will derive a |SharedKey| from the |SharedSecret| and the Challenges in the Handshake using HMAC operations. The derived |SharedKey| allows the establishment of a |SecKeyExchangeCh| (also known as |SecKeyExchangeTName|). The |CryptoPlugin| will use that channel to securely exchange the symmetric keys that the endpoints need to communicate securely. After the handshake concludes with successful authentication and |SharedKey| establishment, symmetric cryptography is used to exchange other keys (see :ref:`p2_core/cryptography:Secure Key Exchange`). Diffie-Hellman adds perfect forward secrecy. This implies that an attacker cannot deduce the |SharedKey|, even if they have access to all the messages exchanged in the communication and even if the private keys of the participants were compromised. Moreover, knowing the |SharedKey| for a session does not provide information about the |SharedKey| of future sessions. Authentication Builtin Topic (ParticipantStatelessMessage) ========================================================== To perform the handshake, |DPs| need to exchange directed messages through a unsecure communication channel. For this purpose, the DDS Security specification introduces a new |AuthT|, also known as the |AuthTName| builtin |TOPIC|. This best-effort stateless |TOPIC| prevents the sequence-number prediction vulnerability that is present in unsecure reliable protocols. The |AuthT| implements the channel that |DPs| need to perform authentication. Data samples exchanged for this |TOPIC| include both the handshake messages (see :ref:`p2_core/authentication:Handshake`) and the re-authentication messages (see :ref:`p2_core/authentication:Re-Authentication`). Fragmentation Support for the Authentication Topic -------------------------------------------------- The Security Plugins support fragmenting |AuthT| samples. This is useful in scenarios with a hard limit on the transport maximum message size. This feature is enabled by default: fragmentation of |AuthT| samples will be triggered when sending samples that 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>`). Related Governance Rules ======================== This section describes the authentication attributes that appear in the Governance Document. Domain-level rules ------------------ The following attributes belong inside a :xmltag:`domain_rule`. allow_unauthenticated_participants (domain_rule) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This attribute may be :xmlval:`TRUE` or :xmlval:`FALSE`. It controls whether or not a remote |DP| that either doesn’t support security or fails the authentication handshake is allowed to proceed in trying to communicate with the local |DP|. Communication with such a |DP| will happen only on the |TOPICs| for which all of the topic-level rules are set to :xmlval:`FALSE` or :xmlval:`NONE` (see :ref:`p2_core/elements_dds_secure_system:Topic-Level Rules`). .. note:: If :xmltag:`allow_unauthenticated_participants` is set to :xmlval:`TRUE`, :xmltag:`rtps_protection_kind` must be set to :xmlval:`NONE`. Cryptographic Algorithms ======================== The |SP| use different cryptographic algorithms for different purposes. Starting with version 7.0.0, the user can modify and select algorithms supported and used by |SecEntity|. This section describes the relationship between the digital signature and key establishment algorithms that can be configured in the |AuthPlugin|. In this section, we also describe the relationship between the algorithms that can be configured in the |AuthPlugin| and the :link_connext_dds_api_cpp2:`ParticipantTrustAlgorithmInfo::signature ` and :link_connext_dds_api_cpp2:`ParticipantTrustAlgorithmInfo::key_establishment ` fields, which are used to propagate the used and supported algorithms for a |DP|. A complete list of values can be found in :numref:`DigitalSignatureBitValues` and :numref:`KeyEstablishmentBitValues`. 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 |SP| for a |DP| may not support it. For example, the |SP| for wolfSSL may support different algorithms than the |SP| for OpenSSL. Finally, this section also defines discovery defaults for every field of the :link_connext_dds_api_cpp2:`ParticipantBuiltinTopicData::trust_algorithm_info `. 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. Digital Signature Algorithms ---------------------------- Digital Signature Algorithms collect algorithms used in the |DP| trust chain as well as for authentication. The following algorithms are supported: * `RSASSA-PSS-MGF1SHA256+2048+SHA256` * `RSASSA-PKCS1-V1_5+2048+SHA256` * `ECDSA-P256+SHA256` * `ECDSA-P384+SHA384` * `EDDSA+ED25519+SHA512` (<< experimental >>) * `EDDSA+ED448+SHAKE256` (<< experimental >>) Digital Signature Algorithms specify four algorithm definitions: * ``trust_chain.supported_mask``: A list of supported trust chain algorithms. The default value is: `RSASSA-PSS-MGF1SHA256+2048+SHA256` and `ECDSA-P256+SHA256`. * ``trust_chain.required_mask``: A list of algorithms used in the |DP|'s identity trust chain. |IdentityCert| determines which algorithm is used. The default value is: `ECDSA-P256+SHA256`. * ``message_auth.supported_mask``: A list of supported authentication digital signature algorithms. The default value is: `RSASSA-PSS-MGF1SHA256+2048+SHA256` and `ECDSA-P256+SHA256`. * ``message_auth.required_mask``: The authentication digital signature algorithm used by a |DP|. |IdentityCert| determines which algorithm is used. The default value is: `ECDSA-P256+SHA256`. .. note:: The ``trust_chain.supported_mask`` are the list of digital signature algorithms supported by the |DP| in the context of creating a chain of trust. This means that they are the algorithms used for verifying the |IdentityCert| against the Identity Certificate Authority. The |SP| enforce during validation of the remote |IdentityCert| chain that the actual used digital signature algorithms are supported. The ``message_auth.supported_mask`` are the list of digital signature algorithms supported by the |DP| for checking that the remote |DP| is authentic. These are the algorithms that a |DP| supports for challenging a remote |DP| to prove that it has the |PrivateKey| corresponding to its |IdentityCert|. Key Establishment Algorithms ---------------------------- Key Establishment Algorithms collect algorithms used in key establishment during |DP| authentications. The following algorithms are supported: * `DHE-MODP+2048+256` * `ECDHE-CEUM+P256` * `ECDHE-CEUM+P384` * `ECDHE-CEUM+X25519` (<< experimental >>) * `ECDHE-CEUM+X448` (<< experimental >>) Key Establishment Algorithms specify two algorithm definitions: * ``supported_mask``: A list of supported key establishment algorithms. The default value is: `DHE-MODP+2048+256` and `ECDHE-CEUM+P256`. * ``required_mask``: Indicates the algorithm the |DP| will use as the key establishment algorithm if the |DP| is the authentication initiator (if not, the algorithm of the other |DP| will be used). It is determined by `authentication.key_establishment_algorithm` property (see :numref:`RTI Security Plugins Properties for Configuring Cryptography`). The default value is: `ECDHE-CEUM+P256`. See :ref:`p2_core/cryptography:allowed_security_algorithms (domain_rule)` to learn how to configure which of these algorithms are supported. Advanced Authentication Concepts ================================ Protecting Participant Discovery -------------------------------- |DP_disc| is sent through an unsecure channel. Consequently, additional mechanisms need to be put in place to make sure the received information comes from a legitimate participant. In the |SP|, the mechanism for protecting the |DP_disc| information is known as TrustedState. Security Plugins TrustedState is an RTI extension to the DDS Security Authentication specification that covers two limitations in the DDS Security specification: * The lack of a standardized mechanism for validating that the |DP_disc| information received by DDS actually matches the information of the authenticated remote |DP|. * |DP_disc| data is immutable after authentication. This prevents functionality such as updating IP addresses. (Only a limitation in DDS Security 1.0, resolved in 1.1.). Security Plugins TrustedState is a digest of the |DP_disc| data, plus information that unambiguously identifies the current local participant state and the current authentication session. TrustedState is exchanged as part of the authentication process as a vendor extension. More specifically, TrustedState is included as a binary property in the |HS_REP| and |HS_FIN| messages. Once the authentication completes, involved participants will validate received |DP_disc| information against the received TrustedState. This way, participants can be sure that the received |DP_disc| comes from the authenticated participant. The |DP_disc| channel is also used to propagate changes in the |DP|’s QoS or in the locators. In order to securely propagate |DP_disc| changes after authenticating the remote participant, the |SP| use the participant's identity private key to sign the |DP_disc| data plus some additional information identifying the local participant state (and which is consistent with the one serialized in the TrustedState). This signature is then serialized as a property in the |DP_disc| data. This way, other participants can validate that the update is legitimate by verifying the received |DP_disc| against the participant's public key. Please note that in DDS Security 1.0 (which |CONNEXT| 5.3.x implements), the DomainParticipantQos for remote |DPs| is immutable. To overcome this limitation, 5.3.x uses the TrustedState extension. Non-RTI participants do not implement TrustedState; therefore, they cannot update DomainParticipantQos Discovery information after authentication. This limitation is solved by DDS Security 1.1, which is adopted in |CONNEXT| 6.0.0+. To increase compatibility with other vendors, |SecDPs| that use the |RTI_SP| will successfully authenticate remote participants that do not provide TrustedState. Non-RTI participants should ignore the TrustedState property in the Handshake since it is a vendor extension. .. caution:: When the :property:`authentication.participant_discovery_protection_key` (<< deprecated >>) property is set (see :numref:`RTI Security Plugins Properties for Configuring Authentication`), the TrustedState mechanism is disabled. Instead, symmetric cryptography based on the pre-shared key specified by this property is used to protect the participant announcements' integrity. Note that, in this scenario, |DPs| cannot validate that the |DP_disc| information received by |CONNEXT| matches the authenticated remote |DPs|. Note that the :property:`authentication.participant_discovery_protection_key` property is required to use |CDS| and the |SP| together. Identity Certificate Chaining ----------------------------- This section assumes you are familiar with the concept of a Certificate Chain, as described in :ref:`p2_core/elements_dds_secure_system:Public Key Infrastructure (PKI)`. You may specify a certificate chain in the :property:`dds.sec.auth.identity_certificate` property (see :numref:`DDS Security Properties for Configuring Authentication`). You can create the certificate chain by concatenating individual certificates and specifying the concatenated result as a single file or string. The local |IdentityCert| will be verified before creating the local |DP|. It will also be sent on the network as part of the handshake. If a certificate chain is specified, then the whole chain will be sent on the network, which may cause significant overhead. To avoid additional overhead, beginning in |CONNEXT| version 6.1.0, the human-readable part of |IdentityCerts| is stripped by default when the certificate is loaded. You can control this behavior with the :property:`authentication.propagate_simplified_identity_certificate` property (see :numref:`RTI Security Plugins Properties for Configuring Authentication`). The CRLs specified in the :property:`authentication.crl` property will be used throughout the verification process (see :numref:`RTI Security Plugins Properties for Configuring Authentication`). This property may contain any number of CRLs, each one signed by either the Identity CA (:property:`dds.sec.auth.identity_ca`), one of the alternative CAs (:property:`authentication.alternative_ca_files`), or one of the intermediate CAs in the |IdentityCert| chain. The |IdentityCert| will be verified against the Identity CA using the following procedure: #. The current certificate is the first certificate in the |IdentityCert| chain. #. Check that the current certificate is valid for the current date. Otherwise, the verification fails immediately. #. If the current certificate is signed and unrevoked by the Identity CA (:property:`dds.sec.auth.identity_ca`) or any of the alternative CAs listed in :property:`authentication.alternative_ca_files`, then the verification succeeds immediately. Otherwise: #. If a next certificate exists in the chain and the current certificate is signed and unrevoked by that next certificate, then the next certificate becomes the current certificate. If none of the certificates in the |IdentityCert| chain lead to the Identity CA (or any of the alternative Identity CAs), then the verification fails. For details on certificate validation, see :ref:`p2_core/authentication:Identity Certificate Validation`. Re-Authentication ----------------- The |SP| support securely re-authenticating remote participants as described in the DDS Security specification. This is needed in scenarios where there is an asymmetric liveliness loss. As depicted in :numref:`figure-re-authentication`, asymmetric liveliness loss occurs between two participants, |P1| and |P2|, when |P1| loses liveliness with |P2|. When this happens, |P1| cleans up all the associated state, while |P2| still keeps the authenticated state. Because |P2| keeps an authenticated state from |P1|, it will not accept new authentication messages from |P1|. Without the ability to re-authenticate, asymmetric liveliness loss will lead to communication not recovering. The same occurs in the case of an asymmetric authentication failure. The |SP| address this problem by including a re-authentication capability as described in the DDS Security specification. If |P1| has not completed an ongoing authentication with |P2| after a specific period, it will send an |AuthReq| (``dds.sec.auth_request``) message that includes a nonce to |P2|. This message will give a hint to |P2| that |P1| is pending authentication with |P2|. This specific period is configured by the property :property:`dds.participant.trust_plugins.authentication_request_delay.sec`, see :numref:`Properties for Configuring Authentication Affecting Any Authentication Plugin`. When |P2| receives an |AuthReq| message, it will check if it already has a valid completed authentication with |P1|. If so, that could mean that an asymmetric liveliness loss has occurred. To verify that the |AuthReq| is legitimate, the two participants will now conduct a whole authentication process that includes the nonce received as part of the triggering ``dds.sec.auth_request`` message. Only if this secondary authentication succeeds, the old state will be removed in |P2| and replaced with the new one, allowing discovery to complete again and communication to recover. If this secondary authentication fails, no change will be made in |P1| and the old authenticated session will be kept. Because the old authenticated state is kept until the new authentication has successfully completed, the |SP| re-authentication is robust against attackers trying to bring down an existing authentication. .. figure:: ../static/re-authentication.png :scale: 50% :alt: :name: figure-re-authentication :align: center Messages Exchanged During the Re-Authentication Process Dynamic Certificate Revalidation -------------------------------- A valid |IdentityCert| or Identity CA may not stay valid forever. When one of them becomes invalid, the |SP| should take appropriate action on the corresponding |DP|. Currently, the |SP| support taking actions based on a certificate's expiration time (the *Not After* X.509 Validity field), and the actions differ between remote |DPs| and the local |DP|. Dynamic Certificate Expiration of Remote |DPs| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If the |IdentityCert| of a remote |DP| is successfully validated during handshaking (see :ref:`p2_core/authentication:Identity Certificate Validation`), the |SP| note the earliest expiration time among the chain of certificates that were involved in the validation. At that time, the |SP| performs the :ref:`p2_core/authentication:Identity Certificate Validation` steps again. If this revalidation fails, then the |SP| will remove the remote |DP|. Note that the remote |DP| is only removed, not ignored, so it will be allowed to rejoin the system if it can be recreated with the same GUID and with a valid |IdentityCert|. If the property :property:`dds.participant.trust_plugins.key_revision_max_history_depth` is set to a value other than :value:`0`, then the |SP| will also create a new |KeyRevision| (see :ref:`p2_core/cryptography:Limiting the Usage of Specific Key Material`) in order to render the remote |DP|'s Key Material outdated. If this property is unset or set to :value:`0`, then the |SP| will generate this log message at the :value:`ENTITIES` category and the :value:`ERROR` verbosity: .. code-block:: text Precondition not met because the participant has not enabled key regeneration using the "dds.participant.trust_plugins.key_revision_max_history_depth" property. You must enable this property to prevent removed or ignored participants from reading your encrypted data or writing data that looks like it came from you!!! Dynamic Certificate Expiration of the Local |DP| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If the |IdentityCert| of the local |DP| is successfully validated during |DP| creation, and the local |DP| is configured with a *DomainParticipantListener* and a *StatusMask* that includes :link_connext_dds_api_cpp2:`INVALID_LOCAL_IDENTITY_ADVANCE_NOTICE_STATUS `, then the |SP| note the earliest expiration time among the chain of certificates that were involved in the validation. The |SP| subtract the value of the :property:`dds.participant.trust_plugins.certificate_expiration_advance_notice_duration.sec` property from that earliest expiration time. At that notification time, the |SP| perform the :ref:`p2_core/authentication:Identity Certificate Validation` steps again for the local |DP|. If this revalidation determines that a certificate has already expired or will expire within the advance notice duration, then the |SP| will notify the user by invoking the :link_connext_dds_api_cpp2:`on_invalid_local_identity_status_advance_notice` callback function. After the first notification, the |SP| will continue notifying the user every second until the certificate chain has finally expired. Currently, the |SP| do not support updating the local |DP|'s |IdentityCert| or Identity CA without deleting and recreating the local |DP|. Properties for Configuring Authentication ========================================= :numref:`DDS Security Properties for Configuring Authentication` and :numref:`RTI Security Plugins Properties for Configuring Authentication` list the properties that you can set for authentication. These properties are configured through the |DP|’s PROPERTY QosPolicy (see :ref:`p2_core/elements_dds_secure_system:QoS Properties`). .. list-table:: DDS Security Properties for Configuring Authentication :name: DDS Security Properties for Configuring Authentication :widths: 40 60 :header-rows: 1 :class: longtable * - Property Name - Property Value Description * - :property:`dds.sec.auth.identity_ca` - :req:`Required` Identity CA certificate. This certificate is used for verifying the |IdentityCerts| of local and remote |DPs| (see :ref:`p2_core/elements_dds_secure_system:Public Key Infrastructure (PKI)`). Two participants that want to securely communicate with each other must use the same Identity CA. You may specify either the file name or the document contents. See the note below for details. :type:`String`. Default: :value:`NULL` * - :property:`dds.sec.auth.private_key` - :req:`Required` The private key associated with the first certificate that appears in :property:`identity_certificate`. You may specify either the file name or the document contents. See the note below for details. :type:`String`. Default: :value:`NULL` * - :property:`dds.sec.auth.identity_certificate` - :req:`Required` |IdentityCert| signed by the Identity CA. Other participants will request this certificate to verify the identity of the local participant. This is an X.509 certificate in PEM format. You may put a chain of certificates in the |IdentityCert| by concatenating individual certificates and specifying the concatenated result as a single file or string. See :ref:`p2_core/authentication:Identity Certificate Chaining` and :ref:`p2_core/elements_dds_secure_system:Public Key Infrastructure (PKI)`. Notes: * For better security, it is recommended, but not required, that different participants have different Common Names. * You may specify either the file name or the document contents. See the note below for details. :type:`String`. Default: :value:`NULL` * - :property:`dds.sec.auth.password` - :req:`Only required if` :property:`private_key` :req:`is encrypted` The password used to decrypt the :property:`private_key`. The value of this property is interpreted as the Base64 encoding of the symmetric key that will be used to decrypt the :property:`private_key`. For example, if the :property:`private_key` was encrypted using this command: .. code-block:: console $ openssl req -new -newkey ec:ecdsaparam2 \ -config example2ECdsa.cnf -keyout peer2keyECdsa.pem \ -passout pass:MyPassword -out peer2reqECdsa.pem you should specify the Base64 encoding of MyPassword, therefore the value of the password property should be :value:`TXlQYXNzd29yZA==`. If the :property:`private_key` was not encrypted, then the password must be :value:`NULL`. :type:`String`. Default: :value:`NULL` .. admonition:: Note regarding document format The Identity CA, Private Key, and |IdentityCert| documents in :numref:`DDS Security Properties for Configuring Authentication` must be in PEM format. You may specify either the file name or the document contents. If specifying the file name, the property value must have the fully qualified path and name of the file, and a prefix :value:`file:` (no space after the colon) is optional. If specifying the contents of the document, the property value must have the prefix :value:`data:,` (no space after the comma), followed by the contents inside the document. Some examples: .. code-block:: text "data:,-----BEGIN CERTIFICATE-----\nabcdef\n-----END CERTIFICATE-----" .. code-block:: text "data:,-----BEGIN PRIVATE KEY-----\nabcdef\n-----END PRIVATE KEY-----" .. code-block:: text "data:,-----BEGIN CERTIFICATE-----\nabcdef\n-----END CERTIFICATE-----" Notice that the two :value:`\n` characters are required. .. code-block:: text "file:../../../dds_security/cert/ecdsa01/identities/ecdsa01Peer01Cert.pem" .. code-block:: text "C:\Users\Name\dds_security\cert\ecdsa01\identities\ecdsa01Peer01Cert.pem" .. list-table:: |RTI_SP| Properties for Configuring Authentication :name: RTI Security Plugins Properties for Configuring Authentication :widths: 40 60 :header-rows: 1 :class: longtable * - Property Name (prefix with :property:`com.rti.serv.secure.`) [#fPrefix]_ - Property Value Description * - :property:`authentication.key_establishment_algorithm` - :req:`Optional` The algorithm used to establish the |SharedSecret| during authentication. The options are Diffie-Hellman Ephemeral with 2048-bit MODP Group parameters (:value:`DHE+MODP-2048-256`), Elliptic Curve Diffie-Hellman Ephemeral with the NIST P-256 curve (:value:`ECDHE-CEUM+P256`), ECDHE with the NIST P-384 curve (:value:`ECDHE-CEUM+P384`), ** << experimental>> ** ECDHE using X25519 as specified in RFC7748 (:value:`ECDHE-CEUM+X25519`), and ** << experimental>> ** ECDHE using X448 as specified in RFC7748 (:value:`ECDHE-CEUM+X448`). There is also the default :value:`AUTO` option, which detects the curve used to sign the |IdentityCert| and uses the same one. If the certificate is not an ECDSA signed certificate, we will default to :value:`ECDHE-CEUM+P256`. If two participants, that specify different property values, discover each other, they will use the algorithm that belongs to the participant with the lower-valued ``participant_key``. :type:`Enum`: :value:`AUTO`, :value:`DHE+MODP-2048-256`, :value:`ECDHE-CEUM+P256`, :value:`ECDHE-CEUM+P384` Default: :value:`AUTO` * - :property:`authentication.shared_secret_algorithm` - :req:`Optional` Same as :property:`authentication.key_establishment_algorithm`. Note: This property is deprecated and has been replaced by :property:`authentication.key_establishment_algorithm`. :type:`Enum`: :value:`dh`, :value:`ecdh` * - :property:`authentication.alternative_ca_files` - :req:`Optional` A comma-separated list of alternative Identity CA Certificates. If the verification of a file fails with the main certificate (:property:`identity_ca`), verification will be retried with all of the corresponding alternative certificates. If none of the alternative certificates can be used to verify the file, the verification process will fail. If any of the alternative certificate files fail to be loaded, the |DP| creation will fail. For details, see :ref:`p2_core/authentication:Identity Certificate Validation`. Each of the elements in the list must be the fully qualified path to the certificate file. This property value may optionally contain :value:`file:` (no space after the colon) as a prefix to any of the elements in the list. :type:`String`. Default: :value:`NULL` * - :property:`authentication.crl` - :req:`Optional` A Certificate Revocation List to keep track of untrusted X.509 certificates. If :property:`authentication.crl` is set to :value:`NULL`, no CRL is checked, and all valid certificates will be considered trusted. If :property:`authentication.crl` is set to an invalid CRL file, the |DP| creation will fail. If :property:`authentication.crl` is set to a valid CRL file, the CRL will be checked upon local |DP| creation and upon discovering remote |DP|. Creating a |DP| with a revoked certificate will fail. If |P1| uses a certificate that does not appear in |P1|’s CRL but does appear in |P2|’s CRL, then |P2| will reject and ignore |P1|. For details, see :ref:`p2_core/authentication:Identity Certificate Validation`. The document should be in PEM format. You may specify either the file name or the document contents. See the note above for details. This property is immutable: changes in the CRL will not be enforced until the |DP| using the CRL is deleted and recreated. :type:`String`. Default: :value:`NULL` * - :property:`authentication.crl_file` - :req:`Optional` Same as :property:`authentication.crl`. Note: This property is deprecated and has been replaced by :property:`authentication.crl`. :type:`String`. Default: :value:`NULL` * - :property:`authentication.x509v3_extension_enforcement.key_usage` - :req:`Optional` How to enforce the presence of the X.509 v3 extension ``keyUsage`` (see https://tools.ietf.org/html/rfc5280#section-4.2.1.3). This property has three possible values (case-insensitive): * :value:`auto`: The |SP| will not do anything special to enforce the presence of ``keyUsage`` in a certificate. Note this is the behavior in |CONNEXT| 6.0.0 and below. * :value:`inherited`: The |SP| will enforce the presence of ``keyUsage`` if the certificate's issuer has ``keyUsage``. For example, if the Identity CA (specified in :property:`identity_ca`) has ``keyUsage``, and it signs the |IdentityCert| (specified in :property:`identity_certificate`) that does NOT have ``keyUsage``, then participant creation will fail. The same applies if :property:`identity_certificate` is set to a certificate chain. * :value:`force`: The |SP| will always enforce the presence of ``keyUsage``. This is not the default, but it will force you to make sure that all of the certificates in the system have their extensions properly set. :type:`Enum`: :value:`auto`, :value:`inherited` :value:`force` Default: :value:`inherited` * - :property:`authentication.propagate_simplified_identity_certificate` - :req:`Optional` If :value:`TRUE`, the human-readable sections from |IdentityCerts| are removed before they are transmitted over the network. |IdentityCerts| in PEM format may contain a human-readable section above the mandatory section delimited by: .. code-block:: text ---BEGIN CERTIFICATE--- ---END CERTIFICATE--- The human-readable section adds no functionality and is not protected in any way. Removing it from the |IdentityCert| before the authentication process reduces the size of the messages on the network. :type:`Boolean`. Default: :value:`TRUE` (only the Base64 part is exchanged) * - :property:`authentication.keyform` - :req:`Optional` The format of the private key specified by :property:`dds.sec.auth.private_key`. The value of this property can be one of the following: * :value:`pem`: The key is in PEM format and will be loaded as a file or a string, depending on its "file:" or "data:," prefix. * :value:`engine`: The key is an array of bytes and will be loaded by the engine specified by :property:`openssl_engine` (see :ref:`p3_advanced/openssl_engines:Support for OpenSSL Engines`). :type:`Enum`: :value:`pem` :value:`engine` Default: :value:`pem` * - :property:`authentication.rsa_pss_pad` - :req:`Optional` The kind of padding used when signing and verifying documents. This property has three possible values: * :value:`AUTO`: Detect the RSA padding from the |DPs|'s |IdentityCert|. The Security Plugins for OpenSSL supports RSA standard (`RSA_PKCS1_PADDING`) and PSS (`RSA_PKCS1_PSS_PADDING`) padding |IdentityCerts|. The Security PLugins for wolfSSL supports only RSA standard (`RSA_PKCS1_PADDING`) |IdentityCerts|. |IdentityCerts| that have a RSA PSS Public Key or Signature are not supported in wolfSSL. * :value:`TRUE`: Use RSA PSS padding (RSA_PKCS1_PSS_PADDING) as specified in the DDS Security specification. * :value:`FALSE`: Use standard RSA padding (RSA_PKCS1_PADDING). If the value of the property is either :value:`AUTO` or :value:`TRUE`, the |DP| will accept (unless stated otherwise by the Governance Document) either `RSA_PKCS1_PSS_PADDING` or `RSA_PKCS1_PADDING` padding to verify the remote |DP|'s signed messages. If the value of the property is :value:`FALSE`, RSA PSS padding is not supported. |DPs| that have this property set to :value:`FALSE` won't be able to communicate with DomainParticipants that are using RSA PSS padding. :type:`Enum`. :value:`AUTO`, :value:`TRUE`, :value:`FALSE`, Default: :value:`TRUE` * - :property:`authentication.participant_discovery_protection_key` - :req:`Optional` .. attention:: HMAC-Only mode is deprecated and will be replaced in the future with |PSKProtection| (PSK), described in :ref:`p3_advanced/pre-shared_key:|PSKProtection|`. PSK for |RTI_CDS| is currently not supported; it will be supported in the next release. Pre-shared key from which the |SP| derive the HMAC Key used to compute message authentication codes over :type:`ParticipantBuiltinTopicData` messages. This key shares many of the same details as :property:`hmac_only.cryptography.key`. See that property's description in :numref:`Properties for Configuring HMAC-Only Mode` for the details. If this property is set, then :type:`ParticipantBuiltinTopicData` messages will be protected with an HMAC operation. |DPs| must set this property to the same value in order to communicate with each other. When this property is set, the |DPs| will not interoperate with non-|CONNEXTSECURE| |DPs|. The purpose of this pre-shared key is to protect against certain DoS attacks against |RTI_CDS|. The value of this property is not used to protect any traffic other than :type:`ParticipantBuiltinTopicData` messages. All other RTPS traffic still gets protected by the standard |CryptoPlugin|, which uses dynamically-generated keys that are exchanged after authentication completes. This property takes effect regardless of the value of :property:`hmac_only.enabled`. If |RTI_CDS| is using the |SP|, then this property is required by all the |DPs| in the |DOMAIN|. For more information, please refer to :ref:`p4_integrations/real-time_wan_transport:Security Considerations when Using Cloud Discovery Service`. :type:`String`. Since this key is provided as a String, it is recommended that you take the appropriate measures to protect any configuration XML file containing this key, or alternatively to securely retrieve and set up this property programmatically. Default: not set * - :property:`authentication.enable_custom_algorithms` - :req:`Optional` **<< EXPERIMENTAL >>** Configures whether to enable custom cryptographic algorithms for the Authentication plugin. When enabled, the |SP| will enable additional digital signature and key establishment algorithms that are not part of the DDS Security specification (EDDSA+ED25519+SHA512, EDDSA+ED448+SHAKE256, ECDHE-CEUM+X25519, ECDHE-CEUM+X448). Currently only supported in combination with OpenSSL: this property will have no effect when used in combination with wolfSSL. Two |DPs| with different configurations of this property will still interoperate as long as neither of them is using one of the custom algorithms. Default: :value:`FALSE` * - :property:`authentication.enable_custom_allocators` - :req:`Optional` Configures whether to set custom crypto library (e.g., OpenSSL) allocators. When enabled (not the default), the |SP| will configure custom allocator functions (alloc, realloc, free) to the loaded crypto library with the goal of reducing memory fragmentation at the cost of a minimum performance impact. This is currently only supported in combination with OpenSSL. This property is only effective the first time a |DP| loads the |SP| within the same process: subsequent |DP| creations will ignore this property and leave the existing configuration unchanged. Moreover, this property is only effective if no allocation has been done with the crypto library builtin allocators before the |SP| have been loaded, otherwise a warning will be logged and no change will be made. For example, if you are using a dynamically linked VxWorks application and the kernel has the IPCRYPTO component, then the kernel will make some allocations at startup, and this property will not be effective. **Important:** Since the allocator functions live within the |SP| library, your application must not make any calls to the crypto library once the |SP| have been unloaded from memory. **If your application uses heap monitoring**: You should call ``OPENSSL_cleanup`` before disabling heap monitoring. ``OPENSSL_cleanup`` finalizes OpenSSL and frees resources allocated by it. If you don't call ``OPENSSL_cleanup``, the function will be called automatically before closing down the library. In this case, heap monitoring will report memory leaks because resource deallocation happens once it is no longer tracking memory. In general, when using custom OpenSSL allocators we recommend you call ``OPENSSL_cleanup`` once your application is done with OpenSSL (including having destroyed any |CONNEXT| entity relying on the |SP| or TLS transport), and do it before unloading the |SP| library if using dynamic loading. Default: :value:`FALSE` .. The following properties are internal (not documented) .. only:: internal * - :property:`authentication.x509_verify.library` - :req:`Optional` The dynamic library that contains an ``X509_STORE_CTX_verify_fn`` function. On Linux systems, the library file name must have a :file:`lib` prefix and a :file:`.so` extension. On other OSs, the value of this property must not have a :file:`lib` prefix or a file extension. :type:`String`. Default: :value:`NULL` * - :property:`authentication.x509_verify.function_name` - :req:`Optional` The name of the ``X509_STORE_CTX_verify_fn`` function that's implemented in :file:`x509_verify.dll`. :type:`String`. Default: :value:`NULL` .. [#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 Authentication Plugin ------------------------------------------------------------ :numref:`Properties for Configuring Authentication Affecting Any Authentication Plugin` lists a set of properties that are not exclusive to the shipped |SP|, but that will affect any |AuthPlugin|. .. list-table:: Properties for Configuring Authentication Affecting Any Authentication Plugin :name: Properties for Configuring Authentication Affecting Any Authentication Plugin :widths: 40 60 :header-rows: 1 :class: longtable * - Property Name (prefix with :property:`dds.participant.trust_plugins.`) - Property Value Description * - :property:`authentication_timeout.sec` - :req:`Optional` Controls the maximum time (in seconds) that an ongoing authentication can remain without completing. After this timeout expires, the authentication process is cancelled, and associated resources are released. For more details, see :ref:`p2_core/authentication:General Considerations`. A |DP| should set its own :property:`authentication_timeout` to be shorter than the :property:`participant_liveliness_lease_duration` (in the DomainParticipant's DISCOVERY_CONFIG QosPolicy) of its peers (see :link_connext_dds_pro_um:`DISCOVERY_CONFIG QosPolicy (DDS Extension) <#users_manual/DISCOVERY_CONFIG_Qos.htm>`). This restriction helps a temporarily disconnected peer to successfully reconnect with the |DP|. :type:`Integer`: :value:`[1, INT_MAX]` Default: :value:`60` * - :property:`authentication_request_delay.sec` - :req:`Optional` Controls the delay (in seconds) before sending an |AuthReq| to the remote participant. For more information, please see :ref:`p2_core/authentication:Re-Authentication`. :type:`Integer`: :value:`[1, INT_MAX]` Default: :value:`5` * - :property:`authentication_request_timeout.sec` - :req:`Optional` Controls the timeout (in seconds) for authentication negotiations started from an authentication request message. :type:`Integer`: :value:`[0, authentication_timeout.sec]`. If set to a value greater than :property:`authentication_timeout.sec`, then :value:`authentication_timeout.sec` will be used instead. Default: :value:`20` * - :property:`certificate_expiration_advance_notice_duration.sec` - :req:`Optional` Controls how much time (in seconds) in advance the :link_connext_dds_api_cpp2:`on_invalid_local_identity_status_advance_notice` *DomainParticipantListener* callback function should notify the user when the local |DP|'s |IdentityCert| or Identity CA is about to expire. For more information, please see :ref:`p2_core/authentication:Dynamic Certificate Expiration of the Local |DP|`. :type:`Integer`: :value:`[0, INT_MAX]`. Default: :value:`0` Configuration Properties Affecting Connext DDS Core Libraries Behavior ---------------------------------------------------------------------- :numref:`Properties Affecting Connext DDS Core Libraries Behavior` lists other properties affecting the |CONNEXT| Core Libraries' behavior. .. list-table:: Properties Affecting Connext DDS Core Libraries Behavior :name: Properties Affecting Connext DDS Core Libraries Behavior :widths: 40 60 :header-rows: 1 :class: longtable * - Property Name - Property Value Description * - :property:`dds.participant.discovery_config.use_stateless_participant_discovery_reader` - :req:`Optional` If :value:`TRUE`, makes Simple Participant Discovery robust against Sequence Number Attacks by switching the local Simple Participant Discovery |DR|'s mode to pure stateless. :type:`Boolean`. Default: :value:`FALSE`