直接回答:双向认证要求两边都有证书:先建根证书,再用它分别签发服务端证书和设备端证书,服务端配置里开启 verify client,客户端带自己的证书和私钥去连接,任何一方缺失都会被拒绝。
准备工作
本文示例使用开发环境:Ubuntu 22.04版本操作系统。
步骤一:生成自定义证书
登录Ubuntu操作系统。
执行以下命令生成设备端和服务端的根证书文件
root-ca.crt。1
2
3
4
5
6
7
8
9openssl req \
-new \
-newkey rsa:2048 \
-days 365 \
-nodes \
-x509 \
-subj "/C=CN/O=Aliyun IOT/CN=IoT CA" \
-keyout root-ca.key \
-out root-ca.crt根据根证书文件
root-ca.crt,自定义服务端证书。执行以下命令生成服务端密钥文件
server.key。1
openssl genrsa -out server.key 2048
执行命令
touch openssl.cnf新建文件openssl.cnf。执行命令
vi openssl.cnf进入文件,填入以下内容后按Esc键,输入:wq保存。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27[policy_match]
countryName = cn
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[req]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
commonName = Server
[req_ext]
subjectAltName = @alt_names
[v3_req]
subjectAltName = @alt_names
[alt_names]
DNS.1 = *.mqtt.iothub.aliyuncs.com
DNS.2 = *.igw.iothub.aliyuncs.com执行以下命令生成服务端请求文件
server.csr。1
openssl req -new -key server.key -config openssl.cnf -out server.csr
执行以下命令生成服务端证书文件
server.crt。1
openssl x509 -req -days 365 -sha256 -in server.csr -CA root-ca.crt -CAkey root-ca.key -CAcreateserial -out server.crt -extensions v3_req -extfile openssl.cnf
执行以下命令验证服务端证书。
1
openssl verify -CAfile root-ca.crt server.crt
根据根证书文件
root-ca.crt,自定义设备端证书。执行以下命令生成设备端密钥文件
client.key。1
openssl genrsa -out client.key 2048
执行以下命令生成设备端证书请求文件
client.csr,设置CN为Client_123。1
openssl req -new -key client.key -out client.csr -subj "/CN=Client_123"
执行以下命令生成设备端证书文件
client.crt。1
openssl x509 -req -days 365 -sha256 -in client.csr -CA root-ca.crt -CAkey root-ca.key -CAcreateserial -out client.crt
执行以下命令验证设备端证书。
1
openssl verify -CAfile root-ca.crt client.crt
自定义证书文件如下:

