设备端使用MQTT、GB/T 32960、JT/T 808或SL 651协议并采用TLS方式接入物联网平台云网关时,需要使用证书进行认证。物联网平台云网关支持使用的证书签名算法有RSA、ECC和国密SM2,您可通过阿里云PCA服务或自行签发需要的CA证书。本文以RSA算法和SM2算法为例,介绍如何签发自定义CA证书。
使用前必读
本文操作步骤以普通用户权限为例。如果您在操作过程中涉及到管理员权限才能执行的操作,可尝试使用sudo
命令执行。
背景信息
物联网平台支持RSA、ECC算法证书双向认证,仅支持国密证书单向认证。使用云网关MQTT、GB/T 32960和JT/T 808协议接入设备的详细内容,请参见MQTT协议云网关概述、GB/T 32960协议云网关概述、JT/T 808协议云网关概述和SL 651协议概述。
PCA(Private Certificate Authority,即私有CA)服务的详细信息,请参见私有证书概述。
准备环境
签发RSA算法的自定义证书,需要使用工具OpenSSL。
签发SM2算法的国密证书,需要使用工具Tongsuo。
Tongsuo支持的操作系统有:各种Linux发行版、macOS、Android、iOS和Windows。
本文购买Alibaba Cloud Linux操作系统的ECS实例(默认已安装OpenSSL工具),通过以下工具生成自定义证书。购买ECS实例的方法,请参见实例创建方式介绍。
您可参考以下步骤,在待使用的操作系统(本文使用Alibaba Cloud Linux)上,准备对应的环境。
登录操作系统。ECS实例登录方式,请参见连接方式概述。
执行以下命令,安装make编译工具。
sudo yum install make
执行以下命令,安装C库和C编译器。
sudo yum install gcc
执行以下命令,安装
unzip
,用于后续解压Tongsuo源码包。说明如果不签发SM2算法证书,无需安装
unzip
。yum update yum install zip
执行以下命令,安装Perl 5以及Text::Template模块,用于后续安装Tongsuo源码库。
说明如果不签发SM2算法证书,无需安装Perl 5以及Text::Template模块。
sudo yum install perl sudo yum install perl-core
签发RSA算法的证书
在ECS实例的操作系统中创建一个文件夹存放生成的证书。
mkdir /home/rsa_certs cd /home/rsa_certs
执行以下命令生成设备端和服务端的根证书文件
root-ca.crt
。openssl 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
。openssl genrsa -out server.key 2048
执行命令
touch openssl.cnf
新建文件openssl.cnf
。执行命令
vi openssl.cnf
进入文件,填入以下内容后按Esc键,输入:wq
保存。[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
。openssl req -new -key server.key -config openssl.cnf -out server.csr
执行以下命令生成服务端证书文件
server.crt
。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
执行以下命令验证服务端证书。
openssl verify -CAfile root-ca.crt server.crt
根据根证书文件
root-ca.crt
,自定义设备端证书。执行以下命令生成设备端密钥文件
client.key
。openssl genrsa -out client.key 2048
执行以下命令生成设备端证书请求文件
client.csr
。本示例设置CN为Client_123
。openssl req -new -key client.key -out client.csr -subj "/CN=Client_123"
执行以下命令生成设备端证书文件
client.crt
。openssl x509 -req -days 365 -sha256 -in client.csr -CA root-ca.crt -CAkey root-ca.key -CAcreateserial -out client.crt
执行以下命令验证设备端证书。
openssl verify -CAfile root-ca.crt client.crt
执行命令
ls
,可查看自定义证书的所有文件。证书文件为:
根证书:
root-ca.crt
。服务端证书私钥:
server.key
。服务端证书:
server.crt
。设备端证书私钥:
client.key
。设备端证书:
client.crt
。
签发SM2算法的证书
签发SM2算法的国密证书,需要使用Tongsuo。本示例下载源码包
Tongsuo-8.4.0-pre3.zip
,相关文件位于源码库的/test/certs/sm2
目录中。安装Tongsuo成功后,Tongsuo会替换操作系统内原有的OpenSSL。
本示例构建一套包含三级证书链的国密证书,签发每级证书签名请求
csr
文件时,设置的countryName、stateOrProvinceName、organizationName、organizationalUnitName必须保持一致,但commonName必须保持唯一。
在ECS实例的操作系统中创建一个文件夹存放生成国密证书相关的文件。
mkdir /home/sm2 cd /home/sm2
按照以下步骤上传并安装Tongsuo。
执行以下命令解压文件包。
unzip Tongsuo-8.4.0-pre3.zip
执行以下命令,进入文件目录
Tongsuo-8.4.0-pre3
并完成安装Tongsuo。cd Tongsuo-8.4.0-pre3 ./config make make install
执行命令
openssl version
确认安装成功。说明如果报错:
openssl: error while loading shared libraries: libssl.so.3: cannot open shared object file: No such file or directory
,可执行如下命令:ldconfig /usr/local/lib64/
后,重新执行命令openssl version
。返回类似如下信息,说明安装成功。
Tongsuo: Tongsuo 8.4.0-pre3 (Library: Tongsuo 8.4.0-pre3) OpenSSL 3.0.3 3 May 2022 (Library: OpenSSL 3.0.3 3 May 2022)
新增路径构建脚本
gen-sm2-cert-sign-dir.sh
,构建文件目录sm2-ca
管理签发的证书。执行命令
touch gen-sm2-cert-sign-dir.sh
,新建脚本文件gen-sm2-cert-sign-dir.sh
。执行命令
vi gen-sm2-cert-sign-dir.sh
进入文件,填入以下内容后输入:wq
保存。#!/bin/bash # create dir certs db private crl csr newcerts under sm2-ca dir. if [ ! -d sm2-ca/certs ]; then mkdir -p sm2-ca/certs fi if [ ! -d sm2-ca/db ]; then mkdir -p sm2-ca/db touch sm2-ca/db/index openssl rand -hex 16 > sm2-ca/db/serial echo 1001 > sm2-ca/db/crlnumber fi if [ ! -d sm2-ca/private ]; then mkdir -p sm2-ca/private chmod 700 sm2-ca/private fi if [ ! -d sm2-ca/crl ]; then mkdir -p sm2-ca/crl fi if [ ! -d sm2-ca/newcerts ]; then mkdir -p sm2-ca/newcerts fi if [ ! -d sm2-ca/csr ]; then mkdir -p sm2-ca/csr fi
执行命令
chmod +x gen-sm2-cert-sign-dir.sh
为脚本文件添加执行权限。执行命令
./gen-sm2-cert-sign-dir.sh
运行脚本,完成构建文件目录sm2-ca
。
执行命令
cd sm2-ca
进入文件目录sm2-ca
,然后参考上一步骤中的touch
和vi
命令,新增配置文件openssl.cnf
、openssl_middleca.cnf
。说明如果需指定域名,可在配置文件
openssl.cnf
和openssl_middleca.cnf
中的[ alt_names ]
下设置。文件内容如下:
openssl.cnf:签发根证书和中间证书
[ ca ] # `man ca` default_ca = CA_default [ CA_default ] # Directory and file locations. dir = ./ certs = $dir/certs crl_dir = $dir/crl new_certs_dir = $dir/newcerts database = $dir/db/index serial = $dir/db/serial RANDFILE = $dir/private/random # The root key and root certificate. private_key = $dir/private/sm2-root.key certificate = $dir/certs/sm2-root.crt # For certificate revocation lists. crlnumber = $dir/crl/crlnumber crl = $dir/crl/ca.crl.pem crl_extensions = crl_ext default_crl_days = 30 # SHA-1 is deprecated, so use SHA-2 instead. default_md = sm3 name_opt = ca_default cert_opt = ca_default default_days = 365 preserve = no policy = policy_strict [ policy_strict ] # The root CA should only sign intermediate certificates that match. # See the POLICY FORMAT section of `man ca`. countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_loose ] # Allow the intermediate CA to sign a more diverse range of certificates. # See the POLICY FORMAT section of the `ca` man page. countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ req ] # Options for the `req` tool (`man req`). default_bits = 2048 distinguished_name = req_distinguished_name string_mask = utf8only # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha256 # Extension to add when the -x509 option is used. x509_extensions = v3_ca req_extensions = v3_req [ req_distinguished_name ] # See <https://en.wikipedia.org/wiki/Certificate_signing_request>. countryName = optional stateOrProvinceName = optional localityName = optional 0.organizationName = optional organizationalUnitName = optional commonName = optional emailAddress = optional # Optionally, specify some defaults. countryName_default = CN stateOrProvinceName_default = China localityName_default = 0.organizationName_default = Alipay #organizationalUnitName_default = #emailAddress_default = [ v3_req ] # Extensions to add to a certificate request basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [ alt_names ] DNS.1 = *.mqtt.iothub.aliyuncs.com DNS.2 = *.igw.iothub.aliyuncs.com [ v3_ca ] # Extensions for a typical CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ v3_intermediate_ca ] # Extensions for a typical intermediate CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ usr_cert ] # Extensions for client certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = client, email nsComment = "OpenSSL Generated Client Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth, emailProtection [ server_cert ] # Extensions for server certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = server nsComment = "OpenSSL Generated Server Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [ crl_ext ] # Extension for CRLs (`man x509v3_config`). authorityKeyIdentifier=keyid:always [ ocsp ] # Extension for OCSP signing certificates (`man ocsp`). basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, digitalSignature extendedKeyUsage = critical, OCSPSigning
openssl_middleca.cnf:签发服务端证书
[ ca ] # `man ca` default_ca = CA_default [ CA_default ] # Directory and file locations. dir = ./ certs = $dir/certs crl_dir = $dir/crl new_certs_dir = $dir/newcerts database = $dir/db/index serial = $dir/db/serial RANDFILE = $dir/private/random # The root key and root certificate. private_key = $dir/private/sm2-intermediate-ca.key certificate = $dir/certs/sm2-intermediate-ca.crt # For certificate revocation lists. crlnumber = $dir/crlnumber crl = $dir/crl/ca.crl.pem crl_extensions = crl_ext default_crl_days = 30 # SHA-1 is deprecated, so use SHA-2 instead. default_md = sm3 name_opt = ca_default cert_opt = ca_default default_days = 365 preserve = no policy = policy_strict [ policy_strict ] # The root CA should only sign intermediate certificates that match. # See the POLICY FORMAT section of `man ca`. countryName = optional stateOrProvinceName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ policy_loose ] # Allow the intermediate CA to sign a more diverse range of certificates. # See the POLICY FORMAT section of the `ca` man page. countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ req ] # Options for the `req` tool (`man req`). default_bits = 2048 distinguished_name = req_distinguished_name string_mask = utf8only # SHA-1 is deprecated, so use SHA-2 instead. default_md = sha256 # Extension to add when the -x509 option is used. x509_extensions = v3_ca req_extensions = v3_req [ req_distinguished_name ] # See <https://en.wikipedia.org/wiki/Certificate_signing_request>. countryName = optional stateOrProvinceName = optional localityName = optional 0.organizationName = optional organizationalUnitName = optional commonName = optional emailAddress = optional # Optionally, specify some defaults. countryName_default = CN stateOrProvinceName_default = China localityName_default = 0.organizationName_default = Alipay #organizationalUnitName_default = #emailAddress_default = [ v3_req ] # Extensions to add to a certificate request basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment subjectAltName = @alt_names [ alt_names ] DNS.1 = *.mqtt.iothub.aliyuncs.com DNS.2 = *.igw.iothub.aliyuncs.com [ v3_ca ] # Extensions for a typical CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ v3_intermediate_ca ] # Extensions for a typical intermediate CA (`man x509v3_config`). subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer basicConstraints = critical, CA:true, pathlen:0 keyUsage = critical, digitalSignature, cRLSign, keyCertSign [ usr_cert ] # Extensions for client certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = client, email nsComment = "OpenSSL Generated Client Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth, emailProtection [ server_cert ] # Extensions for server certificates (`man x509v3_config`). basicConstraints = CA:FALSE nsCertType = server nsComment = "OpenSSL Generated Server Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth subjectAltName = @alt_names [ crl_ext ] # Extension for CRLs (`man x509v3_config`). authorityKeyIdentifier=keyid:always [ ocsp ] # Extension for OCSP signing certificates (`man ocsp`). basicConstraints = CA:FALSE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, digitalSignature extendedKeyUsage = critical, OCSPSigning
执行以下命令,生成根证书私钥
sm2-root.key
和证书sm2-root.crt
。重要执行第2行命令时,需根据提示设置签名参数,例如countryName、stateOrProvinceName、organizationName、organizationalUnitName和commonName等。后续签发中间证书和服务端证书时,countryName、stateOrProvinceName、organizationName、organizationalUnitName设置必须此处设置保持一致,commonName设置必须保持唯一。
openssl ecparam -genkey -name SM2 -out sm2-root.key openssl req -new -key sm2-root.key -out sm2-root.csr -sm3 -sigopt "sm2_id:1234567812345678" mv sm2-root.key private/ && mv sm2-root.csr csr/ openssl ca -selfsign -config openssl.cnf -in csr/sm2-root.csr -extensions v3_ca -days 3650 -out sm2-root.crt mv sm2-root.crt certs/
执行以下命令,生成中间证书私钥
sm2-intermediate-ca.key
和证书sm2-intermediate-ca.crt
。openssl ecparam -genkey -name SM2 -out sm2-intermediate-ca.key openssl req -new -key sm2-intermediate-ca.key -out sm2-intermediate-ca.csr -sm3 -sigopt "sm2_id:1234567812345678" mv sm2-intermediate-ca.key private/ && mv sm2-intermediate-ca.csr csr/ openssl ca -config openssl.cnf -extensions v3_intermediate_ca -days 3650 -in csr/sm2-intermediate-ca.csr -out sm2-intermediate-ca.crt -sigopt "sm2_id:1234567812345678" -sm2-id "1234567812345678" -md sm3 mv sm2-intermediate-ca.crt certs/
执行以下命令,生成服务端证书私钥
sm2-leaf.key
和证书sm2-leaf.crt
。openssl ecparam -genkey -name SM2 -out sm2-leaf.key openssl req -new -key sm2-leaf.key -out sm2-leaf.csr -sm3 -sigopt "sm2_id:1234567812345678" mv sm2-leaf.key private/ && mv sm2-leaf.csr csr/ openssl ca -config openssl_middleca.cnf -extensions server_cert -days 3650 -in csr/sm2-leaf.csr -out sm2-leaf.crt -sigopt "sm2_id:1234567812345678" -sm2-id "1234567812345678" -md sm3 mv sm2-leaf.crt certs/
证书文件最终存放在/sm2-ca/certs
目录下,对应私钥文件存放在/sm2-ca/private
目录下。
根证书和私钥:
sm2-root.crt
、sm2-root.key
。中间证书:
sm2-intermediate-ca.crt
、sm2-intermediate-ca.key
。服务端证书:
sm2-leaf.crt
、sm2-leaf.key
。