Java教程

创建私有证书颁发机构

本文主要是介绍创建私有证书颁发机构,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

本文是对https://www.feistyduck.com/library/openssl-cookbook/online/ch-openssl.html#openssl-private-ca的翻译

创建私有证书颁发机构

如果您想建立自己的 CA,您需要的一切都已包含在 OpenSSL 中。 用户界面纯粹是基于命令行的,因此对用户不是很友好,但这可能会更好。 经历这个过程很有教育意义,因为它迫使你思考每一个方面,甚至是最小的细节。

尽管还有其他原因,设置私有 CA 的教育意义是我建议这样做的主要原因。 基于 OpenSSL 的 CA,尽管它可能很粗糙,但可以很好地满足个人或小团队的需求。 例如,在开发环境中使用私有 CA 比在任何地方都使用自签名证书要好得多。 同样,提供双重身份验证的客户端证书可以显着提高敏感 Web 应用程序的安全性。

运行私有 CA 的最大挑战不是设置所有内容,而是保持基础架构的安全。 例如,根密钥必须保持离线,因为所有安全都依赖于它。 另一方面,CRLs 和 OCSP 响应者证书必须定期刷新,这需要使根联机。

在阅读本节时,您将创建两个配置文件:一个用于控制根 CA (root-ca.conf),另一个用于控制从属 CA (sub-ca.conf)。 虽然您应该可以按照我的说明从头开始做所有事情,但您也可以从我的 GitHub 帐户下载配置文件模板。20后一种方法可以节省您一些时间,但前一种方法可以让您更好地理解所涉及的工作。

特性和限制

在本节的其余部分,我们将创建一个与公共 CA 结构相似的私有 CA。 将有一个根 CA,可以从中创建其他从属 CA。 我们将通过 CRL 和 OCSP 响应程序提供撤销信息。 为了使根 CA 保持离线状态,OCSP 响应者将拥有自己的身份。 这不是您可以拥有的最简单的私有 CA,但它是可以正确保护的。 作为奖励,从属 CA 将在技术上受到限制,这意味着它只能为允许的主机名颁发证书。

设置完成后,必须将根证书安全地分发给所有预期的客户端。 一旦根就位,您就可以开始颁发客户端和服务器证书。 这种设置的主要限制是 OCSP 响应器主要是为测试而设计的,只能用于较轻的负载。

创建根 CA

创建一个新的 CA 涉及几个步骤:配置、创建目录结构和初始化密钥文件,最后生成根密钥和证书。 本节介绍流程以及常见的 CA 操作。

根 CA 配置

在我们实际创建 CA 之前,我们需要准备一个配置文件 (root-ca.conf),它将准确地告诉 OpenSSL 我们希望如何设置。 在正常使用期间,大多数时候不需要配置文件,但在涉及复杂操作(例如创建根 CA)时,它们是必不可少的。 OpenSSL 配置文件功能强大; 在您继续之前,我建议您熟悉它们的功能(命令行上的 man config)。

配置文件的第一部分包含一些基本的 CA 信息,例如名称和基本 URL,以及 CA 专有名称的组成部分。 因为语法很灵活,信息只需要提供一次:

[default]
name                    = root-ca
domain_suffix           = example.com
aia_url                 = http://$name.$domain_suffix/$name.crt
crl_url                 = http://$name.$domain_suffix/$name.crl
ocsp_url                = http://ocsp.$name.$domain_suffix:9080
default_ca              = ca_default
name_opt                = utf8,esc_ctrl,multiline,lname,align

[ca_dn]
countryName             = "GB"
organizationName        = "Example"
commonName              = "Root CA"

第二部分直接控制 CA 的操作。 有关每个设置的完整信息,请参阅 ca 命令的文档(命令行上的 man ca)。 大多数设置是不言自明的; 我们主要告诉 OpenSSL 我们要将文件保存在哪里。 因为这个根 CA 将仅用于下级 CA 的颁发,所以我选择让证书有效期为 10 年。 对于签名算法,默认使用安全的 SHA256。

配置默认策略 (policy_c_o_match),以便从该 CA 颁发的所有证书都具有与 CA 匹配的 countryName 和 organizationName 字段。 公共 CA 通常不会这样做,但它适用于私有 CA:

