Skip to main content

使用自签发X509证书认证并连接设备

分类:  Azure物联网 标签:  #Azure #IoT Hub # #入门 #指南 发布于: 2023-06-13 21:56:43

我们之前的文章已经演示了如何通过SAS Key连接Azure IoT Hub, 我们本节演示如何通过自签发证书认证并连接设备。

请先满足我们的前提条件:

  • 一个Azure账号
  • 创建好一个Azure IoT Hub的资源

我们先准备自签发证书。

需要注意的是自签发证书认证,也称之为指纹认证(thumbprint),因为我们将自签发的证书指纹填充到设备配置上,然后在认证连接时,设备读取存在本地的证书,并建立连接。

准备自签发证书

如果是使用Windows请启用WSL, 安装ubuntu和openssl, 我们使用如下的脚本准备自签发证书, 另外需要注意的是每个设备上用于填充指纹的位置有两个,所以我们需要两个自签发证书。

自签发证书1

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

创建CSR:

openssl req -new -key device1.key -out device1.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) []:testdevice2
Email Address []:

注意输入.表示使用默认值,我们需要在字段Common Name (eg, your name or your server hostname) []这里天上我们设备的ID, 假设我们这里使用testdevice2作为设备ID

检查CSR和自签发证书:

openssl req -text -in device1.csr -noout
openssl x509 -req -days 365 -in device1.csr -signkey device1.key -out device1.crt

使用上述同样的步骤创建自签发证书2:

openssl genpkey -out device2.key -algorithm RSA -pkeyopt rsa_keygen_bits:2048
openssl req -new -key device2.key -out device2.csr
openssl x509 -req -days 365 -in device2.csr -signkey device2.key -out device2.crt

在创建完成两个自签发证书之后,使用如下的方法取得指纹thumbprint:

openssl x509 -in device1.crt -noout -fingerprint
openssl x509 -in device2.crt -noout -fingerprint

由于设备SDK的证书需要使用pfx格式,使用如下的命令转换:

openssl pkcs12 -export -in device1.crt -inkey device1.key -out device1.pfx
openssl pkcs12 -export -in device2.crt -inkey device2.key -out device2.pfx

注意自签发证书指纹返回的格式是这样的:

SHA1 Fingerprint=XX:XX:XX:XX:XX:XX:XX:XX:XX:D9:1F:13:F9:4E:D0:F4:98:3E:C3:6C

两个自签发证书返回都是这样格式的, 我们只需要取Fingerprint=之后的字符串,并将所有的:去掉。
两个指纹都应该这样操作,并保存下来。

注意
本节的代码可以从:https://github.com/hylinux/azure-iot-hub-examples/tree/main/DeviceConnectBySelfSignX509 下载。

创建设备

登录到Azure Portal, 并创建设备,如下图:


  • 1处填写设备ID, 注意必须是testdevice2, 大小写都需要一致,因为我们之前在证书里填写了设备ID
  • 2处先择`X.509 Self-Signed'的认证方式
  • 3处填写第一个自签发证书的指纹,刚刚我们已经拿到的
  • 4处填写另外一个自签发证书的指纹。

填写好之后创建设备。

创建设备应用

我们接下来创建设备的引用:

dotnet new console -o DeviceConnectBySelfSignX509
cd .\DeviceConnectBySelfSignX509\
dotnet add package  Microsoft.Extensions.Hosting
dotnet add package Microsoft.Azure.Devices.Client
mkdir X509

将之前创建好的pfx证书拷贝到目录X509里。需要注意的时,同一时间只能使用一个证书。

我们在本项目中仍然使用Secret Manager来管理必要的机密信息:

dotnet user-secrets init
dotnet user-secrets set "Device:IoTHubHostURL" "<你IoT Hub服务器的网址>"
dotnet user-secrets set "X509:Password" "<你证书的密码>"
dotnet user-secrets set "Device:Id" "testdevice2"

打开文件Program.cs,添加如下的内容:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Azure.Devices.Client;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json;


using IHost host = Host.CreateDefaultBuilder(args).Build();

var iotHubHostURL = host.Services.GetRequiredService<IConfiguration>().GetValue<string>("Device:IoTHubHostURL");
var certPassword = host.Services.GetRequiredService<IConfiguration>().GetValue<string>("X509:Password");
var deviceId = host.Services.GetRequiredService<IConfiguration>().GetValue<string>("Device:Id");

var cert = new X509Certificate2(@"D:\MyProjects\azure-iot-hub-examples\DeviceConnectBySelfSignX509\X509\device.pfx", certPassword);

var auth = new DeviceAuthenticationWithX509Certificate(deviceId, cert);

var deviceClient = DeviceClient.Create(iotHubHostURL, auth, TransportType.Mqtt);

Console.WriteLine("设备连接正常。");

await host.RunAsync();

从上述代码中可以看出要使用自签发证书主要这三行代码在起作用:

var cert = new X509Certificate2(@"D:\MyProjects\azure-iot-hub-examples\DeviceConnectBySelfSignX509\X509\device.pfx", certPassword);

var auth = new DeviceAuthenticationWithX509Certificate(deviceId, cert);

var deviceClient = DeviceClient.Create(iotHubHostURL, auth, TransportType.Mqtt);

在底部加上方法SendDeviceToCloudMessagesAsync的定义,并在Console.WriteLine("设备连接正常。");后面加上以下两行:

using var cts = new CancellationTokenSource();
await SendDeviceToCloudMessagesAsync(deviceClient, cts.Token);

运行应用:

$env:DOTNET_ENVIRONMENT = "Development"
dotnet run

即可以观察连接的结果。