你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

教程:创建和上传用于测试的证书

可以使用 X.509 证书向 IoT 中心对设备进行身份验证。 对于生产环境,我们建议从专业的证书服务供应商处购买 X.509 CA 证书。 然后,作为全面公钥基础结构 (PKI) 战略的一部分,可以在组织内从与购买的 CA 证书链接的内部自管理证书颁发机构 (CA) 颁发证书。 有关从专业证书服务供应商处获取 X.509 CA 证书的详细信息,请参阅使用 X.509 CA 证书验证设备获取 X.509 CA 证书部分。

但是,创建使用内部根 CA 作为信任定位点的自管理专用 CA 足以测试环境。 利用至少有一个从属 CA 链接到内部根 CA 的自管理专用 CA,以及由从属 CA 签名的设备客户端证书,可以模拟建议的生产环境。

注意

不建议在生产环境中使用自签名证书。 此教程仅用于演示目的。

以下教程使用 OpenSSLOpenSSL 指南来描述如何完成以下任务:

  • 创建内部根证书颁发机构 (CA) 和根 CA 证书
  • 创建由内部根 CA 证书签名的内部从属 CA 和从属 CA 证书
  • 将从属 CA 证书上传到 IoT 中心进行测试
  • 使用从属 CA 为要在 IoT 中心测试的 IoT 设备创建客户端证书

注意

Microsoft 提供了 PowerShell 和 Bash 脚本来帮助你了解如何创建你自己的 x.509 证书,并将在 IoT 中心进行身份验证。 这些脚本包含在适用于 C 的 Azure IoT 中心设备 SDK 中。这些脚本仅用于演示目的。 所创建的证书不得用于生产。 证书包含硬编码密码(“1234”)并在 30 天后过期。 必须使用自己的最佳做法在生产环境中创建证书并管理生存期。 有关详细信息,请参阅适用于 C 的 Azure IoT 中心设备 SDK 的 GitHub 存储库中的管理测试 CA 证书示例和教程

先决条件

  • Azure 订阅。 如果没有 Azure 订阅,请在开始之前创建一个免费帐户

  • Azure 订阅中的 IoT 中心。 如果还没有中心,则可以按照创建 IoT 中心中的步骤进行操作。

  • 最新版本的 Git。 确保将 Git 添加到可供命令窗口访问的环境变量。 请参阅软件自由保护组织提供的 Git 客户端工具,了解要安装的最新版 git 工具,其中包括 Git Bash,这是一个命令行应用,可以用来与本地 Git 存储库交互。

  • OpenSSL 安装。 在 Windows 上, Git 安装包含 OpenSSL 安装。 可以从 Git Bash 提示符访问 OpenSSL。 若要验证是否安装了 OpenSSL,请打开 Git Bash 提示符并输入 openssl version

    注意

    除非你熟悉 OpenSSL 并且已将其安装在 Windows 计算机上,否则我们建议从 Git Bash 提示符使用 OpenSSL。 或者,可以选择下载源代码并生成 OpenSSL。 若要了解详细信息,请参阅 OpenSSL 下载页。 或者,可以从第三方下载预生成的 OpenSSL。 若要了解详细信息,请参阅 OpenSSL wiki。 Microsoft 不保证从第三方下载的包的有效性。 如果你确实选择生成或下载 OpenSSL,请确保可在你的路径中访问 OpenSSL 二进制文件,并且 OPENSSL_CNF 环境变量设置为 openssl.cnf 文件的路径。

创建根 CA

