Skip to content

Commit 0aa858b

Browse files
gregersryggjfischer-no
authored andcommitted
scripts: add cert_tool.py
This is a script to generate elliptic curve private keys, create a certificate signing request for a private key, create root CA and subordinate CA certificates and sign a certificate signing request with a CA. The keys are not encrypted with a password or any other protection. It is strictly for testing and evaluation purposes. It is only tested with Azure IoT Hub and Azure DPS, but doesn't include anything specific for Azure, so in theory it should work with other cloud vendors. usage: cert_tool.py [-h] {client_key,root_ca,sub_ca,csr,sign,sign_root} All file-related arguments have default values. Client key/csr/cert is stored in ./certs folder and CA keys/certs are stored in ./ca. Signed-off-by: Gregers Gram Rygg <[email protected]>
1 parent ebf77ed commit 0aa858b

File tree

4 files changed

+625
-38
lines changed

4 files changed

+625
-38
lines changed

doc/nrf/libraries/networking/azure_iot_hub.rst

Lines changed: 262 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,249 @@ For information on how to set up creating an Azure IoT Hub instance using the Az
9898

9999
.. rst-class:: numbered-step
100100

101+
.. _azure_generating_and_provisioning_certificates:
102+
.. _azure_generating_certificates:
103+
104+
Generating certificates
105+
=======================
106+
107+
The connection to Azure IoT Hub with MQTT is secured using TLS.
108+
To creat the device certificate you'll need a Certificate Authority (CA) certificate and private key that is used to sign all of your client certificates.
109+
The CA certificate is uploaded to Azure IoT Hub, so Azure can verify that the device certificate is signed by your CA.
110+
If you do not have a CA certificate, you can purchase one or make a self-signed test CA certificate for testing purposes.
111+
112+
To help generate test CA certificates and handling the device keys and certificates, we've provided a Python script.
113+
You can find this script here: :file:`nrf/scripts/cert_tool.py`.
114+
Either call the script relative from the current working directory, or add it to PATH.
115+
For the rest of this document we'll refer to this script as ``cert_tool.py`` without using the directory name.
116+
117+
.. note::
118+
All of the actions for ``cert_tool.py`` have default values for the input and output file names to make this simple.
119+
See what arguments are available by running adding the ``--help`` argument to the script.
120+
121+
Generate test CA certificates
122+
+++++++++++++++++++++++++++++
123+
124+
* To generate the root CA certificate, use the following command:
125+
126+
.. code-block:: console
127+
128+
cert_tool.py root_ca
129+
130+
This command generates a self-signed root CA certificate and private key and saves them to the files :file:`ca/root-ca-cert.pem` and :file:`ca/root-ca-key.pem`.
131+
132+
* To generate the subordinate CA certificate, use the following command:
133+
134+
.. code-block:: console
135+
136+
cert_tool.py sub_ca
137+
138+
This command generates a subordinate CA certificate (signed by the root CA) and private key and saves them to the files :file:`ca/sub-ca-cert.pem` and :file:`ca/sub-ca-key.pem`.
139+
140+
Upload and verify the root CA certificate
141+
+++++++++++++++++++++++++++++++++++++++++
142+
143+
To perform proof of possession of the root CA key, you can verify the root CA certificate using the following set of commands:
144+
145+
.. code-block:: console
146+
147+
# Upload root CA cert
148+
az iot hub certificate create --hub-name <hub_name> --name <cert_name> --path ca/root-ca-cert.pem
149+
150+
# Ask Azure for a verification code (need two output values)
151+
az iot hub certificate generate-verification-code --hub-name <hub_name> --name <cert_name> --etag "<etag_from_prev_command>"
152+
153+
# Note down the verification code and etag for later
154+
155+
# Generate a new private key
156+
cert_tool.py client_key
157+
158+
# Create a CSR with the verification code as common name
159+
cert_tool.py csr --common-name <verification_code>
160+
161+
# Sign the CSR with the root CA
162+
cert_tool.py sign_root
163+
164+
# Upload the verification certificate
165+
az iot hub certificate verify --hub-name <hub_name> --name <cert_name> --etag "<etag_from_generate_verification_code>" --path certs/client-cert.pem
166+
167+
Setup Device Provisioning Service (DPS)
168+
+++++++++++++++++++++++++++++++++++++++
169+
170+
If you are using DPS to provision devices to your IoT hub, you need to set up an Azure IoT Hub Device Provisioning Service (DPS) instance.
171+
172+
Use the following commands to set up DPS:
173+
174+
.. code-block:: console
175+
176+
# Create the DPS instance
177+
az iot dps create --name <dps_name> --resource-group <resource_name>
178+
179+
# Link the IoT Hub to the DPS instance
180+
az iot dps linked-hub create --dps-name <dps_name> --hub-name <hub_name> --resource-group <resource_name>
181+
182+
# Create an enrollment group
183+
az iot dps enrollment-group create --dps-name <dps_name> --resource-group <resource_name> --enrollment-id <enrollment_name> --certificate-path ca/sub-ca-cert.pem --provisioning-status enabled --iot-hubs <iothub_url> --allocation-policy static
184+
185+
Generate device certificates
186+
++++++++++++++++++++++++++++
187+
188+
There are multiple ways to generate and register device certificates:
189+
190+
* The device key and certificate is generated with ``cert_tool.py`` and provisioned to the device.
191+
* The device generates a key and a Certificate Signing Request (CSR).
192+
This method is more secure because the private key is never leaves the device.
193+
194+
.. tabs::
195+
196+
.. tab:: nRF91: Modem generated private key
197+
198+
.. note::
199+
Generating a key pair on device requires an nRF91 Series device.
200+
If you are using an nRF9160 DK, modem version v1.3.x or later is required.
201+
202+
.. important::
203+
Program the :ref:`at_client_sample` sample to your device before following this guide.
204+
205+
Complete the following steps to generate a key pair and CSR on the modem, which is then signed using your CA and uploaded to Azure:
206+
207+
1. Obtain a list of installed keys using the following command:
208+
209+
.. code-block:: console
210+
211+
nrfcredstore <serial port> list
212+
213+
where ``<serial port>`` is the serial port of your device.
214+
215+
#. Select a security tag that is not yet in use.
216+
This security tag must match the value set in the :kconfig:option:`CONFIG_MQTT_HELPER_SEC_TAG` Kconfig option.
217+
218+
#. Generate a key pair and obtain a CSR using the following command:
219+
220+
.. code-block:: console
221+
222+
nrfcredstore <serial port> generate <sec tag> certs/client-csr.der
223+
224+
|serial_port_sec_tag|
225+
226+
#. Convert the CSR from DER format to PEM format using the following command:
227+
228+
.. code-block:: console
229+
230+
openssl req -inform DER -in certs/client-csr.der -outform PEM -out certs/client-csr.pem
231+
232+
#. Sign the CSR using the subordinate CA certificate using the following command:
233+
234+
.. code-block:: console
235+
236+
cert_tool.py sign
237+
238+
.. note::
239+
This process might vary depending on the CA you are using. See the documentation for your CA for more information on how to sign a CSR.
240+
241+
#. Take note of the Common Name (CN), as it will be required later.
242+
243+
In case you got the certificate from a CA, you can extract the CN using the following command:
244+
245+
.. code-block:: console
246+
247+
openssl x509 -in certs/client-cert.pem -noout -subject
248+
249+
#. Provision the certificate to the modem using the following command:
250+
251+
.. code-block:: console
252+
253+
nrfcredstore <serial port> write <sec tag> CLIENT_CERT certs/client-cert.pem
254+
255+
|serial_port_sec_tag|
256+
257+
#. Register the device certificate to Azure IoT Hub using the following command:
258+
259+
.. tabs::
260+
261+
.. tab:: Register each device by name
262+
263+
.. code-block:: console
264+
265+
az iot hub device-identity create -n <iothub_name> -d <device_id> --am x509_ca
266+
267+
.. tab:: Enroll using DPS
268+
269+
.. code-block:: console
270+
271+
az iot dps enrollment create --enrollment-id <cert_common_name> --device-id <cert_common_name> --provisioning-status enabled --resource-group <resource_group> --iot-hubs <iothub_name> --attestation-type x509 --certificate-path certs/client-cert.pem --dps-name <dps_name> --allocation-policy static --query "registrationId"
272+
273+
.. tab:: nRF91: Script generated private key
274+
275+
.. warning::
276+
When generating the private key on your computer, make sure to keep it secure and not to share it with anyone.
277+
If the private key is compromised, the security of the device is compromised.
278+
279+
.. important::
280+
Program the :ref:`at_client_sample` sample to your device before following this guide.
281+
282+
To obtain a key and certificate generated by ``cert_tool.py``, and to provision them to the modem, complete the following steps:
283+
284+
1. Generate the key and certificate using the following commands:
285+
286+
.. code-block:: console
287+
288+
cert_tool.py client_key
289+
cert_tool.py csr --common-name <device_id>
290+
cert_tool.py sign
291+
292+
This command generates an elliptic curve private key and saves it to :file:`certs/client-key.pem`.
293+
The certificate is saved to :file:`certs/client-cert.pem`.
294+
295+
#. Obtain a list of installed keys using the following command:
296+
297+
.. code-block:: console
298+
299+
nrfcredstore <serial port> list
300+
301+
where ``<serial port>`` corresponds to the serial port of your device.
302+
303+
#. Select a security tag that is not yet in use.
304+
This security tag must match the value set in :kconfig:option:`CONFIG_MQTT_HELPER_SEC_TAG` Kconfig option.
305+
306+
#. Provision the client certificate using the following command:
307+
308+
.. code-block:: console
309+
310+
nrfcredstore <serial port> write <sec tag> CLIENT_CERT certs/client-cert.pem
311+
312+
|serial_port_sec_tag|
313+
314+
#. Provision the client key using the following command:
315+
316+
.. code-block:: console
317+
318+
nrfcredstore <serial port> write <sec tag> CLIENT_KEY certs/client-key.pem
319+
320+
|serial_port_sec_tag|
321+
322+
.. tab:: nRF70: Script generated private key
323+
324+
.. warning::
325+
When generating the private key on your computer, make sure to keep it secure and not to share it with anyone.
326+
If the private key is compromised, the security of the device is compromised.
327+
328+
To obtain a key and certificate generated using ``cert_tool.py``, complete the following steps:
329+
330+
1. Generate the key and certificate using the following commands:
331+
332+
.. code-block:: console
333+
334+
cert_tool.py client_key
335+
cert_tool.py csr --common-name <device_id>
336+
cert_tool.py sign
337+
338+
#. Provision the certificates and private key at runtime to the Mbed TLS stack.
339+
This is achieved by placing the PEM files into a :file:`certs/` subdirectory and ensuring the :kconfig:option:`CONFIG_MQTT_HELPER_PROVISION_CERTIFICATES` Kconfig option is enabled.
340+
For more information, refer to the :ref:`azure_iot_hub` sample as well as the :kconfig:option:`CONFIG_MQTT_HELPER_CERTIFICATES_FILE` Kconfig option.
341+
342+
.. rst-class:: numbered-step
343+
101344
.. _azure_create_device:
102345

