Java中的证书透明度验证
因此,我有一個幼稚的想法,即除了證書有效性檢查(在Java中)之外,將證書透明性驗證作為每個請求的一部分也很容易。
犧牲了整個周末的一半時間,我可以證明這并不是一件小事。 但是, 證書透明性是什么? 簡而言之–它是世界上所有TLS證書的公開日志(即使SSL已過時,仍稱為SSL證書)。 您可以檢查該日志中是否發布了日志,如果沒有發布,則有些可疑,因為CA必須將其所有已頒發的證書推送到日志中。 還有其他用例,例如為您的域注冊新證書的通知,以檢測可能被劫持的DNS管理面板或CA( Facebook免費提供了這樣的工具 )。
我想做的是前者–使來自Java應用程序的每個請求在證書透明性日志中驗證對方的證書。 似乎這不是開箱即用的(如果可以,我找不到它。 在一次有關JEP 244的討論中 ,似乎討論了與證書透明性相關的TLS擴展,但是我找不到它是否是最終支持)。
我開始認為您可以簡單地獲取證書,并通過證書的指紋檢查其是否包含在日志中。 這太容易了–允許通過哈希檢查的日志,但是它不是證書的指紋,而是簽名的證書時間戳–由日志在包含之前發布的簽名。 引用CT RFC :
SCT(簽名證書時間戳記)是日志將證書合并到Merkle樹中的承諾
merkle樹是一種非常酷的數據結構,它通過提供比整個日志短得多的“包含證明”,使外部參與者確信該日志中包含某些內容(從而節省了大量帶寬)。 實際上,merkle樹的涼爽是為什么我首先對證書透明性感興趣的原因(因為我們在我當前的面向日志的公司中使用merkle樹)
因此,為了檢查是否包含 ,您必須以某種方式獲取SCT。 最初,我認為使用Certificate Transparency Java庫是可能的,但事實并非如此。 擁有它之后,您可以使用客戶端在日志中對其進行檢查,但是獲取它比較困難。 (注意:對于服務器端驗證,可以通過HTTP查詢日志; 但是瀏覽器可以使用DNS查詢來保留用戶的匿名性)。
可以通過三種方式來獲取SCT,具體取決于服務器和/或日志和/或CA選擇支持的方式:SCT可以包含在證書中,也可以在TLS握手期間作為TLS擴展提供。 ,也可以在握手期間再次包含在TLS裝訂響應中。 不幸的是,我檢查的少數證書中沒有存儲SCT,因此我必須進入較低級別并調試TLS握手。
我啟用了TLS hadnshake 冗長的輸出 ,瞧瞧-那里什么都沒有。 Google確實將SCT作為TLS擴展包括在內(根據Qualys),但是Java輸出未對此進行任何說明。
幸運的是(?)Google發布了Conscrypt –一種基于Java安全提供程序的Google的OpenSSL分支。 事情開始變得一團糟……但我還是去了,包括Conscrypt并將其注冊為安全提供程序。 我必須使用Conscrypt TrustManager進行連接(已使用JDK中的所有受信任證書初始化):
KeyStore trustStore = KeyStore.getInstance("JKS"); trustStore.load(new FileInputStream(System.getenv("JAVA_HOME") + "/lib/security/cacerts"), "changeit".toCharArray()); ctx.init(null,new TrustManager[] {new TrustManagerImpl(trustStore, null, null, null, logStore, null, new StrictCTPolicy())}, new SecureRandom());URL url = new URL("https://google.com"); HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); conn.setSSLSocketFactory(ctx.getSocketFactory()); conn.connect(); conn.getInputStream(); conn.disconnect();當然,它最初并不起作用,因為Conscrypt不提供一些所需的核心接口(CTLogStore和CTPolicy類)的實現。 實際上,CTLogStore是保存有關所有已知日志信息的重要位(我仍然覺得將“日志提供程序”簡稱為“ log”很奇怪,但這是公認的術語)。 有一個以JSON形式存在的已知日志列表 ,這很酷,只是花了我一段時間(在外部幫助下)才能弄清楚這些公鑰的確切含義。 它們是什么-RSA,ECC? 它們如何編碼? 您在RFC和文檔中都找不到。 在這里可以看到它是“ SubjectPublicKeyInfo ASN.1結構的DER編碼”。 啊。
BouncyCastle進行營救。 我與BouncyCastle的戀愛關系深深。 我討厭它的直觀性和API的復雜性,但是我喜歡它(幾乎)具有您可能需要的所有與密碼相關的東西。 在花費一些時間試圖弄清楚如何將公共密鑰轉換為PublicKey對象之后,我發現使用PublicKeyFactory.createKey(Base64.getDecoder().decode(base64Key)); 為您提供使用任何算法的參數-它可以返回橢圓曲線關鍵參數或RSA關鍵參數。 您只需要將它們包裝在另一個類中,然后將它們傳遞到另一個工廠(典型的BouncyCastle),就可以擁有公共密鑰。
當然,現在Google的Conscrypt不再起作用,因為在轉換之后,publicKey的編碼版本與原始字節不相同,因此日志ID計算錯誤。 但是我經過一番思考后解決了這個問題,最后,它奏效了–查詢了證書透明性日志,并證明該證書有效并且正確地包含在日志中。
整個代碼可以在這里找到 。 是的,它使用了幾個安全提供程序,一些奇怪的BouncyCastle API和Google提供程序中缺少的一些簡單實現。 可能會緩存已知的證書,以便不執行對日志的重復調用,但這超出了我的實驗范圍。
證書透明性似乎是當今互聯網的核心內容。 但是,它是如此晦澀且難以使用。
為什么列表中的公鑰類型沒有記錄(它們至少應在公鑰旁邊放置一個OID,因為事實證明,并非所有日志都使用橢圓曲線-其中兩個使用RSA)。 也許有一個很好的解釋,但是為什么在日志中包括SCT而不是證書的指紋? 為什么不然后要求將SCT包括在證書中,而無需將服務器和客戶端進行其他配置,而不是將其包括在TLS握手中,而TLS握手則需要升級呢?
據我所知,由于數以百萬計的讓我們對證書進行加密,因此證書透明性計劃現在面臨可伸縮性問題。 每個日志(提供者)都應將整個日志提供給所有請求它的人。 解決這不是一件容易的事,并且朝著這個方向努力了,但目前尚無明顯的解決方案。
最后,如果Java沒有簡便的方法,并且所有密碼庫都可用,我想知道其他語言的情況如何。 他們支持證書透明性還是需要升級?
也許我們都很好,因為瀏覽器支持它,但是瀏覽器并不是發出HTTP請求的唯一對象。 API調用是一個巨大的用例,如果可以對其進行劫持,則所造成的損害甚至可能比被騙的單個用戶還要大。 因此,我認為應該在兩件事上付出更多的努力:
1.改進RFC和2.改進編程生態系統。 我希望這篇文章至少能有所貢獻。
翻譯自: https://www.javacodegeeks.com/2019/01/certificate-transparency-verification-java.html
總結
以上是生活随笔為你收集整理的Java中的证书透明度验证的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 咪西是什么意思 咪西的意思
- 下一篇: 不接受平邮是什么意思 不接受平邮解释