必须先创建内部根证书颁发机构 (CA) 和自签名根 CA 证书来充当信任定位点,以便从中创建其他证书进行测试。 用于创建和维护内部根 CA 的文件存储在文件夹结构中,并作为此过程的一部分进行初始化。 执行以下步骤:

  • 创建和初始化根 CA 使用的文件夹和文件
  • 创建 OpenSSL 使用的配置文件来配置根 CA 以及使用根 CA 创建的证书
  • 请求并创建用作根 CA 证书的自签名 CA 证书
  1. 启动 Git Bash 窗口并运行以下命令,将 {base_dir} 替换为要在其中创建根 CA 的所需目录。

    cd {base_dir}
    
  2. 在 Git Bash 窗口中,运行以下命令,一次一个。 此步骤为根 CA 创建以下目录结构和支持文件。

    目录或文件 说明
    rootca 根 CA 的根目录。
    rootca/certs 在其中创建和存储根 CA 的 CA 证书的目录。
    rootca/db 存储根 CA 的证书数据库和支持文件的目录。
    rootca/db/index 根 CA 的证书数据库。 命令 touch 创建不带任何内容的文件,供以后使用。 证书数据库是由 OpenSSL 管理的纯文本文件,其中包含有关颁发的证书的信息。 有关证书数据库的详细信息,请参阅 OpenSSL 文档中的 openssl-ca 手册页。
    rootca/db/serial 用于存储要为根 CA 创建的下一个证书的序列号的文件。 命令 openssl 以十六进制格式创建一个 16 字节随机数,然后将其存储在此文件中,以初始化用于创建根 CA 证书的文件。
    rootca/db/crlnumber 用于存储根 CA 颁发的已吊销证书的序列号的文件。 命令 echo 通过管道将示例序列号 1001 传递到文件中。
    rootca/private 存储根 CA 的私有文件(包括私钥)的目录。
    必须保护此目录中的文件。
    mkdir rootca
    cd rootca
    mkdir certs db private
    chmod 700 private
    touch db/index
    openssl rand -hex 16 > db/serial
    echo 1001 > db/crlnumber
    
  3. 在上一步中创建的 rootca 目录中创建名为 rootca.conf 的文本文件。 在文本编辑器中打开该文件,然后将以下 OpenSSL 配置设置复制并保存到该文件中,将以下占位符替换为其相应的值。

    占位符 说明
    {rootca_name} 根 CA 的名称。 例如 rootca
    {domain_suffix} 根 CA 的域名后缀。 例如 example.com
    {rootca_common_name} 根 CA 的公用名。 例如 Test Root CA

    文件为 OpenSSL 提供配置测试根 CA 所需的值。 对于此示例,文件使用在前面的步骤中创建的目录和文件来配置根 CA。 该文件还提供以下各项的配置设置:

    • 根 CA 用于证书可分辨名称 (DN) 字段的 CA 策略
    • 根 CA 创建的证书请求
    • 应用于根 CA 证书、从属 CA 证书和根 CA 颁发的客户端证书的 X.509 扩展

    注意

    ca_default 部分中的 home 属性设置为 ../rootca,因为在为从属 CA 创建证书时也使用此配置文件。 指定的相对路径允许 OpenSSL 在此过程中从从属 CA 文件夹导航到根 CA 文件夹。

    有关 OpenSSL 配置文件的语法的详细信息,请参阅 OpenSSL 文档中的 config 手册页。

    [default]
    name                     = {rootca_name}
    domain_suffix            = {domain_suffix}
    aia_url                  = http://$name.$domain_suffix/$name.crt
    crl_url                  = http://$name.$domain_suffix/$name.crl
    default_ca               = ca_default
    name_opt                 = utf8,esc_ctrl,multiline,lname,align
    
    [ca_dn]
    commonName               = "{rootca_common_name}"
    
    [ca_default]
    home                     = ../rootca
    database                 = $home/db/index
    serial                   = $home/db/serial
    crlnumber                = $home/db/crlnumber
    certificate              = $home/$name.crt
    private_key              = $home/private/$name.key
    RANDFILE                 = $home/private/random
    new_certs_dir            = $home/certs
    unique_subject           = no
    copy_extensions          = none
    default_days             = 3650
    default_crl_days         = 365
    default_md               = sha256
    policy                   = policy_c_o_match
    
    [policy_c_o_match]
    countryName              = optional
    stateOrProvinceName      = optional
    organizationName         = optional
    organizationalUnitName   = optional
    commonName               = supplied
    emailAddress             = optional
    
    [req]
    default_bits             = 2048
    encrypt_key              = yes
    default_md               = sha256
    utf8                     = yes
    string_mask              = utf8only
    prompt                   = no
    distinguished_name       = ca_dn
    req_extensions           = ca_ext
    
    [ca_ext]
    basicConstraints         = critical,CA:true
    keyUsage                 = critical,keyCertSign,cRLSign
    subjectKeyIdentifier     = hash
    
    [sub_ca_ext]
    authorityKeyIdentifier   = keyid:always
    basicConstraints         = critical,CA:true,pathlen:0
    extendedKeyUsage         = clientAuth,serverAuth
    keyUsage                 = critical,keyCertSign,cRLSign
    subjectKeyIdentifier     = hash
    
    [client_ext]
    authorityKeyIdentifier   = keyid:always
    basicConstraints         = critical,CA:false
    extendedKeyUsage         = clientAuth
    keyUsage                 = critical,digitalSignature
    subjectKeyIdentifier     = hash
    
  4. 在 Git Bash 窗口中,运行以下命令在 rootca 目录中生成证书签名请求 (CSR),并在 rootca/private 目录中生成私钥。 有关 OpenSSL req 命令的详细信息,请参阅 OpenSSL 文档中的 openssl-req 手册页。

    注意

    即使此根 CA 用于测试目的,并且不会作为公钥基础结构 (PKI) 的一部分公开,但我们建议不要复制或共享私钥。

    winpty openssl req -new -config rootca.conf -out rootca.csr \
      -keyout private/rootca.key
    

    系统会提示你为私钥文件输入 PEM 密码,如以下示例所示。 输入并确认密码以生成私钥和 CSR。

    Enter PEM pass phrase:
    Verifying - Enter PEM pass phrase:
    -----
    

    在继续操作之前,请确认 CSR 文件 rootca.csr 存在于 rootca 目录中,私钥文件 rootca.key 存在于 private 子目录中。 有关 CSR 和私钥文件的格式的详细信息,请参阅 X.509 证书

  5. 在 Git Bash 窗口中,运行以下命令以创建自签名根 CA 证书。 命令将 ca_ext 配置文件扩展应用于证书。 这些扩展名表示证书适用于根 CA,可用于签署证书和证书吊销列表 (CRL)。 有关 OpenSSL ca 命令的详细信息,请参阅 OpenSSL 文档中的 openssl-ca 手册页。

    winpty openssl ca -selfsign -config rootca.conf -in rootca.csr -out rootca.crt \
      -extensions ca_ext
    

    系统会提示你为私钥文件提供 PEM 密码,如以下示例所示。 提供密码后,OpenSSL 会生成一个证书,然后提示你为根 CA 签名并提交证书。 为两个提示指定 y,以便为根 CA 生成自签名证书。

    Using configuration from rootca.conf
    Enter pass phrase for ../rootca/private/rootca.key:
    Check that the request matches the signature
    Signature ok
    Certificate Details:
        {Details omitted from output for clarity}
    Certificate is to be certified until Mar 24 18:51:41 2033 GMT (3650 days)
    Sign the certificate? [y/n]:
    
    
    1 out of 1 certificate requests certified, commit? [y/n]
    Write out database with 1 new entries
    Data Base Updated
    

    在 OpenSSL 更新证书数据库后,确认证书文件 rootca.crt 存在于 rootca 目录中,并且证书的 PEM 证书 (.pem) 文件存在于 rootca/certs 目录中。 .pem 文件的文件名与根 CA 证书的序列号匹配。 有关证书文件的格式的详细信息,请参阅 X.509 证书