103346
Register a device in Azure IoT Hub
@@ -122,46 +365,26 @@ You can list your devices in Azure IoT Hub using the following command:
122365
123366
.. rst-class:: numbered-step
124367

125-
.. _azure_generating_and_provisioning_certificates:
126-
.. _azure_generating_certificates:
127-
128-
Generating certificates
129-
=======================
368+
.. _azure_iot_hub_flash_certs:
130369

131-
The connection to Azure IoT Hub with MQTT is secured using TLS.
132-
For testing purposes, see `Creating Azure IoT Hub certificates`_ for the steps to create certificates and a private key for the leaf device, and to register the generated test root certificate to be used with an IoT Hub.
370+
Provisioning certificates
371+
=========================
133372

134373
The Azure IoT Hub library requires provisioning of the following certificates and a private key for a successful TLS connection:
135374

136-
1. `DigiCert Global Root G2`_ - Server certificate, used to verify the server's certificate chain while connecting.
137-
#. Public device certificate - generated by the procedures described in `Creating Azure IoT Hub certificates`_ , used by Azure IoT Hub to authenticate the device.
375+
1. `DigiCert Global Root G2`_ - The root CA certificate, used to verify the server's certificate chain while connecting.
376+
#. `Baltimore CyberTrust Root Certificate`_ - Azures legacy root CA certificate, needed to verify the Azure server's that haven't migrated to `DigiCert Global Root G2`_ yet.
377+
#. Public device certificate - generated by the procedures described in REMOVED , used by Azure IoT Hub to authenticate the device.
138378
#. Private key of the device.
139379