[ca_default]
home                    = .
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             = match
stateOrProvinceName     = optional
organizationName        = match
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

第三部分包含 req 命令的配置,该命令仅在创建自签名根证书期间使用一次。 最重要的部分在扩展中:basicConstraints 扩展表明证书是一个 CA,keyUsage 包含此场景的适当设置:

[req]
default_bits            = 4096
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

配置文件的第四部分包含在构建由根 CA 颁发的证书期间将使用的信息。 如 basicConstraints 扩展所示,所有证书都是 CA,但我们将 pathlen 设置为零,这意味着不允许进一步的从属 CA。

所有从属 CA 都将受到限制,这意味着它们颁发的证书将仅对域名子集和受限用途有效。 首先,extendedKeyUsage 扩展只指定了clientAuth 和serverAuth,即TLS 客户端和服务器认证。 其次,nameConstraints 扩展将允许的主机名仅限于 example.com 和 example.org 域名。 从理论上讲,此设置使您能够将下级 CA 的控制权交给其他人,但仍然可以安全地知道他们不能为任意主机名颁发证书。 如果您愿意,您可以将每个从属 CA 限制在一个小的域名称空间中。 排除这两个 IP 地址范围的要求来自 CA/浏览器论坛的基线要求,其中定义了技术受限的从属 CA。21

在实践中,名称约束并不完全实用,因为一些主要平台目前不识别 nameConstraints 扩展。 如果您将此扩展标记为关键,则此类平台将拒绝您的证书。 如果您不将其标记为关键(如示例中所示),您将不会遇到此类问题,但是其他一些平台不会强制执行它。

[sub_ca_ext]
authorityInfoAccess     = @issuer_info
authorityKeyIdentifier  = keyid:always
basicConstraints        = critical,CA:true,pathlen:0
crlDistributionPoints   = @crl_info
extendedKeyUsage        = clientAuth,serverAuth
keyUsage                = critical,keyCertSign,cRLSign
nameConstraints         = @name_constraints
subjectKeyIdentifier    = hash

[crl_info]
URI.0                   = $crl_url

[issuer_info]
caIssuers;URI.0         = $aia_url
OCSP;URI.0              = $ocsp_url

[name_constraints]
permitted;DNS.0=example.com
permitted;DNS.1=example.org
excluded;IP.0=0.0.0.0/0.0.0.0
excluded;IP.1=0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0

配置的第五部分也是最后一部分指定要与证书一起用于 OCSP 响应签名的扩展。 为了能够运行 OCSP 响应程序,我们生成一个特殊证书并将 OCSP 签名能力委托给它。 此证书不是 CA,您可以从扩展中看到:

[ocsp_ext]
authorityKeyIdentifier  = keyid:always
basicConstraints        = critical,CA:false
extendedKeyUsage        = OCSPSigning
keyUsage                = critical,digitalSignature
subjectKeyIdentifier    = hash

根 CA 目录结构

下一步是创建上一节中指定的目录结构,并初始化一些将在 CA 操作期间使用的文件:

$ mkdir root-ca
$ cd root-ca
$ mkdir certs db private
$ chmod 700 private
$ touch db/index
$ openssl rand -hex 16  > db/serial
$ echo 1001 > db/crlnumber

使用以下子目录:

certs/
证书存储; 新证书将在颁发时放置在这里。

db/
此目录用于证书数据库(索引)和保存下一个证书和 CRL 序列号的文件。 OpenSSL 将根据需要创建一些附加文件。

private/
该目录将存储私钥,一个用于 CA,另一个用于 OCSP 响应者。 重要的是没有其他用户可以访问它。 (事实上​​,如果您要认真对待 CA,存储根材料的机器应该只有最少数量的用户帐户。)

注意
在创建新的 CA 证书时,使用随机数生成器初始化证书序列号很重要,就像我在本节中所做的那样。 如果您最终创建和部署了多个具有相同专有名称的 CA 证书,这将非常有用(如果您犯了错误并需要重新开始,这很常见); 将避免冲突,因为证书将具有不同的序列号。

根 CA 生成

我们采取两个步骤来创建根 CA。 首先,我们生成密钥和 CSR。 当我们使用 - config 开关时,将从配置文件中获取所有必要的信息:

$ openssl req -new \
    -config root-ca.conf \
    -out root-ca.csr \
    -keyout private/root-ca.key