创建从属 CA

创建内部根 CA 后,应创建一个从属 CA,其用作中间 CA 对设备的客户端证书进行签名。 从理论上讲,不需要创建从属 CA;可以将根 CA 证书上传到 IoT 中心,并直接从根 CA 对客户端证书进行签名。 但是,使用从属 CA 作为中间 CA 对客户端证书进行签名可以更密切地模拟建议的生产环境,其中根 CA 保持脱机状态。 还可以使用从属 CA 对另一个从属 CA 进行签名,进而为其他从属 CA 签名,依此类推。 使用从属 CA 对其他从属 CA 进行签名会创建中间 CA 的层次结构,其属于证书信任链的一部分。在生产环境中,证书信任链允许对签名设备进行信任委派。 有关将设备登录到证书信任链的详细信息,请参阅使用 X.509 CA 证书对设备进行身份验证

与根 CA 类似,用于创建和维护从属 CA 的文件存储在文件夹结构中,并在此过程中进行初始化。 执行以下步骤:

  • 创建和初始化从属 CA 使用的文件夹和文件
  • 创建 OpenSSL 使用的配置文件来配置从属 CA 和使用从属 CA 创建的证书
  • 请求并创建由根 CA 签名的 CA 证书,其用作从属 CA 证书
  1. 启动 Git Bash 窗口并运行以下命令,将 {base_dir} 替换为包含以前创建的根 CA 的目录。 对于此示例,根 CA 和从属 CA 都位于同一基目录中。

    cd {base_dir}
    
  2. 在 Git Bash 窗口中,运行以下命令,一次一个,将以下占位符替换为其相应的值。

    占位符 说明
    {subca_dir} 从属 CA 的目录的名称。 例如 subca

    此步骤为从属 CA 创建目录结构和支持文件,类似于在创建根 CA 中为根 CA 创建的文件夹结构和文件。

    mkdir {subca_dir}
    cd {subca_dir}
    mkdir certs db private
    chmod 700 private
    touch db/index
    openssl rand -hex 16 > db/serial
    echo 1001 > db/crlnumber
    
  3. 针对在上一步中创建的从属 CA,在 {subca_dir} 中指定的目录中创建名为 subca.conf 的文本文件。 在文本编辑器中打开该文件,然后将以下 OpenSSL 配置设置复制并保存到该文件中,将以下占位符替换为其相应的值。

    占位符 说明
    {subca_name} 从属 CA 的名称。 例如 subca
    {domain_suffix} 从属 CA 的域名后缀。 例如 example.com
    {subca_common_name} 从属 CA 的公用名。 例如 Test Subordinate CA

    与测试根 CA 的配置文件一样,此文件为 OpenSSL 提供配置测试从属 CA 所需的值。 你可以创建多个从属 CA,用于管理测试方案或环境。

    有关 OpenSSL 配置文件的语法的详细信息,请参阅 OpenSSL 文档中的 config 主手册页。

    [default]
    name                     = {subca_name}
    domain_suffix            = {domain_suffix}
    aia_url                  = http://$name.$domain_suffix/$name.crt
    crl_url                  = http://$name.$domain_suffix/$name.crl
    default_ca               = ca_default
    name_opt                 = utf8,esc_ctrl,multiline,lname,align
    
    [ca_dn]
    commonName               = "{subca_common_name}"
    
    [ca_default]
    home                     = ../{subca_name}
    database                 = $home/db/index
    serial                   = $home/db/serial
    crlnumber                = $home/db/crlnumber
    certificate              = $home/$name.crt
    private_key              = $home/private/$name.key
    RANDFILE                 = $home/private/random
    new_certs_dir            = $home/certs
    unique_subject           = no
    copy_extensions          = copy
    default_days             = 365
    default_crl_days         = 90
    default_md               = sha256
    policy                   = policy_c_o_match
    
    [policy_c_o_match]
    countryName              = optional
    stateOrProvinceName      = optional
    organizationName         = optional
    organizationalUnitName   = optional
    commonName               = supplied
    emailAddress             = optional
    
    [req]
    default_bits             = 2048
    encrypt_key              = yes
    default_md               = sha256
    utf8                     = yes
    string_mask              = utf8only
    prompt                   = no
    distinguished_name       = ca_dn
    req_extensions           = ca_ext
    
    [ca_ext]
    basicConstraints         = critical,CA:true
    keyUsage                 = critical,keyCertSign,cRLSign
    subjectKeyIdentifier     = hash
    
    [sub_ca_ext]
    authorityKeyIdentifier   = keyid:always
    basicConstraints         = critical,CA:true,pathlen:0
    extendedKeyUsage         = clientAuth,serverAuth
    keyUsage                 = critical,keyCertSign,cRLSign
    subjectKeyIdentifier     = hash
    
    [client_ext]
    authorityKeyIdentifier   = keyid:always
    basicConstraints         = critical,CA:false
    extendedKeyUsage         = clientAuth
    keyUsage                 = critical,digitalSignature
    subjectKeyIdentifier     = hash
    
  4. 在 Git Bash 窗口中运行以下命令,在从属 CA 目录中生成私钥和证书签名请求 (CSR)。

    winpty openssl req -new -config subca.conf -out subca.csr \
      -keyout private/subca.key
    

    系统会提示你为私钥文件输入 PEM 密码,如以下示例所示。 输入并验证密码以生成私钥和 CSR。

    Enter PEM pass phrase:
    Verifying - Enter PEM pass phrase:
    -----
    

    在继续操作之前,请确认 CSR 文件 subca.csr 存在于从属 CA 目录中,私钥文件 subca.key 存在于 private 子目录中。 有关 CSR 和私钥文件的格式的详细信息,请参阅 X.509 证书

  5. 在 Git Bash 窗口中运行以下命令,在从属 CA 目录中创建从属 CA 证书。 命令将 sub_ca_ext 配置文件扩展应用于证书。 这些扩展表示证书适用于从属 CA,还可用于签署证书和证书吊销列表 (CRL)。 与根 CA 证书不同,此证书不是自签名证书。 相反,从属 CA 证书使用根 CA 证书进行签名,从而建立一个与用于公钥基础结构 (PKI) 的证书链类似的证书链。 然后,使用从属 CA 证书对客户端证书进行签名,以测试设备。

    winpty openssl ca -config ../rootca/rootca.conf -in subca.csr -out subca.crt \
      -extensions sub_ca_ext
    

    系统会提示输入根 CA 的私钥文件的密码,如以下示例所示。 输入密码后,OpenSSL 会生成并显示证书的详细信息,然后提示你为从属 CA 签名并提交证书。 为两个提示指定 y,以便为从属 CA 生成证书。

    Using configuration from rootca.conf
    Enter pass phrase for ../rootca/private/rootca.key:
    Check that the request matches the signature
    Signature ok
    Certificate Details:
        {Details omitted from output for clarity}
    Certificate is to be certified until Mar 24 18:55:00 2024 GMT (365 days)
    Sign the certificate? [y/n]:
    
    
    1 out of 1 certificate requests certified, commit? [y/n]
    Write out database with 1 new entries
    Data Base Updated
    

    OpenSSL 更新证书数据库后,确认证书文件 subca.crt 存在于从属 CA 目录中,并且证书的 PEM 证书 (.pem) 文件存在于 rootca/certs 目录中。 .pem 文件的文件名与从属 CA 证书的序列号匹配。 有关证书文件的格式的详细信息,请参阅 X.509 证书