140380
.. important::
141381
Azure has started the process of migrating their DPS server certificates from `Baltimore CyberTrust Root Certificate`_ to `DigiCert Global Root G2`_.
142382
Azure IoT Hub servers have finished this transition, and only DigiCert Global Root G2 is used now for those connections.
143383
Azure advises to have both Baltimore CyberTrust Root and DigiCert Global Root G2 certificates for all devices to avoid disruption of service during the transition.
144384
Refer to `Azure IoT TLS: Critical changes`_ for updated information and timeline.
145-
Due to this, it is recommended to provision the DigiCert Baltimore CyberTrust Root Certificate to a secondary security tag set by the :kconfig:option:`CONFIG_MQTT_HELPER_SECONDARY_SEC_TAG` option.
385+
Due to this, it is recommended to provision the Baltimore CyberTrust Root Certificate to a secondary security tag set by the :kconfig:option:`CONFIG_MQTT_HELPER_SECONDARY_SEC_TAG` option.
146386
This ensures that the device can also connect after the transition.
147387

148-
The location and name of the generated public device certificate and private key files vary depending on the method you use for the credential generation as follows:
149-
150-
* For PowerShell scripts, the device certificate is called :file:`<mydevice>-public.pem` and the private key is :file:`<mydevice>-private.pem`.
151-
These files are located in the working directory with the other generated files.
152-
153-
* For bash scripts, the public device certificate is called :file:`<mydevice>.cert.pem` and is located in a directory called :file:`certs` within the :file:`script` directory.
154-
The private key is called :file:`<mydevice>.key.pem` and located in a directory called :file:`private` within the :file:`script` directory.
155-
156-
The file and directory names may change if Azure changes their scripts.
157-
158-
.. rst-class:: numbered-step
159-
160-
.. _azure_iot_hub_flash_certs:
161-
162-
Provisioning certificates
163-
=========================
164-
165388
To provision the certificates, use any of the following methods, depending on the DK you are using.
166389

