2011-05-26 480 views
15

我想驗證一個針對java密鑰庫的證書,這是我使用的代碼如下所示。如果它成功完成,那麼我認爲驗證已經正確完成,否則如果拋出異常,則驗證失敗。 我擔心的是:使用Java API驗證X509證書

以下是足夠的代碼驗證證書?在這裏有什麼我在這裏失蹤(像檢查發送給我的證書的計算機簽名的數據?)? 2.是否應驗證證書中包含的簽名?如果是,如何?

在此先感謝您的回覆! 普拉迪普

// To check the validity of the dates 
cert.checkValidity(); 
//Check the chain 
CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
List<X509Certificate> mylist = new ArrayList<X509Certificate>();   
mylist.add(cert); 
CertPath cp = cf.generateCertPath(mylist); 
PKIXParameters params = new PKIXParameters(getTrustStore()); 
params.setRevocationEnabled(false); 
CertPathValidator cpv = 
     CertPathValidator.getInstance(CertPathValidator.getDefaultType()); 
PKIXCertPathValidatorResult pkixCertPathValidatorResult = 
     (PKIXCertPathValidatorResult) cpv.validate(cp, params); 
+0

爲什麼? JSSE已經爲你做了這一切。 – EJP 2013-06-04 02:07:22

+0

@EJP,請您詳細說明JSSE如何做到這一點。謝謝。 – user674669 2017-08-01 19:31:22

回答

0

如果一個證書(在你的例子cert)已經通過任何的可信CA的信任庫簽署(直接)你在這裏做的檢驗。
此外,您檢查過期,但不執行吊銷檢查。
因此,如果cert尚未由任何受信任的CA簽名,您將得到一個例外。
因此,代碼足以驗證是否cert已經通過任何信任的CA


如果你指的服務器認證已簽署,然後在後的代碼是不夠的。
此代碼僅驗證特定證書是否由受信任的CA簽署。
儘管發送您此證書的「實體」實際上是證書的所有者(即他們擁有與此證書關聯的私鑰),但您沒有任何跡象。
這是SSL認證的一部分,例如,客戶端發送用遠程服務器的公鑰加密的消息ClientKeyExchange,並且確定如果另一方是假的,則不可能解密消息

+0

感謝您的快速響應! 上面的代碼是否足以驗證證書本身?我的意思是,如果我從服務器獲得此證書,並執行上述檢查,我可以安全地假定服務器的證書是有效的,並且服務器是它說的那個人。 謝謝,您的幫助非常感謝。 – user771870 2011-05-26 20:31:46

+0

已更新的答案。希望這可以幫助 – Cratylus 2011-05-26 20:51:01

+0

這確實有幫助。我正在嘗試爲SSH實現服務器身份驗證。因此,一旦我在初始交換期間從服務器獲取證書,我正在嘗試驗證它以確保服務器不是假的,並執行類似於SSL執行相同的驗證過程。 那麼這就意味着SSH會在密鑰交換期間處理服務器認證(交換證書之前),我所要做的就是確保證書是有效的證書?感謝您的迴應和道歉,如果這些問題看起來很愚蠢。我只是開始通過SSH工作流進行挖掘:) – user771870 2011-05-26 21:04:28

6

通常,證書將由中間頒發機構頒發,不是一個「根」權威(這應該在你的信任存儲中)。大多數協議鼓勵發送證書的「連鎖」,而不僅僅是實體的證書。

您應該添加所有的中間證書的,這樣可以形成一個完整的鏈條。

爲了某些證書仍然有效,你不應該禁用吊銷檢查。如果您不想檢索CRL(可能很大),發行人可能會提供OCSP支持。但是,這必須通過設置某些系統屬性在Java運行時啓用。

如果路徑驗證成功返回,你不需要檢查別的。如果證書無效,則會引發異常。

另外,對有效日期的明確檢查是不必要的。這發生在驗證過程中(使用當前時間,除非您通過PKIXParameters指定時間)。


對於更廣泛驗證的討論,包括示例代碼,see a previous answer of mine.

+0

感謝您的回覆! 您的意思是我必須將所有中間證書添加到證書列表(mylist.add(cert);),然後使用CertPath創建一個鏈?謝謝! – user771870 2011-05-26 20:48:33

+0

是的,沒錯。 – erickson 2011-05-26 20:52:34

+0

感謝您的迴應! – user771870 2011-05-26 21:04:45

2

如果你喜歡默認的信任設置(因爲它們將被用於默認SSLContext),你可以建立一個X509TrustManager獨立於SSL/TLS,並使用是否獨立驗證您的證書。

它應該是這樣的:

TrustManagerFactory trustManagerFactory = 
    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 
trustManagerFactory.init((KeyStore)null); 
// you could use a non-default KeyStore as your truststore too, instead of null. 

for (TrustManager trustManager: trustManagerFactory.getTrustManagers()) { 
    if (trustManager instanceof X509TrustManager) { 
     X509TrustManager x509TrustManager = (X509TrustManager)trustManager; 
     x509TrustManager.checkServerTrusted(...); 
    } 
} 

(您也應該檢查服務器的標識和證書的比賽,看到RFC 6125 (Representation and Verification of Domain-Based Application Service Identity within Internet Public Key Infrastructure Using X.509 (PKIX) Certificates in the Context of Transport Layer Security (TLS))。)

+1

呃,'...'是怎麼回事? – 2016-05-11 22:19:41

+0

@PaulDraper第一個參數是X509Certificate的數組,第二個參數是密鑰交換算法(例如「RSA」),另請參見X509TrustManager的Javadoc https://docs.oracle.com/javase/7/docs/api/javax /net/ssl/X509TrustManager.html – 2017-07-28 14:07:29

+1

請注意,如果TrustManagerFactory沒有trustManager從而接受證書,則此代碼不會引發異常。我瞥了一眼TrustManagerFactory的Javadoc,我相信這可能會發生,如果你的默認密鑰庫不包含CA的X509證書。爲了安全起見,我會更改代碼,以便在for循環找不到X509TrustManager時拋出異常。 – 2017-07-28 14:18:25