WinInet 能否返回正在使用的 TLS

Posted

技术标签:

【中文标题】WinInet 能否返回正在使用的 TLS【英文标题】:Can WinInet return which TLS is being used 【发布时间】:2016-05-17 11:52:59 【问题描述】:

我们使用 WinInet 和 Delphi 使用 HTTPS 进行通信。 WinInet 中是否有一个函数会返回给我会话中已协商的协议,即 TLS1.1、TLS 1.2 等。

【问题讨论】:

【参考方案1】:

很遗憾,显然不是(在 Windows 7 和 Internet Explorer 11 上测试)。

InternetQueryOptionINTERNET_OPTION_SECURITY_CERTIFICATEINTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT 结合使用是我在WinInet 文档中能找到的最接近的(参见INTERNET_CERTIFICATE_INFO 中的lpszProtocolName),但它们返回空字符串(参见下面的输出)。

lpszProtocolName

Pointer to a buffer that contains the name of the protocol used to provide the
secure connection. The application must call LocalFree to release the resources
allocated for this parameter.

我找不到任何其他暗示 Wininet 公开底层 SChannel 连接属性的内容。

program test_wininet;

$APPTYPE CONSOLE

$R *.res

uses
  System.SysUtils,
  Winapi.Windows,
  Winapi.Wininet;

type
  // fixed declaration
  PInternetCertificateInfo = ^TInternetCertificateInfo;
  TInternetCertificateInfo = record
    ftExpiry: TFileTime;
    ftStart: TFileTime;
    lpszSubjectInfo: PAnsiChar;
    lpszIssuerInfo: PAnsiChar;
    lpszProtocolName: PAnsiChar;
    lpszSignatureAlgName: PAnsiChar;
    lpszEncryptionAlgName: PAnsiChar;
    dwKeySize: DWORD;
  end;

procedure FreeCertificateInfo(var Info: TInternetCertificateInfo);
begin
  if Assigned(Info.lpszSubjectInfo) then
    LocalFree(NativeUInt(Info.lpszSubjectInfo));
  if Assigned(Info.lpszIssuerInfo) then
    LocalFree(NativeUInt(Info.lpszIssuerInfo));
  if Assigned(Info.lpszProtocolName) then
    LocalFree(NativeUInt(Info.lpszProtocolName));
  if Assigned(Info.lpszSignatureAlgName) then
    LocalFree(NativeUInt(Info.lpszSignatureAlgName));
  if Assigned(Info.lpszEncryptionAlgName) then
    LocalFree(NativeUInt(Info.lpszEncryptionAlgName));
end;

function GetCertificateInfo(H: HINTERNET): TInternetCertificateInfo;
var
  Size: Cardinal;
begin
  Size := SizeOf(Result);
  FillChar(Result, Size, 0);
  Win32Check(InternetQueryOption(H, INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT, @Result, Size));
end;

function GetCertificateInfoStr(H: HINTERNET): AnsiString;
var
  Buffer: array[0..1024] of AnsiChar;
  BufferSize: Cardinal;
  L: Integer;
begin
  Result := '';
  BufferSize := SizeOf(Buffer);
  FillChar(Buffer, BufferSize, 0);
  Win32Check(InternetQueryOption(H, INTERNET_OPTION_SECURITY_CERTIFICATE, @Buffer[0], BufferSize));
  L := StrLen(PAnsiChar(@Buffer[0]));
  if L > 0 then
    SetString(Result, Buffer, L);
end;

procedure Main;
var
  H, H2: HINTERNET;
  Info: TInternetCertificateInfo;
  SysTime: TSystemTime;
begin
  H := InternetOpen('test', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  try
    H2 := InternetOpenUrl(H, 'https://www.microsoft.com', nil, 0, INTERNET_FLAG_NO_UI or INTERNET_FLAG_SECURE, 0);
    try
      Writeln('InternetQueryOption with INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: ');
      Info := GetCertificateInfo(H2);
      try
        Writeln('Subject:');
        Writeln(Info.lpszSubjectInfo);
        Writeln('Issuer:');
        Writeln(Info.lpszIssuerInfo);
        Writeln(Format('Security Protocol: %s', [Info.lpszProtocolName]));
        Writeln(Format('Signature Type: %s', [Info.lpszSignatureAlgName]));
        Writeln(Format('Encryption Type: %s', [Info.lpszEncryptionAlgName]));
        FileTimeToSystemTime(Info.ftStart, SysTime);
        Writeln(Format('Effective Date: %s', [FormatDateTime('dd/mmm/yy hh:nn:ss', SystemTimeToDateTime(SysTime))]));
        FileTimeToSystemTime(Info.ftExpiry, SysTime);
        Writeln(Format('Expiration Date: %s', [FormatDateTime('dd/mmm/yy hh:nn:ss', SystemTimeToDateTime(SysTime))]));
        Writeln(Format('Key size: %d', [Info.dwKeySize]));
        Writeln;
      finally
        FreeCertificateInfo(Info);
      end;

      Writeln('InternetQueryOption with INTERNET_OPTION_SECURITY_CERTIFICATE:');
      Writeln(GetCertificateInfoStr(H2));
      Writeln;
    finally
      InternetCloseHandle(H2);
    end;
  finally
    InternetCloseHandle(H);
  end;
end;

begin
  try
    Main;
    Readln;
  except
    on E: Exception do
    begin
      ExitCode := 1;
      Writeln(Format('[%s] %s', [E.ClassName, E.Message]));
    end;
  end;
end.

以上代码产生以下输出:

InternetQueryOption with INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT:
Subject:
US
Washington
Private Organization
600413485
US
98052
Washington
Redmond
1 Microsoft Way
Microsoft Corporation
www.microsoft.com
Issuer:
US
Symantec Corporation
Symantec Trust Network
Symantec Class 3 EV SSL CA - G3
Security Protocol:
Signature Type:
Encryption Type:
Effective Date: 24-Mar-16 00:00:00
Expiration Date: 25-Mar-18 23:59:59
Key size: 256

InternetQueryOption with INTERNET_OPTION_SECURITY_CERTIFICATE:
Subject:
US
Washington
Private Organization
600413485
US
98052
Washington
Redmond
1 Microsoft Way
Microsoft Corporation
www.microsoft.com
Issuer:
US
Symantec Corporation
Symantec Trust Network
Symantec Class 3 EV SSL CA - G3
Effective Date: 24-Mar-16 00:00:00
Expiration Date:        25-Mar-18 23:59:59
Security Protocol:      (null)
Signature Type: (null)
Encryption Type:        (null)
Privacy Strength:       High (256 bits)

【讨论】:

以上是关于WinInet 能否返回正在使用的 TLS的主要内容,如果未能解决你的问题,请参考以下文章

尝试使用 wininet 将文件上传到 FTP 时遇到问题 [Id 返回 1 退出状态]

在 MFC 中使用 WinINet 的问题

对于大多数 FTP 函数,IE 11 中的 wininet 随机返回错误 12003

Wininet 给出链接器错误我正在使用 devc++

FtpGetFile WinINet 永远不会返回

如何使用 wininet.dll 对代理进行身份验证?