使用openssl从服务器获取证书


353

我正在尝试获取远程服务器的证书,然后可以将其用于添加到我的密钥库中并在我的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标志,但似乎无济于事。我尝试了多条路径都无济于事。

请让我知道我要去哪里了。

Answers:


461

使用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

3
嗯 尝试该命令时,我仍然收到相同的错误。我注意到我的Openssl版本是“ OpenSSL 0.9.8g 2007年10月19日”。你有什么想法?
讨厌的馅饼

39
有用:echo "" | openssl s_client -connect server:port -prexit 2>/dev/null | sed -n -e '/BEGIN\ CERTIFICATE/,/END\ CERTIFICATE/ p' stackoverflow.com/a/12918442/843000
mbrownnyc 2013年

16
另类有用的脚本,从madboa.comecho | openssl s_client -connect server:port 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > cert.pem
rmeakins

9
为了使这个多一点简洁,可以更换sed使用openssl x509,并在使用一个子shell阅读:openssl x509 -in <(openssl s_client -connect server:port -prexit 2>/dev/null)
加布马丁Dempesy

27
另外echo | openssl s_client -connect google.com:443 2>/dev/null | openssl x509
MattSizzle,2014年

68

当我同意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文件效果很好。


奇。自Java 6以来,我一直在Windows上使用带有keytool的PEM证书,并且从未遇到过问题。
imgx64 '17

39

事实证明,这里存在更多的复杂性:我需要提供更多详细信息来进行滚动。我认为这与以下事实有关:它的连接需要客户端身份验证,并且握手器需要更多信息才能继续进行证书转储的阶段。

这是我的工作命令:

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

希望这对任何可以提供更多信息的人来说都是正确的方向。


6
抱歉,您的回答没有多大意义。您需要将证书传递到服务器才能获得证书?
Ari Maniatis

2
是的 客户端身份验证AFAIK。
讨厌的馅饼

11
事实证明,“-prexit”也将返回该数据。例如; openssl s_client -connect host:port -prexit
Robert

39

一种单线从PEM格式的远程服务器提取证书,这次使用sed

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

2
这个证书几乎是提取证书的完美-servername选择,只是缺少选项,不知道为什么,但是我必须使用它来获取完整的证书。
Karl.S

-servername是服务器名称指示(SNI)所必需的。网络搜索可以扩展其余的内容。
Sam Gleske

32

为此,最简单的命令行包括将其添加到密钥库的PEM输出以及人类可读的输出,并且还支持SNI,如果您使用的是HTTP服务器,则该SNI非常重要:

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

-servername选项是让SNI支持和OpenSSL的X509 -text打印出人类可读的格式的证书。


您可以将您的子域添加到-servername中,例如ws.example.com而不是example.com(也可以将其应用于-connect参数)。
russellhoff

24

要获得远程服务器的证书,可以使用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/run中sudo update-ca-trust extract

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


12
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

6

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

# 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

正是我在CentOS7上需要的。谢谢!
亚瑟·赫伯特

5

您可以使用下一个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'") }'

只是覆盖所需的变量。


4

如果您的服务器是电子邮件服务器(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格式)


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.