2014-12-02 85 views
2

如何獲得服務器的完整證書鏈?儘管有些索賠one should be able to do just thatopenssl s_client -showcerts,但情況並非總是如此。獲取包含根證書的完整證書鏈

echo | openssl s_client -CApath /etc/ssl/certs -connect www.ssllabs.com:443 \ 
         -showcerts | grep -B2 BEGIN 
depth=3 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root 
verify return:1 
depth=2 C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = COMODO RSA Certification Authority 
verify return:1 
depth=1 C = GB, ST = Greater Manchester, L = Salford, O = COMODO CA Limited, CN = COMODO RSA Domain Validation Secure Server CA 
verify return:1 
depth=0 OU = Domain Control Validated, OU = PositiveSSL, CN = www.ssllabs.com 
verify return:1 
0 s:/OU=Domain Control Validated/OU=PositiveSSL/CN=www.ssllabs.com 
    i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA 
-----BEGIN CERTIFICATE----- 
-- 
1 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA 
    i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority 
-----BEGIN CERTIFICATE----- 
-- 
2 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority 
    i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root 
-----BEGIN CERTIFICATE----- 
DONE 

這裏我們有三個證書我們四個。所有除AddTrust External CA Root證書。 (可能是因爲它沒有包含在證書包中,不需要這樣做,是的,我可以在/etc/ssl/certs找到丟失的文件)

如何以全自動方式獲取服務器的所有證書?

回答

2

你拿到鏈包括verify_callback(見SSL_CTX_set_verify裏面內置的受信任的根證書在一個小的Perl程序,你可以轉儲鏈是這樣的:

#!/usr/bin/perl 
use strict; 
use warnings; 
use IO::Socket::SSL; 

IO::Socket::SSL->new(
    PeerHost => 'www.google.com:443', 
    SSL_verify_callback => sub { 
     my $cert = $_[4]; 
     my $subject = Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_subject_name($cert)); 
     my $issuer = Net::SSLeay::X509_NAME_oneline(Net::SSLeay::X509_get_issuer_name($cert)); 
     print "# $subject (issuer=$issuer)\n"; 
     print Net::SSLeay::PEM_get_string_X509($cert),"\n"; 
     return 1; 
    } 
) or die $SSL_ERROR||$!; 
3

Meta:我試圖以超級用戶的方式回答這個問題,但是你刪除了它。幸運的是,當我發現這份副本時,我的大部分工作仍然坐在筆記本上,我沒有關閉,否則我不會願意做兩次研究工作。

s_client -showcerts顯示由服務器發送的證書;根據RFC,這個應該是以上行順序的有效鏈,除了,根MAY(在RFC2119定義中,即允許但不是特別推薦的)被省略。但是,並非所有服務器都配置正確,有些可能會發送額外的,缺少的和/或無序的證書。也取決於使用的CA可能有多個有效的鏈,但服務器只能發送一個。 openssl目前將只使用鏈接發送,但這將在1.0.2中很快發生變化,其他反饋者有時會發現與發送鏈不同的鏈。

的OpenSSL:如果接收到的鏈是完成多達和也許包括根部,其是在使用的信任(其默認位置取決於系統或建立,並且在任何情況下,總是可以被重寫),然後OpenSSL的客戶端會驗證它是否可用 - 除非它已過期,或者被撤銷,並且通常不可用的信息。在這種情況下,您可以編寫一個客戶端程序,該程序在設置cert-verify回調函數之後進行連接,該函數輸出由驗證循環處理的完整證書或其他信息,而不是s_client,該函數使用回調函數只記錄depth=n行中的主題名稱,您可以在示例中看到這些主題名稱,其中包含鏈中的所有4個證書。 openssl是開源的,因此一個客戶端程序主要用於s_client,可以是s_client的修改副本(在本例中爲s_cb.c)。

Java也可以做到這一點,並且編寫起來比較簡單,但需要安裝Java。如果接收到的鏈在中使用的信任庫(缺省爲一組公共根,但可以修改或重寫,並且可以具有非根錨),那麼您同樣可以編寫一個程序(可能是20行)使用HandshakeCompletedListener進行連接,其中轉儲來自event.getPeerCertificates()的信息。但是,如果鏈不驗證,Java將中止握手併產生異常,並且根本不會獲得任何證書,這與openssl案例中的錯誤發生前可能獲得部分信息不同 - 至少默認情況下,openssl的檢查isn無論如何,這並不是很嚴格。

更新:爲了完整起見,在Java 7+中,命令行keytool -printcert -sslserver顯示以相當混亂的格式發送的鏈。

其中瀏覽器我可以很容易地檢查,Windows上的Firefox和Chrome(至少)可以寫出他們找到並驗證的鏈。 ISTR,但不能輕易地重新測試Firefox錯誤/異常對話框,也可以對無法驗證並可能不完整的鏈執行此操作。這些不是自動的,但我已經看到許多「模擬GUI用戶輸入」工具的廣告,顯然可以根據需要驅動它們。