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

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

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

这工作,但我得到一些错误,例如,谷歌Chrome:

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

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

2580211 次浏览

你可以在一个命令中做到这一点:

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

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

您可以将days参数(365)替换为任何数字以影响到期日期。然后它会提示您输入“国家名称”之类的内容,但您可以点击输入并接受默认值。

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

自签名证书不会通过任何第三方进行验证,除非您之前将它们导入浏览器。如果您需要更多安全性,您应该使用由证书颁发机构(CA)签名的证书。

以下是@陈志立中描述的选项,从留档中更详细地描述:

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

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

-x509

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

-newkey arg

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

-keyout filename

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

-out filename

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

-days n

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

-nodes

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

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

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

来自接受的答案的相同命令行-@diegow添加了-sha256

openssl req-x509-sha256-newkey rsa: 2048-keyoutkey.pem-outcert.pem

更多信息谷歌安全博客

2018年5月更新。正如许多人在评论中指出的那样,使用SHA-2不会为自签名证书添加任何安全性。但我仍然建议使用它作为不使用过时/不安全的加密哈希函数的好习惯。完整的解释可在为什么最终实体证书之上的证书可以基于SHA-1?中找到。

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

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

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

现代浏览器(如我们在2014/2015年使用的ware z)想要一个链接到信任锚点的证书,他们希望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大致是当您征集像StartcomCAcert这样的CA的服务时,您现在对面向公众的服务器所做的事情。步骤1和5允许您避免第三方权威,并充当您自己的权威(谁比您自己更值得信任?)。

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

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

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


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

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

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

