Tian Jiale's Blog

记 SSL 证书使用一大坑

SSL 是什么?

SSL(Secure Sockets Layer 安全套接字协议),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层应用层之间对网络连接进行加密。

SSL 证书

SSL 证书是一种遵守 SSL 协议的服务器数字证书,由受信任的根证书颁发机构颁发。

证书格式

  • .DER .CER,文件是二进制格式,只保存证书,不保存私钥。

  • .PEM,一般是文本格式,可保存证书,可保存私钥。

  • .CRT,可以是二进制格式,可以是文本格式,与 .DER 格式相同,不保存私钥。

  • .PFX .P12,二进制格式,同时包含证书和私钥,一般有密码保护。

  • .JKS,二进制格式,同时包含证书和私钥,一般有密码保护。

证书转换

  1. CER/CRT

    将“cert.crt”证书文件直接重命名为“cert.pem”。

  2. PFX

    • 提取私钥命令,以“cert.pfx”转换为“key.pem”为例。

      openssl pkcs12 -in cert.pfx -nocerts -out key.pem

    • 提取证书命令,以“cert.pfx”转换位“cert.pem”为例。

      openssl pkcs12 -in cert.pfx -nokeys -out cert.pem

  3. P7B

    • 证书转换,以“cert.p7b”转换为“cert.cer”为例。

      openssl pkcs7 -print_certs -in cert.p7b -out cert.cer

    • 将“cert.cer”证书文件直接重命名为“cert.pem”。

  4. DER

    • 提取私钥命令,以“privatekey.der”转换为“privatekey.pem”为例。 openssl rsa -inform DER -outform PEM -in privatekey.der -out privatekey.
  5. pem

    • 提取证书命令,以“cert.cer”转换为“cert.pem”为例。 openssl x509 -inform der -in cert.cer -out cert.pem

遇到的坑

在上面我们可以很清楚地区分各个 SSL 证书的格式和区别,我遇到的问题开头就说了是两个字母的问题。

场景复现

我的证书是从OHTTPS上申请的,该网站提供的证书是 PEM 格式,同时提供了文件 cert.key - 私钥文件、cert.cer - 证书文件、fullchain.cer - 证书文件(包含证书和中间证书)。

我的使用场景是 EwoMail 开源版邮件服务器。官网的要求是:

默认使用本地证书,IMAP,SMTP,POP,WEB 访问都是通用一个文件

使用互联网经过认证的证书,将你申请生成的 nginx 证书替换以下 2 个文件

公匙 /etc/ssl/certs/dovecot.pem

私匙 /etc/ssl/private/dovecot.pem

所以我理所应当地就把 cert.cer 文件中内容复制到了 /etc/ssl/certs/dovecot.pem 中,把 cert.key 文件中的内容复制到了 /etc/ssl/private/dovecot.pem 中,但执行时总是报下面的这个错误:

Sep 17 21:54:30 VM-4-3-centos nginx[15958]: nginx: [emerg] cannot load certificate “/etc/ssl/certs/> dovecot.pem”: PEM_read_bio_X509_AUX() failed (SSL: error:0906D06C:PEM routines:PEM_read_bio:no start > line:Expecting: TRUSTED CERTIFICATE)

Sep 17 21:54:30 VM-4-3-centos nginx[15958]: nginx: configuration file /ewomail/nginx/conf/nginx.conf test failed

Sep 17 21:54:30 VM-4-3-centos systemd[1]: nginx.service: control process exited, code=exited status=1

Sep 17 21:54:30 VM-4-3-centos systemd[1]: Failed to start The NGINX HTTP and reverse proxy server.

Sep 17 21:54:30 VM-4-3-centos systemd[1]: Unit nginx.service entered failed state.

Sep 17 21:54:30 VM-4-3-centos systemd[1]: nginx.service failed.

我能咋办,当然是去 愉快 地 Google 去喽,从 SSL 证书格式到 SSL 证书标准,从 SSL 官网的 Configure 到 NGINX 和 dovecot 的配置,在找了几个小时并逐渐崩溃后,在 StackOverflow 看到了这个问题 nginx SSL no start line: expecting: TRUSTED CERTIFICATE,提问的回复里有下面这句话:

It is expecting BEGIN TRUSTED CERTIFICATE instead of BEGIN CERTIFICATE and same for the end. The filename and extension are irelevant (you can name it foobar.42 and it will work the same way) only the content of the file is important.

死马当活马医,我把 BEGIN CERTIFICATE 换成了 BEGIN TRUSTED CERTIFICATEEND CERTIFICATE 换成了END TRUSTED CERTIFICATE,一运行,成了!!!

问题发现

证书由一个“证书颁发机构”通过一个或多个中间人签署。这将建立一个直到根证书的信任链,其中颁发者等于主体,该证书对自身进行签名。

上文中的证书某种情况下是一个“自签名”证书,在技术上与 CA 证书没有区别,除了默认情况下没有系统(包括您自己的系统)会在没有特定配置的情况下信任此类证书。

这基本上说明:应用程序说它正在根据您的配置加载一个无法验证的证书(因为它是自签名的),同时没有明确地将其配置为信任它。

所以加上这个 TRUSTED 就等同于通知使用这个证书的程序这个证书是可信的。在 openssl 程序中有这样一个参数 -clrtrust , 它就是证书中有无 TRUSTED 的说明。可以通过 openssl x509 -in trusted.pem -clrtrust -out normal.pem 来将未取信的证书转换成取信的证书。