如何使用您的证书颁发机构为证书签名请求进行签名?

276

在我的搜索中,我发现了几种签署SSL证书签名请求的方法:

  1. 使用x509模块:

  2. openssl x509 -req -days 360 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
    
  3. 使用ca模块:

    openssl ca -cert ca.crt -keyfile ca.key -in server.csr -out server.crt
    

注意:我不确定这个问题的正确参数使用方法,请指导我如何正确使用。

使用哪种方式来使用您的认证机构签署证书请求?是否有一种方法比另一种更好(例如,一种已被弃用)?


1
可能是如何使用openssl构建自签名证书?的重复问题。 - jww
从我所看到的,ca 是针对那些更认真地想成为CA的情况。 - x-yuri
你可能会觉得我的回答很有趣。 - x-yuri
1
Stack Overflow是一个关于编程和开发问题的网站。这个问题似乎不属于编程或开发范畴。请参阅帮助中心中的我可以在这里问什么样的问题。也许超级用户Unix&Linux Stack Exchange更适合提问。 - jww
被接受的答案很好,还请查看我对它的小补充 https://dev59.com/5WEi5IYBdhLWcg3wZ7u8#47970330 - humble_wolf
4个回答

620
1. Using the x509 module
openssl x509 ...
...

2 Using the ca module
openssl ca ...
...

你缺少这些命令的前奏。
这是一个两步骤的过程。首先,您设置您的CA,然后签署终端实体证书(也称为服务器或用户)。这两个命令将两个步骤合并为一个。它们都假定您已经为CA和服务器(终端实体)证书设置了OpenSSL配置文件。
首先,创建一个基本的配置文件
$ touch openssl-ca.cnf

然后,将以下内容添加到其中:
HOME            = .
RANDFILE        = $ENV::HOME/.rnd

####################################################################
[ ca ]
default_ca    = CA_default      # The default ca section

[ CA_default ]

default_days     = 365          # How long to certify for
default_crl_days = 30           # How long before next CRL
default_md       = sha256       # Use public key default MD
preserve         = no           # Keep passed DN ordering

x509_extensions = ca_extensions # The extensions to add to the cert

email_in_dn     = no            # Don't concat the email in the DN
copy_extensions = copy          # Required to copy SANs from CSR to cert

####################################################################
[ req ]
default_bits       = 4096
default_keyfile    = cakey.pem
distinguished_name = ca_distinguished_name
x509_extensions    = ca_extensions
string_mask        = utf8only

####################################################################
[ ca_distinguished_name ]
countryName         = Country Name (2 letter code)
countryName_default = US

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

localityName                = Locality Name (eg, city)
localityName_default        = Baltimore

organizationName            = Organization Name (eg, company)
organizationName_default    = Test CA, Limited

organizationalUnitName         = Organizational Unit (eg, division)
organizationalUnitName_default = Server Research Department

commonName         = Common Name (e.g. server FQDN or YOUR name)
commonName_default = Test CA

emailAddress         = Email Address
emailAddress_default = test@example.com

####################################################################
[ ca_extensions ]

subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid:always, issuer
basicConstraints       = critical, CA:true
keyUsage               = keyCertSign, cRLSign

上面的字段来自于一个更复杂的 openssl.cnf 文件(可以在 /usr/lib/openssl.cnf 找到),但我认为它们是创建 CA 证书和私钥的基本要素。
根据您的需要调整上述字段。默认值可节省您在尝试配置文件和命令选项时输入相同信息的时间。
我省略了与 CRL 相关的内容,但您的 CA 操作应该包含它们。请参见 openssl.cnf 和相关的 crl_ext 部分。
然后,执行以下操作。 -nodes 省略密码或口令,以便您可以检查证书。省略密码或口令是一个非常糟糕的主意。
$ openssl req -x509 -config openssl-ca.cnf -days 365 -newkey rsa:4096 -sha256 -nodes -out cacert.pem -outform PEM

执行该命令后,cacert.pem 将成为您进行 CA 操作的证书,而 cakey.pem 将是私钥。请注意,私钥没有密码或密码短语。
您可以使用以下命令转储证书。
$ openssl x509 -in cacert.pem -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 11485830970703032316 (0x9f65de69ceef2ffc)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=MD, L=Baltimore, CN=Test CA/emailAddress=test@example.com
        Validity
            Not Before: Jan 24 14:24:11 2014 GMT
            Not After : Feb 23 14:24:11 2014 GMT
        Subject: C=US, ST=MD, L=Baltimore, CN=Test CA/emailAddress=test@example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    00:b1:7f:29:be:78:02:b8:56:54:2d:2c:ec:ff:6d:
                    ...
                    39:f9:1e:52:cb:8e:bf:8b:9e:a6:93:e1:22:09:8b:
                    59:05:9f
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                4A:9A:F3:10:9E:D7:CF:54:79:DE:46:75:7A:B0:D0:C1:0F:CF:C1:8A
            X509v3 Authority Key Identifier:
                keyid:4A:9A:F3:10:9E:D7:CF:54:79:DE:46:75:7A:B0:D0:C1:0F:CF:C1:8A

            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Key Usage:
                Certificate Sign, CRL Sign
    Signature Algorithm: sha256WithRSAEncryption
         4a:6f:1f:ac:fd:fb:1e:a4:6d:08:eb:f5:af:f6:1e:48:a5:c7:
         ...
         cd:c6:ac:30:f9:15:83:41:c1:d1:20:fa:85:e7:4f:35:8f:b5:
         38:ff:fd:55:68:2c:3e:37

