For context, check the intro post.
Summary: How to use Signed Certificates in an IoT supply chain. Without giving away your private keys to your subcontractor.
At the end of this post, you completed 33% of the end-to-end process.
The IoTConnect.io cloud will know your root certificate, and will trust that you own it.
In this post, I'm:
- Generating my Root CA certificate for the conglomerate "United States Manufacturing".
- Load it to IoTConnect Cloud as the certificate that will be used to accept any of your Things connections.
- Validate it.
Actors:
- only the top in the hierarchy: Root CA "United States Manufacturing".
Readers of my previous article Connect to AVNET iotconnect.io with Node-RED - part 8b: safer connect with CA certificates will find overlap.
But that's partly. The series 9 of this saga defines policies and rules that deal with delegating while keeping control.
Everything in this post is one-off. And except for the public certificates, the artifacts should be kept in your most secret vaults.
Never share private key or password.
Create the Root CA certificate and Upload to IoTConnect Cloud
In this series, we are dealing with a number of partners that already have a chain of trust.
That is common in a supply chain where you've negotiated contracts. Or when dealing with subsidiaries, depatments, employees.
If you are in a scenario where the relationship is legal, or business financial (orders, invoices, ...), you may want to (but not always have to) consider to purchase the genesis certificate from a universally trusted commercial provider.
Attribution: Most of the commands I use are copied from, or/and adapted from Jamie Nguyen's great OpenSSL Certificate Authority article.
Folder structure and infrastructure
mkdir ~/.openssl_certification_authority_USM cd ~/.openssl_certification_authority_USM mkdir ca cd ca mkdir certs crl newcerts private proof_of_ownership chmod 700 private touch index.txt echo 1000 > serial
Root CA configuration
You can set policies and defaults for the root CA authority. You do that in a configuration file.
This will help to generate consistent certificates for intermediate partners later.
In the ca folder; create a file called openssl.cnf, Adapt where appropriate.
[ ca ] # `man ca` default_ca = CA_default [ CA_default ] # Directory and file locations. dir = ~/.openssl_certification_authority_USM/ca certs = $dir/certs crl_dir = $dir/crl new_certs_dir = $dir/newcerts database = $dir/index.txt serial = $dir/serial RANDFILE = $dir/private/.rand # The root key and root certificate. private_key = $dir/private/ca.key.pem certificate = $dir/certs/ca.cert.pem # For certificate revocation lists. crlnumber = $dir/crlnumber crl = $dir/crl/ca.crl.pem crl_extensions = crl_ext default_crl_days = 30 # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha256 name_opt = ca_default cert_opt = ca_default default_days = 375 preserve = no policy = policy_strict [ policy_strict ] # The root CA should only sign intermediate certificates that match. # See the POLICY FORMAT section of `man ca`. countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_loose ] # Allow the intermediate CA to sign a more diverse range of certificates. # See the POLICY FORMAT section of the `ca` man page. countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ req ] # Options for the `req` tool (`man req`). default_bits = 2048 distinguished_name = req_distinguished_name string_mask = utf8only # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha256 # Extension to add when the -x509 option is used. x509_extensions = v3_ca [ req_distinguished_name ] # See <https://en.wikipedia.org/wiki/Certificate_signing_request>. countryName = Country Name (2 letter code) stateOrProvinceName = State or Province Name localityName = Locality Name 0.organizationName = Organization Name organizationalUnitName = Organizational Unit Name commonName = Common Name emailAddress = Email Address # Optionally, specify some defaults. countryName_default = BE stateOrProvinceName_default = Brussels Capital District localityName_default = Schaarbeek 0.organizationName_default = United States Manufacturing organizationalUnitName_default = emailAddress_default = openssl_certification_authority.usm@gmail.com [ v3_ca ] # Extensions for a typical CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ v3_intermediate_ca ] # Extensions for a typical intermediate CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ usr_cert ] # Extensions for client certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = client, email nsComment = "OpenSSL Generated Client Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth, emailProtection [ server_cert ] # Extensions for server certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = server nsComment = "OpenSSL Generated Server Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth [ validation_cert ] # Extensions for IoTConnect and Azure CA validation certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = client nsComment = "OpenSSL Generated Client Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth [ crl_ext ] # Extension for CRLs (`man x509v3_config`). authorityKeyIdentifier=keyid:always [ ocsp ] # Extension for OCSP signing certificates (`man ocsp`). basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, digitalSignature extendedKeyUsage = critical, OCSPSigning
The configuration file holds a mix of defaults, rules, policies and locations.
It allows for several sorts of certificates. Two of them I'll use in this series: Intermediate and Validation.
The Intermediate in the next post, when I'm creating a CA for the intermediate partner "Louisiana Branch".
The Validation certificate I'll use in this post. To prove to IoTConnect that I am the owner of the CA Root certificate.
Create the root key
The first artifact I'll create (and carefully not share with anyone) is the private key that 'll be used by United States Manufacturing Root CA.
Whenever this entity issues a downstream certificate, this key will be used to sign it and make it valid.
You'll be asked to set and confirm a password. Keep that one safe too. And remember it. You need it every time you want to issue a certificate based on this root.
openssl genrsa -aes256 -out private/ca.key.pem 4096 chmod 400 private/ca.key.pem
Create the root certificate
This is the self signed public certificate (sometimes called public key).
It's valid for a whopping 7300 days.
openssl req -config openssl.cnf \ -key private/ca.key.pem \ -new -x509 -days 7300 -sha256 -extensions v3_ca \ -out certs/ca.cert.pem chmod 444 certs/ca.cert.pem
When prompted for the Common Name: United States Manufacturing Root CA
Inspect the root certificate
openssl x509 -noout -text -in certs/ca.cert.pem
...
Upload to IoTConnect.io as a CA certificate candidate
IoTConnect.io and other Azure based clouds (and others) will use your root certificate as an authentication checker, once you uploaded and validated it.
I've done this before in a previous post where I didn't use intermediate signing authorities. The mechanism is exactly the same.
The nice thing is that I only have to upload the root. No need to load the intermediates.
My story is different between than many other articles on Azure integration, where the authors say the intermediate has to be uploaded. If you follow all the steps carefully and consistently, only your (validated!) root certificate is required.
Log on to the IoTConnect portal, select Devices -> Certificates -> Create.
Name the certificate, then select the public certificate you just created in the previous step.
The certificate is uploaded now. But it's not trusted yet, because IoTConnect doesn't know yet if I control it.
Proof to IoTConnect Cloud that I Own the Root Certificate
That's the next phase. Two steps:
- The portal gave a challenge code when I uploaded the certificate. You can spot it in the screenprint: 5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F807.
I challenge is that I have to use that root certificate, its private key and password to generate a temporary validation certificate.
It's a one-off certificate that has to have the challenge code as its common name.
You need to have the key and password to complete that exercise.
When you are able to generate such a temporary validation certificate, IoTConnect knows you own the keys, and that the root certificate is indeed controlled by you. - You then need to upload that certificate to the portal. If validation passes, your root certificate becomes a valid and active validation mechanism on IoTConnect Cloud.
generate the temporary validation certificate
In these steps, filenames and attributes do not play a role, except the Common Name attribute.
The certificate will not require a password.
Key:
openssl genrsa \ -out proof_of_ownership/5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F807.key.pem 2048 chmod 400 proof_of_ownership/5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F807.key.pem
Request: attention: enter the challenge code as Common Name (in my case 5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F80)
openssl req -config openssl.cnf \ -key proof_of_ownership/5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F807.key.pem \ -new -sha256 \ -out proof_of_ownership/5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F807.csr.pem
Certificate:
openssl ca -config openssl.cnf \ -extensions validation_cert -days 10 -notext -md sha256 \ -in proof_of_ownership/5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F807.csr.pem \ -out proof_of_ownership/5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F807.cert.pem chmod 444 proof_of_ownership/5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F807.cert.pem
Verify how well I did this:
cat index.txt openssl x509 -noout -text \ -in proof_of_ownership/5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F807.cert.pem openssl verify -CAfile certs/ca.cert.pem \ proof_of_ownership/5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F807.cert.pem
For your own training, read the outputs and try to understand them.
The last line of output is the real check that we did all right:
proof_of_ownership/5FBEA1E31A4A99B2C7AFE1C4FBFB288948B655B8B028F807.cert.pem: OK
upload the validation certificate to IoTConnect Cloud to activate the Root Certificate
Now use the public certificate you just created to validate the root certificate on IoTConnect Cloud:
When successful, you get this message at the bottom of the screen:
... and the certificate shows as verified. It is now valid.
At this point, feel free to remove the proof_of_ownership folder and its content. This temporary certificate has played its role.
What Have You Achieved: 33%
You generated and installed a root certificate on IoTConnect Cloud.
You built a major part of the infrastructure that you will later use to generate the intermediate certificates.
Next article: Build the Intermediate CA infrastructure and generate a certificate for one of your subcontractors/suppliers.