使用openssl从服务器获取证书

我正在尝试获得远程服务器的证书,然后可以将其添加到我的密钥存储库中并在Java应用程序中使用。

一位高级开发人员(他正在度假:)告诉我,我可以运行这个:

openssl s_client -connect host.host:9999

来获得一个原始证书,然后我可以复制和导出。我收到以下输出:

depth=1 /C=NZ/ST=Test State or Province/O=Organization Name/OU=Organizational Unit Name/CN=Test CA
verify error:num=19:self signed certificate in certificate chain
verify return:0
23177:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure:s3_pkt.c:1086:SSL alert number 40
23177:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:188:

我也尝试过这个选项:

-showcerts

还有这个(在Debian上运行):

-CApath /etc/ssl/certs/

但是我得到了同样的错误。

这个源说我可以使用这个CApath标志,但它似乎没有帮助。我尝试了多种途径,但都无济于事。

请告诉我哪里做错了。

1094480 次浏览

与SNI

如果远程服务器使用SNI(即在一个IP地址上共享多个SSL主机),则需要发送正确的主机名以获得正确的证书。

openssl s_client -showcerts -servername www.example.com -connect www.example.com:443 </dev/null

没有SNI

如果远程服务器没有使用SNI,那么你可以跳过-servername参数:

openssl s_client -showcerts -connect www.example.com:443 </dev/null


要查看站点证书的完整细节,您也可以使用以下命令链:

$ echo | \
openssl s_client -servername www.example.com -connect www.example.com:443 2>/dev/null | \
openssl x509 -text

事实证明这里有更多的复杂性:我需要提供更多的细节来启动它。我认为这与这是一个需要客户端身份验证的连接有关,而握手需要更多的信息才能继续到转储证书的阶段。

下面是我的工作命令:

openssl s_client -connect host:port -key our_private_key.pem -showcerts \
-cert our_server-signed_cert.pem

希望这对那些需要更多信息的人来说是一个正确的方向。

虽然我同意Ari的回答(并为其点赞:),但我需要做额外的步骤来让它在Windows上与Java一起工作(需要在Windows上部署):

openssl s_client -showcerts -connect www.example.com:443 < /dev/null | openssl x509 -outform DER > derp.der

在添加openssl x509 -outform DER转换之前,我从Windows上的keytool得到一个错误,抱怨证书的格式。导入.der文件工作正常。

要获得远程服务器的证书,你可以使用openssl工具,你可以在BEGIN CERTIFICATEEND CERTIFICATE之间找到它,你需要复制并粘贴到你的证书文件(CRT)。

下面是演示它的命令:

ex +'/BEGIN CERTIFICATE/,/END CERTIFICATE/p' <(echo | openssl s_client -showcerts -connect example.com:443) -scq > file.crt

要从链中返回所有证书,只需添加g (global),如下所示:

ex +'g/BEGIN CERTIFICATE/,/END CERTIFICATE/p' <(echo | openssl s_client -showcerts -connect example.com:443) -scq

然后,您可以简单地将证书文件(file.crt)导入到您的钥匙链中,并使其受信任,因此Java不应该抱怨。

在OS X上,你可以双击文件或拖放你的钥匙链访问,所以它会出现在登录/证书。然后双击导入的证书并使其始终信任SSL

在CentOS 5上,你可以将它们附加到/etc/pki/tls/certs/ca-bundle.crt文件中(并运行:sudo update-ca-trust force-enable),或者在CentOS 6中将它们复制到/etc/pki/ca-trust/source/anchors/中并运行sudo update-ca-trust extract

在Ubuntu中,将它们复制到/usr/local/share/ca-certificates并运行sudo update-ca-certificates

最简单的命令行包括PEM输出,将其添加到密钥库中,以及人类可读的输出,还支持SNI,如果您使用HTTP服务器,这很重要:

openssl s_client -servername example.com -connect example.com:443 \
</dev/null 2>/dev/null | openssl x509 -text

servername选项用于启用SNI支持,而Openssl x509 -text . txt则以人类可读的格式打印证书。

为了像我这样在访问AWS CloudFront时试图遵循这里的好建议但失败的人的利益,诀窍是添加-servername domain.name..

来源:https://serverfault.com/a/780450/8972

您可以使用next bash脚本获取并存储服务器根证书:

CERTS=$(echo -n | openssl s_client -connect $HOST_NAME:$PORT -showcerts | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p')
echo "$CERTS" | awk -v RS="-----BEGIN CERTIFICATE-----" 'NR > 1 { printf RS $0 > "'$SERVER_ROOT_CERTIFICATE'"; close("'$SERVER_ROOT_CERTIFICATE'") }'

只需覆盖所需的变量。

HOST=gmail-pop.l.google.com
PORT=995


openssl s_client -servername $HOST -connect $HOST:$PORT < /dev/null 2>/dev/null | openssl x509 -outform pem

只打印证书链,而不打印服务器的证书:

# MYHOST=myhost.com
# MYPORT=443
# openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null </dev/null | awk '/^.*'"${MYHOST}"'/,/-----END CERTIFICATE-----/{next;}/-----BEGIN/,/-----END CERTIFICATE-----/{print}'

在CentOS/RHEL 6/7上更新CA信任:

# update-ca-trust enable
# openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null </dev/null | awk '/^.*'"${MYHOST}"'/,/-----END CERTIFICATE-----/{next;}/-----BEGIN/,/-----END CERTIFICATE-----/{print}' >/etc/pki/ca-trust/source/anchors/myca.cert
# update-ca-trust extract

在CentOS/RHEL 5上:

# openssl s_client -connect ${MYHOST}:${MYPORT} -showcerts 2>/dev/null </dev/null | awk '/^.*'"${MYHOST}"'/,/-----END CERTIFICATE-----/{next;}/-----BEGIN/,/-----END CERTIFICATE-----/{print}' >>/etc/pki/tls/certs/ca-bundle.crt

从远程服务器以PEM格式提取证书的一行程序,这次使用sed:

openssl s_client -connect www.google.com:443 2>/dev/null </dev/null |  sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'

如果你的服务器是电子邮件服务器(MS Exchange或Zimbra),你可能需要添加starttlssmtp标志:

openssl s_client -starttls smtp -connect HOST_EMAIL:SECURE_PORT 2>/dev/null </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > CERTIFICATE_NAME.pem

在那里,

  • HOST_EMAIL为服务器域,例如mail-server.com。

  • SECURE_PORT为通信端口,如587、465

  • CERTIFICATE_NAME输出的文件名(BASE 64/PEM格式)

启动客户端:

openssl s_client -showcerts stackoverflow.com:443

通过停止STDIN (CTRL+D)或终止进程(CTRL+C)退出。

禁用输入,并在显示证书后强制客户端退出。

openssl s_client -showcerts stackoverflow.com:443 < /dev/null

我也有同样的挑战,然后我发现openssl不返回根ca。我已经专门为此目的构建了一个替代方案,这可能对其他开发人员有用,参见这里:GitHub -证书开膛手

使用

  • 打印到控制台
crip print --url=https://stackoverflow.com/ --format=pem
  • 导出到p12信任库
crip export --url=https://stackoverflow.com/