如何使用OpenSSL生成自签名SSL证书?

1932

我正在为一个嵌入式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 等浏览器时出现了一些错误:

这可能不是您正在寻找的网站!
网站的安全证书不受信任!

我是否漏掉了什么?这是构建自签名证书的正确方式吗?


63
自签名证书在互联网上被认为是不安全的。Firefox会将该网站视为具有无效证书,而Chrome则会像处理普通的HTTP连接一样处理。更多详情请访问:http://www.gerv.net/security/self-signed-certs/ - user1202136
62
您需要将您的CA证书导入浏览器,并告诉浏览器您信任该证书 - 或者 - 由已经被浏览器信任的一些大型机构签署该证书 - 或者 - 忽略警告并点击继续。我自己喜欢最后一个选项。 - trojanfoe
20
你不应该使用“存储” OpenSSL 设置。这是因为你不能在主体备用名称(SAN)中放置DNS名称。你需要提供一个带有alternate_names部分的配置文件,并使用-config选项传递它。同时,在通用名称(CN)中放置DNS名称被IETF和CA/Browser论坛弃用(但不被禁止)。在CN中的任何DNS名称也必须存在于SAN中。无法避免使用SAN。请参见下面的答案。 - jww
6
除了@jww的评论之外,根据2017年5月的规定,Chrome不再接受没有(空)SAN的证书:“此站点的证书不包含包含域名或IP地址的主题备用名称扩展。” - GerardJP
11
现在,只要您的Web服务器在互联网上通过FQDN(全限定域名)的80端口可以访问,就可以使用Let's Encrypt并获得免费的完整CA证书(有效期90天,可自动更新),这些证书不会导致任何浏览器警告或消息。请访问www.letsencrypt.com。 - DisappointedByUnaccountableMod
6
Let's Encrypt网站不是.com,而是.org - Yu Jiaao
23个回答

3083

你可以用一条命令完成这个操作:

# interactive
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365
# non-interactive and 10 years expiration
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 3650 -nodes -subj "/C=XX/ST=StateName/L=CityName/O=CompanyName/OU=CompanySectionName/CN=CommonNameOrHostname"

如果你不想用密码保护你的私钥,你还可以添加-nodes(即"no DES"的缩写)。否则它会提示你输入至少4个字符的密码。

days参数(365)可以替换为任何数字以影响到期日期。然后它会提示你输入"Country Name"等信息,但你可以直接按下Enter键并接受默认值。

添加-subj '/CN=localhost'以避免询问证书内容(将localhost替换为你想要的域名)。

自签名证书在未导入浏览器之前不会经过任何第三方验证。如果你需要更高的安全性,应该使用由证书颁发机构(CA)签名的证书。


27
如果有任何人感兴趣,这里是文档链接,如果你想要自己核实任何内容。 - user456814
32
与第三方签署协议如何提供更多的安全性? - James Mills
321
对于任何在自动化中使用此参数的人,以下是主题的所有常见参数:-subj "/C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=www.example.com" - Alex S
74
@JamesMills 我的意思是,想一想——如果一个看起来可疑的家伙在他的货车上写着“免费糖果”,邀请你进去,你肯定会三思而后行,并对此保持警惕——但如果你信任的人——真的非常信任——告诉你,“不,他是真的”,你就会全身心地投入到这个免费糖果中。 - BrainSlugs83
88
记得使用“-sha256”生成基于SHA-256的证书。 - Gea-Suan Lin
显示剩余26条评论

722
截至2023年,使用OpenSSL ≥ 1.1.1,以下命令可以满足您的所有需求,包括主题备用名称(SAN)
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 \
  -nodes -keyout example.com.key -out example.com.crt -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:*.example.com,IP:10.0.0.1"

如果你更喜欢ECC而不是RSA,你可以指定不同的加密参数:
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -days 3650 \
  -nodes -keyout example.com.key -out example.com.crt -subj "/CN=example.com" \
  -addext "subjectAltName=DNS:example.com,DNS:*.example.com,IP:10.0.0.1"

在旧的系统上,如OpenSSL ≤ 1.1.0的Debian ≤ 9或CentOS ≤ 7,需要使用一个更长的版本的命令:
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 \
  -nodes -keyout example.com.key -out example.com.crt -extensions san -config \
  <(echo "[req]"; 
    echo distinguished_name=req; 
    echo "[san]"; 
    echo subjectAltName=DNS:example.com,DNS:*.example.com,IP:10.0.0.1
    ) \
  -subj "/CN=example.com"

