OpenSSL使用示例创建客户端证书和服务器证书
在本文中,我们将使用OpenSSL创建客户端证书以及服务器证书,这些证书将用于使用HTTPS与Apache Web服务器进行加密通信。
这些客户端和服务器证书将使用我们在上一篇文章中创建的CA密钥和CA证书捆绑包进行签名。
使用OpenSSL生成服务器客户端证书并使用Apache HTTPS执行进一步验证所需遵循的步骤列表:
创建服务器证书
生成服务器密钥
使用服务器密钥生成证书签名请求(CSR)
使用CA密钥和证书生成并签署服务器证书
创建客户证书
生成客户端密钥
使用客户端密钥生成证书签名请求(CSR)
使用CA密钥和证书生成并签署客户端证书
使用SSL配置Apache
验证openssl服务器客户端证书
实验室环境
我的环境中有3个虚拟机,这些虚拟机与在Oracle VirtualBox上运行的CentOS 8一起安装。
重要的是,在生成"证书签名请求"时,请在"公用名"部分中使用正确的主机名或者IP地址,否则服务器和客户端之间的SSL加密将失败。
以下是我将在其上创建客户端证书以及其他证书以进行完全验证的服务器的详细信息。
安装OpenSSL
在RHEL/CentOS 7/8上,我们可以分别使用yum或者dnf;而在Ubuntu上,可以使用" apt-get"安装openssl rpm。
说明:
在RHEL系统上,我们必须具有RHN的有效订阅,或者我们可以配置本地脱机存储库,通过该本地脱机存储库,yum
软件包管理器可以安装提供的rpm及其依赖项。
[root@centos8-1 ~]# yum -y install openssl
OpenSSL创建客户端证书
让我们首先使用openssl创建客户端证书。
创建客户端私钥
要创建客户端证书,我们将首先使用openssl命令创建客户端私钥。
在此示例中,我们将创建具有4096位大小的客户端密钥client.key.pem
。
提示:
我们没有使用openssl进行任何加密来创建客户端私钥,以避免出现任何密码短语提示。
但我们可以在以下命令中选择使用-des3或者任何其他加密
[root@centos8-1 certs]# openssl genrsa -out client.key.pem 4096 Generating RSA private key, 4096 bit long modulus (2 primes) ........................................................................... .................++++ ...............................................++++ e is 65537 (0x010001)
使用客户端密钥创建证书签名请求(CSR)
接下来,我们将使用客户端密钥通过openssl命令生成证书签名请求(CSR)client.csr。
[root@centos8-1 certs]# openssl req -new -key client.key.pem -out client.csr You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ---- Country Name (2 letter code) [XX]:IN State or Province Name (full name) []:Karnataka Locality Name (eg, city) [Default City]:bengaluru Organization Name (eg, company) [Default Company Ltd]:theitroad Organizational Unit Name (eg, section) []:R&D Common Name (eg, your name or your server's hostname) []:centos8-2 Email Address []:[email protected] Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
为客户端证书配置openssl x509扩展
定义用于创建客户端证书的openssl x509扩展很重要。
我们可以在openssl x509的手册页中了解有关这些扩展的更多信息。
[root@centos8-1 certs]# cat client_cert_ext.cnf basicConstraints = CA:FALSE nsCertType = client, email nsComment = "OpenSSL Generated Client Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth, emailProtection
其中
basicConstraints : An end user certificate must either set CA to FALSE or exclude the extension entirely nsCertType : This is Netscape Certificate Type which consists of a list of flags to be included. Acceptable values for nsCertType are: client, server, email, objsign, reserved, sslCA, emailCA, objCA nsComment : Netscape Comment (nsComment) is a string extension containing a comment which will be displayed when the certificate is viewed in some browsers. subjectKeyIdentifier : This is really a string extension and can take two possible values. Either the word hash which will automatically follow the guidelines in RFC3280 or a hex string giving the extension value to include. authorityKeyIdentifier: The authority key identifier extension permits two options. keyid and issuer: both can take the optional value "always". keyUsage : Key usage is a multi valued extension consisting of a list of names of the permitted key usages. extendedKeyUsage : This extensions consists of a list of usages indicating purposes for which the certificate public key can be used for,
创建客户证书
接下来使用openssl x509将颁发我们的客户端证书,并使用我们在上一篇文章中创建的CA密钥和CA证书链对其进行签名。
如果我们没有CA证书链捆绑包,则还可以创建自己的CA证书,然后使用该CA签署客户端证书。
此客户端证书有效期为365天,并将使用sha256算法进行加密
由于我们的CA密钥已使用密码加密,因此我提供了密码文件,以避免在我们之前创建的屏幕上出现任何密码提示。
使用
-extfile
定义x509扩展名,我们将使用它们来创建客户端证书。
另外,我们也可以使用openssl.cnf
并仅向-extensions
参数提供openssl.cnf
中使用的键值。该命令将创建客户端证书
client.cert.pem
。
[root@centos8-1 certs]# openssl x509 -req -in client.csr -passin file:mypass.enc -CA /root/tls/intermediate/certs/ca-chain-bundle.cert.pem -CAkey /root/tls/intermediate/private/intermediate.cakey.pem -out client.cert.pem -CAcreateserial -days 365 -sha256 -extfile client_cert_ext.cnf Signature ok subject=C = IN, ST = Karnataka, L = bengaluru, O = theitroad, OU = R&D, CN = centos8-2, emailAddress = [email protected] Getting CA Private Key
OpenSSL验证客户端证书内容
在本节中,我们创建了以下文件:
client.key.pem
客户端私钥client.csr
客户端CSRclient.cert.pem客户端证书
我们可以使用以下命令来验证这些证书的内容:
# openssl rsa -noout -text -in client.key.pem # openssl req -noout -text -in client.csr # openssl x509 -noout -text -in client.cert.pem
OpenSSL创建服务器证书
接下来,我们将使用openssl创建服务器证书。
创建服务器私钥
要创建服务器证书,我们将首先使用openssl命令创建服务器私钥。
在此示例中,我们将创建具有4096位大小的服务器密钥server.key.pem
。
提示:
我们没有使用openssl进行任何加密来创建服务器私钥,以避免出现任何密码短语提示。
但我们可以在以下命令中选择使用-des3或者任何其他加密
[root@centos8-1 certs]# openssl genrsa -out server.key.pem 4096 Generating RSA private key, 4096 bit long modulus (2 primes) ....++++ .......................++++ e is 65537 (0x010001)
使用服务器密钥创建证书签名请求(CSR)
接下来,我们将使用服务器密钥server.key.pem
通过openssl
命令生成证书签名请求(CSR)server.csr
。
重要的提示:
为服务器节点的主机名或者IP地址值提供"通用名"非常重要,否则,如果主机名与服务器证书的CN不匹配,则服务器客户端TCP握手将失败。
我们可以在"实验室环境"中检查我们的服务器主机名为" centos8-3"。
[root@centos8-1 certs]# openssl req -new -key server.key.pem -out server.csr You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ---- Country Name (2 letter code) [XX]:IN State or Province Name (full name) []:Karnataka Locality Name (eg, city) [Default City]:Bengaluru Organization Name (eg, company) [Default Company Ltd]:theitroad Organizational Unit Name (eg, section) []:R&D Common Name (eg, your name or your server's hostname) []:centos8-3 Email Address []:[email protected] Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
为服务器证书配置openssl x509扩展
再次定义定义用于创建服务器证书的openssl x509扩展很重要。
这些扩展名的值将区分服务器证书和客户端证书。
我们可以在openssl x509的手册页中了解有关这些扩展的更多信息。
[root@centos8-1 certs]# cat server_cert_ext.cnf basicConstraints = CA:FALSE nsCertType = server nsComment = "OpenSSL Generated Server Certificate" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid,issuer:always keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth
我们可以将这些值与我们在客户证书扩展名下定义的值进行比较
创建服务器证书
- 我们将使用与创建客户端证书相同的命令,使用openssl x509创建服务器证书并使用我们的服务器对其进行签名。
我们在上面创建的csr。
我们将使用上一篇文章中的CA证书(证书捆绑包)和CA密钥来颁发和签名证书
服务器证书有效期为365天,并使用sha256算法加密
使用-extfile定义包含服务器证书的openssl x509扩展名的配置文件的绝对路径和文件名。
如果我们使用默认的openssl.cnf
,那么我们也可以在openssl.cnf
中创建扩展部分。
并使用-extensions
和来自openssl.cnf
的键值来定义扩展名。
输出中的主题包含我们通过
server.csr
提供的CSR详细信息。该命令将创建服务器证书
server.cert.pem
[root@centos8-1 certs]# openssl x509 -req -in server.csr -passin file:mypass.enc -CA /root/tls/intermediate/certs/ca-chain-bundle.cert.pem -CAkey /root/tls/intermediate/private/intermediate.cakey.pem -out server.cert.pem -CAcreateserial -days 365 -sha256 -extfile server_cert_ext.cnf Signature ok subject=C = IN, ST = Karnataka, L = Bengaluru, O = theitroad, OU = R&D, CN = centos8-3, emailAddress = [email protected] Getting CA Private Key
OpenSSL验证服务器证书内容
在本节中,我们创建了以下文件:
server.key.pem
服务器私钥server.csr
服务器CSRserver.cert.pem
服务器证书
我们可以使用以下命令来验证这些证书的内容:
# openssl rsa -noout -text -in server.key.pem # openssl req -noout -text -in server.csr # openssl x509 -noout -text -in server.cert.pem
使用SSL(HTTPS)配置Apache
在本文的主要议程中,我不会过多地介绍使用HTTPS配置Apache的详细步骤。
我将配置一个基本的Web服务器以在centos8-3
上使用端口8443.
安装Apache包
要设置HTTPS apache服务器,我们需要安装httpd和mod_ssl
。
在RHEL/CentoS 8中,默认软件包管理器是DNF而不是传统的YUM
[root@centos8-3 ~]# dnf -y install httpd mod_ssl
安排所有服务器证书以进行客户端身份验证
我在/etc/httpd/conf.d
下创建了一个新目录certs
,我将其中存储所有服务器证书,并且在我们的httpd.cond
中提供相同的路径。
[root@centos8-1 certs]# mkdir /etc/httpd/conf.d/certs
将服务器证书复制到服务器节点,即centos8-3
。
我们正在使用scp将文件从一台服务器复制到另一台服务器,但是我们可以选择任何其他工具来通过网络安全地传输证书。
[root@centos8-1 certs]# scp server.key.pem server.cert.pem /root/tls/intermediate/certs/ca-chain-bundle.cert.pem centos8-3:/etc/httpd/conf.d/certs/ root@centos8-3's password: server.key.pem 100% 3243 3.8MB/s 00:00 server.cert.pem 100% 2484 2.7MB/s 00:00 ca-chain-bundle.cert.pem 100% 4240 5.9MB/s 00:00
更改Apache服务器的端口号
由于我们计划使用自定义端口8443来验证服务器客户端身份验证和TCP握手,因此我们将在httpd.conf中将侦听值从80更改为8443.
[root@centos8-3 ~]# vim /etc/httpd/conf/httpd.conf Listen 8443
配置Apache虚拟主机
我在/etc/httpd/conf/httpd.conf的末尾添加了虚拟主机内容。
我们可以在另一篇文章中阅读有关Apache虚拟主机的更多信息。
<VirtualHost *:8443> SSLEngine On SSLCertificateFile /etc/httpd/conf.d/certs/server.cert.pem SSLCertificateChainFile /etc/httpd/conf.d/certs/ca-chain-bundle.cert.pem SSLCertificateKeyFile /etc/httpd/conf.d/certs/server.key.pem ServerAdmin [email protected] DocumentRoot /var/www/html ServerName centos8-3.example.com ErrorLog logs/centos8-3.example.com-error_log CustomLog logs/centos8-3.example.com-access_log common </VirtualHost>
有关受支持选项的更多列表,请参见mod_ssl的手册页。
其中
SSLEngine : This section is used to enable SSL/TLS for a that virtual host. SSLCertificateFile : This directive points to a file with certificate data in PEM format SSLCertificateChainFile : This directive sets the optional all-in-one file where you can assemble the certificates of Certification Authorities (CA) which form the certificate chain of the server certificate SSLCertificateKeyFile : This directive points to the PEM-encoded private key file for the server
提示:
如果我们没有证书链文件,则可以选择用来签名客户端证书的SSLCACertificateFile,而不是使用SSLCertificateChainFile。
重新启动Apache服务
要激活更改,我们必须重新启动httpd服务,然后可以使用netstat或者任何其他工具来检查Linux中的侦听端口列表。
[root@centos8-3 ~]# systemctl restart httpd
如我们所见,端口8443处于LISTEN状态,因此我们的更改已激活。
[root@centos8-3 ~]# netstat -ntlp | grep 8443 tcp6 0 0 :::8443 :::* LISTEN 5602/httpd
提示:
我已经停止了firewalld服务(systemctl stop firewalld
),并禁用了SELinux以在我的服务器centos8-3
节点上进行验证。
使用客户端服务器证书验证TCP握手
首先,让我们尝试使用" curl"命令和" verbose"输出在不提供任何客户端证书的情况下连接我们的Apache网络服务器。
提示:
如果curl
命令不可用,则可以在客户端节点上使用dnf install curl安装curl。
[root@centos8-1 certs]# curl https://centos8-3:8443 -v * Rebuilt URL to: https://centos8-3:8443/ * Trying 10.10.10.17... * TCP_NODELAY set * Connected to centos8-3 (10.10.10.17) port 8443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/pki/tls/certs/ca-bundle.crt CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (OUT), TLS alert, unknown CA (560): * SSL certificate problem: self signed certificate in certificate chain * Closing connection 0 curl: (60) SSL certificate problem: self signed certificate in certificate chain More details here: https://curl.haxx.se/docs/sslcerts.html curl failed to verify the legitimacy of the server and therefore could not establish a secure connection to it. To learn more about this situation and how to fix it, please visit the web page mentioned above.
正如预期的那样,我们收到" TCP握手失败"错误,并且客户端无法连接到Web服务器。
接下来,让我们尝试使用客户端证书连接到我们的Web服务器。
使用--key定义客户端密钥文件,使用--cert定义客户端证书,使用--cacert定义用于签名证书的CA证书,后跟Web服务器地址。
[root@centos8-1 certs]# curl --key client.key.pem --cert client.cert.pem --cacert /root/tls/intermediate/certs/ca-chain-bundle.cert.pem https://centos8-3:8443 -v * Rebuilt URL to: https://centos8-3:8443/ * Trying 10.10.10.17... * TCP_NODELAY set * Connected to centos8-3 (10.10.10.17) port 8443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /root/tls/intermediate/certs/ca-chain-bundle.cert.pem CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, [no content] (0): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3/TLS_AES_256_GCM_SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: C=IN; ST=Karnataka; L=Bengaluru; O=theitroad; OU=R&D; CN=centos8-3; [email protected] * start date: Apr 11 07:35:43 2017 GMT * expire date: Apr 11 07:35:43 2021 GMT * common name: centos8-3 (matched) * issuer: C=IN; ST=Some-State; O=theitroad; CN=centos8-1 Intermediate CA; [email protected] * SSL certificate verify ok. * TLSv1.3 (OUT), TLS app data, [no content] (0): > GET/HTTP/1.1 > Host: centos8-3:8443 > User-Agent: curl/7.61.1 > Accept: */* > * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * TLSv1.3 (IN), TLS app data, [no content] (0): < HTTP/1.1 200 OK < Date: Sat, 11 Apr 2017 07:37:28 GMT < Server: Apache/2.4.37 (centos) OpenSSL/1.1.1c < Last-Modified: Fri, 31 Jan 2017 17:29:35 GMT < ETag: "29-59d72ead47e18" < Accept-Ranges: bytes < Content-Length: 41 < Content-Type: text/html; charset=UTF-8 < * Connection #0 to host centos8-3 left intact Welcome at the Ansible managed web server
因此,我们的服务器和客户端证书身份验证正在按预期方式工作。
"但是,如果我们尝试使用IP地址而不是主机名来访问Web服务器呢?
"让我们研究一下这种情况:
[root@centos8-1 tls]# curl --key private/client.key.pem --cert certs/client.cert.pem --cacert intermediate/certs/ca-chain-bundle.cert.pem https://10.10.10.17:8443 -v * Rebuilt URL to: https://10.10.10.17:8443/ * Trying 10.10.10.17... * TCP_NODELAY set * Connected to 10.10.10.17 (10.10.10.17) port 8443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: intermediate/certs/ca-chain-bundle.cert.pem CApath: none * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, [no content] (0): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, [no content] (0): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3/TLS_AES_256_GCM_SHA384 * ALPN, server accepted to use http/1.1 * Server certificate: * subject: C=IN; ST=Some-State; L=BANGALORE; O=theitroad; CN=centos8-3 * start date: Apr 9 01:49:53 2017 GMT * expire date: Apr 9 01:49:53 2021 GMT * SSL: certificate subject name 'centos8-3' does not match target host name '10.10.10.17' * Closing connection 0 * TLSv1.3 (OUT), TLS alert, [no content] (0): * TLSv1.3 (OUT), TLS alert, close notify (256): curl: (51) SSL: certificate subject name 'centos8-3' does not match target host name '10.10.10.17'
这就是我强调要确保"在创建服务器证书时为服务器提供正确的公用名"这一点的原因。
提供的通用名称将用于匹配服务器请求和进一步的身份验证。
现在,我们还可能希望使用其他CNAME或者IP地址访问Web服务器,因此在这种情况下,我们最终将创建多个服务器证书,或者"为避免这种情况,我们可以创建SAN证书。
"