请使用以下方式测试其用途(不必担心Any Purpose: Yes; 参见 "critical,CA:FALSE" but "Any Purpose CA : Yes")。

$ openssl x509 -purpose -in cacert.pem -inform PEM
Certificate purposes:
SSL client : No
SSL client CA : Yes
SSL server : No
SSL server CA : Yes
Netscape SSL server : No
Netscape SSL server CA : Yes
S/MIME signing : No
S/MIME signing CA : Yes
S/MIME encryption : No
S/MIME encryption CA : Yes
CRL signing : Yes
CRL signing CA : Yes
Any Purpose : Yes
Any Purpose CA : Yes
OCSP helper : Yes
OCSP helper CA : Yes
Time Stamp signing : No
Time Stamp signing CA : Yes
-----BEGIN CERTIFICATE-----
MIIFpTCCA42gAwIBAgIJAJ9l3mnO7y/8MA0GCSqGSIb3DQEBCwUAMGExCzAJBgNV
...
aQUtFrV4hpmJUaQZ7ySr/RjCb4KYkQpTkOtKJOU1Ic3GrDD5FYNBwdEg+oXnTzWP
tTj//VVoLD43
-----END CERTIFICATE-----

第二部分,我将创建另一个易于理解的配置文件。首先,touch openssl-server.cnf (您还可以为用户证书创建一个)。

$ touch openssl-server.cnf

然后打开它,添加以下内容。
HOME            = .
RANDFILE        = $ENV::HOME/.rnd

####################################################################
[ req ]
default_bits       = 2048
default_keyfile    = serverkey.pem
distinguished_name = server_distinguished_name
req_extensions     = server_req_extensions
string_mask        = utf8only

####################################################################
[ server_distinguished_name ]
countryName         = Country Name (2 letter code)
countryName_default = US

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

localityName         = Locality Name (eg, city)
localityName_default = Baltimore

organizationName            = Organization Name (eg, company)
organizationName_default    = Test Server, Limited

commonName           = Common Name (e.g. server FQDN or YOUR name)
commonName_default   = Test Server

emailAddress         = Email Address
emailAddress_default = test@example.com

####################################################################
[ server_req_extensions ]

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

####################################################################
[ alternate_names ]

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

