协慌网

登录 贡献 社区

如何使用 OpenSSL 创建自签名证书

我正在为嵌入式 Linux 设备添加 HTTPS 支持。我尝试使用以下步骤生成自签名证书:

openssl req -new > cert.csr
openssl rsa -in privkey.pem -out key.pem
openssl x509 -in cert.csr -out cert.pem -req -signkey key.pem -days 1001
cat key.pem>>cert.pem

这有效,但我在使用 Google Chrome 时遇到了一些错误:

这可能不是您要找的网站!
该网站的安全证书不受信任!

我错过了什么吗?这是构建自签名证书的正确方法吗?

答案

您可以在一个命令中执行此操作:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365

如果您不想使用密码短语保护私钥,也可以添加-nodesno DES简称)。否则它会提示您输入 “至少 4 个字符” 的密码。

days参数(365)可以替换为任何数字以影响到期日期。然后它会提示您输入 “国家 / 地区名称” 等内容,但您只需按 Enter 键即可接受默认设置。

添加-subj '/CN=localhost'以禁止有关证书内容的问题(将localhost替换为您所需的域)。

除非您先前将自签名证书导入浏览器,否则不会向任何第三方验证自签名证书。如果需要更高的安全性,则应使用由证书颁发机构 (CA)签名的证书

我错过了什么吗?这是构建自签名证书的正确方法吗?

创建自签名证书很容易。您只需使用openssl req命令。创建一个可供最大客户端选择的服务器(如浏览器和命令行工具)可能会很棘手。

这很困难,因为浏览器有自己的一套要求,而且它们比IETF更具限制性。浏览器使用的要求记录在CA / 浏览器论坛中 (请参阅下面的参考资料)。这些限制出现在两个关键领域:(1)信任锚,以及(2)DNS 名称。

现代浏览器(如我们在 2014/2015 年使用的 warez)需要一个链接回信任锚的证书,并且他们希望在证书中以特定方式呈现 DNS 名称。浏览器正在积极地反对自签名服务器证书。

某些浏览器并不能完全轻松导入自签名服务器证书。事实上,你不能用某些浏览器,比如 Android 的浏览器。所以完整的解决方案就是成为你自己的权威。

如果没有成为您自己的权限,您必须获得正确的 DNS 名称,以便为证书提供最大的成功机会。但我鼓励你成为自己的权威。很容易成为你自己的权威,它会回避所有的信任问题(谁比你自己更信任?)。


这可能不是您要找的网站!
该网站的安全证书不受信任!

这是因为浏览器使用预定义的信任锚列表来验证服务器证书。自签名证书不会链回到受信任的锚点。

避免这种情况的最佳方法是:

  1. 创建自己的权限(即成为CA
  2. 为服务器创建证书签名请求(CSR)
  3. 使用 CA 密钥对服务器的 CSR 进行签名
  4. 在服务器上安装服务器证书
  5. 在客户端上安装 CA 证书

步骤 1 - 创建自己的权限只是意味着使用CA: true创建自签名证书CA: true和正确的密钥用法。这意味着SubjectIssuer是同一个实体,CA 在Basic Constraints 中设置为 true(它也应该被标记为关键),密钥用法是keyCertSigncrlSign (如果你使用的是 CRL), 主题密钥标识符 (SKI) )与授权密钥标识符 (AKI)相同。

要成为您自己的证书颁发机构,请参阅 * 如何使用您的证书颁发机构签署证书签名请求?在 Stack Overflow 上。然后,将您的 CA 导入浏览器使用的 Trust Store。

当您获得 CA(如StartcomCAcert)的服务时,步骤 2 - 4 大致就是面向公共服务器的操作。步骤 1 和 5 允许您避免第三方权限,并充当您自己的权限(谁比您自己更信任?)。

避免浏览器警告的下一个最佳方法是信任服务器的证书。但有些浏览器,比如 Android 的默认浏览器,不允许你这样做。所以它永远不会在平台上运行。

信任自签名证书的浏览器(和其他类似用户代理)的问题将成为物联网(IoT)中的一个大问题。例如,当您连接到恒温器或冰箱进行编程时会发生什么?答案是,就用户体验而言,没什么好处。

W3C 的 WebAppSec 工作组正在开始研究这个问题。例如,请参阅提案:将 HTTP 标记为不安全


如何使用 OpenSSL 创建自签名证书

以下命令和配置文件创建自签名证书(它还向您显示如何创建签名请求)。它们在一个方面与其他答案不同:用于自签名证书的 DNS 名称位于主题备用名称(SAN)中 ,而不是公用名称(CN)

DNS 名称通过配置文件放在 SAN 中,其中行subjectAltName = @alternate_names (无法通过命令行执行此操作)。然后在配置文件中有一个alternate_names部分(你应该调整它以适合你的口味):

[ alternate_names ]

DNS.1       = example.com
DNS.2       = www.example.com
DNS.3       = mail.example.com
DNS.4       = ftp.example.com

# Add these if you need them. But usually you don't want them or
#   need them in production. You may need them for development.
# DNS.5       = localhost
# DNS.6       = localhost.localdomain
# DNS.7       = 127.0.0.1

# IPv6 localhost
# DNS.8     = ::1

把 DNS 名称的 SAN,而不是在 CN,因为无论是 IETF 和 CA / 浏览器论坛指定的做法是很重要的。它们还指定不推荐使用 CN 中的 DNS 名称(但不禁止)。 如果在 CN 中放置 DNS 名称,则必须将其包含在 CA / B 策略下的 SAN 中。因此,您无法避免使用主题备用名称。