167390
.. tabs::
@@ -183,13 +406,13 @@ To provision the certificates, use any of the following methods, depending on th
183406

184407
.. code-block:: console
185408
186-
nrfcredstore <serial port> write <sec tag> CLIENT_KEY {device_name}.key.pem
409+
nrfcredstore <serial port> write <sec tag> CLIENT_KEY certs/client-key.pem
187410
188411
#. Provision the client certificate and replace the placeholders:
189412

190413
.. code-block:: console
191414
192-
nrfcredstore <serial port> write <sec tag> CLIENT_CERT {device_name}.cert.pem
415+
nrfcredstore <serial port> write <sec tag> CLIENT_CERT certs/client-cert.pem
193416
194417
#. Provison the server certificates, which you downloaded previously, by running the following commands:
195418

@@ -210,7 +433,8 @@ To provision the certificates, use any of the following methods, depending on th
210433

211434
Provision the certificates and private key at runtime to the MbedTLS stack.
212435
This is achieved by placing the PEM files into a :file:`certs/` subdirectory and ensuring the :kconfig:option:`CONFIG_MQTT_HELPER_PROVISION_CERTIFICATES` Kconfig option is enabled.
213-
For more information, refer to the :ref:`aws_iot` sample as well as the :kconfig:option:`CONFIG_MQTT_HELPER_CERTIFICATES_FILE` Kconfig option.
436+
Save DigiCertGlobalRootG2.crt.pem as :file:`certs/ca-cert.pem`, and BaltimoreCyberTrustRoot.crt.pem as :file:`certs/ca-cert-2.pem`.
437+
For more information, refer to the :ref:`azure_iot_hub` sample as well as the :kconfig:option:`CONFIG_MQTT_HELPER_CERTIFICATES_FILE` Kconfig option.
214438

