.. 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. .. note:: In the case of |LIGHT_SP_BUILTIN|, which implements |SEC_SPEC_12| builtin PSK plugins, the |AuthPlugin| does not perform any operation to cryptographically enforce |DP| Authentication. Consequently, most of this chapter (with some exceptions such as the descriptions of :property:`files_poll_interval` and :property:`authentication.enable_custom_allocators`) is only applicable to |SP_BUILTIN| or custom security plugins implementing 3-way handshake PKI-based authentication. In the case of |SP_BUILTIN|, 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 |SP_BUILTIN| 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 |SEC_SPEC|, |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_SP_PRODUCT_HEADING| 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_BUILTIN| 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_SP_PRODUCT_HEADING| 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 each |DP| is responsible for specifying its own CRL; a CRL is not exchanged during discovery or handshaking. Also note that the revocation list is mutable as described in :ref:`p2_core/authentication:Dynamic Certificate Revocation of Remote |DPs|`. 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_SP_PRODUCT_HEADING| 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. GUID Validation --------------- .. note:: The |SP_BUILTIN| cause a |DP| to have a different GUID than it would normally have. If a secure |DP| is allowed to have whatever GUID it wants, then it becomes possible for an attacker to send a storm of participant announcements with different GUIDs while using its own certificate and private key to successfully complete the handshakes with the other |DPs| in the domain. Legitimate |DPs| that have a GUID that the attacker already used will be unable to join the domain. To prevent this denial-of-service attack, a |DP| that would have had a certain GUID when not using the |SP_BUILTIN| (let's call this the "candidate GUID") will have this GUID adjusted by the |SP_BUILTIN|. This adjusted GUID becomes the GUID that the |DP| effectively uses for everything, and it is also the GUID that is outputted by the API ``DDS_DomainParticipant_get_qos`` in the ``wire_protocol.rtps_host_id``, ``wire_protocol.rtps_app_id``, and ``wire_protocol.rtps_instance_id`` fields of the DomainParticipantQos. The adjustment works as follows: * The first bit (bit 0) is set to 1. * The 47 bits following the first bit (bits 1 to 47) are set to the first 47 bits of the SHA-256 hash of the ASN.1 DER encoding of the subject name appearing in the |IdentityCert|. * The following 48 bits (bits 48 to 95) are set to the first 48 bits of the SHA-256 hash of the candidate GUID. By mixing in a value that depends on the certificate subject name, the |DP| GUID selection mechanism is protected from duplication or reuse by |DPs| that cannot authenticate that their identity is indeed that subject name. Thus, as part of the processing of a Handshake Reply and a Handshake Final, the receiver checks that the middle 47 bits of the GUID match the hash of the subject name. If they do not match, then 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 |SEC_SPEC| 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 |RTI_SP_PRODUCT| 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`). .. warning:: If :xmltag:`allow_unauthenticated_participants` is set to :xmlval:`TRUE`, :xmltag:`rtps_protection_kind` must be set to :xmlval:`NONE`. If the value of :xmltag:`allow_unauthenticated_participants` is :xmlval:`TRUE`, then the local |DP| will still be able to discover remote |SecDPs| with an incompatible configuration (see :ref:`p2_core/cryptography:Discovery of a remote Secure Entity`), running an incompatible set of plugins, or just failing the authentication process. These |DPs| will be treated as unauthenticated: communication with them will happen only on the |TOPICs| for which all of the topic-level rules are set to :xmlval:`FALSE` or :xmlval:`NONE`. If the local |DP| is communicating with an unauthenticated |DP|, and the local |DP| has set the :property:`dds.participant.discovery_config.use_stateless_participant_discovery_reader` property to :value:`TRUE` (see :numref:`Properties Affecting Connext DDS Core Libraries Behavior`), then the local |DP| can potentially discover another |DP| with the same GUID as the unauthenticated participant. When this discovery happens, the local |DP| will attempt to authenticate the new |DP|. If this authentication fails or if the new |DP| does not support security, then the local |DP| will remain in communication with the old |DP|. If this authentication succeeds, then the local |DP| will stop communicating with the old |DP| and start communicating with the new |DP|. 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 |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 |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 `. 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_BUILTIN| 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_SP_PRODUCT_HEADING| 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_BUILTIN|, the mechanism for protecting the |DP_disc| information is known as TrustedState. |RTI_SP_PRODUCT| TrustedState is an RTI extension to the DDS Security Authentication specification that covers two limitations in the |SEC_SPEC|: * 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.). |RTI_SP_PRODUCT| 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_BUILTIN| 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_PRODUCT| 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:: The TrustedState mechanism is disabled when |PSKProtection| is enabled. Participant announcements are protected with symmetric cryptography and there is no need for TrustedState. For details, see :ref:`p3_advanced/pre-shared_key:|PSKProtection| and the cloud`. 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_SP_PRODUCT_HEADING| Properties for Configuring Authentication`). The CRLs specified in the :property:`authentication.crl` property will be used throughout the verification process (see :numref:`|RTI_SP_PRODUCT_HEADING| 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 |RTI_SP_PRODUCT| support securely re-authenticating remote participants as described in the |SEC_SPEC|. 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 states, 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_BUILTIN| address this problem by including a re-authentication capability as described in the |SEC_SPEC|. 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 (this is, if |P2| triggers the timeout configured through the :property:`dds.participant.trust_plugins.authentication_request_timeout.sec` property), no change will be made in |P2| and the old authenticated session will be kept. Because the old authenticated state is kept until the new authentication has successfully completed, the |SP_BUILTIN| 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 .. note:: When running |SP_BUILTIN| in constrained devices, or when the number of total |DPs| simultaneously created under the same Domain is high, you may get the following error during system startup for a subset of the ongoing authentications: :property:`failed to verify challenge signature`. This error could trigger as a result of inadequate configuration of the authentication process for the system size, leading to mismatched authentication processes between |DP| pairs. When this error triggers, it will generate unnecessary CPU load and network traffic overhead. See section :ref:`p2_core/authentication:Guidelines for Minimizing Authentication Negotiation Times` for a set of guidelines for minimizing authentication negotiation times. Guidelines for Minimizing Authentication Negotiation Times ---------------------------------------------------------- To minimize authentication negotiation times during system startup, follow these guidelines: * Set :property:`dds.participant.trust_plugins.authentication_timeout.sec` to a value that is twice the time it takes to authenticate all of the |DPs| during the system startup. A too short value will trigger additional authentication negotiations, generating additional CPU load and network traffic, and generally slowing down the system startup. * Set :property:`dds.participant.trust_plugins.authentication_request_delay.sec` to a value that is higher than the time it takes to authenticate all of the |DPs| during the system startup. A too short value will generate additional traffic and potentially additional unnecessary authentication negotiations. * Set :property:`dds.participant.trust_plugins.authentication_request_timeout.sec` to the average time it takes to authenticate a |DP| in your system at startup. * Make sure that the sum of the configured values for :property:`dds.participant.trust_plugins.authentication_request_delay.sec` and :property:`dds.participant.trust_plugins.authentication_request_timeout.sec` is lower than the :property:`dds.participant.trust_plugins.authentication_timeout.sec`. Dynamic Certificate Revalidation -------------------------------- A valid |IdentityCert| or Identity CA may not stay valid forever. When one of them becomes invalid, the |SP_BUILTIN| should take appropriate action on the corresponding |DP|. Currently, the |SP_BUILTIN| support taking actions based on a certificate's expiration time (the *Not After* X.509 Validity field) and presence in a CRL, 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 |RTI_SP_PRODUCT| note the earliest expiration time among the chain of certificates that were involved in the validation. At that time, the |RTI_SP_PRODUCT| performs the :ref:`p2_core/authentication:Identity Certificate Validation` steps again. If this revalidation fails, then the |RTI_SP_PRODUCT| 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 |RTI_SP_PRODUCT| 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 |RTI_SP_PRODUCT| will generate this log message at the :value:`SECURITY` category and the :value:`WARNING` 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_BUILTIN| note the earliest expiration time among the chain of certificates that were involved in the validation. The |SP_BUILTIN| 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_BUILTIN| 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 |RTI_SP_PRODUCT| 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 |RTI_SP_PRODUCT| will continue notifying the user at a configurable period until the certificate chain has finally expired. The property for configuring this period is :property:`dds.participant.trust_plugins.certificate_expiration_advance_notice_reminder_period.sec`. Dynamic Certificate Revocation of Remote |DPs| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If the |IdentityCert| of a remote |DP| does not appear in the local |DP|'s CRL when the remote |DP| is first discovered, it's still possible for the |IdentityCert| to appear in the CRL later. The CRL is mutable in two ways: * Changing the value of the :property:`authentication.crl` property using the |DP| ``set_qos`` API. If the new CRL is invalid, then ``set_qos`` will return DDS_RETCODE_ERROR, and the old CRL, if it exists, will remain in use. * Leaving the value of the :property:`authentication.crl` property unchanged and instead changing the contents of the actual CRL file. The |SP_BUILTIN| enforce these changes as long as :value:`file:` is the prefix of the property value and :property:`files_poll_interval` is set to a value other than :value:`0`. In this case, the |RTI_SP_PRODUCT| use a separate thread dedicated to periodically checking if any of the following have occurred: * The CRL file has been deleted. * The CRL file modification timestamp has changed. * The MD5 hash of the file contents has changed. If any of those events have occurred, then the |SP_BUILTIN| will reload the CRL file. If the reloaded CRL is invalid or if the CRL file is actually deleted, then the previous version of the CRL will remain in use. As soon as a CRL change is detected, the |RTI_SP_PRODUCT| will remove any newly revoked remote |DPs|. Note that the |DPs| are removed but not ignored. So if a later CRL change results in any remote |DPs| becoming unrevoked, then communication with those |DPs| will resume after any in-progress authentications are timed out (the timeout is configurable using the property :property:`dds.participant.trust_plugins.authentication_timeout.sec`) and after the local |DP| receives participant announcements from the remote |DPs| (the announcement period is configurable using the field :property:`DomainParticipantQos::discovery_config::participant_announcement_period`). 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_BUILTIN| 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_BUILTIN| will generate the same log message as the one described in :ref:`p2_core/authentication:Dynamic Certificate Expiration of Remote |DPs|`. Of course, you may combine these two ways of mutability. For example, you may change the CRL filename from ``one.crl`` to ``two.crl``, change the value of :property:`authentication.crl` from ``file:one.crl`` to ``file:two.crl``, and change the contents of ``file:two.crl``. Dynamic Certificate Revocation of Local |DPs| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Creation of the local |DP| will fail with DDS_RETCODE_ERROR if its |IdentityCert| appears in the CRL. However, even if the |IdentityCert| of the local |DP| is not in the CRL upon |DP| creation, it's still possible for the |IdentityCert| to appear in the CRL later. This is because the CRL is mutable, as described in :ref:`p2_core/authentication:Dynamic Certificate Revocation of Remote |DPs|`. The |RTI_SP_PRODUCT| will detect a change in either the CRL contents (when :property:`files_poll_interval` is set to a value other than :value:`0`) or in the value of the :property:`authentication.crl` property itself (through the |DP| ``set_qos`` API). If the new value is invalid, then the |SP_BUILTIN| will keep using the previous version of the CRL. If the new value is valid, then the |SP_BUILTIN| will update the CRL. The ``set_qos`` API returns DDS_RETCODE_ERROR if the new CRL value is invalid. Otherwise, the ``set_qos`` API returns DDS_RETCODE_OK. This return code is independent of whether the |IdentityCert| of the local |DP| appears in the updated CRL or not. When the |IdentityCert| of the local |DP| appears in the updated CRL, then the |SP_BUILTIN| will log an exception message due to a change in the security status. In particular, the message indicates that the |IdentityCert| of the local |DP| has been revoked. Dynamic Certificate Revocation of Remote |DPs| through Whitelisting ------------------------------------------------------------------- The |SP_BUILTIN| support defining a whitelist of allowed subject names (enabled when :property:`dds.participant.trust_plugins.subject_name_whitelist` is set). This whitelist provides a way to dynamically allow/deny access to |DPs| into a domain. The whitelist configures a set of (semicolon-separated) allowed subject names for authenticated |DPs|. If set (even if empty), authenticated |DPs| will be allowed into the system only if their subject name matches one of the ones in the whitelist. Any authenticated |DP| not matching the whitelist will be ignored automatically upon authentication completion, before it has access to any secure topic data. The whitelist has no effect on intraparticipant communication: a |DP| will always be able to communicate with itself independently of the contents of the whitelist. .. warning:: The subject names in the whitelist must be **exactly** as returned in the ``Subject`` field by the following |OpenSSL| command: .. code-block:: console $ openssl x509 -in -text -nameopt sep_comma_plus_space,sname,esc_2253 where ```` is the path to the certificate file. Changing the order of the attributes is not allowed. Interactions with allow_unauthenticated_participants ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Since the whitelist is enforced only on authenticated |DPs|, this property does not impact allowed non-authenticated |DPs|: if :xmltag:`allow_unauthenticated_participants` is set to :xmlval:`TRUE`, |DPs| not using security and |DPs| failing authentication early will still be allowed into the system. Whitelist mutability ^^^^^^^^^^^^^^^^^^^^ The whitelist allows for dynamic changes in the set of allowed subject names without restarting the local |DP|. If the list is modified once the |DP| is enabled, any previously ignored |DP| will be unignored, which will create an opportunity to successfully authenticate if it is now part of the updated whitelist (if not, the |DP| will be ignored as usual). The new authentication will happen after the local |DP| receives a participant announcement from the remote |DP| (the announcement period is configurable using the field :property:`DomainParticipantQos::discovery_config::participant_announcement_period`). Additionally, any previously trusted |DP| that becomes ignored as a result of a whitelist update will trigger an immediate key regeneration as long as key regeneration is enabled through the "dds.participant.trust_plugins.key_revision_max_history_depth" property. Interactions with ignore_participant API ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |CONNEXT| keeps the state about whitelist-based ignored |DPs| independent from the state about the |DPs| ignored through a call to the :property:`ignore_participant` method. Consequently, |DPs| ignored through the :property:`ignore_participant` method will remain ignored independently of the whitelist configuration. Still, whitelist-based ignored |DPs| still count towards the limit set by the :property:`ignored_entity_allocation` resource limit. Whitelist format ^^^^^^^^^^^^^^^^ The whitelist expects a set of subject names separated by the semicolon ';' character. In order to evaluate a |DP|'s subject name as a match against the list, one of the elements in the list must be evaluated as equal (based on the result of :property:`strcmp`) against the subject name returned by a call to :property:`DDS_DomainParticipant_get_discovered_participant_subject_name` for that |DP|'s :property:`InstanceHandle`. Whitelist elements are tokenized based on the semicolon ';' delimiter character. Any whitespace, including whitespace around the semicolons, will be considered part of the subject names. If any of the subject names in the list uses a semicolon, you need to escape this character by adding `\\` before it. Example: - ``C=US, ST=CA, O=Real Time Innovations\; CN=as one, CN=RTI ECDSA01\; (p256) PEER11, emailAddress=ecdsa01\;Peer\,11@rti.com`` CRL Expiration -------------- It is possible for a CRL to expire if it is still being used by the time the value of its ``Next Update`` field (see https://www.ietf.org/rfc/rfc5280.txt) is reached. When a CRL expires, the behavior is as follows: * For any |DPs| that are discovered **after** the CRL expires, if the |DP| Identity Certificate chain includes a certificate that is signed by the same CA that signed the CRL, then the |DP| will fail authentication and be rejected. It doesn't matter if the |DP|'s certificate does not appear in the CRL. If checking the CRL is required for checking the certificate's validity and the CRL is expired, then the |SP_BUILTIN| will assume that the certificate is invalid. * For any |DPs| that are discovered **before** the CRL expires, the |SP_BUILTIN| do nothing. The |SP_BUILTIN| do not retroactively reject any previously discovered |DP| whose Identity Certificate was signed by the same CA that signed the CRL. If a |DP| changes its Identity Certificate and checking the certificate's validity requires checking the expired CRL, then the |SP_BUILTIN| will reject the new certificate and continue using the old one without ceasing communication with the |DP|. If a |DP|'s Identity Certificate expires, then communication will still cease as described in :ref:`p2_core/authentication:Dynamic Certificate Expiration of Remote |DPs|`. Dynamic Certificate Renewal of a |DP| ------------------------------------- When you get notified in advance that your |IdentityCert| is about to expire (see :ref:`p2_core/authentication:Dynamic Certificate Expiration of the Local |DP|`), you may want to update your |IdentityCert| to have a later expiration date. Currently, the |SP_BUILTIN| supports updating the local |DP|'s |IdentityCert| (but not its Identity CA) without deleting and recreating the local |DP|. The |IdentityCert| is mutable in two ways, as long as the public key and subject name of the leaf certificate (the first certificate in the chain) remain the same and the digital signature algorithms are allowed according to :ref:`p2_core/cryptography:allowed_security_algorithms (domain_rule)` in the |GovernanceDoc|: * Changing the value of the :property:`dds.sec.auth.identity_certificate` property using the |DP| ``set_qos`` API. If the new |IdentityCert| is invalid, then ``set_qos`` will return DDS_RETCODE_ERROR. If the new |IdentityCert| violates the aforementioned mutability restrictions, then ``set_qos`` will return DDS_RETCODE_NOT_ALLOWED_BY_SECURITY. If ``set_qos`` returns a value other than DDS_RETCODE_OK, then the old |IdentityCert| will remain in use. * Leaving the value of the :property:`dds.sec.auth.identity_certificate` property unchanged and instead changing the contents of the actual |IdentityCert| file. The |SP_BUILTIN| enforce these changes as long as :value:`file:` is the prefix of the property value and :property:`files_poll_interval` is set to a value other than :value:`0`. In this case, the |RTI_SP_PRODUCT| use a separate thread dedicated to periodically checking if any of the following have occurred: * The |IdentityCert| file has been deleted. * The |IdentityCert| file modification timestamp has changed. * The MD5 hash of the |IdentityCert| file contents has changed. If any of those events have occurred, then the |SP_BUILTIN| will reload the |IdentityCert| file. If the reloaded |IdentityCert| is invalid or if the |IdentityCert| file is actually deleted, then the previous version of the |IdentityCert| will remain in use. If the reloaded |IdentityCert| does not have any changes in the section between ``-----BEGIN CERTIFICATE-----`` and ``-----END CERTIFICATE-----``, then no further action is taken. Once the |SP_BUILTIN| detect that you have successfully updated your |IdentityCert| to a different one, the |SP_BUILTIN| will propagate your new |IdentityCert| to other |DPs| via the |SecKeyExchangeCh|. The remote |DPs| will try to validate your new |IdentityCert|. If this validation is successful for a remote |DP|, then the remote |DP| will recognize the expiration time of your new |IdentityCert|, and communication with the remote |DP| will not stop when your old |IdentityCert| expires. If, for some reason, this validation is unsuccessful for a remote |DP|, then the remote |DP| will treat you as if you are still using your old |IdentityCert|, and you can expect communication with the remote |DP| to cease once your old |IdentityCert| expires. Notice that this |IdentityCert| renewal process does not involve a whole new handshake because since the public key is immutable, you do not have to prove again that you have the corresponding private key, and since the subject name is also immutable, you do not have to use a new |PermissionsDoc|. If you update your |IdentityCert| while you are in the middle of an authentication handshake with a remote |DP|, then you will finish the handshake using your old |IdentityCert| and then send your new |IdentityCert| to the remote |DP| once the |SecKeyExchangeCh| has been established with the remote |DP|. Properties for Configuring Authentication ========================================= :numref:`DDS Security Properties for Configuring Authentication` and :numref:`|RTI_SP_PRODUCT_HEADING| 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. This property is mutable through the |DP| ``set_qos`` API as long as the public key and subject name remain the same and the digital signature algorithms are allowed according to :ref:`p2_core/cryptography:allowed_security_algorithms (domain_rule)` in the |GovernanceDoc|. In addition, changes in the |IdentityCert| will be enforced if :property:`files_poll_interval` is set to a value other than :value:`0`. :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_PRODUCT| Properties for Configuring Authentication :name: |RTI_SP_PRODUCT_HEADING| 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, the |DP| creation will fail. A CRL that is missing the signature of the CA is considered invalid. If :property:`authentication.crl` is set to a valid CRL, 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`. A signed CRL that lists no certificates is considered valid. See :link_connext_dds_secure_gsg:`Hands-on 4 ` in the |SP_GSG| for example OpenSSL commands to generate a CRL. The document should be in PEM format. You may specify either the file name or the document contents. See the "Note regarding document format" above for details. This property is mutable through the |DP| ``set_qos`` API. In addition, changes in the CRL will be enforced if :property:`files_poll_interval` is set to a value other than :value:`0`. :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:`files_poll_interval` - :req:`Optional` The interval at which the |RTI_SP_PRODUCT| check for any changes in the files it tracks. The |RTI_SP_PRODUCT| can currently track CRL, |IdentityCert|, and pre-shared key seed files, provided that each of them is configured with the prefix :value:`file:` and is populated with valid data. A :property:`files_poll_interval` value of :value:`0` will disable tracking of any files. To track all the files, the |RTI_SP_PRODUCT| will create a separate thread dedicated to periodically checking if the contents of any of the files have changed. The :property:`files_poll_interval` property configures the length of this interval in seconds. If the contents have changed to other valid data, then the |RTI_SP_PRODUCT| will use this new data. In the context of the CRL file change, the newly revoked |DPs| will be removed. If the file is deleted or the contents have changed to invalid content, then the |RTI_SP_PRODUCT| will continue using the previous data. This property is not mutable. :type:`Integer`: :value:`[0, INT_MAX]` Default: :value:`5` * - :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_BUILTIN| 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_BUILTIN| 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_BUILTIN| 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.enable_discovery_subject_name_propagation` - :req:`Optional` If :value:`TRUE`, the Subject Name of the local |DP|'s |IdentityCert| will be propagated during discovery. This allows a remote |DP| to get the local |IdentityCert|'s subject name before completing authentication. If :value:`FALSE`, the Subject Name of the local |DP|'s |IdentityCert| will not be propagated during discovery. The consequence is that if a remote |DP| calls ``discovered_participant_subject_name`` with the local |DP|'s `InstanceHandle_t` and the remote |DP| has not yet authenticated the local |DP|, then this function will return DDS_RETCODE_NO_DATA. See :property:`discovered_participant_subject_name` in :ref:`p3_advanced/apis:Relevant functions`. :type:`Boolean`. Default: :value:`FALSE` * - :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 that the |DP| uses and supports for RSA digital signatures. This property has three possible values: * :value:`AUTO`: Detect the RSA padding from the |DPs|'s |IdentityCert|. The |RTI_SP_PRODUCT| for OpenSSL supports RSA standard (`RSA_PKCS1_PADDING`) and PSS (`RSA_PKCS1_PSS_PADDING`) padding |IdentityCerts|. The |RTI_SP_PRODUCT| 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 |SEC_SPEC|. * :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. The ``message_auth.supported_mask`` and ``trust_chain.supported_mask`` bits of the ``PID_PARTICIPANT_SECURITY_DIGITAL_SIGNATURE_ALGO`` PID (see :ref:`p2_core/cryptography:Discovery of a remote Secure Entity`) are not set. :type:`Enum`. :value:`AUTO`, :value:`TRUE`, :value:`FALSE`, Default: :value:`TRUE` * - :property:`authentication.participant_discovery_protection_key` - :req:`Optional` **<< DEPRECATED >>** .. attention:: This feature is deprecated and will be removed in the future. Please use |PSKProtection| (described in :ref:`p3_advanced/pre-shared_key:|PSKProtection|`) instead. In this release, this feature remains functional with intention to use only when interoperability with legacy systems is necessary. This description is provided for high-level reference only. For detailed information, please refer to |RTI_SP_PRODUCT| 6.1.2 documentation. 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 other |DPs| unless they are running |SP_BUILTIN| using the same configuration for this property. 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. :type:`String`. 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_BUILTIN| will enable additional digital signature and key establishment algorithms that are not part of the |SEC_SPEC| (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 |RTI_SP_PRODUCT| 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 |RTI_SP_PRODUCT| 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 |RTI_SP_PRODUCT| 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 |RTI_SP_PRODUCT| library, your application must not make any calls to the crypto library once the |RTI_SP_PRODUCT| 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 |RTI_SP_PRODUCT| or TLS transport), and do it before unloading the |RTI_SP_PRODUCT| 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_BUILTIN|, 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`, and :ref:`p2_core/authentication:Guidelines for Minimizing Authentication Negotiation Times`. A |DP| should set its own :property:`authentication_timeout` to be shorter than the :property:`participant_liveliness_lease_duration` (in the |DP|'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 |DP|. For more information, please see :ref:`p2_core/authentication:Re-Authentication`, and :ref:`p2_core/authentication:Guidelines for Minimizing Authentication Negotiation Times`. :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. For more information, please see :ref:`p2_core/authentication:Re-Authentication`, and :ref:`p2_core/authentication:Guidelines for Minimizing Authentication Negotiation Times`. :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` * - :property:`certificate_expiration_advance_notice_reminder_period.sec` - :req:`Optional` Once it's time to start the advance notifications of the local |DP|'s impending certificate expiration, this property controls how often these notifications happen. Notifications will happen at this period until the certificate finally expires or the certificate gets updated such that its expiration date is beyond the current time plus the advance notice duration. For more information, please see :ref:`p2_core/authentication:Dynamic Certificate Expiration of the Local |DP|`. :type:`Integer`: :value:`[1, INT_MAX]`. Default: :value:`1` * - :property:`subject_name_whitelist` - :req:`Optional` Configures a (semicolon-separated) whitelist of subject names for authenticated |DPs|. If set (even if empty), authenticated |DPs| will be allowed into the system only if their subject name matches one of the ones in the whitelist. For more information, please see :ref:`p2_core/authentication:Dynamic Certificate Revocation of Remote |DPs| through Whitelisting`. :type:`String`. Default: :value:`NULL` 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. Setting this value to :value:`TRUE` is required for allowing discovery of a |DP| (which may successfully complete authentication) with the same GUID as an existing |DP| (which may not be authenticated if :xmltag:`allow_unauthenticated_participants` is set to :xmlval:`TRUE`). :type:`Boolean`. Default: :value:`FALSE`