如果您没有在 DNS 中放置 DNS 名称,则证书将无法在遵循 CA / 浏览器论坛指南的浏览器和其他用户代理下进行验证。

相关:浏览器遵循 CA / 浏览器论坛政策; 而不是 IETF 的政策。这是使用 OpenSSL(通常遵循 IETF)创建的证书有时不在浏览器下验证(浏览器遵循 CA / B)的原因之一。它们是不同的标准,它们具有不同的发布策略和不同的验证要求。


创建自签名证书 (注意添加-x509选项):

openssl req -config example-com.conf -new -x509 -sha256 -newkey rsa:2048 -nodes \
    -keyout example-com.key.pem -days 365 -out example-com.cert.pem

创建签名请求 (注意缺少-x509选项):

openssl req -config example-com.conf -new -sha256 -newkey rsa:2048 -nodes \
    -keyout example-com.key.pem -days 365 -out example-com.req.pem

打印自签名证书

openssl x509 -in example-com.cert.pem -text -noout

打印签名请求

openssl req -in example-com.req.pem -text -noout

配置文件(通过-config选项传递)

[ req ]
default_bits        = 2048
default_keyfile     = server-key.pem
distinguished_name  = subject
req_extensions      = req_ext
x509_extensions     = x509_ext
string_mask         = utf8only

# The Subject DN can be formed using X501 or RFC 4514 (see RFC 4519 for a description).
#   Its sort of a mashup. For example, RFC 4514 does not provide emailAddress.
[ subject ]
countryName         = Country Name (2 letter code)
countryName_default     = US

stateOrProvinceName     = State or Province Name (full name)
stateOrProvinceName_default = NY

localityName            = Locality Name (eg, city)
localityName_default        = New York

organizationName         = Organization Name (eg, company)
organizationName_default    = Example, LLC

# Use a friendly name here because it's presented to the user. The server's DNS
#   names are placed in Subject Alternate Names. Plus, DNS names here is deprecated
#   by both IETF and CA/Browser Forums. If you place a DNS name here, then you
#   must include the DNS name in the SAN too (otherwise, Chrome and others that
#   strictly follow the CA/Browser Baseline Requirements will fail).
commonName          = Common Name (e.g. server FQDN or YOUR name)
commonName_default      = Example Company

emailAddress            = Email Address
emailAddress_default        = [email protected]

# Section x509_ext is used when generating a self-signed certificate. I.e., openssl req -x509 ...
[ x509_ext ]

subjectKeyIdentifier        = hash
authorityKeyIdentifier    = keyid,issuer

# You only need digitalSignature below. *If* you don't allow
#   RSA Key transport (i.e., you use ephemeral cipher suites), then
#   omit keyEncipherment because that's key transport.
basicConstraints        = CA:FALSE
keyUsage            = digitalSignature, keyEncipherment
subjectAltName          = @alternate_names
nsComment           = "OpenSSL Generated Certificate"

# RFC 5280, Section 4.2.1.12 makes EKU optional
#   CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
#   In either case, you probably only need serverAuth.
# extendedKeyUsage    = serverAuth, clientAuth

# Section req_ext is used when generating a certificate signing request. I.e., openssl req ...
[ req_ext ]

subjectKeyIdentifier        = hash

basicConstraints        = CA:FALSE
keyUsage            = digitalSignature, keyEncipherment
subjectAltName          = @alternate_names
nsComment           = "OpenSSL Generated Certificate"

# RFC 5280, Section 4.2.1.12 makes EKU optional
#   CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
#   In either case, you probably only need serverAuth.
# extendedKeyUsage    = serverAuth, clientAuth

[ alternate_names ]

DNS.1       = example.com
DNS.2       = www.example.com
DNS.3       = mail.example.com
DNS.4       = ftp.example.com

# Add these if you need them. But usually you don't want them or
#   need them in production. You may need them for development.
# DNS.5       = localhost
# DNS.6       = localhost.localdomain
# DNS.7       = 127.0.0.1

# IPv6 localhost
# DNS.8     = ::1

您可能需要为 Chrome 执行以下操作。否则Chrome 可能会抱怨公用名无效( ERR_CERT_COMMON_NAME_INVALID 。我不确定 SAN 中的 IP 地址与此实例中的 CN 之间的关系。

# IPv4 localhost
# IP.1       = 127.0.0.1

# IPv6 localhost
# IP.2     = ::1

关于在 X.509 / PKIX 证书中处理 DNS 名称还有其他规则。有关规则,请参阅这些文档:

列出了 RFC 6797 和 RFC 7469,因为它们比其他 RFC 和 CA / B 文档更具限制性。 RFC 6797 和 7469 不允许 IP 地址。

以下是@ diegows 的答案中描述的选项,从文档中更详细地描述:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days XXX
req

PKCS#10 证书请求和证书生成实用程序。

-x509

此选项输出自签名证书而不是证书请求。这通常用于生成测试证书或自签名根 CA.

-newkey arg

此选项可创建新证书请求和新私钥。该论证采用了几种形式之一。 rsa:nbits ,其中nbits是位数,生成大小为nbits的 RSA 密钥。

-keyout filename

这给出了将新创建的私钥写入的文件名。

-out filename

这默认指定要写入的输出文件名或标准输出。

-days n

当使用-x509选项时,它指定证书证书的天数。默认值为 30 天。

-nodes

如果指定了此选项,则如果创建了私钥,则不会对其进行加密。

文档实际上比上面更详细; 我只是在这里总结一下。