.. include:: vars.rst .. _section-sec-HO4: Hands-On 4: Generating Your Own Certificates Using OpenSSL ========================================================== In this Hands-On, you will take control of your project's keys and certificates. This way, you will not need to rely on the example artifacts provided with |CONNEXT| to secure your applications. We will start by generating a self-signed Identity CA, which will issue the |IdentityCerts| for Alice and Bob. This will require us to set up a minimal security infrastructure first. Then we will generate a new Permissions CA that will sign the |GovernanceFile| and all the |PermissionsFiles|. After each certificate generation, we will refer to the modifications needed to make your project load the new artifacts. We will show examples for ECDSA and RSA as the public-key algorithm to generate the certificates. Note that you can use any public-key algorithm listed in :link_sec_um:`Supported Cryptographic Algorithms in the Security Plugins User's Manual `. .. note:: We will use the **OpenSSL CLI** to perform the security operations in the generation of the security artifacts. Make sure to include in the path your OpenSSL binary directory [#openssl_lm_path]_. The installation process is described in the :link_sec_install_guide:`RTI Security Plugins Installation Guide `. Note that the |SP| do not depend on OpenSSL to generate these artifacts; you can use the security toolkit of your choice. .. _section-sec-HO4-preliminary-steps: Preliminary Steps ----------------- Setting up a security infrastructure requires some preliminary configuration. We will cover a minimal setup here. #. If you followed the steps in :ref:`section-sec-HO1`, you should have an OpenSSL configuration file named :file:`cert/ecdsa01/ca/ecdsa01RootCa.cnf`. Make two copies of this file and call them :file:`pmiIdentityCa.cnf` and :file:`pmiPermissionsCa.cnf`. To better organize your project, save these copies in a new directory called :file:`cert/pmi/ca`, along with a new folder called :file:`newCerts`: .. tabs:: .. group-tab:: Linux .. code-block:: console $ mkdir -p cert/pmi/ca/newCerts $ cp cert/ecdsa01/ca/ecdsa01RootCa.cnf cert/pmi/ca/pmiIdentityCa.cnf $ cp cert/ecdsa01/ca/ecdsa01RootCa.cnf cert/pmi/ca/pmiPermissionsCa.cnf .. group-tab:: macOS .. code-block:: console $ mkdir -p cert/pmi/ca/newCerts $ cp cert/ecdsa01/ca/ecdsa01RootCa.cnf cert/pmi/ca/pmiIdentityCa.cnf $ cp cert/ecdsa01/ca/ecdsa01RootCa.cnf cert/pmi/ca/pmiPermissionsCa.cnf .. group-tab:: Windows .. code-block:: doscon > mkdir cert\pmi\ca\newCerts > copy cert\ecdsa01\ca\ecdsa01RootCa.cnf cert\pmi\ca\pmiIdentityCa.cnf 1 file(s) copied. > copy cert\ecdsa01\ca\ecdsa01RootCa.cnf cert\pmi\ca\pmiPermissionsCa.cnf 1 file(s) copied. .. hint:: If you want to use RSA as your public-key algorithm, you may want to copy the homologous example files from the :file:`cert/rsa01/` directory. #. Modify :file:`pmiIdentityCa.cnf` to redefine the ``name`` variable. Note that this configuration file uses this variable to derive some filenames, such as those used in the next section: .. code-block:: openssl ... # Variables defining this CA name = pmiIdentityCa # Name desc = # Description ... .. _section-sec-HO4-initialize-openssl-ca-database: Initialize the OpenSSL CA Database ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When using a CA to perform an operation, OpenSSL relies on special database files to keep track of the issued certificates, serial numbers, revoked certificates, etc. We need to create these database files to be able to use the :command:`openssl ca` command: .. tabs:: .. group-tab:: Linux .. code-block:: console $ mkdir cert/pmi/ca/database $ touch cert/pmi/ca/database/pmiIdentityCaIndex $ echo 01 > cert/pmi/ca/database/pmiIdentityCaSerial .. group-tab:: macOS .. code-block:: console $ mkdir cert/pmi/ca/database $ touch cert/pmi/ca/database/pmiIdentityCaIndex $ echo 01 > cert/pmi/ca/database/pmiIdentityCaSerial .. group-tab:: Windows .. code-block:: doscon > mkdir cert\pmi\ca\database > type nul > cert\pmi\ca\database\pmiIdentityCaIndex > echo 01> cert\pmi\ca\database\pmiIdentityCaSerial Limit the Access of the CA's Private Key ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ It is also a good practice to store the CA's private key in a separate directory with more restrictive access rights, so only you can sign certificates. .. tabs:: .. group-tab:: Linux .. code-block:: console $ mkdir cert/pmi/ca/private $ chmod 700 cert/pmi/ca/private .. group-tab:: macOS .. code-block:: console $ mkdir cert/pmi/ca/private $ chmod 700 cert/pmi/ca/private .. group-tab:: Windows .. code-block:: doscon > mkdir cert\pmi\ca\private > icacls cert\pmi\ca\private /t /inheritance:d processed file: cert\pmi\ca\private Successfully processed 1 files; Failed processing 0 files > icacls cert\pmi\ca\private /t /remove Administrator "Authenticated Users" BUILTIN Everyone System Users processed file: cert\pmi\ca\private Successfully processed 1 files; Failed processing 0 files > icacls cert\pmi\ca\private /grant %USERNAME%:F processed file: cert\pmi\ca\private Successfully processed 1 files; Failed processing 0 files .. _section-sec-HO4-generating-new-identity-ca: Generating a New Identity CA ---------------------------- #. Modify :file:`cert/pmi/ca/pmiIdentityCa.cnf` and specify the fields in the ``req_distinguished_name`` section. This information will be incorporated into your certificate: .. code-block:: openssl ... [ req_distinguished_name ] countryName = US stateOrProvinceName = CA localityName = Santa Clara 0.organizationName = Patient Monitoring Innovations commonName = PMI Identity CA emailAddress = identityca@pmi.com ... #. Use the OpenSSL CLI to generate a self-signed certificate using the Identity CA's configuration. Run the following command from the :file:`cert/pmi` directory: .. tabs:: .. group-tab:: ECDSA .. code-block:: text openssl req -nodes -x509 -days 1825 -text -sha256 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -keyout ca/private/pmiIdentityCaKey.pem -out ca/pmiIdentityCaCert.pem -config ca/pmiIdentityCa.cnf .. group-tab:: RSA .. code-block:: text openssl req -nodes -x509 -days 1825 -text -sha256 -newkey rsa:2048 -keyout ca/private/pmiIdentityCaKey.pem -out ca/pmiIdentityCaCert.pem -config ca/pmiIdentityCa.cnf This will produce a new private key, ``pmiIdentityCaKey.pem`` in the ``cert/pmi/ca/private`` directory, and a new certificate, ``pmiIdentityCaCert.pem``, in the ``cert/pmi/ca`` directory. This certificate will be valid for 1825 days (5 years) starting today. .. _section-sec-HO4-specifying-new-identity-ca-cert-qos-profiles: Specifying the New Identity CA Certificate in QoS Profiles ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Modify :file:`USER_QOS_PROFILES.xml` to make your |DPs| load the certificate of the new Identity CA: .. code-block:: xml ... dds.sec.auth.identity_ca file:./cert/pmi/ca/pmiIdentityCaCert.pem ... .. _section-sec-HO4-generating-identity-certificates: Generating Identity Certificates -------------------------------- As explained in :ref:`section-sec-intro`, |IdentityCerts| are verified against the Identity CA when authenticating remote |DPs|. Therefore, in the simplest scenario, it is the Identity CA that is responsible for issuing |IdentityCerts|. [#]_ We will create a certificate signing request (CSR) for Alice. Then we will use the new Identity CA to issue the certificate requested by the CSR. #. Add the information you want to include in Alice's certificate in a file called :file:`pmiAlice.cnf`. Save this file in a new directory called :file:`cert/pmi/identities`. You may want to use the following contents as a reference: .. code-block:: openssl :caption: Sample contents of pmiAlice.cnf prompt = no distinguished_name = req_distinguished_name [ req_distinguished_name ] countryName = US stateOrProvinceName = CA localityName = Santa Clara organizationName = Patient Monitoring Innovations emailAddress = alice@pmi.com commonName = Alice You are free to modify any field except ``countryName``, ``stateOrProvinceName``, and ``organizationName``. These fields must match the ones of the Identity CA; otherwise it will refuse to issue the requested certificate (note that a ``commonName`` is also required). These requirements are specified in :file:`pmiIdentityCa.cnf`, in the ``policy_match`` section. |br| |br| #. Generate Alice's key and CSR. Run the following command from the :file:`cert/pmi` directory: .. tabs:: .. group-tab:: ECDSA .. code-block:: text openssl req -nodes -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -config identities/pmiAlice.cnf -keyout identities/pmiAliceKey.pem -out identities/pmiAlice.csr .. group-tab:: RSA .. code-block:: text openssl req -nodes -new -newkey rsa:2048 -config identities/pmiAlice.cnf -keyout identities/pmiAliceKey.pem -out identities/pmiAlice.csr This will produce an RSA private key, :file:`pmiAliceKey.pem`, and a CSR based on that key, :file:`pmiAlice.csr`. Since CSRs have all the information and cryptographic material that a CA needs to issue a certificate, Alice's private key must never be known to anyone but her. |br| |br| #. Use the new Identity CA's certificate and private key to issue Alice's |IdentityCert|. Run the following command from the :file:`cert/pmi` directory: .. code-block:: text openssl ca -config ca/pmiIdentityCa.cnf -days 730 -in identities/pmiAlice.csr -out identities/pmiAliceCert.pem #. A dialog will prompt you to confirm the certificate signature. After your confirmation, the Identity CA will issue Alice's public certificate, :file:`pmiAliceCert.pem`, which will be valid for 730 days (2 years) starting today. .. [#] Depending on your use case, the |IdentityCerts| may be issued by an intermediate CA in your PKI instead. For further information, see :link_sec_um:`Public Key Infrastructure (PKI) in the Security Plugins User's Manual `. .. _section-sec-HO4-specifying-new-identity-certificates-your-qos-profiles: Specifying the New Identity Certificates to Your QoS Profiles ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Modify :file:`USER_QOS_PROFILES.xml` to make your publisher application load the new pair of certificate and private key: .. code-block:: xml ... dds.sec.auth.identity_certificate file:./cert/pmi/identities/pmiAliceCert.pem dds.sec.auth.private_key file:./cert/pmi/identities/pmiAliceKey.pem ... .. _section-sec-HO4-updating-permissions-files-new-credentials: Updating Permissions Files with New Credentials ----------------------------------------------- As explained in :ref:`section-sec-HO3-binding-permissions-file`, grants in a |PermissionsFile| are bound to |DP| identities. We will update Alice's |PermissionsFile| with the same information we included in Alice's |IdentityCert|. #. To meet the format requirements of the |PermissionsFile|, you may want to check your certificate's information with the following command: .. tabs:: .. group-tab:: Linux .. code-block:: console :emphasize-lines: 11 $ openssl x509 -in cert/pmi/identities/pmiAliceCert.pem -text -noout Certificate: Data: Version: 1 (0x0) Serial Number: 1 (0x1) Signature Algorithm: ecdsa-with-SHA256 Issuer: C=US, ST=CA, L=Santa Clara, O=Patient Monitoring Innovations, CN=PMI Identity CA, emailAddress=identityca@pmi.com Validity Not Before: Feb 7 15:37:09 2021 GMT Not After : Feb 7 15:37:09 2023 GMT Subject: C=US, ST=CA, O=Patient Monitoring Innovations, CN=Alice, emailAddress=alice@pmi.com Subject Public Key Info: ... .. group-tab:: macOS .. code-block:: console :emphasize-lines: 11 $ openssl x509 -in cert/pmi/identities/pmiAliceCert.pem -text -noout Certificate: Data: Version: 1 (0x0) Serial Number: 1 (0x1) Signature Algorithm: ecdsa-with-SHA256 Issuer: C=US, ST=CA, L=Santa Clara, O=Patient Monitoring Innovations, CN=PMI Identity CA, emailAddress=identityca@pmi.com Validity Not Before: Feb 7 15:37:09 2021 GMT Not After : Feb 7 15:37:09 2023 GMT Subject: C=US, ST=CA, O=Patient Monitoring Innovations, CN=Alice, emailAddress=alice@pmi.com Subject Public Key Info: ... .. group-tab:: Windows .. code-block:: doscon :emphasize-lines: 11 > openssl x509 -in cert\pmi\identities\pmiAliceCert.pem -text -noout Certificate: Data: Version: 1 (0x0) Serial Number: 1 (0x1) Signature Algorithm: ecdsa-with-SHA256 Issuer: C=US, ST=CA, L=Santa Clara, O=Patient Monitoring Innovations, CN=PMI Identity CA, emailAddress=identityca@pmi.com Validity Not Before: Feb 7 15:37:09 2021 GMT Not After : Feb 7 15:37:09 2023 GMT Subject: C=US, ST=CA, O=Patient Monitoring Innovations, CN=Alice, emailAddress=alice@pmi.com Subject Public Key Info: ... #. Modify the :xmltag:`subject_name` in the |PermissionsFile|, :file:`xml/pmiPermissionsAlice.xml`, to match the certificate's subject. |br| |br| #. You may also want to update the :xmltag:`validity` tag with the information from the |IdentityCert|. Note that you are not required to have the same validity dates in the |PermissionsFile| and the |IdentityCert| (upon creation, your |DP| will independently verify that the |IdentityCert| and the grant in your |PermissionsFile| are valid for the current date). If you decide to update the :xmltag:`validity` tag, pay attention to the date/time format. .. code-block:: xml ... C=US, ST=CA, O=Patient Monitoring Innovations, CN=Alice, emailAddress=alice@pmi.com 2019-11-25T16:17:07 2021-11-24T16:17:07 ... .. _section-sec-HO4-generating-new-permissions-ca: Generating a New Permissions CA ------------------------------- .. note:: * The Identity CA and Permissions CA may be the same, depending on your use case. * This section is analogous to :ref:`section-sec-HO4-generating-new-identity-ca`. #. Modify :file:`cert/pmi/ca/pmiPermissionsCa.cnf` and specify the fields under the :file:`req_distinguished_name` section. This information will be incorporated into your certificate: .. code-block:: openssl ... [ req_distinguished_name ] countryName = US stateOrProvinceName = CA localityName = Santa Clara 0.organizationName = Patient Monitoring Innovations commonName = PMI Permissions CA emailAddress = permissionsca@pmi.com ... #. Use the OpenSSL CLI to generate a self-signed certificate using the Permissions CA's configuration. Run the following command from the :file:`cert/pmi` directory: .. tabs:: .. group-tab:: ECDSA .. code-block:: text openssl req -nodes -x509 -days 1825 -text -sha256 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -keyout ca/private/pmiPermissionsCaKey.pem -out ca/pmiPermissionsCaCert.pem -config ca/pmiPermissionsCa.cnf .. group-tab:: RSA .. code-block:: text openssl req -nodes -x509 -days 1825 -text -sha256 -newkey rsa:2048 -keyout ca/private/pmiPermissionsCaKey.pem -out ca/pmiPermissionsCaCert.pem -config ca/pmiPermissionsCa.cnf This will produce a new private key, :file:`pmiPermissionsCaKey.pem` in the :file:`cert/pmi/ca/private` directory, and a new certificate, :file:`pmiPermissionsCaCert.pem`, in the :file:`cert/pmi/ca` directory. This certificate will be valid for 1825 days (5 years) starting today. .. _section-sec-HO4-specifying-new-permissions-ca-certificates-qos-profiles: Specifying the New Permissions CA Certificate in QoS Profiles ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Modify :file:`USER_QOS_PROFILES.xml` to make your |DPs| load the certificate of the new Permissions CA: .. code-block:: xml ... dds.sec.access.permissions_ca file:./cert/pmi/ca/pmiPermissionsCaCert.pem ... .. _section-sec-HO4-signing-governance-permissions-files: Signing the Governance and Permissions Files -------------------------------------------- .. note:: This section was covered in :ref:`section-sec-HO2-signing-governance-file` and :ref:`section-sec-HO3-signing-permissions-files`. We will use the Permissions CA's certificate and key that we generated to sign the Governance and Permissions Files that we composed in previous Hands-On sections. #. Run the command below to create the signed |GovernanceFile| (with PKCS#7 format) named :file:`xml/signed/pmiSigned_pmiGovernance.p7s`: .. code-block:: text openssl smime -sign -in xml/pmiGovernance.xml -text -out xml/signed/pmiSigned_pmiGovernance.p7s -signer cert/pmi/ca/pmiPermissionsCaCert.pem -inkey cert/pmi/ca/private/pmiPermissionsCaKey.pem #. Run the command below to create the signed |PermissionsFile| (with PKCS#7 format) named :file:`xml/signed/pmiSigned_pmiPermissionsAlice.p7s`: .. code-block:: text openssl smime -sign -in xml/pmiPermissionsAlice.xml -text -out xml/signed/pmiSigned_pmiPermissionsAlice.p7s -signer cert/pmi/ca/pmiPermissionsCaCert.pem -inkey cert/pmi/ca/private/pmiPermissionsCaKey.pem .. _section-sec-HO4-specifying-new-governance-permissions-files-your-qos-profiles: Specifying the New Governance and Permissions Files in Your QoS Profiles ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Lastly, update :file:`USER_QOS_PROFILES.xml` so that your |DPs| will load the Governance and Permissions Files signed by your Permissions CA: .. code-block:: xml ... dds.sec.access.governance file:./xml/signed/pmiSigned_pmiGovernance.p7s dds.sec.access.permissions file:./xml/signed/pmiSigned_pmiPermissionsAlice.p7s ... .. _section-sec-HO4-further-exercises: Further Exercises ----------------- At this point, you have control of the keys and certificates used in your project. Congratulations! In the previous steps, we have focused on updating your publisher application, Alice, with a new identity and matching permissions. Now, we will update Bob's identity and permissions accordingly. #. Create an identity for your subscriber application, Bob, as described in :ref:`section-sec-HO4-generating-identity-certificates`. After this step, Bob's QoS profile in :file:`USER_QOS_PROFILES.xml` should load his new |IdentityCert|, :file:`pmiBob.pem`, and private key, :file:`pmiBobKey.pem`. #. Update Bob's |PermissionsFile|, :file:`pmiPermissionsBob.xml`, to match his new credentials (see :ref:`section-sec-HO4-updating-permissions-files-new-credentials`). #. Finally, sign Bob's |PermissionsFile| with your new Permissions CA, as explained in :ref:`section-sec-HO4-signing-governance-permissions-files`. After this step, Bob's QoS profile in :file:`USER_QOS_PROFILES.xml` should load the signed version of his new |PermissionsFile|, :file:`pmiSigned_pmiPermissionsBob.p7s`. Now, run your publisher and subscriber using |DOMAIN| *1* (specified with the :command:`-d` option in the command line). You should see communication. .. only:: cpp98 .. tabs:: .. group-tab:: Linux Publisher: .. literalinclude:: snippets/snippets.py :language: console :start-after: snippet_console_publisher_cpp98_d1_ok :end-before: """ Subscriber: .. literalinclude:: snippets/snippets.py :language: console :start-after: snippet_console_subscriber_cpp98_d1_ok :end-before: """ .. group-tab:: macOS Publisher: .. literalinclude:: snippets/snippets.py :language: console :start-after: snippet_console_publisher_cpp98_d1_ok :end-before: """ Subscriber: .. literalinclude:: snippets/snippets.py :language: console :start-after: snippet_console_subscriber_cpp98_d1_ok :end-before: """ .. group-tab:: Windows Publisher: .. literalinclude:: snippets/snippets.py :language: doscon :start-after: snippet_doscon_publisher_cpp98_d1_ok :end-before: """ Subscriber: .. literalinclude:: snippets/snippets.py :language: doscon :start-after: snippet_doscon_subscriber_cpp98_d1_ok :end-before: """ .. only:: cpp11 .. tabs:: .. group-tab:: Linux Publisher: .. literalinclude:: snippets/snippets.py :language: console :start-after: snippet_console_publisher_cpp11_d1_ok :end-before: """ Subscriber: .. literalinclude:: snippets/snippets.py :language: console :start-after: snippet_console_subscriber_cpp11_d1_ok :end-before: """ .. group-tab:: macOS Publisher: .. literalinclude:: snippets/snippets.py :language: console :start-after: snippet_console_publisher_cpp11_d1_ok :end-before: """ Subscriber: .. literalinclude:: snippets/snippets.py :language: console :start-after: snippet_console_subscriber_cpp11_d1_ok :end-before: """ .. group-tab:: Windows Publisher: .. literalinclude:: snippets/snippets.py :language: doscon :start-after: snippet_doscon_publisher_cpp11_d1_ok :end-before: """ Subscriber: .. literalinclude:: snippets/snippets.py :language: doscon :start-after: snippet_doscon_subscriber_cpp11_d1_ok :end-before: """ .. [#openssl_lm_path] In the license-managed version (with "``lm``" in the bundle name), OpenSSL is installed automatically when you install the |CONNEXT| host bundle. After installation, OpenSSL will be in ``/third_party/openssl-``. .. _section-sec-HO4-troubleshooting: Troubleshooting --------------- * When I run my subscriber, I get the following error: .. code-block:: text [CREATE Participant] RTI_Security_CertHelper_loadPrivateKey:private_key is not encrypted, yet password is supplied. Aborting participant creation due to inconsistent configuration. In previous Hands-On sections, your subscriber used the :file:`ecdsa01Peer02Key.pem` private key, which is password protected. If you did not specify a password for :file:`BobKey.pem`, make sure you remove the :property:`dds.sec.auth.password` property from Bob's profile in :file:`USER_QOS_PROFILES.xml`. For further troubleshooting, see :ref:`Troubleshooting in Hands-On 3 `.