将从属 CA 证书注册到 IoT 中心

创建从属 CA 证书后,必须将从属 CA 证书注册到 IoT 中心,后者在注册和连接期间使用该证书对设备进行身份验证。 注册证书是一个两步过程,包括上传证书文件,然后建立所有权证明。 将从属 CA 证书上传到 IoT 中心时,可以将其设置为自动验证,这样就无需手动建立所有权证明。 以下步骤介绍如何将从属 CA 证书上传到 IoT 中心并自动验证。

  1. 在 Azure 门户中,导航到你的 IoT 中心,从资源菜单中的“安全设置”下选择“证书”。

  2. 从命令栏中选择“添加”,以添加新的 CA 证书。

  3. 在“证书名称”字段中输入从属 CA 证书的显示名称。

  4. rootca/certs 目录中选择从属 CA 证书的 PEM 证书 (.pem) 文件,以添加到“证书 .pem 或 .cer 文件”字段中。

  5. 选中“在上传时将证书状态设置为已验证”旁边的复选框。

    屏幕截图显示如何在上传时自动验证证书状态。

  6. 选择“保存”。

你上传的从属 CA 证书在工作窗格的“证书”选项卡上显示,其状态设置为“已验证”。

为设备创建客户端证书

创建从属 CA 后,可以为设备创建客户端证书。 你为从属 CA 创建的文件和文件夹用于存储客户端证书的 CSR、私钥和证书文件。

