Tutorial: Use OpenSSL to create test certificates

For production environments, we recommend that you purchase an X.509 CA certificate from a public root certificate authority (CA). However, creating your own test certificate hierarchy is adequate for testing IoT Hub device authentication. For more information about getting an X.509 CA certificate from a public root CA, see the Get an X.509 CA certificate section of Authenticate devices using X.509 CA certificates.

The following example uses OpenSSL and the OpenSSL Cookbook to create a certificate authority (CA), a subordinate CA, and a device certificate. The example then signs the subordinate CA and the device certificate into a certificate hierarchy. This example is presented for demonstration purposes only.

Note

Microsoft provides PowerShell and Bash scripts to help you understand how to create your own X.509 certificates and authenticate them to an IoT hub. The scripts are included with the Azure IoT Hub Device SDK for C. The scripts are provided for demonstration purposes only. Certificates created by them must not be used for production. The certificates contain hard-coded passwords (“1234”) and expire after 30 days. You must use your own best practices for certificate creation and lifetime management in a production environment. For more information, see Managing test CA certificates for samples and tutorials in the GitHub repository for the Azure IoT Hub Device SDK for C.

Step 1 - Create the root CA directory structure

Create a directory structure for the certificate authority.

  • The certs directory stores new certificates.
  • The db directory stores the certificate database.
  • The private directory stores the CA private key.
  mkdir rootca
  cd rootca
  mkdir certs db private
  touch db/index
  openssl rand -hex 16 > db/serial
  echo 1001 > db/crlnumber

Step 2 - Create a root CA configuration file

Before creating a CA, create a configuration file and save it as rootca.conf in the rootca directory.

[default]
name                     = rootca
domain_suffix            = example.com
aia_url                  = http://$name.$domain_suffix/$name.crt
crl_url                  = http://$name.$domain_suffix/$name.crl
default_ca               = ca_default
name_opt                 = utf8,esc_ctrl,multiline,lname,align

[ca_dn]
commonName               = "Test Root CA"

[ca_default]
home                     = ../rootca
database                 = $home/db/index
serial                   = $home/db/serial
crlnumber                = $home/db/crlnumber
certificate              = $home/$name.crt
private_key              = $home/private/$name.key
RANDFILE                 = $home/private/random
new_certs_dir            = $home/certs
unique_subject           = no
copy_extensions          = none
default_days             = 3650
default_crl_days         = 365
default_md               = sha256
policy                   = policy_c_o_match

[policy_c_o_match]
countryName              = optional
stateOrProvinceName      = optional
organizationName         = optional
organizationalUnitName   = optional
commonName               = supplied
emailAddress             = optional

[req]
default_bits             = 2048
encrypt_key              = yes
default_md               = sha256
utf8                     = yes
string_mask              = utf8only
prompt                   = no
distinguished_name       = ca_dn
req_extensions           = ca_ext

[ca_ext]
basicConstraints         = critical,CA:true
keyUsage                 = critical,keyCertSign,cRLSign
subjectKeyIdentifier     = hash

[sub_ca_ext]
authorityKeyIdentifier   = keyid:always
basicConstraints         = critical,CA:true,pathlen:0
extendedKeyUsage         = clientAuth,serverAuth
keyUsage                 = critical,keyCertSign,cRLSign
subjectKeyIdentifier     = hash

[client_ext]
authorityKeyIdentifier   = keyid:always
basicConstraints         = critical,CA:false
extendedKeyUsage         = clientAuth
keyUsage                 = critical,digitalSignature
subjectKeyIdentifier     = hash

Step 3 - Create a root CA

First, generate a private key and the certificate signing request (CSR) in the rootca directory.

  openssl req -new -config rootca.conf -out rootca.csr -keyout private/rootca.key

