The Azure Device Provisioning Service (DPS) provisioning process assumes an x.509 certificate is already installed on the device. This is where X.509 Bootstrap (aka XBoot) comes in.
When the IoT device first boots, the IoT device generates an x.509 certificate signing request (CSR) using the (optional) XBoot.Client SDK, sends the CSR to the XBoot.Server REST endpoint, and receives a signed x.509 certificate back. This certificate can then be used by the device to attest to Azure Device Provisioning Service (DPS) and to authenticate with Azure IoT Hub.
XBoot allows IoT device builders to have a generic firmware loaded onto their devices at time of manufacturing and avoid the cost of installing individual x.509 certificates onto each device, during or post-manufacturing.
XBoot consists of the following components:
- XBoot.Client is a .NET Core 3.1 SDK (packaged as a nuget) that allows IoT devices to generate and send a x.509 CSR to the XBoot.Server and receive back a pfx containing a signed certificate and private key.
- Note: The private key never leaves the IoT device!
- XBoot.Server is a .NET Core 3.1 Azure Function which acts as a PKI server. It exposes a REST endpoint that accepts Certificate Signing Requests from IoT Devices running the XBoot.Client SDK, signs them using your ceritificate, and sends back the signed x.509 certificate to the XBoot.Client. Optionally, you can modify the XBoot.Server code to:
- Call into your own, or your partner, PKI APIs rather than acting as a PKI server.
- Validate the device RegistrationID with a backend database or API.
- XBoot.SampleClient is a .NET Core 3.1 console application that shows an E2E example of an IoT device sending a CSR, receiving a certificate back, and using that certificate to register with DPS and finally to authenticate with IoT Hub.
- The sample client sends a GUID as its RegistrationID. In reality a client should send something unique to the device which can be verified against a backend database or API. For example, a MAC address, IMEI, etc.
- The sample client does not integrate with a HSM. If your device has an HSM, this would be highly recommended!
The following shows the output from the XBoot.SampleClient:
Link to sequence diagram.
- Generate your root and intermediate certificate by following the Generating Certificates for XBoot.Server instructions below. The intermediate certificate will be the signing certificate.
- Decide where you will store the signing certificate and its private key and follow the instructions below for that option. Options are:
- Key Vault
- Files
- Blob
- App Settings
- Deploy the XBoot.Server Azure Function, either to Azure or you can run it locally to test. When deploying to Azure, ensure the settings you configured in the
local.settings.json
are in your Function App > Configuration > Application Settings. - Once the XBoot.Server Azure Function is deployed, copy the Azure Function REST endpoint URL and paste it into the
xbootUri
in the XBoot.SampleClientProgram.cs
file. You can obtain this under Function App > Functions > Certificate > Get Function URL. - Create an Azure IoT Hub.
- Create an Azure DPS instance. Copy the ID Scope into
idScope
in the XBoot.SampleClientProgram.cs
file. - Link the DPS instance to your IoT Hub.
- Upload and verify your intermediate certificate to DPS.
- In DPS, create an Enrollment Group.
- Set the Attestation Type to Certificate.
- Set the Certificate Type to CA Certificate or Intermediate Certificate.
- Configure the remaining Enrollment Group settings as needed.
- Edit the CSR details on lines 30-36 of the XBoot.SampleClient
Program.cs
file. - Build and run the XBoot.SampleClient.
When the signing certificate and private key are going to be stored in Key Vault...
- Create an Azure Key Vault. Record the Key Vault name.
- Import your signing certificate, which also contains your private key, to the Certificates section of Azure Key Vault. Record the certificate name.
- No need to import the private key as a Key. XBoot.Server will extract the private key from the certificate so you do not need to specify the location of the private key.
- Create a Managed Identity for your Azure Function. Go to your Function App > Identity > System assigned > Status = On. Copy your Object ID.
- In Key Vault > Access policies > Add access policy choose Key, Secret & Certificate Management as the template and choose your Object ID under Select principal. Leave authorized application as none selected.
Add the following to your local.settings.json
when running the XBoot.Server Azure Function locally on your development computer. When running the XBoot.Server Azure Function in Azure, ensure the settings below are in your Azure Function App Application Settings.
{
...,
"Location": 0,
"KeyVaultName": "MyKeyVault",
"CertificateFile": "Intermediate"
}
Where:
KeyVaultName
is the name of your Azure Key Vault.CertificateFile
is the name of the signing certificate you imported into Azure Key Vault under Certificates
When the signing certificate and private key are stored in files...
- Save the files to a location and record that location.
Note: This should only be used in development/testing.
Add the following to your local.settings.json
when running the XBoot.Server Azure Function locally on your development computer.
{
...,
"Location": 1,
"PrivateKeyFile": "c:\\openssl_stuff\\ia.key",
"CertificateFile": "c:\\openssl_stuff\\ia.cer"
}
When the signing certificate and private key are stored in Azure Blob Storage...
- Create an Azure Blob Storage account.
- Azure Blob Storage account > Access keys and copy one of the two Connections strings.
- Create a Container. Record the container name.
- Upload the certificate file and the private key file to the Container.
Add the following to your local.settings.json
when running the XBoot.Server Azure Function locally on your development computer. When running the XBoot.Server Azure Function in Azure, ensure the settings below are in your Azure Function App Application Settings.
{
...,
"Location": 2,
"BlobConnectionString": "DefaultEndpointsProtocol=https;AccountName=<blobaccountname>;AccountKey=...",
"BlobContainerName": "xboot",
"PrivateKeyFile": "ia.key",
"CertificateFile": "ia.cer"
}
When the signing certificate and private key are stored directly in the App Settings...
Note: This should only be used in development/testing.
Add the following to your local.settings.json
when running the XBoot.Server Azure Function locally on your development computer.
{
...,
"Location": 3,
"PrivateKeyFile": "-----BEGIN RSA PRIVATE KEY-----blahblahblah-----END RSA PRIVATE KEY-----",
"CertificateFile": "-----BEGIN CERTIFICATE-----blahblahblah-----END CERTIFICATE-----"
}
The following steps can be used to generate a root certificate and an intermediate certificate. The intermediate certificate can be used by the XBoot.Server as the signing certificate. The root certificate can be stored offline.
Generate private and public key pair for root CA; output is a pem file (pkcs8 format).
openssl genrsa -out ca.key 2048
Generate self signed root certificate. When prompted, fill in certificate details.
openssl req -new -x509 -days 1826 -key ca.key -out ca.cer
Generate private and public key pair for intermediate CA; output is a pem file (pkcs8 format).
openssl genrsa -out ia.key 2048
Generate CSR for intermediate. When prompted, fill in certificate details.
openssl req -new -key ia.key -out ia.csr
Generate intermediate cert signed using the root certificate.
openssl x509 -req -days 730 -in ia.csr -CA ca.cer -CAkey ca.key -set_serial 01 -out ia.cer -extfile intextensions.txt -extensions v3_intermediate_ca
intextensions.txt contents:
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA.
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
Package in PKCS 12
openssl pkcs12 -export -out ia.p12 -inkey ia.key -in ia.cer -chain -CAfile ca.cer
See XBoot Backlog under Projects.