215439
The CA will be provisioned to the security tag set by the :kconfig:option:`CONFIG_MQTT_HELPER_SEC_TAG` Kconfig option.
216440

@@ -242,7 +466,7 @@ To connect to Azure IoT Hub without using DPS, complete the following minimum re
242466
The device ID must match with the one used while creating the certificates.
243467
You can also set the device ID at run time by populating the ``device_id`` member of the :c:struct:`azure_iot_hub_config` structure passed to the :c:func:`azure_iot_hub_connect` function when connecting.
244468
If the ``device_id.size`` buffer size is zero, the compile-time option :kconfig:option:`CONFIG_AZURE_IOT_HUB_DEVICE_ID` is used.
245-
#. Make sure that the device is already registered with your Azure IoT Hub, or follow the instructions in `Registering the device with Azure IoT Hub`_.
469+
#. Make sure that the device is already registered with your Azure IoT Hub, or follow the instructions in :ref:`azure_create_device`.
246470
#. Set the :kconfig:option:`CONFIG_MQTT_HELPER_SEC_TAG` Kconfig option to the security tag used in :ref:`azure_iot_hub_flash_certs`.
247471

248472
Optionally, set the :kconfig:option:`CONFIG_MQTT_HELPER_SECONDARY_SEC_TAG` Kconfig option if multiple server certificates are provisioned.
@@ -254,14 +478,15 @@ Configuration using DPS
254478

255479
To connect to Azure IoT Hub using DPS, complete the following steps:
256480

257-
1. `Set up an Azure IoT Hub Device Provisioning Service (DPS) instance`_ and obtain the ID scope.
258-
#. `Add certificates to the DPS instance`_.
259-
#. Create an *enrollment group* as described in `Device enrollments with Azure Portal`_ and link it to your IoT hub. Select the certificate added in the previous step as the *Primary certificate​​​​​​​*.
260-
#. Enable the :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS` Kconfig option.
261-
#. In the `Azure Portal`_, click :guilabel:`Device Provisioning Services` and select the DPS instance to use.
262-
#. In the overview page, locate and copy the ``ID Scope`` and set the :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_ID_SCOPE` Kconfig option to this string.
481+
1. `Set up an Azure IoT Hub Device Provisioning Service (DPS) instance`_ if you haven't done this already.
482+
#. Set the :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_ID_SCOPE` Kconfig option to the ``ID Scope`` for your DPS instance:
483+
484+
.. code-block:: console
485+
486+
az iot dps show --name <dps_name> --query "properties.idScope"
263487
264488
Alternatively, you can set the registration ID at run time.
489+
265490
#. Set the :kconfig:option:`CONFIG_AZURE_IOT_HUB_DPS_REG_ID` Kconfig option to the registration ID.
266491

267492
You can also set the registration ID at run time.

doc/nrf/links.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,6 @@
875875
.. _`Creating an Azure IoT Hub instance using the Azure portal`: https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-create-through-portal
876876
.. _`Azure IoT Hub Device Provisioning Service (DPS)`: https://docs.microsoft.com/en-us/azure/iot-dps/
877877
.. _`Set up an Azure IoT Hub Device Provisioning Service (DPS) instance`: https://docs.microsoft.com/en-us/azure/iot-dps/quick-setup-auto-provision
878-
.. _`Creating Azure IoT Hub certificates`: https://docs.microsoft.com/en-us/azure/iot-hub/tutorial-x509-scripts
879878
.. _`Azure IoT Hub direct method`: https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-direct-methods
880879
.. _`Azure IoT Hub MQTT protocol support`: https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-mqtt-support
881880
.. _`Azure IoT Explorer`: https://docs.microsoft.com/en-us/azure/iot-pnp/howto-use-iot-explorer

doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,10 @@ This section provides detailed lists of changes by :ref:`script <scripts>`.
12721272
The ZIP format is used for update images in the nRF Connect SDK.
12731273
The change simplifies integrating new update image file formats.
12741274

1275+
* Added ``cert_tool.py`` script.
1276+
1277+
This is a script to generate EC private keys, create CSRs, create root CA and subordinate CA certificates and sign CSRs.
1278+
12751279
MCUboot
12761280
=======
12771281

0 commit comments

Comments
 (0)