Using Azure Device Provisioning Service with Self Signed X.509 Certificates – Part 4

Contents:

  1. A Primer on DPS
  2. Creating DPS and IoT Hub Instances and Linking Them
  3. Creating X.509 Certificates with OpenSSL
  4. Uploading to the Cloud (This Post)
  5. Verifying X.509 Certificates (Proof of Possession)
  6. Creating X.509 Enrollment Groups
  7. Setting up a Simulated IoT Device (C#)

Uploading to the Cloud

Now that we have our certificates created locally, it’s time to upload them to DPS. But not all of them! We’re about to see which ones go where and why.

Which Certificates to Upload?

Before we start uploading, let’s be clear about what goes where:

CertificateUpload to DPS?Purpose
Root CA✅ YESTrust anchor, must be verified
Intermediate CA✅ YESUsed in enrollment groups, must be verified
Device Certificate❌ NODevices present this, signed by intermediate

Key Point: You NEVER upload device certificates to DPS. Instead, you upload and verify the CA certificates that signed them.

Why This Works

DPS uses a trust chain model:

  1. You upload and verify CA certificates in DPS
  2. Devices present certificates signed by those CAs
  3. DPS validates the signature chain
  4. If valid, device is trusted and registered

Prerequisites

  • DPS instance created (from previous section)
  • Root and intermediate CA certificates generated (from section 03)
  • Azure CLI with IoT extension installed
  • Certificates stored in certs/root/ and certs/intermediate/ directories

Set your variables:

PowerShell
# Set variables (use your actual names)
$dpsName = "my-dps-x509"<br>$resourceGroup = "iot-x509-demo-rg"

Verify everything is ready:

PowerShell
# Check DPS exists
az iot dps show --name $dpsName --resource-group $resourceGroup

# Check certificates exist locally
Get-ChildItem certs/root/root.pem
Get-ChildItem certs/intermediate/intermediate.pem

Step 1: Upload Root CA Certificate

First, we’ll upload the root CA certificate. This is the trust anchor for your entire certificate hierarchy.

PowerShell
az iot dps certificate create `
  --dps-name $dpsName `
  --resource-group $resourceGroup `
  --certificate-name "my-root-ca" `
  --path "certs/root/root.pem"

What this command does:

  • create: Adds a new certificate to DPS
  • --certificate-name: Friendly name for the certificate in DPS (not the CN, just for organization)
  • --path: Full or relative path to your root CA .pem file

Expected output:

{
  "etag": "AAAAAAFPTRo=",
  "id": "/subscriptions/.../certificates/my-root-ca",
  "name": "my-root-ca",
  "properties": {
    "certificate": "-----BEGIN CERTIFICATE-----...",
    "created": "2026-01-21T10:00:00Z",
    "isVerified": false,
    "subject": "CN=My-Root-CA",
    "thumbprint": "ABCDEF0123456789...",
    "updated": "2026-01-21T10:00:00Z"
  }
}

Look for:

  • ✅ "name": "my-root-ca" – Confirms certificate name
  • ✅ "subject": "CN=My-Root-CA" – Confirms this is your root CA
  • ⚠️ "isVerified": false – Expected! We’ll verify in the next section
  • 📝 "etag": "..." – Save this for the verification step (or we can retrieve it later)

Step 2: Upload Intermediate CA Certificate

Next, upload the intermediate CA certificate. DPS will use this in the enrollment group to validate device certificates.

PowerShell
az iot dps certificate create `
  --dps-name $dpsName `
  --resource-group $resourceGroup `
  --certificate-name "my-intermediate-ca" `
  --path "certs/intermediate/intermediate.pem"

Look for:

  • ✅ "name": "my-intermediate-ca" – Confirms name
  • ✅ "subject": "CN=My-Intermediate-CA" – Confirms intermediate CA
  • ⚠️ "isVerified": false – Expected, we’ll verify next

Step 3: Verify Upload via Azure Portal

Let’s confirm both uploads in the Azure Portal. This visual check ensures the certificates are in DPS before we proceed to verification.

  1. Navigate to Azure Portal
  2. Go to your DPS instance
  3. Click Certificates in the left menu

You should see both certificates listed:

NameSubjectThumbprintStatusCreated
my-root-caCN=My-Root-CAABCD…⚠️ UnverifiedJan 21, 2026
my-intermediate-caCN=My-Intermediate-CAEF01…⚠️ UnverifiedJan 21, 2026

View Certificate Details

PowerShell
# View root CA details
az iot dps certificate show `
  --dps-name $dpsName `
  --resource-group $resourceGroup `
  --certificate-name "my-root-ca" `
  --query "{name:name, subject:properties.subject, isVerified:properties.isVerified}" `
  -o table

Output:

Name          Subject          IsVerified
------------  ---------------  -----------
my-root-ca    CN=My-Root-CA    False

List All Certificates

PowerShell
az iot dps certificate list `
  --dps-name $dpsName `
  --resource-group $resourceGroup `
  --query "value[].{Name:name, Subject:properties.subject, Verified:properties.isVerified}" `
  -o table

Output:

Name                 Subject                    Verified
-------------------  -------------------------  ---------
my-root-ca           CN=My-Root-CA              False
my-intermediate-ca   CN=My-Intermediate-CA      False

Common Errors and Solutions

Error: “Certificate already exists”

Error: Certificate with name 'my-root-ca' already exists

Solution: Either delete the existing certificate or use a different name:

PowerShell
# Delete existing certificate
az iot dps certificate delete `
  --dps-name $dpsName `
  --resource-group $resourceGroup `
  --certificate-name "my-root-ca" `
  --etag "AAAAAAFPTRo="

# Or use a different name
--certificate-name "my-root-ca-v2"

Error: “Invalid certificate format”

Error: The certificate is not in valid PEM format

Solution: Verify your .pem file:

  • Should start with -----BEGIN CERTIFICATE-----
  • Should end with -----END CERTIFICATE-----
  • No extra whitespace or characters
PowerShell
# View the file</em>
Get-Content certs/root/root.pem

# Should look like:</em>
# -----BEGIN CERTIFICATE-----
# MIIDXTCCAkWgAwIBAgIJAKJ3mE...
# ...</em>
# -----END CERTIFICATE-----

Error: “File not found”

Error: Unable to open file 'certs/root/root.pem'

Solution: Check your path:

PowerShell
# Use absolute path
--path "C:\repos\skittlesorter\certs\root\root.pem"

# Or navigate to the directory first
cd C:\repos\skittlesorter
--path "certs/root/root.pem"

What About Device Certificates?

Do NOT upload device certificates to DPS!

Here’s why:

  • ❌ Doesn’t scale (imagine 10,000 devices)
  • ❌ Defeats the purpose of certificate chains
  • ❌ DPS doesn’t need them

Instead:

  • ✅ Upload and verify CA certificates (root and intermediate)
  • ✅ Devices present their certificates during provisioning
  • ✅ DPS validates the signature chain automatically

Understanding the Status

After uploading, certificates have an Unverified status. This is expected and important:

Why Unverified?

DPS requires proof that you own the private key for the CA certificate. Anyone can upload a public certificate, but only the owner of the private key can sign verification certificates.

What Verification Does

Verification proves:

  1. ✅ You possess the CA private key
  2. ✅ You can sign certificates with this CA
  3. ✅ Devices presenting certificates signed by this CA should be trusted

Certificate Properties to Note

When you view a certificate in DPS, pay attention to:

Subject: The CN (Common Name) from the certificate

  • Root: CN=My-Root-CA
  • Intermediate: CN=My-Intermediate-CA

Thumbprint: SHA-1 fingerprint (unique identifier)

  • Used for verification commands
  • Useful for debugging

Created/Updated: Timestamps

  • Track when certificates were uploaded or modified

isVerified: Boolean status

  • false = uploaded but not verified
  • true = verified and trusted (what we want)

Next Steps

Now that we’ve uploaded our CA certificates, we need to verify them through the proof-of-possession process. This is a critical security step that proves we own the private keys.

In the next section, we’ll:

  1. Generate verification codes from DPS
  2. Create verification certificates
  3. Complete the verification process
  4. See our certificates marked as “Verified” ✅

Next: Verifying X.509 Certificates >