如果您正在开发并需要将您的工作站用作服务器,则可能需要对Chrome执行以下操作。否则,Chrome可能会抱怨通用名称无效(ERR_CERT_COMMON_NAME_INVALID。我不确定在此情况下SAN中的IP地址与CN之间的关系是什么。

# IPv4 localhost
IP.1     = 127.0.0.1

# IPv6 localhost
IP.2     = ::1

然后,创建服务器证书请求。确保省略-x509。添加-x509将创建证书而不是请求。
$ openssl req -config openssl-server.cnf -newkey rsa:2048 -sha256 -nodes -out servercert.csr -outform PEM

执行此命令后,您将在servercert.csr中获得一个请求,并在serverkey.pem中获得私钥。您可以再次检查它。
$ openssl req -text -noout -verify -in servercert.csr
Certificate:
    verify OK
    Certificate Request:
        Version: 0 (0x0)
        Subject: C=US, ST=MD, L=Baltimore, CN=Test Server/emailAddress=test@example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:ce:3d:58:7f:a0:59:92:aa:7c:a0:82:dc:c9:6d:
                    ...
                    f9:5e:0c:ba:84:eb:27:0d:d9:e7:22:5d:fe:e5:51:
                    86:e1
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Subject Key Identifier:
                1F:09:EF:79:9A:73:36:C1:80:52:60:2D:03:53:C7:B6:BD:63:3B:61
            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Key Usage:
                Digital Signature, Key Encipherment
            X509v3 Subject Alternative Name:
                DNS:example.com, DNS:www.example.com, DNS:mail.example.com, DNS:ftp.example.com
            Netscape Comment:
                OpenSSL Generated Certificate
    Signature Algorithm: sha256WithRSAEncryption
         6d:e8:d3:85:b3:88:d4:1a:80:9e:67:0d:37:46:db:4d:9a:81:
         ...
         76:6a:22:0a:41:45:1f:e2:d6:e4:8f:a1:ca:de:e5:69:98:88:
         a9:63:d0:a7

接下来,您必须使用您的CA进行签名。
你已经几乎可以通过CA签署服务器证书。在执行命令之前,CA的openssl-ca.cnf需要增加两个部分。
首先,打开openssl-ca.cnf并添加以下两个部分。
####################################################################
[ signing_policy ]
countryName            = optional
stateOrProvinceName    = optional
localityName           = optional
organizationName       = optional
organizationalUnitName = optional
commonName             = supplied
emailAddress           = optional

####################################################################
[ signing_req ]
subjectKeyIdentifier   = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints       = CA:FALSE
keyUsage               = digitalSignature, keyEncipherment

其次,在openssl-ca.cnf文件的[ CA_default ]部分添加以下内容。我之前没有包含它们,因为它们可能会使事情变得复杂(当时未使用)。现在您将看到它们如何使用,希望它们能够让您理解。
base_dir      = .
certificate   = $base_dir/cacert.pem   # The CA certifcate
private_key   = $base_dir/cakey.pem    # The CA private key
new_certs_dir = $base_dir              # Location for new certs after signing
database      = $base_dir/index.txt    # Database index file
serial        = $base_dir/serial.txt   # The current serial number

unique_subject = no  # Set to 'no' to allow creation of
                     # several certificates with same subject.

第三步,触摸index.txtserial.txt:
$ touch index.txt
$ echo '01' > serial.txt

然后,执行以下操作:
$ openssl ca -config openssl-ca.cnf -policy signing_policy -extensions signing_req -out servercert.pem -infiles servercert.csr

您应该看到类似于以下内容:
Using configuration from openssl-ca.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'US'
stateOrProvinceName   :ASN.1 12:'MD'
localityName          :ASN.1 12:'Baltimore'
commonName            :ASN.1 12:'Test CA'
emailAddress          :IA5STRING:'test@example.com'
Certificate is to be certified until Oct 20 16:12:39 2016 GMT (1000 days)
Sign the certificate? [y/n]:Y

1 out of 1 certificate requests certified, commit? [y/n]Y
Write out database with 1 new entries
Data Base Updated

执行该命令后,您将获得一个全新的服务器证书,保存在servercert.pem中。私钥早已创建,并存储在serverkey.pem中。
最后,您可以使用以下命令检查您的全新证书:
$ openssl x509 -in servercert.pem -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 9 (0x9)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=MD, L=Baltimore, CN=Test CA/emailAddress=test@example.com
        Validity
            Not Before: Jan 24 19:07:36 2014 GMT
            Not After : Oct 20 19:07:36 2016 GMT
        Subject: C=US, ST=MD, L=Baltimore, CN=Test Server
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:ce:3d:58:7f:a0:59:92:aa:7c:a0:82:dc:c9:6d:
                    ...
                    f9:5e:0c:ba:84:eb:27:0d:d9:e7:22:5d:fe:e5:51:
                    86:e1
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                1F:09:EF:79:9A:73:36:C1:80:52:60:2D:03:53:C7:B6:BD:63:3B:61
            X509v3 Authority Key Identifier:
                keyid:42:15:F2:CA:9C:B1:BB:F5:4C:2C:66:27:DA:6D:2E:5F:BA:0F:C5:9E

            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Key Usage:
                Digital Signature, Key Encipherment
            X509v3 Subject Alternative Name:
                DNS:example.com, DNS:www.example.com, DNS:mail.example.com, DNS:ftp.example.com
            Netscape Comment:
                OpenSSL Generated Certificate
    Signature Algorithm: sha256WithRSAEncryption
         b1:40:f6:34:f4:38:c8:57:d4:b6:08:f7:e2:71:12:6b:0e:4a:
         ...
         45:71:06:a9:86:b6:0f:6d:8d:e1:c5:97:8d:fd:59:43:e9:3c:
         56:a5:eb:c8:7e:9f:6b:7a

之前,您已将以下内容添加到CA_default中:copy_extensions = copy。这将复制由发出请求的人提供的扩展。

如果省略了copy_extensions = copy,那么您的服务器证书将缺少主题备用名称(SANs),例如www.example.commail.example.com

如果使用了copy_extensions = copy,但没有查看请求,则请求者可能会欺骗您签署类似于下级根证书的东西(而不是服务器或用户证书)。这意味着他/她将能够铸造链回您信任的根的证书。在签名之前,请务必使用openssl req -verify验证请求。


如果您省略unique_subject或将其设置为yes,则您只能在主题的可分辨名称下创建一个证书。
unique_subject = yes            # Set to 'no' to allow creation of
                                # several ctificates with same subject.

尝试在实验中创建第二个证书,使用 CA 的私钥签署服务器证书时,会导致以下结果:
Sign the certificate? [y/n]:Y
failed to update database
TXT_DB error number 2

所以unique_subject = no非常适合测试。


如果您希望确保自签名CA、下级CA和终端实体证书之间的组织名称一致,则请将以下内容添加到您的CA配置文件中:
[ policy_match ]
organizationName = match

如果你想允许更改组织名称,那么使用以下代码:

[ policy_match ]
organizationName = supplied

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

RFC 6797和RFC 7469被列为更加严格的标准,因为它们比其他RFC和CA/B文档更加限制。RFC 6797和RFC 7469都不允许使用IP地址。

5
谢谢你提供这么详细的答案... 然而,我现在有点不知所措。 根据你的回答,我理解openssl req用于生成CSR,openssl req -x509用于生成CA证书(我在别处看到您还可以创建自签名证书),openssl ca用于使用CA证书签署CSR。对吗?令我困惑的是,相同的openssl.cnf文件部分根据命令使用不同的值... 我现在感到非常迷茫。 - Bernard Rosset
35
首先,使用“openssl req -x509”命令来创建CA。其次,使用“openssl req”命令创建服务器的CSR。第三步,使用“openssl ca”命令来创建服务器证书,并用CA的签名进行认证。 - jww
4
“我感到困惑的是 openssl.cnf 中相同的部分也让我感到困惑...”- 是的,这就是为什么我为您将它们分成了 openssl-ca.cnfopenssl-server.cnf。当您熟悉它们以及如何调用各个部分后,您可以将它们合并为像 openssl.cnf 这样的庞然大物。 - jww
1
谢谢@jww,描述得很好。我不明白的一件事是CA证书的持续时间。openssl-ca.cnf说默认天数为1000,但证书的有效期只有一个多月。这30天是从哪里来的? - ahnkle
6
如果需要使用不同于默认的30天的选项,请使用“-days”选项。【摘自OpenSSL文档】。 - george
显示剩余18条评论

29

有时候,比如进行测试,您只需要一种简单的方法来生成一个签名证书,而不需要设置完整的CA配置。使用 openssl reqopenssl x509 命令就可以实现。尽管您永远不会在生产环境中使用此方法来生成证书,但由于它对某些非生产环境很有用,因此以下是命令。

生成自签名的签名证书

首先创建一个自签名证书,该证书将用作信任根:

openssl req -x509 -days 365 -key ca_private_key.pem -out ca_cert.pem

或等价的,如果您想要在单个命令中生成私钥和自签名证书:

openssl req -x509 -days 365 -newkey rsa:4096 -keyout ca_private_key.pem -out ca_cert.pem

生成证书请求

接下来,为待签署的证书创建证书请求:

openssl req -new -key my_private_key.pem -out my_cert_req.pem

如果需要,您可以同时生成私钥和证书请求:

openssl req -new -newkey rsa:4096 -keyout my_private_key.pem -out my_cert_req.pem

生成签名证书

最后,使用自签发的签名证书从证书请求中生成签名证书:

openssl x509 -req -in my_cert_req.pem -days 365 -CA ca_cert.pem -CAkey ca_private_key.pem -CAcreateserial -out my_signed_cert.pem

23
除了@jww的回答,我想说一下在openssl-ca.cnf中的配置问题。
default_days     = 1000         # How long to certify for

该参数定义由此根证书签名的证书默认有效期天数。要设置根证书本身的有效期,您应该在以下选项中使用“-days n”:

openssl req -x509 -days 3000 -config openssl-ca.cnf -newkey rsa:4096 -sha256 -nodes -out cacert.pem -outform PEM

如果不这样做,你的根证书只有一个月的有效期,由此签署的任何证书也只有一个月的有效期。


2
对于任何进行iOS或macOS开发的人,请注意,颁发1000天证书将不会在iOS 13+中受到信任(还需要extendedKeyUsage)。我最终能够使用这两个答案以及此处的答案签署自己的可信证书:https://apple.stackexchange.com/questions/371725/why-does-ios-13-not-trust-my-own-root-ca - Jeff Camera

0

我找到了一个方便的脚本sscg来完成这个任务 - https://github.com/sgallagher/sscg
以下是Fedora Linux的示例:
安装:

sudo yum install sscg

例子:

sscg \
--ca-key-password-prompt \
--lifetime=3650 \
--country=XX \
--state=myState \
--locality=myCity \
--organization=myOrg \
--organizational-unit=myUnit \
--email=myemail@example.com \
--hostname=foo.example.com  \
--subject-alt-name=*.example.com \
--ca-key-file=CA.key \
--ca-file=CA.pem \
--cert-key-file=foo.example.com.key \
--cert-file=foo.example.com.pem

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