每个上述命令都会创建一个证书,该证书:
- 对于域名example.com(SAN)有效, - 对于通配符域名*.example.com(SAN)也有效, - 对于IP地址10.0.0.1(SAN)也有效, - 相对强大(截至2023年)并且 - 有效期为3650天(约10年)。
生成以下文件:
- 私钥:example.com.key - 证书:example.com.crt 所有信息都在命令行提供。没有让您烦恼的交互式输入。没有需要处理的配置文件。所有必要的步骤都由单个OpenSSL调用执行:从私钥生成到自签名证书。

备注 #1:加密参数

由于证书是自签名的,需要用户手动接受,因此使用短期过期或弱密码学是没有意义的。

在将来,您可能希望为RSA密钥使用超过4096位,并且使用比sha256更强大的哈希算法,但截至2023年,这些值是合理的。它们足够强大,同时又得到了所有现代浏览器的支持。

备注 #2:参数 "-nodes"

理论上,您可以省略-nodes参数(表示"无DES加密"),在这种情况下,example.key将使用密码进行加密。然而,对于服务器安装来说,这几乎从不有用,因为您要么必须将密码存储在服务器上,要么每次重新启动时都必须手动输入密码。

备注 #3:参见


5
我尝试在mingw64的Windows上使用oneliner#2 (modern),但在-subj参数上遇到了一个bug。$ openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout localhost.key -out localhost.crt -subj '/CN=localhost' -addext subjectAltName=DNS:localhost,IP:127.0.0.1 生成RSA私钥 [...] 将新私钥写入 'localhost.key' ----- 名称应该符合格式/type0=value0/type1=value1/type2=...,其中字符可以通过\进行转义。但是该名称不符合此格式:'C:/Program Files/Git/CN=localhost' 出现制作证书请求时的问题 - Yuri Pozniak
5
我无法确定在arg/CN=localhost扩展为C:/Program Files/Git/CN=localhost中到底是什么原因导致的问题,因此我只是在普通的cmd.exe中运行了整个命令,并且它完美地工作了。以防有人遇到这个问题而苦恼。 - Yuri Pozniak
2
@FranklinYu,你确定在未来10年内rsa:2048足够吗?因为这是有效期。正如所述,使用短期过期或弱加密是没有意义的。大多数2048位RSA密钥的有效期最多只有1-3年。关于OpenSSL 1.1.1,我仍然在其中留下sha256,这样更明确和明显,以便在需要更强的哈希时进行更改。 - vog
7
如果你在Windows上使用git bash,像@YuriyPozniak一样,你会遇到他列出的错误,其中/CN=localhost被扩展为C:/Program Files/Git/CN=localhost。如果你添加一个额外的斜杠,那么就不会发生这种扩展了。 //CN=localhost - Dave Ferguson
2
截至2020年8月31日,我可以保证这个有效!非常感谢! 我真的很想看到一个简单易懂的参考资料,解释为什么这个正在如此快速地发展。我的一部分怀疑是因为创建自签名证书的想法对于大型科技公司来说是有反生产力的。未来10或20年需要什么?这是疯狂的,而openssl上关于这类问题所产生的活动量就是这种疯狂的证明。 - Alex. S.
显示剩余24条评论

660

我有所遗漏吗?这是构建自签名证书的正确方法吗?

创建自签名证书很容易,只需使用openssl req命令即可。但要创建一个可以被大多数客户端(如浏览器和命令行工具)接受的证书可能有些棘手。

这很困难,因为浏览器有自己的一套要求,而且它们比IETF更为严格。浏览器使用的要求在CA/Browser Forums中有记录(见下面的参考资料)。限制主要出现在两个关键领域:(1)信任锚点和(2)DNS名称。

现代浏览器(如我们在2014/2015年使用的浏览器)希望证书可以追溯到信任锚点,并且希望DNS名称以特定方式呈现在证书中。而且,浏览器正在积极地反对自签名服务器证书。

某些浏览器并不那么容易导入自签名服务器证书。事实上,像Android的浏览器这样的浏览器根本无法导入。因此,完整的解决方案是成为自己的权威机构。

