2012-11-27 241 views
5

我已經瀏覽了因特網,但未找到有關如何通過使用TIdHTTP通過HTTPS進行連接時驗證證書的解決方案或方法。Delphi Indy驗證服務器證書SSL

我連接了一個IdSSLIOHandlerSocketOpenSSL組件作爲IOHandler,設置SSLModes等,但是當我瀏覽到https://s3.amazonaws.com時,它無法驗證證書。

OpenSSL的(印)給出

「使用SSL連接SSL3_GET_SERVER_CERTIFICATE錯誤:證書驗證失敗」

OpenSSL庫已成功加載(檢查與WhichFailedToLoad)。該OnStatusInfo事​​件寫入以下內容:

SSL狀態: 「前/連接初始化」

SSL狀態: 「前/連接初始化」

SSL狀態 「的SSLv2/v3的寫客戶端問候A」

SSL狀態: 「讀SSLv3的服務器問候A」

SSL狀態: 「SSLv3的讀取服務器證書B」

SSL小號tatus: 「SSLv3的讀取服務器證書B」

SSL狀態: 「SSLv3的讀取服務器證書B」

而且OnVerifyPeer,AOK =假。

我怎樣才能得到它的正確驗證。這是怎麼回事?

感謝您的閱讀, 阿德里安

回答

7

你要實現你的TIdSSLIOHandlerSocketOpenSSL組件的OnVerifyPeer事件的事件處理程序。

從IdSSLOpenSSL.pas:

請注意,你真的應該始終 實施OnVerifyPeer,對等的,否則證書你 連接不檢查,以確保它是有效的。

如果你只是要考慮有效的圖書館認爲也適用同樣的證書,你就必須實現它是這樣的:

function TForm1.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509; 
    AOk: Boolean; ADepth, AError: Integer): Boolean; 
begin 
    Result := AOk; 
end; 

至於證書和合格的有效性印首先檢查你是否確定或不在AOk參數中。最後一句話是在你的代碼中,因爲你可能想要讓某些小驗證錯誤像過時一樣,或甚至詢問用戶證書是否被接受,以防出現任何錯誤(小或不)。

要理解爲什麼它以這種方式工作,您可能還需要閱讀IdSSLOpenSSL頂部的所有註釋。PAS文件:

{

重要信息有關OnVerifyPeer: 版本2005年2月的1.39故意打破了OnVerifyPeer接口, 它(明顯?)只會影響實現該回調 程序作爲SSL的一部分談判。請注意,你確實應該始終使用 實現OnVerifyPeer,否則不會檢查連接到的對等證書以確保其有效。

在此之前,如果SSL庫檢測與證書 問題或深度不足(即VerifyCallback 「確定」參數爲0/FALSE),那麼無論你OnVerifyPeer是否返回真 或錯誤的是,SSL連接將故意失敗。

這在創建一個問題,即使在僅僅存在一個很小的 問題與該鏈中的證書之一,其中用戶可以 已經(OnVerifyPeer一種用於在證書鏈中的每個證書稱爲 一次)很高興接受,SSL協商將失敗。但是, 更改代碼以允許SSL連接,當用戶爲OnVerifyPeer返回True 意味着依賴於 自動拒絕無效證書的現有代碼將接受 無效證書,這將是不可接受的安全性 更改。

因此,OnVerifyPeer已更改爲通過添加AOk參數故意破壞現有代碼 。爲了保留以前的功能,您的OnVerifyPeer事件應該執行「Result:= AOk;」。如果您希望考慮 接受SSL庫認爲無效的證書,然後在您的OnVerifyPeer中使用 ,請確保您確信證書 確實有效,然後將Result設置爲True。實際上,除了檢查AOk的 之外,還應該執行代碼,以確保只有 接受有效的證書(至少從您的角度來看)。

夏蘭Costelloe,ccostelloe [_a_t_] flogas.ie

}

{

RLebeau 1/12/2011:斷裂OnVerifyPeer事件,這一次增加一個額外的 AERROR參數(補丁提供「jvlad」,[email protected])。這 幫助用戶代碼區分自簽名和無效 證書。

}

1

如果你喜歡SSL3_GET_SERVER_CERTIFICATE:certificate verify failed錯誤,那麼請繼續閱讀:

似乎在印第安納波利斯10,如果你設置的0一個VerifyDepth,該0實際上意味着all。不幸的是,印似乎只瞭解根CA,所以爲了驗證僅根部,請嘗試以下OnVerify方法:

function TForm1.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509; 
    AOk: Boolean; ADepth, AError: Integer): Boolean; 
begin 
    if ADepth = 0 then 
    begin 
    Result := AOk; 
    end 
    else 
    begin 
    Result := True; 
    end; 
end; 
+1

這是錯誤的。 Indy默認不知道根證書。這使你容易受到MitM攻擊。您至少需要設置'VerifyMode','VerifyDepth'和'RootCertFile'來完成安全連接。之後,您可以將'AOk'返回任意深度,因爲OpenSSL爲您做了正確的事情。 – TobiX

1

我知道這是一個古老的職位,但它是所有我能找到解決這個問題。所以我想給Marcus的答案加上同樣的問題: 當OpenSSL在PC上找不到根證書時,AError將返回#19(X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN),並且根證書的AOK將爲false。當您手動從文件加載根證書,AOK應該總是返回真值(和你有某種取得證書釘扎過):

FSSLIOHandlerSocketOpenSSL.SSLOptions.RootCertFile:=「MyRoot.cer」;