Next, create a self-signed CA certificate. Self-signing is suitable for testing purposes. Specify the ca_ext configuration file extensions on the command line. These extensions indicate that the certificate is for a root CA and can be used to sign certificates and certificate revocation lists (CRLs). Sign the certificate, and commit it to the database.

  openssl ca -selfsign -config rootca.conf -in rootca.csr -out rootca.crt -extensions ca_ext

Step 4 - Create the subordinate CA directory structure

Create a directory structure for the subordinate CA at the same level as the rootca directory.

  mkdir subca
  cd subca
  mkdir certs db private
  touch db/index
  openssl rand -hex 16 > db/serial
  echo 1001 > db/crlnumber

Step 5 - Create a subordinate CA configuration file

Create a configuration file and save it as subca.conf in the subca directory.

[default]
name                     = subca
domain_suffix            = example.com
aia_url                  = http://$name.$domain_suffix/$name.crt
crl_url                  = http://$name.$domain_suffix/$name.crl
default_ca               = ca_default
name_opt                 = utf8,esc_ctrl,multiline,lname,align

[ca_dn]
commonName               = "Test Subordinate CA"

[ca_default]
home                     = .
database                 = $home/db/index
serial                   = $home/db/serial
crlnumber                = $home/db/crlnumber
certificate              = $home/$name.crt
private_key              = $home/private/$name.key
RANDFILE                 = $home/private/random
new_certs_dir            = $home/certs
unique_subject           = no
copy_extensions          = copy
default_days             = 365
default_crl_days         = 90
default_md               = sha256
policy                   = policy_c_o_match

[policy_c_o_match]
countryName              = optional
stateOrProvinceName      = optional
organizationName         = optional
organizationalUnitName   = optional
commonName               = supplied
emailAddress             = optional

[req]
default_bits             = 2048
encrypt_key              = yes
default_md               = sha256
utf8                     = yes
string_mask              = utf8only
prompt                   = no
distinguished_name       = ca_dn
req_extensions           = ca_ext

[ca_ext]
basicConstraints         = critical,CA:true
keyUsage                 = critical,keyCertSign,cRLSign
subjectKeyIdentifier     = hash

[sub_ca_ext]
authorityKeyIdentifier   = keyid:always
basicConstraints         = critical,CA:true,pathlen:0
extendedKeyUsage         = clientAuth,serverAuth
keyUsage                 = critical,keyCertSign,cRLSign
subjectKeyIdentifier     = hash

[client_ext]
authorityKeyIdentifier   = keyid:always
basicConstraints         = critical,CA:false
extendedKeyUsage         = clientAuth
keyUsage                 = critical,digitalSignature
subjectKeyIdentifier     = hash

Step 6 - Create a subordinate CA

This example shows you how to create a subordinate or registration CA. Because you can use the root CA to sign certificates, creating a subordinate CA isn’t strictly necessary. Having a subordinate CA does, however, mimic real world certificate hierarchies in which the root CA is kept offline and a subordinate CA issues client certificates.

From the subca directory, use the configuration file to generate a private key and a certificate signing request (CSR).

  openssl req -new -config subca.conf -out subca.csr -keyout private/subca.key

Submit the CSR to the root CA and use the root CA to issue and sign the subordinate CA certificate. Specify sub_ca_ext for the extensions switch on the command line. The extensions indicate that the certificate is for a CA that can sign certificates and certificate revocation lists (CRLs). When prompted, sign the certificate, and commit it to the database.

  openssl ca -config ../rootca/rootca.conf -in subca.csr -out subca.crt -extensions sub_ca_ext

Step 7 - Demonstrate proof of possession