在没有成为自己的权威机构的情况下,您需要正确获取DNS名称以使证书成功的可能性最大化。但我鼓励您成为自己的权威机构。成为自己的权威机构很容易,并且将避开所有信任问题(谁比你自己更可信呢?)。

这可能不是您要找的网站!
该网站的安全证书无法得到信任!

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

避免此问题的最佳方法是:

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

步骤1 - 创建自己的授权 意味着使用CA: true和适当的密钥用法创建自签名证书。这意味着主题颁发者是同一实体,基本限制中设置了CA为true(它也应标记为关键),密钥用法为keyCertSigncrlSign(如果您正在使用CRL),并且主题密钥标识符(SKI)与授权密钥标识符(AKI)相同。

要成为自己的证书颁发机构,请参见Stack Overflow上的*如何使用您的认证机构对证书签名请求进行签名?。然后,将您的CA导入浏览器使用的信任存储中。

步骤2-4大致上是您现在为公共服务器做的事情,当您使用CA(如StartcomCAcert)的服务时。步骤1和5允许您避免第三方机构,并充当自己的机构(谁比您自己更值得信任?)。
避免浏览器警告的下一个最佳方法是信任服务器的证书。但是一些浏览器(如Android的默认浏览器)不允许您这样做。因此,在该平台上永远不会起作用。
浏览器(和其他类似的用户代理)不信任自签名证书的问题将成为物联网(IoT)中的一个大问题。例如,当您连接到恒温器或冰箱以进行编程时,会发生什么?答案是,就用户体验而言,没有好处。
W3C的WebAppSec工作组开始研究这个问题。请参见,例如,Proposal: Marking HTTP As Non-Secure
以下命令和配置文件创建自签名证书(还演示了如何创建签名请求)。与其他答案不同之处在于,用于自签名证书的DNS名称位于Subject Alternate Name (SAN)中,而不是Common Name (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
# IP.1        = 127.0.0.1
# IP.2        = ::1

重要的是将DNS名称放在SAN中而不是CN中,因为 IETF和 CA / Browser论坛 都指定了这种做法。他们还指定CN中的DNS名称已被弃用(但不是禁止)。如果您将DNS名称放入CN中,则必须根据CA / B策略在SAN中包含它。因此,您无法避免使用主题备用名称。
如果您不将DNS名称放入SAN中,则证书将无法在遵循CA / Browser Forum准则的浏览器和其他用户代理下验证。
相关:浏览器遵循CA / Browser论坛政策,而不是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        = test@example.com

# 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地址。

5
alternate_names 部分中使用通配符是否可行?特别是子域名。 我有一个关于此答案的问题:http://serverfault.com/questions/711596/can-i-use-wildcards-with-san-self-signed-certificates - LeonardChallis
3
我刚回复了他的具体问题。我认为在答案如此简单的情况下,加上这么长的安全说明没有意义。 - Diego Woitasen
20
@diegows - 你的回答不完整或不正确。原因在于长篇帖子中有讨论,但你不想阅读 :) - jww
4
谢谢@jww。你说,“1.创建自己的授权机构(即成为CA)”,然后说,“5.在客户端上安装CA证书”。如果根密钥被攻击者破解,恶意人士可以使用该密钥为任何域名签署证书,如果他们诱骗您访问他们的网站,那么现在他们可以进行中间人攻击。有没有一种方式可以创建根CA,使其只能签署中介CA而不是证书?然后您可以使用名称限制来保护您的中介CA。 - Robin Zimmermann
1
@jww 是哪篇长帖?这个答案有什么不完整或不正确的地方吗? - Rony Tesler
显示剩余4条评论

454

以下是@diegows's answer中描述的选项,更详细的信息请参考文档

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

PKCS#10 certificate request and certificate generating utility.

-x509

this option outputs a self signed certificate instead of a certificate request. This is typically used to generate a test certificate or a self signed root CA.

-newkey arg

this option creates a new certificate request and a new private key. The argument takes one of several forms. rsa:nbits, where nbits is the number of bits, generates an RSA key nbits in size.

-keyout filename

this gives the filename to write the newly created private key to.

-out filename

This specifies the output filename to write to or standard output by default.

-days n