客户端证书的使用者公用名 (CN) 字段的值必须设置为在 Azure IoT 中心注册相应设备时使用的设备 ID 值。 有关证书字段的详细信息,请参阅 X.509 证书证书字段部分。

执行以下步骤:

  • 为客户端证书创建私钥和证书签名请求 (CSR)
  • 创建由从属 CA 证书签名的客户端证书
  1. 启动 Git Bash 窗口并运行以下命令,将 {base_dir} 替换为包含以前创建的根 CA 和从属 CA 的目录。

    cd {base_dir}
    
  2. 在 Git Bash 窗口中,运行以下命令,一次一个,将以下占位符替换为其相应的值。 此步骤为客户端证书创建私钥和 CSR。

    占位符 说明
    {subca_dir} 从属 CA 的目录的名称。 例如 subca
    {device_name} IoT 设备的名称。 例如 testdevice

    此步骤为客户端证书创建 2048 位 RSA 私钥,然后使用该私钥生成证书签名请求 (CSR)。

    cd {subca_dir}
    winpty openssl genpkey -out private/{device_name}.key -algorithm RSA \
      -pkeyopt rsa_keygen_bits:2048
    winpty openssl req -new -key private/{device_name}.key -out {device_name}.csr
    

    系统会提示你提供证书详细信息,如以下示例所示。 将以下占位符替换为相应的值。

    占位符 说明
    *{device_id} IoT 设备的标识符。 例如 testdevice

    此值必须与 IoT 中心内为你的设备的相应设备标识指定的设备 ID 匹配。

    可以选择为其他字段(例如“国家/地区名称”、“组织名称”等)输入自己的值。 无需输入质询密码或可选公司名称。 提供证书详细信息后,OpenSSL 会生成并显示证书的详细信息,然后提示你为从属 CA 签名并提交证书。 为两个提示指定 y,以便为从属 CA 生成证书。

    -----
    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) []:'{device_id}'
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    
    

    在继续操作之前,请确认 CSR 文件存在于从属 CA 目录中,私钥文件存在于 private 子目录中。 有关 CSR 和私钥文件的格式的详细信息,请参阅 X.509 证书

  3. 在 Git Bash 窗口中,运行以下命令,将以下占位符替换为其相应的值。 此步骤在从属 CA 目录中创建客户端证书。 命令将 client_ext 配置文件扩展应用于证书。 这些扩展指示证书适用于客户端证书,不能将其用作 CA 证书。 客户端证书使用从属 CA 证书进行签名。

    winpty openssl ca -config subca.conf -in {device_name}.csr -out {device_name}.crt \
      -extensions client_ext
    

    系统会提示输入从属 CA 的私钥文件的密码,如以下示例所示。 输入密码后,OpenSSL 会生成并显示证书的详细信息,然后提示你为设备签名并提交客户端证书。 为两个提示指定 y 以生成客户端证书。

    Using configuration from subca.conf
    Enter pass phrase for ../subca/private/subca.key:
    Check that the request matches the signature
    Signature ok
    Certificate Details:
        {Details omitted from output for clarity}
    Certificate is to be certified until Mar 24 18:51:41 2024 GMT (365 days)
    Sign the certificate? [y/n]:
    
    
    1 out of 1 certificate requests certified, commit? [y/n]
    Write out database with 1 new entries
    Data Base Updated
    

    OpenSSL 更新证书数据库后,确认客户端证书的证书文件存在于从属 CA 目录中,并且客户端证书的 PEM 证书 (.pem) 文件存在于从属 CA 目录的 certs 子目录中。 .pem 文件的文件名与客户端证书的序列号匹配。 有关证书文件的格式的详细信息,请参阅 X.509 证书

后续步骤

你可以向 IoT 中心注册设备,以测试为该设备创建的客户端证书。 有关注册设备的详细信息,请参阅使用 Azure 门户创建 IoT 中心中的在 IoT 中心注册新设备部分。

如果有多个相关设备要测试,则可以使用 Azure IoT 中心设备预配服务在注册组中预配多个设备。 有关在设备预配服务中使用注册组的详细信息,请参阅教程:使用注册组预配多个 X.509 设备