我正在尝试获取远程服务器的证书,然后我可以将其添加到我的密钥库并在我的 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/
但我得到同样的错误。
This source 说我可以使用那个 CApath 标志,但它似乎没有帮助。我尝试了多种路径均无济于事。
请让我知道我哪里出错了。
使用 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
从远程服务器以 PEM 格式提取证书的单行程序,这次使用 sed
:
openssl s_client -connect www.google.com:443 2>/dev/null </dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
-servername
选项,不知道为什么,但我不得不用它来获取完整的证书。
虽然我同意 Ari 的回答(并赞成 :),但我需要做一个额外的步骤才能让它在 Windows 上与 Java 一起工作(需要部署它的地方):
openssl s_client -showcerts -connect www.example.com:443 < /dev/null | openssl x509 -outform DER > derp.der
在添加 openssl x509 -outform DER
转换之前,我从 Windows 上的 keytool 收到一个错误,抱怨证书的格式。导入 .der 文件工作正常。
事实证明这里有更多的复杂性:我需要提供更多的细节来实现这一点。我认为这与它的连接需要客户端身份验证有关,而 hankshake 需要更多信息才能继续转储证书的阶段。
这是我的工作命令:
openssl s_client -connect host:port -key our_private_key.pem -showcerts \
-cert our_server-signed_cert.pem
希望这对于任何可以使用更多信息的人来说都是一个正确的方向。
最简单的命令行,包括 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 以人类可读格式打印证书。
要获取远程服务器的证书,您可以使用 openssl
工具,您可以在 BEGIN CERTIFICATE
和 END CERTIFICATE
之间找到它,您需要将其复制并粘贴到您的证书文件 (CRT) 中。
这是演示它的命令:
ex +'/BEGIN CERTIFICATE/,/END CERTIFICATE/p' <(echo | openssl s_client -showcerts -connect example.com:443) -scq > file.crt
要从链中返回所有证书,只需添加 g
(全局),如:
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
。
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
我也遇到了同样的挑战,接下来我发现 openssl 不返回根 ca。我为此专门构建了一个替代方案,可能对其他开发人员有用,请参见此处:GitHub - Certificate ripper
用法
打印到控制台
crip print --url=https://stackoverflow.com/ --format=pem
导出到 p12 信任库
crip export --url=https://stackoverflow.com/
crip
实用程序,因此不要混淆。
您可以使用下一个 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'") }'
只需覆盖所需的变量。
如果您的服务器是电子邮件服务器(MS Exchange 或 Zimbra),您可能需要添加 starttls
和 smtp
标志:
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 格式)
为了像我这样在访问 AWS CloudFront 时尝试遵循此处的好建议但失败的其他人的利益,诀窍是添加 -servername domain.name..
。
来源:https://serverfault.com/a/780450/8972
启动客户端:
openssl s_client -showcerts stackoverflow.com:443
通过停止 STDIN (CTRL+D) 或终止进程 (CTRL+C) 退出。
要在显示证书后禁用输入并强制客户端退出:
openssl s_client -showcerts stackoverflow.com:443 < /dev/null
echo "" | openssl s_client -connect server:port -prexit 2>/dev/null | sed -n -e '/BEGIN\ CERTIFICATE/,/END\ CERTIFICATE/ p'
stackoverflow.com/a/12918442/843000echo | openssl s_client -connect server:port 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > cert.pem
sed
替换为openssl x509
,并使用子 shell 读取它:openssl x509 -in <(openssl s_client -connect server:port -prexit 2>/dev/null)
echo | openssl s_client -connect google.com:443 2>/dev/null | openssl x509