Che*_*esy 5 delphi ssl openssl certificate indy
我正在使用Indy TIdHTTP(随XE2一起提供)和OpenSSL库DLL V1.0.1m在通过HTTPS连接时验证证书.我已经为组件的OnVerifyPeer事件实现了一个事件处理程序TIdSSLIOHandlerSocketOpenSSL.
function TForm1.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509;
AOk: Boolean; ADepth, AError: Integer): Boolean;
begin
(...)
end;
Run Code Online (Sandbox Code Playgroud)
根据RFC 2818第3.1章,如果客户端可以使用主机名,客户端必须根据服务器证书消息中提供的服务器身份进行检查,以防止中间人攻击.
现在我有一个问题是验证服务器证书的主机名:
虽然服务器证书(*.google.com)中"主题"字段的"公用名"(CN)字段中存在通配符,但Certificate.Subject.OneLine该OnVerifyPeer事件的参数将返回没有任何通配符的CN(即google.com而不是*.google .COM).
如RFC 2818第3.1章所述.通配符*用于匹配任何单个域名组件或组件片段.
任何人都可以确认Indy或OpenSSL库删除了通配符,尽管有必要验证主机名吗?
有没有人想在这些情况下验证主机名?
任何帮助是极大的赞赏.谢谢阅读.
不幸的是,由于内部规范,我必须坚持使用 XE2-Indy 和 OpenSSL V1.0.1m。
为了根据主题 CN 和主题备用名称验证主机名,我执行了以下操作(使用cURL 的实现方法):
1. 在应用程序启动时,我尝试一次扩展对 Indy 加密库中方法的访问。
function ExtendIndyCryptoLibrary(): Boolean;
var
hIdCrypto: HMODULE;
begin
Result := False;
// Try to get handle to Indy used crypto library
if not IdSSLOpenSSL.LoadOpenSSLLibrary() then
Exit;
hIdCrypto := IdSSLOpenSSLHeaders.GetCryptLibHandle();
if hIdCrypto = 0 then
Exit();
// Try to get exported methods that are needed additionally
@X509_get_ext_d2i := GetProcAddress(hIdCrypto, 'X509_get_ext_d2i');
Result := Assigned(X509_get_ext_d2i);
end;
Run Code Online (Sandbox Code Playgroud)
2.以下课程帮助我访问和验证SAN和CN。
type
THostnameValidationResult = (hvrMatchNotFound, hvrNoSANPresent, hvrMatchFound);
var
X509_get_ext_d2i: function(a: PX509; nid: TIdC_INT; var pcrit: PIdC_INT; var pidx: PIdC_INT): PSTACK_OF_GENERAL_NAME; cdecl = nil;
type
TIdX509Access = class(TIdX509)
protected
function Hostmatch(Hostname, Pattern: String): Boolean;
function MatchesSAN(Hostname: String): THostnameValidationResult;
function MatchesCN(Certificate: TIdX509; Hostname: String): THostnameValidationResult;
public
function ValidateHostname(Certificate: TIdX509; Hostname: String): THostnameValidationResult;
end;
implementation
{ TIdX509Access }
function TIdX509Access.Hostmatch(Hostname, Pattern: String): Boolean;
begin
// Match hostname against pattern using RFC, CA/Browser Forum, ...
// (...)
end;
function TIdX509Access.MatchesSAN(Hostname: String): THostnameValidationResult;
var
pcrit, pidx: PIdC_INT;
psan_names: PSTACK_OF_GENERAL_NAME;
san_names_nb: Integer;
pcurrent_name: PGENERAL_NAME;
i: Integer;
DnsName: String;
begin
Result := hvrMatchNotFound;
// Try to extract the names within the SAN extension from the certificate
pcrit := nil;
pidx := nil;
psan_names := X509_get_ext_d2i(FX509, NID_subject_alt_name, pcrit, pidx);
// Check if SAN is present
if psan_names <> nil then
begin
san_names_nb := sk_num(PSTACK(psan_names));
// Check each name within the extension
for i := 0 to san_names_nb-1 do
begin
pcurrent_name := PGENERAL_NAME( sk_value(PSTACK(psan_names), i) );
if pcurrent_name._type = GEN_DNS then
begin
// Current name is a DNS name, let's check it
DnsName := String(pcurrent_name.d.dNSName.data);
// Compare expected hostname with the DNS name
if Hostmatch(Hostname, DnsName) then
begin
Result := hvrMatchFound;
Break;
end;
end;
end;
end
else
Result := hvrNoSANPresent;
// Clean up
sk_free(PSTACK(psan_names));
end;
function TIdX509Access.MatchesCN(Certificate: TIdX509;
Hostname: String): THostnameValidationResult;
var
TempList: TStringList;
Cn: String;
begin
Result := hvrMatchNotFound;
// Extract CN from Subject
TempList := TStringList.Create();
TempList.Delimiter := '/';
TempList.DelimitedText := Certificate.Subject.OneLine;
Cn := Trim(TempList.Values['CN']);
FreeAndNil(TempList);
// Compare expected hostname with the CN
if Hostmatch(Hostname, Cn) then
Result := hvrMatchFound;
end;
function TIdX509Access.ValidateHostname(Certificate: TIdX509;
Hostname: String): THostnameValidationResult;
begin
// First try the Subject Alternative Names extension
Result := MatchesSAN(Hostname);
if Result = hvrNoSANPresent then
begin
// Extension was not found: try the Common Name
Result := MatchesCN(Certificate, Hostname);
end;
end;
Run Code Online (Sandbox Code Playgroud)
3、在TIdSSLIOHandlerSocketOpenSSL组件的OnVerifyPeer事件中,可以使用该类,如下:
function TForm1.IdSSLIOHandlerSocketOpenSSL1VerifyPeer(Certificate: TIdX509;
AOk: Boolean; ADepth, AError: Integer): Boolean;
begin
// (...)
Result := TIdX509Access(Certificate).ValidateHostname(Certificate, IdHttp1.URL.Host) = hvrMatchFound;
// (...)
end;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1422 次 |
| 最近记录: |