【问题标题】:Using openssl to get the certificate from a server使用 openssl 从服务器获取证书
【发布时间】:2011-12-14 16:58:31
【问题描述】:

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

请告诉我哪里出错了。

【问题讨论】:

    标签: linux security certificate openssl ssl-certificate


    【解决方案1】:

    使用 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 版本是“OpenSSL 0.9.8g 2007 年 10 月 19 日”。你有什么想法吗?
    • 有用的:echo "" | openssl s_client -connect server:port -prexit 2&gt;/dev/null | sed -n -e '/BEGIN\ CERTIFICATE/,/END\ CERTIFICATE/ p'stackoverflow.com/a/12918442/843000
    • 另类有用的脚本,来自madboa.com:echo | openssl s_client -connect server:port 2&gt;&amp;1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' &gt; cert.pem
    • 为了更简洁,您可以将sed 替换为openssl x509,并使用子shell 读取:openssl x509 -in &lt;(openssl s_client -connect server:port -prexit 2&gt;/dev/null)
    • 还有echo | openssl s_client -connect google.com:443 2&gt;/dev/null | openssl x509
    【解决方案2】:

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

    这是我的工作命令:

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

    希望这对于任何可以使用更多信息的人来说是一个正确的方向。

    【讨论】:

    • 很抱歉,您的回答没有多大意义。您需要将证书传递给服务器才能获得证书吗?
    • 是的。客户端身份验证 AFAIK。
    • 事实证明,'-prexit' 也会返回该数据。例如。; openssl s_client -connect host:port -prexit
    【解决方案3】:

    虽然我同意 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 证书,并且从未遇到过问题。
    【解决方案4】:

    要获取远程服务器的证书,您可以使用openssl 工具,您可以在BEGIN CERTIFICATEEND 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

    【讨论】:

      【解决方案5】:

      最简单的命令行,包括 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 以人类可读的格式打印证书。

      【讨论】:

      • 您可以将您的子域添加到您的 -servername 中,例如 ws.example.com 而不是 example.com(也将其应用于 -connect 参数)。
      【解决方案6】:

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

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

      【讨论】:

        【解决方案7】:

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

        只需覆盖所需的变量。

        【讨论】:

          【解决方案8】:
          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
          

          【讨论】:

            【解决方案9】:

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

            # 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 上所需要的。谢谢!
            【解决方案10】:

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

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

            【讨论】:

            • 这个几乎可以完美提取证书,只是少了-servername选项,不知道为什么,但我不得不用它来获取完整的证书。
            • -servername 是服务器名称指示 (SNI) 所必需的。网络搜索可以扩展其余部分。
            【解决方案11】:

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

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

            在哪里,

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

            • SECURE_PORT为通讯端口,例如587或465

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

            【讨论】:

              【解决方案12】:

              启动客户端:

              openssl s_client -showcerts stackoverflow.com:443
              

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

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

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

              【讨论】:

                【解决方案13】:

                我也遇到了同样的挑战,接下来我发现 openssl 不返回根 ca。我专门为此目的构建了一个替代方案,可能对其他开发人员有用,请参见此处:GitHub - Certificate ripper

                用法

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

                【讨论】:

                • 非常有用的工具!有什么方法可以指定导出的目标文件吗?我正在考虑路径和格式。谢谢
                • 我正要分叉并添加该选项,但我看到您已经添加了它 - 非常感谢! :)
                • 是的,我已添加并今天发布。感谢您提及这个想法,在应用程序中有这个选项很好
                • 注意到一个小问题,发布的源码不是最新的^^
                • 我已经重新发布了,希望它现在是正确的:) 你可以重试吗?
                猜你喜欢
                • 2018-11-29
                • 1970-01-01
                • 2014-09-05
                • 2011-07-03
                • 2020-08-22
                • 2012-11-22
                • 1970-01-01
                • 1970-01-01
                • 2012-09-26
                相关资源
                最近更新 更多