Azure IoT Device Provisioning Service – Device Registrations C# SDK – “CA certificate not found”

136 Views Asked by At

Referring to the sample from the link - X509 Enrollment Group Guide Using Cert Chain

I am trying to create a restful service (.net7 web api) that does the following 3 things:

  1. Upload a root ca cert to the DPS instance – using the REST API : Upload Cert REST API
  2. Create enrollment group with X509 attestation (intermediate cert from the chain) using the C# SDK sample: SDK Sample EG
  3. Register the device using the C# SDK sample : Device Registration SDK C#

All the above steps are working fine from my local host (WSL - Ubuntu) instance where I am able to communicate to my DPS instance and perform all the above 3 actions.

But when I try to deploy my service to azure app service (Linux) instance, steps 1 and 2 work fine but step #3 fails with the following error – “CA Certificate not found” Error code: 401002. Snap below:

enter image description here

Here is the code snipped I am using, which is pretty much referred to, from the SDK samples:


using ProvisioningTransportHandler transport = CertificateHelper.GetTransportHandler(Microsoft.Azure.Devices.Client.TransportType.Mqtt_WebSocket_Only);  

var deviceClient = ProvisioningDeviceClient.Create(globalDPSEndpoint, idScope, security, transport);  

DeviceRegistrationResult regResult = await deviceClient.RegisterAsync();  

if (regResult.Status != ProvisioningRegistrationStatusType.Assigned)  
{      
  return (false, $"Registration status did not assign a hub, so exiting...");  
}  
else  
{      
  return (true, $"Successfully registered Device:{regResult.DeviceId} to Hub: {regResult.AssignedHub}.");  
}

The exception is generated from the line:

DeviceRegistrationResult regResult = await deviceClient.RegisterAsync();

After much googling, I found that for non-windows environments, the SDK ProvisioningDeviceClient class requires both the leaf cert with private key and the full certificate chain to perform the TLS handshake to register the device. Hence after passing both, it started working from my localhost environment but still failing when deployed to the app service instance.

But, If I try to register the device using the REST api as mentioned here, Device Registration REST API,

via a CURL command and pass the full chain .pfx certificate with the password, the registration is successful. It just doesn’t work from code from inside the app service (linux) environment.

Some additional things I have found and tried:

  1. GitHub Issue - 63
  2. GitHub Issue - 1040

I am wondering if there is any additional configuration I need to perform in the app service instance for the TLS handshake to be done correctly as the client is not able to find the CA cert to validate the leaf cert from the chain. But again, the same thing works fine from local machine.

Any help on this is much appreciated!

Thanks.

1

There are 1 best solutions below

2
Sampath On

The "CA Certificate not found" error in Azure IoT Device Provisioning Service (DPS) indicates a problem with the certificate and some differences in the environment causing this issue. The code below registers devices in an IoT scenario using Azure IoT Hub and Device Provisioning Service (DPS).place the certificate under wwwroot and change the path to wwwroot

  • Provision an X.509 certificate simulated device to Microsoft Azure IoT Hub
  • Code taken from git.

Controller.cs

[HttpPost("register")]  
public async Task<IActionResult> Register()  

{  
//read cert for file system below for demo purpose

var path = "path to full cert chain pfx : root > intermediate > device/leaf certificate";

isDeviceRegistered = await _dpsService.RegisterDevice(path, password);

return Ok(isDeviceRegistered.Item2);

}

Service.cs

public async Task<(bool, string)> RegisterDevice(string certPath, string password)  
{  
var cert = new X509Certificate2(certPath, password);  
//Check if device already registered  
try  
{  
using var provisioningServiceClient = ProvisioningServiceClient.CreateFromConnectionString(_config["AzureIotHubDPS:ConnectionString"]);  
var deviceId = cert.Subject.Replace("CN=", "");  
var statResult = await provisioningServiceClient.GetDeviceRegistrationStateAsync(deviceId); // generates exception on registration not found  
if (statResult.Status == EnrollmentStatus.Assigned)  
{  
return (true, $"Device {statResult.RegistrationId} already registered to {statResult.AssignedHub}.");  
}  
}  
catch (ProvisioningServiceClientHttpException ex)  
{  
var exResponse = JsonConvert.DeserializeObject<ExResponse>(ex.Body);  
  
if (exResponse?.ErrorCode == 404202 && exResponse.Message.Equals("Registration not found."))  
{  
//Register Device to iothub DPS  
var idScope = _config["AzureIotHubDPS:IdScope"];  
var globalDPSEndpoint = _config["AzureIotHubDPS:DPSGlobalEndpoint"];  
  
using var security = new SecurityProviderX509Certificate(cert);  
using ProvisioningTransportHandler transport = CertificateHelper.GetTransportHandler(Microsoft.Azure.Devices.Client.TransportType.Mqtt_WebSocket_Only);  
var deviceClient = ProvisioningDeviceClient.Create(globalDPSEndpoint, idScope, security, transport);  
DeviceRegistrationResult regResult = await deviceClient.RegisterAsync(); // produces 500 error with "CA cert not found - works from localhost NOT from app service linux instance in azure"  
if (regResult.Status != ProvisioningRegistrationStatusType.Assigned)  
{  
return (false, $"Registration status did not assign a hub, so exitting...");  
}  
else  
{  
return (true, $"Successfully registered Device:{regResult.DeviceId} to Hub: {regResult.AssignedHub}.");  
}  
}  
}  
return (false, $"Device registration Failed!");  
}


enter image description here

enter image description here

enter image description here