You now have both a root CA certificate and a subordinate CA certificate. You can use either one to sign device certificates. The one you choose must be uploaded to your IoT Hub. The following steps assume that you're using the subordinate CA certificate. To upload and register your subordinate CA certificate to your IoT Hub:

  1. In the Azure portal, navigate to your IoTHub and select Settings > Certificates.

  2. Select Add to add your new subordinate CA certificate.

  3. Enter a display name in the Certificate Name field, and select the PEM certificate file you created previously.

    Note

    The .crt certificates created above are the same as .pem certificates. You can simply change the extension when uploading a certificate to prove possession, or you can use the following OpenSSL command:

    openssl x509 -in mycert.crt -out mycert.pem -outform PEM
    
  4. Select Save. Your certificate is shown in the certificate list with a status of Unverified. The verification process will prove that you own the certificate.

  5. Select the certificate to view the Certificate Details dialog.

  6. Select Generate Verification Code. For more information, see Prove Possession of a CA certificate.

  7. Copy the verification code to the clipboard. You must set the verification code as the certificate subject. For example, if the verification code is BB0C656E69AF75E3FB3C8D922C1760C58C1DA5B05AAA9D0A, add that as the subject of your certificate as shown in step 9.

  8. Generate a private key.

    openssl genpkey -out pop.key -algorithm RSA -pkeyopt rsa_keygen_bits:2048
    
  9. Generate a certificate signing request (CSR) from the private key. Add the verification code as the subject of your certificate.

    openssl req -new -key pop.key -out pop.csr
    
      -----
      Country Name (2 letter code) [XX]:.
      State or Province Name (full name) []:.
      Locality Name (eg, city) [Default City]:.
      Organization Name (eg, company) [Default Company Ltd]:.
      Organizational Unit Name (eg, section) []:.
      Common Name (eg, your name or your server hostname) []:BB0C656E69AF75E3FB3C8D922C1760C58C1DA5B05AAA9D0A
      Email Address []:
    
      Please enter the following 'extra' attributes
      to be sent with your certificate request
      A challenge password []:
      An optional company name []:
    
    
  10. Create a certificate using the subordinate CA configuration file and the CSR for the proof of possession certificate.

    openssl ca -config subca.conf -in pop.csr -out pop.crt -extensions client_ext
    
  11. Select the new certificate in the Certificate Details view. To find the PEM file, navigate to the certs folder.

  12. After the certificate uploads, select Verify. The CA certificate status should change to Verified.

Step 8 - Create a device in your IoT Hub

Navigate to your IoT Hub in the Azure portal and create a new IoT device identity with the following values:

  1. Provide the Device ID that matches the subject name of your device certificates.

  2. Select the X.509 CA Signed authentication type.

  3. Select Save.

Step 9 - Create a client device certificate

To generate a client certificate, you must first generate a private key. The following command shows how to use OpenSSL to create a private key. Create the key in the subca directory.

openssl genpkey -out device.key -algorithm RSA -pkeyopt rsa_keygen_bits:2048

Create a certificate signing request (CSR) for the key. You don't need to enter a challenge password or an optional company name. You must, however, enter the device ID in the common name field. You can also enter your own values for the other parameters such as Country Name, Organization Name, and so on.

openssl req -new -key device.key -out device.csr

-----
Country Name (2 letter code) [XX]:.
State or Province Name (full name) []:.
Locality Name (eg, city) [Default City]:.
Organization Name (eg, company) [Default Company Ltd]:.
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server hostname) []:`<your device ID>`
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Check that the CSR is what you expect.

openssl req -text -in device.csr -noout

Send the CSR to the subordinate CA for signing into the certificate hierarchy. Specify client_ext in the -extensions switch. Notice that the Basic Constraints in the issued certificate indicate that this certificate isn't for a CA. If you're signing multiple certificates, be sure to update the serial number before generating each certificate by using the openssl rand -hex 16 > db/serial command.

openssl ca -config subca.conf -in device.csr -out device.crt -extensions client_ext

Next Steps

Go to Tutorial: Test certificate authentication to determine if your certificate can authenticate your device to your IoT Hub. The code on that page requires that you use a PFX certificate. Use the following OpenSSL command to convert your device .crt certificate to .pfx format.

openssl pkcs12 -export -in device.crt -inkey device.key -out device.pfx