when the -x509 option is being used this specifies the number of days to certify the certificate for. The default is 30 days.

-nodes

if this option is specified then if a private key is created it will not be encrypted.

实际上,文档比上面的更详细;我只是在这里进行了总结。


3
原始命令中的“XXX”应替换为“证书认证的天数”。默认值为30天。例如,如果您想让您的证书有效期为365天,则“-days XXX”变为“-days 365”。更多信息请参见文档 - Nathan Jones
感谢您添加文档。这个IBM链接提供了使用[与此答案相同的命令](https://www.ibm.com/support/knowledgecenter/SSWHYP_4.0.0/com.ibm.apimgmt.cmc.doc/task_apionprem_gernerate_self_signed_openSSL.html)创建自签名证书的方法。 - Nate Anderson

184

我无法进行评论,因此我将其作为单独的答案发布。我发现这个被接受的一行代码有几个问题:

  • 这个一行代码在密钥中包含了一个口令。
  • 这个一行代码使用SHA-1,在许多浏览器中会在控制台中抛出警告。

这里是一个简化版,去掉了口令,提高了安全性以避免警告,并在注释中提供了建议,以传递-subj以删除完整的问题列表:

openssl genrsa -out server.key 2048
openssl rsa -in server.key -out server.key
openssl req -sha256 -new -key server.key -out server.csr -subj '/CN=localhost'
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt

将“localhost”替换为您需要的域。由于OpenSSL会提示输入密码短语,因此您需要逐个运行前两个命令。

将两个文件合并为.pem文件:

cat server.crt server.key > cert.pem

7
我需要一个用于 https://github.com/molnarg/node-http2 的开发者证书,这个答案是最好的。 - Capaj
1
将证书和密钥合并到单个文件中:cat server.crt server.key> foo-cert.pem。适用于 openssl-1.0.2d/demos/ssl/ 中的示例。 - 18446744073709551615
1
谢谢,使用TLS在FreeBSD 10上可以很好地创建自签名证书,适用于OpenLDAP 2.4。 - Thiago Pereira
5
关于 key.pem 文件呢? - quikchange
@quikchange 根据我的了解,server.key 文件是相同的。 - Syed M. Sannan
显示剩余7条评论

89

如果自签名证书缺少SAN(主体备用名称),现代浏览器会抛出安全错误,即使证书本身是格式良好的。 OpenSSL没有提供命令行方式来指定SAN,因此许多开发者的教程和书签突然过时了。

最快恢复运行的方法是创建一个短小的独立配置文件:

  1. 创建OpenSSL配置文件(例如:req.cnf

    [req]
    distinguished_name = req_distinguished_name
    x509_extensions = v3_req
    prompt = no
    [req_distinguished_name]
    C = US
    ST = VA
    L = SomeCity
    O = MyCompany
    OU = MyDivision
    CN = www.company.com
    [v3_req]
    keyUsage = critical, digitalSignature, keyAgreement
    extendedKeyUsage = serverAuth
    subjectAltName = @alt_names
    [alt_names]
    DNS.1 = www.company.com
    DNS.2 = company.com
    DNS.3 = company.net
    
  2. 使用此配置文件创建证书

  3. openssl req -x509 -nodes -days 730 -newkey rsa:2048 \
     -keyout cert.key -out cert.pem -config req.cnf -sha256
    

示例配置来源于 https://support.citrix.com/article/CTX135602


1
在 Windows 上使用 OpenSSL。最后,我成功解决了这个问题!感谢。在删除最后一个参数“-extensions 'v3_req'”后,它对我起作用,该参数导致错误。 - CGodo
1
是的,这现在非常相关,五年后。正如所述,大多数其他答案突然停止工作。此答案中给出的最小配置非常有用,因为通过试错可能需要相当长的时间才能弄清楚。 - Andrew Savinykh
2
稳妥的方式。谢谢。我建议添加“-sha256”。 - cherouvim
6
现在你可以使用命令行参数-extension 'subjectAltName = DNS:dom.ain, DNS:oth.er'来指定证书的 SAN 了。请参见 https://github.com/openssl/openssl/pull/4986。 - Alexandre DuBreuil
3
看起来现在这个选项被称为“-addext”了。 - Alexandr Zarubkin
显示剩余5条评论

76

我建议添加-sha256参数,使用SHA-2哈希算法,因为主要浏览器正在考虑将"SHA-1证书"标记为不安全。

与被接受的答案相同的命令行——@diegows,加上了-sha256。

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

更多信息请参见谷歌安全博客

更新于2018年5月。正如许多评论中指出的那样,使用SHA-2对于自签名证书并不能增加任何安全性。但还是建议使用它作为一种良好习惯,以避免使用过时/不安全的密码哈希函数。完整的解释可在为什么终端实体证书以上的证书可以基于SHA-1?中找到。


2
如果这是一个自签名密钥,它将会在浏览器中生成错误,所以这并不重要。 - Mark
33
@Mark,这很重要,因为SHA-2更安全。 - Maris B.
1
@Maris:这里并不是更安全,因为它是自签名的! - jmd
2
世界级加密 * 零身份验证 = 零安全性。http://www.gerv.net/security/self-signed-certs/ - x-yuri
4
请注意:自签名证书所使用的签名算法并不影响其可信度。根CA证书是自签名的,截至2018年5月,仍有许多活跃的根CA证书使用SHA-1签名。因为一个证书是否信任自身以及该证书如何验证信任并不重要。您只需要相信根/自签名证书所说的是谁,或者您不相信。参见https://security.stackexchange.com/questions/91913/why-is-it-fine-for-certificates-above-the-end-entity-certificate-to-be-sha1-based。 - Andrew Henle
显示剩余6条评论

28

我无法发表评论,因此我添加了一个单独的答案。我尝试为NGINX创建自签名证书,这很容易,但当我想将其添加到Chrome白名单时遇到了问题。我的解决方案是创建一个根证书,并使用它签署一个子证书。

所以逐步进行。 创建文件config_ssl_ca.cnf 注意,配置文件有一个选项basicConstraints = CA:True ,这意味着该证书应该是根证书。

这是一个好习惯,因为您只需创建一次即可重用。

[ req ]
default_bits = 2048

prompt = no
distinguished_name=req_distinguished_name
req_extensions = v3_req

[ req_distinguished_name ]
countryName=UA
stateOrProvinceName=root region
localityName=root city
organizationName=Market(localhost)
organizationalUnitName=roote department
commonName=market.localhost
emailAddress=root_email@root.localhost

[ alternate_names ]
DNS.1        = market.localhost
DNS.2        = www.market.localhost
DNS.3        = mail.market.localhost
DNS.4        = ftp.market.localhost
DNS.5        = *.market.localhost

[ v3_req ]
keyUsage=digitalSignature
basicConstraints=CA:true
subjectKeyIdentifier = hash
subjectAltName = @alternate_names

下一个用于您的子证书的配置文件将被称为config_ssl.cnf

[ req ]
default_bits = 2048

prompt = no
distinguished_name=req_distinguished_name
req_extensions = v3_req

[ req_distinguished_name ]
countryName=UA
stateOrProvinceName=Kyiv region
localityName=Kyiv
organizationName=market place
organizationalUnitName=market place department
commonName=market.localhost
emailAddress=email@market.localhost

[ alternate_names ]
DNS.1        = market.localhost
DNS.2        = www.market.localhost
DNS.3        = mail.market.localhost
DNS.4        = ftp.market.localhost
DNS.5        = *.market.localhost

[ v3_req ]
keyUsage=digitalSignature
basicConstraints=CA:false
subjectAltName = @alternate_names
subjectKeyIdentifier = hash

第一步 - 创建根密钥和证书

openssl genrsa -out ca.key 2048
openssl req -new -x509 -key ca.key -out ca.crt -days 365 -config config_ssl_ca.cnf

第二步是创建子密钥并生成CSR - 证书签名请求文件。因为我们的想法是通过根证书签署子证书并获得正确的证书。

openssl genrsa -out market.key 2048
openssl req -new -sha256 -key market.key -config config_ssl.cnf -out market.csr
在Linux终端中执行以下命令。
echo 00 > ca.srl
touch index.txt

ca.srl 文本文件包含下一个要使用的十六进制序列号。 必须存在且包含有效的序列号。

最后一步,创建另一个配置文件并将其命名为config_ca.cnf

# we use 'ca' as the default section because we're usign the ca command
[ ca ]
default_ca = my_ca

[ my_ca ]
#  a text file containing the next serial number to use in hex. Mandatory.
#  This file must be present and contain a valid serial number.
serial = ./ca.srl

# the text database file to use. Mandatory. This file must be present though
# initially it will be empty.
database = ./index.txt

# specifies the directory where new certificates will be placed. Mandatory.
new_certs_dir = ./

# the file containing the CA certificate. Mandatory
certificate = ./ca.crt

# the file contaning the CA private key. Mandatory
private_key = ./ca.key

# the message digest algorithm. Remember to not use MD5
default_md = sha256

# for how many days will the signed certificate be valid
default_days = 365

# a section with a set of variables corresponding to DN fields
policy = my_policy

# MOST IMPORTANT PART OF THIS CONFIG
copy_extensions = copy

[ my_policy ]
# if the value is "match" then the field value must match the same field in the
# CA certificate. If the value is "supplied" then it must be present.
# Optional means it may be present. Any fields not mentioned are silently
# deleted.
countryName = match
stateOrProvinceName = supplied
organizationName = supplied
commonName = market.localhost
organizationalUnitName = optional
commonName = supplied

你可能想知道,为什么这么难,为什么我们必须创建一个新的配置文件来通过根证书签署子证书。答案很简单,因为子证书必须有一个SAN块 - Subject Alternative Names。

如果我们使用“openssl x509”工具签署子证书,根证书将删除子证书中的SAN字段。

因此,我们使用“openssl ca”而不是“openssl x509”来避免删除SAN字段。我们创建了一个新的配置文件,并告诉它复制所有扩展字段copy_extensions = copy

openssl ca -config config_ca.cnf -out market.crt -in market.csr

程序会向您询问2个问题:

  1. 签署证书?回答“Y”
  2. 1 个证书请求已认证,确认提交吗?回答“Y”

在终端中,您可以看到一个带有“数据库”一词的句子,它表示您通过命令“touch”创建的文件index.txt。该文件将包含您使用“openssl ca”工具创建的所有证书的信息。 要检查证书是否有效,请使用以下命令:

openssl rsa -in market.key -check
如果你想看到CRT里面的内容:
openssl x509 -in market.crt -text -noout

如果您想了解CSR内部情况:

openssl req -in market.csr -noout -text 

4
虽然这个过程看起来很复杂,但是对于.dev域名来说,这正是我们所需要的,因为这个域名不支持自签名证书,而Chrome和Firefox正在强制使用HSTS。我所做的就是按照这些步骤进行操作:创建CA、创建证书并用我的CA进行签名,最后在浏览器中信任我的CA。谢谢。 - bajicdusko
1
你的常用名称是错误的。不是名字/姓氏,而是你的域名cn,即www.yoursite.com。请参见https://www.ssl.com/faqs/common-name/。 - mirageglobe
1
没有问题。有一些文件中也会提到名字(yourname),这可能会有点误导。但是常用名称应该是实际域名。从这个意义上讲,它应该是(your"domain"name)他们试图表达的意思。当通过交互式方法创建证书时,它确实会显示cn=domain example。因此,常用名称应该是域名。 - mirageglobe
更新答案以解决 https://dev59.com/HVkS5IYBdhLWcg3w8acL - mrkiril
1
我尝试了一下,它可以工作。我需要做一些额外的步骤,将 ca.crt 复制到 ca.pem,执行 cp ca.crt ca.pem 并在 CentOS 上安装 ca.pem 作为受信任的证书颁发机构。现在使用 curl 操作非常完美!要在 CentOS 上安装证书颁发机构,请将 ca.pem 复制到 /etc/pki/ca-trust/source/anchors/,并执行命令 update-ca-trust extract;https://unix.stackexchange.com/a/438698/418196 - atish.s
1
我尝试了一下,它有效果。我需要做一些额外的步骤,将ca.crt复制为ca.pem,执行cp ca.crt ca.pem并将ca.pem安装为CentOS上的受信任证书颁发机构。现在使用curl操作非常完美!要在CentOS上安装证书颁发机构,请将ca.pem复制到/etc/pki/ca-trust/source/anchors/目录,并执行命令update-ca-trust extract;https://unix.stackexchange.com/a/438698/418196 - atish.s

23

这是我在本地计算机上使用的脚本,用于设置自签名证书中的SAN(subjectAltName)。

此脚本接受域名(例如example.com),并为*.example.com和example.com生成相同证书中的SAN。下面的部分已经进行了注释。命名该脚本(例如generate-ssl.sh),并赋予可执行权限。文件将被写入与脚本相同的目录中。

Chrome 58及以上版本要求在自签名证书中设置SAN。

#!/usr/bin/env bash

# Set the TLD domain we want to use
BASE_DOMAIN="example.com"

# Days for the cert to live
DAYS=1095

# A blank passphrase
PASSPHRASE=""

# Generated configuration file
CONFIG_FILE="config.txt"

cat > $CONFIG_FILE <<-EOF
[req]
default_bits = 2048
prompt = no
default_md = sha256
x509_extensions = v3_req
distinguished_name = dn

[dn]
C = CA
ST = BC
L = Vancouver
O = Example Corp
OU = Testing Domain
emailAddress = webmaster@$BASE_DOMAIN
CN = $BASE_DOMAIN

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = *.$BASE_DOMAIN
DNS.2 = $BASE_DOMAIN
EOF

# The file name can be anything
FILE_NAME="$BASE_DOMAIN"

# Remove previous keys
echo "Removing existing certs like $FILE_NAME.*"
chmod 770 $FILE_NAME.*
rm $FILE_NAME.*

echo "Generating certs for $BASE_DOMAIN"

# Generate our Private Key, CSR and Certificate
# Use SHA-2 as SHA-1 is unsupported from Jan 1, 2017

openssl req -new -x509 -newkey rsa:2048 -sha256 -nodes -keyout "$FILE_NAME.key" -days $DAYS -out "$FILE_NAME.crt" -passin pass:$PASSPHRASE -config "$CONFIG_FILE"

# OPTIONAL - write an info to see the details of the generated crt
openssl x509 -noout -fingerprint -text < "$FILE_NAME.crt" > "$FILE_NAME.info"

# Protect the key
chmod 400 "$FILE_NAME.key"

这个脚本还会写入一个信息文件,因此您可以检查新证书并验证SAN是否设置正确。

                ...
                28:dd:b8:1e:34:b5:b1:44:1a:60:6d:e3:3c:5a:c4:
                da:3d
            Exponent: 65537 (0x10001)
    X509v3 extensions:
        X509v3 Subject Alternative Name: 
            DNS:*.example.com, DNS:example.com
Signature Algorithm: sha256WithRSAEncryption
     3b:35:5a:d6:9e:92:4f:fc:f4:f4:87:78:cd:c7:8d:cd:8c:cc:
     ...
如果您正在使用Apache,则可以在配置文件中像这样引用上面的证书:
<VirtualHost _default_:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/htdocs

    SSLEngine on
    SSLCertificateFile path/to/your/example.com.crt
    SSLCertificateKeyFile path/to/your/example.com.key
</VirtualHost>

请记得重新启动您的Apache(或Nginx,或IIS)服务器,以使新证书生效。


适用于 macOS High Sierra 和 Chrome 58 - Saqib Omer
我仍然不确定CN如何影响整体设置?我试图将其作为localhost127.0.0.1:port#运行,这种情况下对应的CN是什么? - DJ2
@DJ2 我会将 BASE_DOMAIN 设置为“localhost”。 - Drakes

11

2017年度一行代码:

openssl req \
-newkey rsa:2048 \
-x509 \
-nodes \
-keyout server.pem \
-new \
-out server.pem \
-subj /CN=localhost \
-reqexts SAN \
-extensions SAN \
-config <(cat /System/Library/OpenSSL/openssl.cnf \
    <(printf '[SAN]\nsubjectAltName=DNS:localhost')) \
-sha256 \
-days 3650

这在Chrome 57中也适用,因为它提供了SAN,而不需要另一个配置文件。它是从这里的答案中得出的。
这将创建一个包含私钥和证书的单个.pem文件。如果需要,您可以将它们移动到单独的.pem文件中。

2
对于Linux用户,您需要更改配置文件的路径。例如,在当前Ubuntu上,/etc/ssl/openssl.conf是有效的。 - declension
1
对于不需要指定openssl.cnf位置的一行代码,请参见:https://dev59.com/4Gkw5IYBdhLWcg3wDWIk#41366949 - vog

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接