步骤二:创建设备认证的FC函数
登录函数计算控制台,在左侧导航栏,单击服务及函数。
在顶部菜单栏,选择华东2(上海)地域,然后在服务列表页面,单击创建服务。
在创建服务面板,填写服务名称,例如:IoT_Service,然后单击确定。
在函数管理页面,单击创建函数。
在创建函数页面,配置以下配置项,然后单击创建。
在函数详情页面,将示例代码替换为以下代码,单击部署代码。
认证函数将设备证书的CN作为deviceName返回。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33# -*- coding: utf-8 -*-
import logging
import json
import time
import enum
import random
import string
class Request:
def __init__(self, json_str):
self.clientId = None
self.username = None
self.password = None
self.certificateCommonName = None
for key, value in json.loads(json_str).items():
setattr(self, key, value)
class Response:
def __init__(self):
self.deviceName = None
self.result = 'true'
self.message = 'success'
def handler(self, request):
# 将设备证书的CN作为deviceName返回
self.deviceName = request.certificateCommonName
return json.dumps(self.__dict__)
def handler(event, context):
request = Request(event)
return Response().handler(request)
步骤三:创建云网关产品
登录物联网平台控制台,在页面左上方选择**华东2(上海)**地域。
在实例概览页面,单击目标尊享型实例。
在左侧导航栏,选择设备管理 > 云网关,单击添加云网关。
配置如下信息,单击确定。
服务端证书为
server.crt,服务端证书私钥为server.key,设备根证书为root-ca.crt。参数详细说明,请参见添加云网关。在云网关列表,复制网关URL保存。
步骤四:开发设备端程序
返回Ubuntu操作系统。
执行以下命令,安装依赖库。
1
2sudo apt-get install build-essential gcc make cmake cmake-gui cmake-curses-gui
sudo apt-get install libssl-dev执行以下命令,安装MQTT开源库Paho。
1
2
3
4
5git clone https://github.com/eclipse/paho.mqtt.c.git
mkdir build && cd build
cmake ../paho.mqtt.c -DPAHO_WITH_SSL=TRUE -DCMAKE_INSTALL_PREFIX="/usr/lib"
make -j
sudo make install && cd ..执行命令
touch aiot_mqtt_demo.c新建设备模拟程序文件aiot_mqtt_demo.c。执行命令
vi aiot_mqtt_demo.c进入文件,填入以下内容。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
printf("message recv < topic [%s], payload [%s]\n", topicName, (char *)message->payload);
MQTTClient_freeMessage(&message);
MQTTClient_free(topicName);
return 1;
}
int main(int argc, char* argv[])
{
MQTTClient client;
MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
MQTTClient_SSLOptions ssl_opts = MQTTClient_SSLOptions_initializer;
int rc;
/* 创建一个mqtt_client, 待替换 */
const char *host = "ssl://iot-0****.igw.iothub.aliyuncs.com:1883";
const char *client_id = "12345";
MQTTClient_create(&client, host, client_id, MQTTCLIENT_PERSISTENCE_NONE, NULL);
MQTTClient_setCallbacks(client, NULL, NULL, msgarrvd, NULL);
/* 配置建连参数:证书、用户名、密码,待替换*/
ssl_opts.trustStore = "root-ca.crt";
ssl_opts.privateKey = "client.key";
ssl_opts.keyStore = "client.crt";
conn_opts.ssl = &ssl_opts;
conn_opts.username = "sdk_test01";
conn_opts.password = "hello123";
/* mqtt完成建连 */
if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
printf("Failed to connect, return code %d\n", rc);
exit(EXIT_FAILURE);
}
printf("connect success username %s, password %s\n", conn_opts.username, conn_opts.password);
/* 订阅消息 */
MQTTClient_subscribe(client, "/user/aiot_mqtt_demo_downraw", 1);
/* 生成消息并循环发布消息 */
MQTTClient_message pubmsg = MQTTClient_message_initializer;
const char *topic = "/user/aiot_mqtt_demo_upraw";
pubmsg.payload = "Hello Service!";
pubmsg.payloadlen = (int)strlen(pubmsg.payload);
pubmsg.qos = 1;
for(int i = 0; i < 100; i++) {
MQTTClient_publishMessage(client, topic, &pubmsg, NULL);
printf("message send > topic [%s], payload [%s]\n", topic, (char *)pubmsg.payload);
sleep(10);
}
/* 断开连接并删除client */
MQTTClient_disconnect(client, 10000);
MQTTClient_destroy(&client);
return rc;
}在以上代码中修改实际设备相关参数,然后按Esc键,输入
:wq保存文件aiot_mqtt_demo.c。参数 说明 host MQTT云网关设备接入地址,格式为 ssl://${网关接入地址}:${端口号}。${网关接入地址}和${端口号}为本文“步骤三:创建云网关产品”中复制保存的网关URL中的域名和自定义端口号。client_id (可选)客户端ID,需自定义,长度不可超过64个字符。建议使用设备的MAC地址或SN码,方便您识别区分不同的客户端。 ssl_opts.trustStore 设备端根证书 root-ca.crt的路径。ssl_opts.privateKey 设备端密钥文件 client.key的路径。ssl_opts.keyStore 设备端证书文件 client.crt的路径。conn_opts.username MQTT的userName。userName支持英文字母、数字、短划线(-)、下划线(_)、at(@)、英文句号(.)和英文冒号(:),长度限制为4~32个字符。userName在产品维度下不可重复。 conn_opts.password MQTT的password。password支持英文字母、数字、短划线(-)、下划线(_)、at(@)、英文句号(.)和英文冒号(:),长度限制为1~32个字符。
本示例相关库的安装、证书的制作和设备程序的开发完成,如下所示:
步骤五:编译运行
执行以下命令编译运行设备程序文件
aiot_mqtt_demo.c。1
2gcc -o aiot_mqtt_demo aiot_mqtt_demo.c -lpaho-mqtt3cs
./aiot_mqtt_demo运行成功后,通过FC认证函数返回的deviceName:
Client_123会作为物联平台设备的DeviceName,在物联网平台控制台实例下的设备管理 > 设备页面,自动创建设备Client_123,设备状态显示为在线。
这篇笔记整理自我自己的实践记录,如果做法有出入,或者你踩过别的坑,欢迎到留言板一起聊聊。