第二步,我们创建一个自签名证书。 -extensions 开关指向配置文件中的 ca_ext 部分,该部分激活适用于根 CA 的扩展:

$ openssl ca -selfsign \
    -config root-ca.conf \
    -in root-ca.csr \
    -out root-ca.crt \
    -extensions ca_ext

数据库文件的结构

db/index 中的数据库是一个包含证书信息的明文文件,每行一个证书。 在创建根 CA 之后,它应该只包含一行:

V    240706115345Z        1001    unknown    /C=GB/O=Example/CN=Root CA

每行包含由制表符分隔的六个值:

  1. 状态标志(V 为有效,R 为已撤销,E 为过期)
  2. 到期日期(YYMMDDHHMMSSZ 格式)
  3. 撤销日期或未撤销则为空
  4. 序列号(十六进制)
  5. 文件位置或未知(如果不知道)
  6. 专有名称

根 CA 操作

要从新 CA 生成 CRL,请使用 ca 命令的 -gencrl 开关:

$ openssl ca -gencrl \
    -config root-ca.conf \
    -out root-ca.crl

要颁发证书,请使用所需参数调用 ca 命令。 重要的是-extensions 开关指向配置文件中的正确部分(例如,您不想创建另一个根CA)。

$ openssl ca \
    -config root-ca.conf \
    -in sub-ca.csr \
    -out sub-ca.crt \
    -extensions sub_ca_ext

要撤销证书,请使用 ca 命令的 -revoke 开关; 您需要有一份您希望撤销的证书的副本。 因为所有的证书都存放在 certs/ 目录下,所以只需要知道序列号即可。 如果您有专有名称,则可以在数据库中查找序列号。

为 -crl_reason 开关中的值选择正确的原因。 该值可以是以下之一:unspecified、keyCompromise、CACompromise、affiliationChanged、superseded、cessationOfOperation、certificateHold 和 removeFromCRL。

$ openssl ca \
    -config root-ca.conf \
    -revoke certs/1002.pem \
    -crl_reason keyCompromise

为 OCSP 签名创建证书

首先,我们为 OCSP 响应者创建一个密钥和 CSR。 这两个操作与任何非 CA 证书一样完成,这就是我们不指定配置文件的原因:

$ openssl req -new \
    -newkey rsa:2048 \
    -subj "/C=GB/O=Example/CN=OCSP Root Responder" \
    -keyout private/root-ocsp.key \
    -out root-ocsp.csr

其次,使用根 CA 颁发证书。 -extensions 开关的值指定 ocsp_ext,它确保设置了适合 OCSP 签名的扩展。 我将新证书的生命周期缩短到 365 天(从默认的 3,650 天)。 因为这些 OCSP 证书不包含吊销信息,所以它们不能被吊销。 因此,您希望尽可能缩短生命周期。 假如您准备以一个频率生成新的证书,30 天是一个不错的选择:

$ openssl ca \
    -config root-ca.conf \
    -in root-ocsp.csr \
    -out root-ocsp.crt \
    -extensions ocsp_ext \
    -days 30

现在您已准备好启动 OCSP 响应程序。 对于测试,您可以在根 CA 所在的同一台机器上进行。 但是,对于生产环境,您必须将 OCSP 响应者密钥和证书移到其他地方:

$ openssl ocsp \
    -port 9080
    -index db/index \
    -rsigner root-ocsp.crt \
    -rkey private/root-ocsp.key \
    -CA root-ca.crt \
    -text

您可以使用以下命令行测试 OCSP 响应程序的操作:

$ openssl ocsp \
    -issuer root-ca.crt \
    -CAfile root-ca.crt \
    -cert root-ocsp.crt \
    -url http://127.0.0.1:9080

在输出中,verify OK 表示签名已正确验证,good 表示证书尚未被吊销。

Response verify OK
root-ocsp.crt: good
        This Update: Jul  9 18:45:34 2014 GMT

创建从属 CA

从属 CA 的生成过程很大程度上与根 CA 的过程相同。 在本节中,我将仅在适当的地方强调差异。 有关其他所有内容,请参阅上一节。

从属 CA 配置