[ alternate_names ]
DNS.1       = example.comDNS.2       = www.example.comDNS.3       = mail.example.comDNS.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 Forum政策;而不是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        = 2048default_keyfile     = server-key.pemdistinguished_name  = subjectreq_extensions      = req_extx509_extensions     = x509_extstring_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 AddressemailAddress_default        = test@example.com
# Section x509_ext is used when generating a self-signed certificate. I.e., openssl req -x509 ...[ x509_ext ]
subjectKeyIdentifier        = hashauthorityKeyIdentifier    = 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:FALSEkeyUsage            = digitalSignature, keyEnciphermentsubjectAltName          = @alternate_namesnsComment           = "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:FALSEkeyUsage            = digitalSignature, keyEnciphermentsubjectAltName          = @alternate_namesnsComment           = "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.comDNS.2       = www.example.comDNS.3       = mail.example.comDNS.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可能会抱怨Common Name无效(#0)。我不确定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地址。

您的一般过程是正确的。命令的语法如下。

openssl req -new -key {private key file} -out {output file}

但是,会显示警告,因为浏览器无法通过使用已知证书授权中心(CA)验证证书来验证标识。

由于这是自签名证书,因此没有CA,您可以安全地忽略警告并继续。如果您想获得公共Internet上任何人都可以识别的真实证书,那么程序如下。

  1. 生成私钥
  2. 使用该私钥创建CSR文件
  3. 向CA(威瑞信或其他机构等)提交CSR
  4. 在Web服务器上安装从CA收到的证书
  5. 根据证书类型将其他证书添加到身份验证链

我在保护连接:使用OpenSSL创建安全证书的帖子中有更多关于这个的细节

我不能发表评论,所以我将把它作为一个单独的答案。我发现了一些与接受的一行回答有关的问题:

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

这是一个简化的版本,它删除了密码短语,提高了安全性以抑制警告,并在注释中建议传入-subj以删除完整的问题列表:

openssl genrsa -out server.key 2048openssl rsa -in server.key -out server.keyopenssl 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

生成密钥

我使用/etc/mysql进行证书存储,因为/etc/apparmor.d/usr.sbin.mysqld包含/etc/mysql/*.pem r

sudo su -cd /etc/mysqlopenssl genrsa -out ca-key.pem 2048;openssl req -new -x509 -nodes -days 1000 -key ca-key.pem -out ca-cert.pem;openssl req -newkey rsa:2048 -days 1000 -nodes -keyout server-key.pem -out server-req.pem;openssl x509 -req -in server-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem;openssl req -newkey rsa:2048 -days 1000 -nodes -keyout client-key.pem -out client-req.pem;openssl x509 -req -in client-req.pem -days 1000 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out client-cert.pem;

添加配置

/etc/mysql/my.cnf

[client]ssl-ca=/etc/mysql/ca-cert.pemssl-cert=/etc/mysql/client-cert.pemssl-key=/etc/mysql/client-key.pem
[mysqld]ssl-ca=/etc/mysql/ca-cert.pemssl-cert=/etc/mysql/server-cert.pemssl-key=/etc/mysql/server-key.pem

在我的设置中,Ubuntu服务器登录到:/var/log/mysql/error.log

后续跟进说明:

  • SSL error: Unable to get certificate from '...'

    如果您的证书文件不在设备配置中,MySQL可能会被拒绝读取访问权限.正如前面的步骤^中提到的,将我们所有的证书保存为/etc/mysql/目录中的.pem文件,该目录默认情况下由设备批准(或修改您的设备/SELinux以允许访问您存储它们的任何地方。)

  • SSL error: Unable to get private key

    您的MySQL服务器版本可能不支持默认的rsa:2048格式

    将生成的rsa:2048转换为普通rsa

    openssl rsa -in server-key.pem -out server-key.pemopenssl rsa -in client-key.pem -out client-key.pem
  • Check if local server supports SSL:

    mysql -u root -pmysql> show variables like "%ssl%";+---------------+----------------------------+| Variable_name | Value                      |+---------------+----------------------------+| have_openssl  | YES                        || have_ssl      | YES                        || ssl_ca        | /etc/mysql/ca-cert.pem     || ssl_capath    |                            || ssl_cert      | /etc/mysql/server-cert.pem || ssl_cipher    |                            || ssl_key       | /etc/mysql/server-key.pem  |+---------------+----------------------------+
  • 验证与数据库的连接是否经过SSL加密

    正在验证连接

    登录到MySQL实例时,您可以发出查询:

    show status like 'Ssl_cipher';

    如果您的连接未加密,结果将为空:

    mysql> show status like 'Ssl_cipher';+---------------+-------+| Variable_name | Value |+---------------+-------+| Ssl_cipher    |       |+---------------+-------+1 row in set (0.00 sec)

    否则,它将显示正在使用的cypher的非零长度字符串:

    mysql> show status like 'Ssl_cipher';+---------------+--------------------+| Variable_name | Value              |+---------------+--------------------+| Ssl_cipher    | DHE-RSA-AES256-SHA |+---------------+--------------------+1 row in set (0.00 sec)
  • 特定用户的连接需要ssl('需要ssl'):

    • SSL

    告诉服务器仅允许帐户的SSL加密连接。

    GRANT ALL PRIVILEGES ON test.* TO 'root'@'localhost'REQUIRE SSL;

    要连接,客户端必须指定--ssl-ca选项来验证服务器证书,并且可以另外指定--ssl-key和--ssl-cert选项。如果既未指定--ssl-ca选项也未指定--ssl-capath选项,则客户端不会验证服务器证书。


备用链接:安全的PHP连接到MySQL与SSL中的冗长教程。

截至2022年,OpenSSL≥1.1.1,以下命令可满足您的所有需求,包括主题备用名称(SAN)

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \-keyout example.key -out example.crt -subj "/CN=example.com" \-addext "subjectAltName=DNS:example.com,DNS:www.example.net,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.key -out example.crt -extensions san -config \<(echo "[req]";echo distinguished_name=req;echo "[san]";echo subjectAltName=DNS:example.com,DNS:www.example.net,IP:10.0.0.1) \-subj "/CN=example.com"

任一命令创建一个证书

  • 对于(子)域example.comwww.example.net(SAN)有效,
  • 也适用于IP地址10.0.0.1(SAN),
  • 相对强劲(截至2022年)和
  • 有效期为3650天(~10年)。

生成以下文件:

  • 私钥:example.key
  • 证书:example.crt

所有信息都在命令行中提供。有无交互输入让您烦恼。有没有配置文件您必须处理。所有必要的步骤都由单个OpenSSL调用执行:从私钥生成到自签名证书。


备注#1:加密参数

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

将来,你可能希望使用超过4096位的RSA密钥和比sha256更强的哈希算法,但截至2022年,这些都是理智的值。在所有现代浏览器都支持的情况下,它们足够强大。

备注#2:参数“-nodes

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

备注#3:另见

如果缺少SAN(主题备用名称),现代浏览器现在会为格式良好的自签名证书抛出安全错误。OpenSSL不提供命令行方式来指定此,所以许多开发人员的教程和书签突然过时了。

再次运行的最快方法是一个简短的独立conf文件:

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

    [req]distinguished_name = req_distinguished_namex509_extensions = v3_reqprompt = no[req_distinguished_name]C = USST = VAL = SomeCityO = MyCompanyOU = MyDivisionCN = www.company.com[v3_req]keyUsage = critical, digitalSignature, keyAgreementextendedKeyUsage = serverAuthsubjectAltName = @alt_names[alt_names]DNS.1 = www.company.comDNS.2 = company.comDNS.3 = company.net
  2. Create the certificate referencing this config file

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

Example config from https://support.citrix.com/article/CTX135602

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

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

Chrome58,需要在自签名证书中设置SAN。

#!/usr/bin/env bash
# Set the TLD domain we want to useBASE_DOMAIN="example.com"
# Days for the cert to liveDAYS=1095
# A blank passphrasePASSPHRASE=""
# Generated configuration fileCONFIG_FILE="config.txt"
cat > $CONFIG_FILE <<-EOF[req]default_bits = 2048prompt = nodefault_md = sha256x509_extensions = v3_reqdistinguished_name = dn
[dn]C = CAST = BCL = VancouverO = Example CorpOU = Testing DomainemailAddress = webmaster@$BASE_DOMAINCN = $BASE_DOMAIN
[v3_req]subjectAltName = @alt_names
[alt_names]DNS.1 = *.$BASE_DOMAINDNS.2 = $BASE_DOMAINEOF
# The file name can be anythingFILE_NAME="$BASE_DOMAIN"
# Remove previous keysecho "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 crtopenssl x509 -noout -fingerprint -text < "$FILE_NAME.crt" > "$FILE_NAME.info"
# Protect the keychmod 400 "$FILE_NAME.key"

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

                ...28:dd:b8:1e:34:b5:b1:44:1a:60:6d:e3:3c:5a:c4:da:3dExponent: 65537 (0x10001)X509v3 extensions:X509v3 Subject Alternative Name:DNS:*.example.com, DNS:example.comSignature Algorithm: sha256WithRSAEncryption3b:35:5a:d6:9e:92:4f:fc:f4:f4:87:78:cd:c7:8d:cd:8c:cc:...

如果您使用的是Apache,那么您可以在配置文件中引用上述证书,如下所示:

<VirtualHost _default_:443>ServerName example.comServerAlias www.example.comDocumentRoot /var/www/htdocs
SSLEngine onSSLCertificateFile path/to/your/example.com.crtSSLCertificateKeyFile path/to/your/example.com.key</VirtualHost>

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

一个线性FTW。我喜欢保持简单。为什么不使用一个包含所有所需参数的命令?这就是我喜欢的方式-这会创建一个x509证书及其PEM密钥:

openssl req -x509 \-nodes -days 365 -newkey rsa:4096 \-keyout self.key.pem \-out self-x509.crt \-subj "/C=US/ST=WA/L=Seattle/CN=example.com/emailAddress=someEmail@gmail.com"

该命令包含您通常为证书详细信息提供的所有答案。这样您就可以设置参数并运行命令,获取您的输出-然后去喝咖啡。

>更多<<

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

这也适用于Chrome57,因为它提供了SAN,而无需另一个配置文件。答案这里

这将创建一个包含私钥和证书的. pem文件。如果需要,您可以将它们移动到单独的. pem文件中。

单行版本2017:

CentOS:

openssl req -x509 -nodes -sha256 -newkey rsa:2048 \-keyout localhost.key -out localhost.crt \-days 3650 \-subj "CN=localhost" \-reqexts SAN -extensions SAN \-config <(cat /etc/pki/tls/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=IP:127.0.0.1,DNS:localhost"))

ubuntu:

openssl req -x509 -nodes -sha256 -newkey rsa:2048 \-keyout localhost.key -out localhost.crt \-days 3650 \-subj "/CN=localhost" \-reqexts SAN -extensions SAN \-config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=IP:127.0.0.1,DNS:localhost"))

编辑:为Ubuntu添加了前置斜杠到“subj”选项。

正如已经详细讨论过的,自签名证书在互联网上不受信任。你可以将您的自签名证书添加到许多但不是所有浏览器。或者你可以成为您自己的证书颁发机构

人们不想从证书颁发机构获得签名证书的主要原因是成本赛门铁克证书每年收费995美元-1,999美元-仅用于内部网络的证书,赛门铁克每年收费399美元。如果您正在处理信用卡付款或为高利润公司的利润中心工作,那么成本很容易证明是合理的。对于一个在互联网上创建的个人项目,或者一个以最低预算运行的非营利组织,或者如果一个人在组织的成本中心工作,成本中心总是试图用更少的钱做更多的事情,这是许多人无法承受的。

另一种方法是使用certbot(请参阅关于certbot)。Certbot是一个易于使用的自动客户端,可为您的Web服务器获取和部署SSL/TLS证书。

如果您设置了certbot,您可以启用它来创建和维护由让我们加密证书颁发机构为您颁发的证书。

我在周末为我的组织做了这件事。我在我的服务器(Ubuntu 16.04)上安装了certbot所需的软件包,然后运行设置和启用certbot所需的命令。一个人可能需要certbot的dns插件-我们目前正在使用DigitalOcean,尽管可能很快就会迁移到另一个服务。

请注意,有些说明不太正确,需要一点时间和谷歌来弄清楚。第一次花了我相当多的时间,但现在我想我可以在几分钟内完成。

对于DigitalOcean,我遇到的一个问题是当我被提示输入DigitalOcean凭据INI文件的路径时。脚本所指的是应用程序和API页面和该页面上的Tokens/Key选项卡。您需要拥有或生成DigitalOcean API的个人访问令牌(读取和写入)-这是一个65个字符的十六进制字符串。然后需要将此字符串放入您运行certbot的网络服务器上的文件中。该文件的第一行可以有注释(注释以#开头)。seccond行是:

dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff

一旦我弄清楚了如何为DigitalOcean的API设置读+写令牌,就很容易使用certbot设置通配符证书。请注意,不必设置通配符证书,可以指定想要证书应用的每个域和子域。通配符证书需要包含DigitalOcean个人访问令牌的凭据INI文件。

请注意,公钥证书(也称为身份证书或SSL证书)过期并需要续订。因此,您需要定期(重复)续订证书。certbot留档涵盖续订证书

我的计划是编写一个脚本来使用openssl命令获取我的证书的到期日期,并在证书到期前30天或更短的时间触发续订。然后我将此脚本添加到cron并每天运行一次。

以下是读取证书到期日期的命令:

root@prod-host:~# /usr/bin/openssl x509 -enddate -noout -in path-to-certificate-pem-filenotAfter=May 25 19:24:12 2019 GMT

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

一步一步来。创建文件config_ssl_ca.cnf请注意,配置文件有一个选项基本约束=CA: true,这意味着此证书应该是root。

这是一个很好的实践,因为您只创建一次并且可以重用。

[ req ]default_bits = 2048
prompt = nodistinguished_name=req_distinguished_namereq_extensions = v3_req
[ req_distinguished_name ]countryName=UAstateOrProvinceName=root regionlocalityName=root cityorganizationName=Market(localhost)organizationalUnitName=roote departmentcommonName=market.localhostemailAddress=root_email@root.localhost
[ alternate_names ]DNS.1        = market.localhostDNS.2        = www.market.localhostDNS.3        = mail.market.localhostDNS.4        = ftp.market.localhostDNS.5        = *.market.localhost
[ v3_req ]keyUsage=digitalSignaturebasicConstraints=CA:truesubjectKeyIdentifier = hashsubjectAltName = @alternate_names

您的子证书的下一个配置文件将调用config_ssl.cnf

[ req ]default_bits = 2048
prompt = nodistinguished_name=req_distinguished_namereq_extensions = v3_req
[ req_distinguished_name ]countryName=UAstateOrProvinceName=Kyiv regionlocalityName=KyivorganizationName=market placeorganizationalUnitName=market place departmentcommonName=market.localhostemailAddress=email@market.localhost
[ alternate_names ]DNS.1        = market.localhostDNS.2        = www.market.localhostDNS.3        = mail.market.localhostDNS.4        = ftp.market.localhostDNS.5        = *.market.localhost
[ v3_req ]keyUsage=digitalSignaturebasicConstraints=CA:falsesubjectAltName = @alternate_namessubjectKeyIdentifier = hash

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

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

第二步创建子密钥并提交CSR-证书签名请求。因为这个想法是按根对子证书进行签名并获得正确的证书

openssl genrsa -out market.key 2048openssl req -new -sha256 -key market.key -config config_ssl.cnf -out market.csr

打开Linux终端并执行此命令

echo 00 > ca.srltouch 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. Mandatorycertificate = ./ca.crt
# the file contaning the CA private key. Mandatoryprivate_key = ./ca.key
# the message digest algorithm. Remember to not use MD5default_md = sha256
# for how many days will the signed certificate be validdefault_days = 365
# a section with a set of variables corresponding to DN fieldspolicy = my_policy
# MOST IMPORTANT PART OF THIS CONFIGcopy_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 = matchstateOrProvinceName = suppliedorganizationName = suppliedcommonName = market.localhostorganizationalUnitName = optionalcommonName = supplied

你可能会问,为什么这么难,为什么我们必须再创建一个配置来按root签署子证书。答案很简单,因为子证书必须有一个SAN块-主题替代名称。如果我们使用“openssl x509”utils签署子证书,根证书将删除子证书中的SAN字段。所以我们使用“openssl ca”而不是“openssl x509”来避免删除SAN字段。我们创建一个新的配置文件并告诉它复制所有扩展字段copy_extensions=复制

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

程序会问你两个问题:

  1. 签署证书?说“Y”
  2. 1个证书请求中的1个已认证,提交?说“Y”

在终端中,您可以看到一个带有单词“数据库”的句子,它意味着您通过命令“touch”创建的文件index.txt。它将包含您通过“openssl ca”util创建的所有证书的所有信息。检查证书是否有效:

openssl rsa -in market.key -check

如果你想在CRT中看到什么:

openssl x509 -in market.crt -text -noout

如果你想看看CSR里面有什么:

openssl req -in market.csr -noout -text

openssl允许通过单个命令生成自签名证书(-newkey指示生成私钥,-x509指示发出自签名证书而不是签名请求)::

openssl req -x509 -newkey rsa:4096 \-keyout my.key -passout pass:123456 -out my.crt \-days 365 \-subj /CN=localhost/O=home/C=US/emailAddress=me@mail.internal \-addext "subjectAltName = DNS:localhost,DNS:web.internal,email:me@mail.internal" \-addext keyUsage=digitalSignature -addext extendedKeyUsage=serverAuth

您可以在单独的步骤中生成私钥和构造自签名证书::

openssl genrsa -out my.key -passout pass:123456 2048
openssl req -x509 \-key my.key -passin pass:123456 -out my.csr \-days 3650 \-subj /CN=localhost/O=home/C=US/emailAddress=me@mail.internal \-addext "subjectAltName = DNS:localhost,DNS:web.internal,email:me@mail.internal" \-addext keyUsage=digitalSignature -addext extendedKeyUsage=serverAuth

查看生成的证书e::

openssl x509 -text -noout -in my.crt

Javakeytool创建PKCS#12 store::

keytool -genkeypair -keystore my.p12 -alias master \-storetype pkcs12 -keyalg RSA -keysize 2048 -validity 3650 \-storepass 123456 \-dname "CN=localhost,O=home,C=US" \-ext 'san=dns:localhost,dns:web.internal,email:me@mail.internal'

导出自签名证书e::

keytool -exportcert -keystore my.p12 -file my.crt \-alias master -rfc -storepass 123456

查看生成的证书e::

keytool -printcert -file my.crt

来自GnuTLS的certtool不允许从CLI传递不同的属性。我不喜欢弄乱配置文件(((

这对我有用

openssl req -x509 -nodes -subj '/CN=localhost'  -newkey rsa:4096 -keyout ./sslcert/key.pem -out ./sslcert/cert.pem -days 365

server.js

var fs = require('fs');var path = require('path');var http = require('http');var https = require('https');var compression = require('compression');var express = require('express');var app = express();
app.use(compression());app.use(express.static(__dirname + '/www'));
app.get('/*', function(req,res) {res.sendFile(path.join(__dirname+'/www/index.html'));});
// your express configuration here
var httpServer = http.createServer(app);var credentials = {key: fs.readFileSync('./sslcert/key.pem', 'utf8'),cert: fs.readFileSync('./sslcert/cert.pem', 'utf8')};var httpsServer = https.createServer(credentials, app);
httpServer.listen(8080);httpsServer.listen(8443);
console.log(`RUNNING ON  http://127.0.0.1:8080`);console.log(`RUNNING ON  http://127.0.0.1:8443`);

生成一个没有密码和证书的密钥10年,简短的方法:

openssl req  -x509 -nodes -new  -keyout server.key -out server.crt -days 3650 -subj "/C=/ST=/L=/O=/OU=web/CN=www.server.com"

对于标志-subj | -subject允许空值-subj "/C=/ST=/L=/O=/OU=web/CN=www.server.com",但您可以根据需要设置更多细节:

  • C-国家名称(2个字母代码)
  • ST-州
  • L-地区名称(例如,城市)
  • O-组织名称
  • OU-组织单位名称
  • CN-通用名称-必填!

经过多次尝试,使用各种解决方案,我仍然面临为localhost颁发自签名证书的问题,给我错误

ERR_CERT_INVALID

在扩展细节时,chrome说:

您现在无法访问localhost,因为网站发送了打乱证书…

唯一丑陋的方式是输入(直接在这个屏幕上,看不到文本的任何光标):

(输入键盘)这是不安全的

这让我继续。

直到我发现extendedKeyUsage = serverAuth, clientAuth

太长别读

  1. openssl genrsa -out localhost.key 2048

  2. openssl req -key localhost.key -new -out localhost.csr

  3. (在所有内容上单击回车,然后用localhost或您的其他FQDN填写通用名称(CN)。

  4. 将以下内容放入名为v3.ext的文件中(编辑您需要的任何内容):

subjectKeyIdentifier   = hashauthorityKeyIdentifier = keyid:always,issuer:alwaysbasicConstraints       = CA:TRUEkeyUsage               = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSignextendedKeyUsage       = serverAuth, clientAuthsubjectAltName         = DNS:localhost, DNS:localhost.localdomainissuerAltName          = issuer:copy
  1. openssl x509 -req -in localhost.csr -signkey localhost.key -out localhost.pem -days 3650 -sha256 -extfile v3.ext

哇!您可以访问网站,展开“高级”并单击“继续localhost(不安全)”。

这个非常简单的Python应用程序创建了一个自签名证书。代码:

from OpenSSL import crypto, SSLfrom secrets import randbelowprint("Please know, if you make a mistake, you must restart the program.")def cert_gen(emailAddress=input("Enter Email Address: "),commonName=input("Enter Common Name: "),countryName=input("Enter Country Name (2 characters): "),localityName=input("Enter Locality Name: "),stateOrProvinceName=input("Enter State of Province Name: "),organizationName=input("Enter Organization Name: "),organizationUnitName=input("Enter Organization Unit Name: "),serialNumber=randbelow(1000000),validityStartInSeconds=0,validityEndInSeconds=10*365*24*60*60,KEY_FILE = "private.key",CERT_FILE="selfsigned.crt"):#can look at generated file using openssl:#openssl x509 -inform pem -in selfsigned.crt -noout -text# create a key pairk = crypto.PKey()k.generate_key(crypto.TYPE_RSA, 4096)# create a self-signed certcert = crypto.X509()cert.get_subject().C = countryNamecert.get_subject().ST = stateOrProvinceNamecert.get_subject().L = localityNamecert.get_subject().O = organizationNamecert.get_subject().OU = organizationUnitNamecert.get_subject().CN = commonNamecert.get_subject().emailAddress = emailAddresscert.set_serial_number(serialNumber)cert.gmtime_adj_notBefore(0)cert.gmtime_adj_notAfter(validityEndInSeconds)cert.set_issuer(cert.get_subject())cert.set_pubkey(k)cert.sign(k, 'sha512')with open(CERT_FILE, "wt") as f:f.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode("utf-8"))with open(KEY_FILE, "wt") as f:f.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, k).decode("utf-8"))print("GENERATED")input("Press enter to close program.")cert_gen()

但是,您仍然会收到“证书不受信任”错误。这是因为几个原因:

  1. 它是自签名/未验证的(经过验证的证书需要CA(证书授权中心),例如Let's Encrypt才能在所有设备上受信任)。
  2. 它在您的计算机上不受信任。(这个答案显示了如何使Windows信任您的证书)。

你根本不需要使用openssl糟糕的用户交互界面!试试mkcert

$ brew install mkcert nss[...]
$ mkcert -installCreated a new local CA 💥The local CA is now installed in the system trust store! ⚡️The local CA is now installed in the Firefox trust store (requires browser restart)! 🦊
$ mkcert example.com "*.example.com" example.test localhost 127.0.0.1 ::1
Created a new certificate valid for the following names 📜- "example.com"- "*.example.com"- "example.test"- "localhost"- "127.0.0.1"- "::1"
The certificate is at "./example.com+5.pem" and the key at "./example.com+5-key.pem" ✅

快速命令行:最小版本

“我想要一个自签名的证书,以pfx形式,www.example.com最小的麻烦”:

openssl req -x509 -sha256 -days 365 -nodes -out cert.crt -keyout cert.key -subj "/CN=www.example.com"openssl pkcs12 -export -out cert.pfx -inkey cert.key -in cert.crt

如果您想使用open ssl生成自签名证书-这是我们生成的脚本,可以按原样使用。

#!/bin/bash
subj='//SKIP=skip/C=IN/ST=Country/L=City/O=MyCompany/OU=Technology'red='\033[31m'        # redyellow='\033[33m'        # yellowgreen='\033[32m'        # greenblue='\033[34m'        # Bluepurple='\033[35m'      # Purplecyan='\033[36m'        # Cyanwhite='\033[37m'       # White

gencerts(){certname=$1pkname=$2alias=$3$(openssl genrsa -out $pkname'pem.pem' 4096)$(openssl req -new -sha256 -key $pkname'pem.pem' -out $certname'csr.csr' -subj $subj)$(openssl x509 -req -sha256 -days 3650 -in $certname'csr.csr' -signkey $pkname'pem.pem' -out $certname'.crt')$(openssl pkcs12 -export -out $pkname'.p12' -name $alias -inkey $pkname'pem.pem' -in $certname'.crt')}
verify(){pkname=$1keytool -v -list -storetype pkcs12 -keystore $pkname'.p12'}
echo -e "${purple}WELCOME TO KEY PAIR GENERATOR"echo -e "${yellow} Please enter the name of the certificate required: "read certnameecho -e "${green}Please enter the name of the Private Key p12 file required: "read pknameecho -e "${cyan}Please enter the ALIAS of the Private Key p12 file : "read pkaliasecho -e "${white}Please wait while we generate your Key Pair"
gencerts $certname $pkname $pkaliasecho -e "${white}Now lets verify the private key :)"
tput bel     # Play a bell
verify $pkname
  • 请让我知道是否可以对脚本进行任何改进。