签发自定义证书

设备端使用MQTTGB/T 32960JT/T 808SL 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)上,准备对应的环境。

  1. 登录操作系统。ECS实例登录方式,请参见连接方式概述

  2. 执行以下命令,安装make编译工具。

    sudo yum install make
  3. 执行以下命令,安装C库和C编译器。

    sudo yum install gcc
  4. 执行以下命令,安装unzip,用于后续解压Tongsuo源码包。

    说明

    如果不签发SM2算法证书,无需安装unzip

    yum update
    yum install zip
  5. 执行以下命令,安装Perl 5以及Text::Template模块,用于后续安装Tongsuo源码库。

    说明

    如果不签发SM2算法证书,无需安装Perl 5以及Text::Template模块。

    sudo yum install perl
    sudo yum install perl-core

签发RSA算法的证书

  1. 在ECS实例的操作系统中创建一个文件夹存放生成的证书。

    mkdir /home/rsa_certs
    cd /home/rsa_certs
  2. 执行以下命令生成设备端和服务端的根证书文件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
  3. 根据根证书文件root-ca.crt,自定义服务端证书。

    1. 执行以下命令生成服务端密钥文件server.key

      openssl genrsa -out server.key 2048
    2. 执行命令touch openssl.cnf新建文件openssl.cnf

    3. 执行命令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
    4. 执行以下命令生成服务端请求文件server.csr

      openssl req -new -key server.key -config openssl.cnf -out server.csr
    5. 执行以下命令生成服务端证书文件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
    6. 执行以下命令验证服务端证书。

      openssl verify -CAfile root-ca.crt server.crt
  4. 根据根证书文件root-ca.crt,自定义设备端证书。

    1. 执行以下命令生成设备端密钥文件client.key

      openssl genrsa -out client.key 2048
    2. 执行以下命令生成设备端证书请求文件client.csr。本示例设置CNClient_123

      openssl req -new -key client.key -out client.csr -subj "/CN=Client_123"
    3. 执行以下命令生成设备端证书文件client.crt

      openssl x509 -req -days 365 -sha256 -in client.csr -CA root-ca.crt -CAkey root-ca.key -CAcreateserial -out client.crt
    4. 执行以下命令验证设备端证书。

      openssl verify -CAfile root-ca.crt client.crt
  5. 执行命令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文件时,设置的countryNamestateOrProvinceNameorganizationNameorganizationalUnitName必须保持一致,但commonName必须保持唯一

  1. 在ECS实例的操作系统中创建一个文件夹存放生成国密证书相关的文件。

    mkdir /home/sm2
    cd /home/sm2
  2. 按照以下步骤上传并安装Tongsuo

    1. 下载Tongsuo的文件包Tongsuo-8.4.0-pre3.zip

    2. 上传本地文件到操作系统的“sm2”文件目录下

    3. 执行以下命令解压文件包。

      unzip Tongsuo-8.4.0-pre3.zip
    4. 执行以下命令,进入文件目录Tongsuo-8.4.0-pre3并完成安装Tongsuo。

      cd Tongsuo-8.4.0-pre3
      ./config
      make
      make install
    5. 执行命令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)
  3. 新增路径构建脚本gen-sm2-cert-sign-dir.sh,构建文件目录sm2-ca管理签发的证书。

    1. 执行命令touch gen-sm2-cert-sign-dir.sh,新建脚本文件gen-sm2-cert-sign-dir.sh

    2. 执行命令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
      
      
    3. 执行命令chmod +x gen-sm2-cert-sign-dir.sh为脚本文件添加执行权限。

    4. 执行命令./gen-sm2-cert-sign-dir.sh运行脚本,完成构建文件目录sm2-ca

  4. 执行命令cd sm2-ca 进入文件目录sm2-ca,然后参考上一步骤中的touchvi命令,新增配置文件openssl.cnfopenssl_middleca.cnf

    说明

    如果需指定域名,可在配置文件openssl.cnfopenssl_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
    
    
  5. 执行以下命令,生成根证书私钥sm2-root.key和证书sm2-root.crt

    重要

    执行第2行命令时,需根据提示设置签名参数,例如countryNamestateOrProvinceNameorganizationNameorganizationalUnitNamecommonName等。后续签发中间证书和服务端证书时,countryNamestateOrProvinceNameorganizationNameorganizationalUnitName设置必须此处设置保持一致,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/
  6. 执行以下命令,生成中间证书私钥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/
  7. 执行以下命令,生成服务端证书私钥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.crtsm2-root.key

  • 中间证书:sm2-intermediate-ca.crtsm2-intermediate-ca.key

  • 服务端证书:sm2-leaf.crtsm2-leaf.key

相关文档