要为从属 CA 生成配置文件 (sub-ca.conf),请从我们用于根 CA 的文件开始,并进行本节中列出的更改。 我们将名称更改为 sub-ca 并使用不同的专有名称。 我们会将 OCSP 响应程序放在不同的端口上,但这只是因为 ocsp 命令不支持虚拟主机。 如果您为 OCSP 响应程序使用了适当的 Web 服务器,则可以完全避免使用特殊端口。 新证书的默认有效期为 365 天,我们将每 30 天生成一次新的 CRL。

将 copy_extensions 更改为 copy 意味着来自 CSR 的扩展将被复制到证书中,但前提是它们尚未在我们的配置中设置。 通过此更改,准备 CSR 的任何人都可以将所需的替代名称放入其中,从中提取的信息将被提取并放入证书中。 此功能有些危险(您允许其他人对证书中的内容进行有限的直接控制),但我认为它适用于较小的环境:

[default]
name                    = sub-ca
ocsp_url                = http://ocsp.$name.$domain_suffix:9081

[ca_dn]
countryName             = "GB"
organizationName        = "Example"
commonName              = "Sub CA"

[ca_default]
default_days            = 365
default_crl_days        = 30
copy_extensions         = copy

在配置文件的末尾,我们将添加两个新配置节,分别用于客户端证书和服务器证书。 唯一的区别在于 keyUsage 和 extendedKeyUsage 扩展。 请注意,我们指定了 basicConstraints 扩展,但将其设置为 false。 我们这样做是因为我们从 CSR 复制扩展。 如果我们不考虑这个扩展,我们最终可能会使用 CSR 中指定的扩展:

[server_ext]
authorityInfoAccess     = @issuer_info
authorityKeyIdentifier  = keyid:always
basicConstraints        = critical,CA:false
crlDistributionPoints   = @crl_info
extendedKeyUsage        = clientAuth,serverAuth
keyUsage                = critical,digitalSignature,keyEncipherment
subjectKeyIdentifier    = hash

[client_ext]
authorityInfoAccess     = @issuer_info
authorityKeyIdentifier  = keyid:always
basicConstraints        = critical,CA:false
crlDistributionPoints   = @crl_info
extendedKeyUsage        = clientAuth
keyUsage                = critical,digitalSignature
subjectKeyIdentifier    = hash

对配置文件满意后,按照与根 CA 相同的过程创建目录结构。 只需使用不同的目录名称,例如 sub-ca。

从属 CA 生成

和根 CA 一样,我们采取两个步骤来创建从属 CA。 首先,我们生成密钥和 CSR。 当我们使用 -config 开关时,所有必要的信息都将从配置文件中获取。

$ openssl req -new \
    -config sub-ca.conf \
    -out sub-ca.csr \
    -keyout private/sub-ca.key

第二步,我们让根 CA 颁发证书。 -extensions 开关指向配置文件中的 sub_ca_ext 部分,该部分激活适用于从属 CA 的扩展。

$ openssl ca \
    -config root-ca.conf \
    -in sub-ca.csr \
    -out sub-ca.crt \
    -extensions sub_ca_ext

从属 CA 操作

要颁发服务器证书,请在 -extensions 开关中指定 server_ext 时处理 CSR:

$ openssl ca \
    -config sub-ca.conf \
    -in server.csr \
    -out server.crt \
    -extensions server_ext

要颁发客户端证书,请在 -extensions 开关中指定 client_ext 时处理 CSR:

$ openssl ca \
    -config sub-ca.conf \
    -in client.csr \
    -out client.crt \
    -extensions client_ext

注意
当请求新证书时,其所有信息将在操作完成之前提供给您进行验证。 您应该始终确保一切都是合宜的,尤其是当您正在使用其他人准备的 CSR 时。 请特别注意证书专有名称以及 basicConstraints 和 subjectAlternativeName 扩展。

CRL 生成和证书吊销与根 CA 相同。 OCSP 响应器唯一不同的是端口。 从属 CA 应改为使用 9081。 建议响应者使用自己的证书,这样可以避免将从属 CA 保留在公共服务器上。


[20] OpenSSL CA configuration templates (Bulletproof TLS and PKI GitHub repository, retrieved 20 October 2021)
[21] Baseline Requirements (The CA/Browser Forum, retrieved 9 July 2014)

这篇关于创建私有证书颁发机构的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!