-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Chain of trust issues with a single CA certificate #282
Comments
These are the slides from the meeting. |
This is a shell script that demonstrates the problem. The script is set up to use Foxy because that is what we use internally but the problem still exists in Rolling. Run the script in an empty directory. It will:
Shell script. (This is a .txt file because Github won't accept .sh.) |
@ruffsl asked for a mention. |
Hey @amrc-benmorrow , thanks for opening the ticket! So I looked into this a bit deeper, and what I suspect is that this issue has less to do with sros2 than it does with DDS vendor compliance. SpecificationI’ll start first by citing the current DDS Security Specification, where the following section excerpts here are of particular relevance:
From section 9.4.1.1, we can gather that the chosen Permissions CA is to be used to sign Domain Governance and Domain Permissions documents, and is not delegatable. Consequently, it appears the specification leaves no room for the signing of such documents to be delegated beyond that certificate authority, regardless of any chains of trust in public certificates. Similarly, from section 9.3.1.1, we can also gather that the chosen Identity CA is to be used to issue Identity Certificates, and is not delegatable. Consequently, it again appears the specification leaves no room for the issuing of such certificates to be delegated beyond that certificate authority, regardless of any chains of trust in public certificates. Under the current specification, we can conclude that combining the roles of such Permissions and Identity into a single CA is admissible for at least two reasons. First, that the role of either CA is never defined as being mutually exclusive. Although admittedly the omission of a "shall not" clause remains a rather weak argument in the contexts of complex protocol specifications, it can also be justified by the explicit disregard of how either CA certificate is itself signed. As a counter example, let's assume the following axioms about the specification are true:
Consequently, validating delegated signatures would inherently necessitate validating a chain of trust for issued certificates. However, given the specification does not restrict the issuing identities of either the Permissions or Identity CA, we can assume the chain of trust for such issuing identities to be arbitrary. Without loss of generality, we can assume such issuing identities to be a single self-signed root level CA, as would be common among corporate infrastructures. However, the mere possibility of this permissible chain of trust subsequently contradicts our last two axioms, given that such a trusted root level issuer CA would allow valid chain of trust to be built when validating either Identity Certificates issued by the Permissions CA, or when validating delegated Identity CA signatures embedded in Governance and Permissions documents. Thus it stands to reason that 1) the delegation of the Permissions and Identity CA role signature authority remains inadmissible, while 2) the validity of Permissions and Identity CA signatures is evaluated regardless of the issuer of such CA certificates. ComplianceAt present, I believe the root cause of the discussed chain of trust exploit stems from a non-compliant implementation of permission document verification used by some DDS vendors. Specifically, an improper use of the OpenSSL PKCS7_verify function used to validate S/MIME signatures. Consulting the OpenSSL documentation for PKCS7_verify:
We can see this function takes 6 arguments, including 1) the PKCS#7 signedData structure to be verified, 2) the set of certificates in which to search for signer's certificates, 3) x509 store that may be NULL or point to the trusted certificate store to use for chain verification, 4) input buffer for signed data in question if content is detached, 5) output buffer of signed content read, and 6) optional set of flags used to modify verification behavior. For reference, we can see the use of this function in both Fast-DDS and Cyclonedds:
Note that for these DDS implementations: while the set of certificates in which to search for signer's certificates is set to null, only the store of trusted certificates to use for chain verification is provided, with just the PKCS7_TEXT flag being set. Thus, the resulting verification is prone to admissible delegation of role signature authority given the inclusion of the CA within the trusted certificate store allows for any certificate issued by that CA to pass the signature verification by proxy, due to the nature of issuing-certificate chain of trust. Furthermore, this chain of trust could then also be extended, given p7 may contain extra untrusted CA certificates that may be used for chain building. SolutionTo correct existing vendor implementations and remain in compliance with the DDS Security Specification, I would recommend the following:
However, it is still unclear if this change would introduce other side effects. E.g. My guess is that verification of signatures using the chain of trust primitives also inherently checks the period of validity for each certificate used in such a search with regards to the current date and system time. With the use of PKCS7_NOVERIFY and thus no chain verification, I’m unsure if the period of certificates would still be validated. However, given the specification disregards the issuer for such Identity and Permissions CAs, and that they are allowed to be self signed, the period of validity for the public certificate of such CAs may be well inconsequential as far as the specification is concerned. TestingUpon testing the following DDS vendor implementations supported by ROS 2 using the provided minimal viable example, the table below depicts which implementations are susceptible to the discussed chain of trust exploit:
Future workIt may be worth auditing how such x509 trust stores are constructed, and where else they are used in existing DDS implementations. E.g. could the same trust store also be used for establishing a chain of trust in validating identity certificates, or could the Permission CA be inadvertently included in another x509 trust store, again defeating any separation of concerns between CA roles, even when separate CAs are intentionally deployed? |
Problem ------- Assume a usage of DDS Security where the same CA is used for both permissions and identity. The certificates issued to particpants allow them to sign documents. Assume the participant generates a permissions file and then signs it. Chain verification causes verification attempts to succeed since the signing certificate, i.e., the participant's certificate, can be chained back to the permission CA's certificate (which is also the identity CA). This problem was identified in ros2/sros2#282. Solution -------- Implement the suggestion in ros2/sros2#282. Specifically, use PKCS7_NOINTERN to not accept any signatures in the signed document. This, in turn, requires the use of the `certs` parameter to `PKCS7_verify`. PKCS7_NOVERIFY is used since the permissions CA certificate will not be chain verified.
This issue has been mentioned on ROS Discourse. There might be relevant details there: https://discourse.ros.org/t/ros-2-tsc-meeting-minutes-2023-01-19/29423/1 |
As stated in: OpenDDS/OpenDDS#3992 (comment) "Implement the suggestion in ros2/sros2#282. Specifically, use PKCS7_NOINTERN to not accept any signatures in the signed document. This, in turn, requires the use of the certs parameter to PKCS7_verify. PKCS7_NOVERIFY is used since the permissions CA certificate will not be chain verified." Fixes: eclipse-cyclonedds#1546 Related to: ros2/sros2#282 Signed-off-by: James Pace <[email protected]>
As stated in: OpenDDS/OpenDDS#3992 (comment) "Implement the suggestion in ros2/sros2#282. Specifically, use PKCS7_NOINTERN to not accept any signatures in the signed document. This, in turn, requires the use of the certs parameter to PKCS7_verify. PKCS7_NOVERIFY is used since the permissions CA certificate will not be chain verified." Fixes: eclipse-cyclonedds#1546 Related to: ros2/sros2#282 Signed-off-by: James Pace <[email protected]>
As stated in: OpenDDS/OpenDDS#3992 (comment) "Implement the suggestion in ros2/sros2#282. Specifically, use PKCS7_NOINTERN to not accept any signatures in the signed document. This, in turn, requires the use of the certs parameter to PKCS7_verify. PKCS7_NOVERIFY is used since the permissions CA certificate will not be chain verified." Fixes: #1546 Related to: ros2/sros2#282 Signed-off-by: James Pace <[email protected]>
As stated in: OpenDDS/OpenDDS#3992 (comment) "Implement the suggestion in ros2/sros2#282. Specifically, use PKCS7_NOINTERN to not accept any signatures in the signed document. This, in turn, requires the use of the certs parameter to PKCS7_verify. PKCS7_NOVERIFY is used since the permissions CA certificate will not be chain verified." Fixes: eclipse-cyclonedds#1546 Related to: ros2/sros2#282 Signed-off-by: James Pace <[email protected]>
Currently the security keystores created by
ros2 security
use a single CA symlinked as both Identity CA and Permissions CA. This opens a security hole where a malicious node can sign its own permissions document:permissions.xml
and signs it with its own enclave certificate and private key.I don't believe it is possible to work around this with certificate flags; the enclave certificate must have the
digitalSignature
flag in order to be able to participate in Secure DDS. The solution is to separate the two CA roles into different certificates.The text was updated successfully, but these errors were encountered: