简体   繁体   中英

How to clear WinInet SSL state programmatically (is there a Windows API call)?

I need to mimic the same behavior as the "Clear SSL State" button in the "Internet Options" dialog ("Contents" tab) using an API function in Delphi.

My intention is to use this with WinInet to make subsequent independent SSL connections. Without this, two WinInet connections share the same SSL state, preventing me from correcting a wrong SSL certificate password, for example.

Without clearing the SSL state between two connection attempts, the first one returns "wrong password", then I correct the password and try again, but the second attempt returns "Secure Channel Support Error".

The "Clear SSL State" button simply executes the following undocumented command-line command:

"C:\Windows\system32\rundll32.exe" "C:\Windows\system32\WININET.dll",DispatchAPICall 3

Use CreateProcess() to execute the same command in your Delphi code.

You're right: if rundll can do it, you can do it programmatically:

//somewhere in an interface section:
procedure DispatchAPICall(h: HWND; hinst: HINST; lpszCmdLine: PAnsiChar; nCmdShow: integer); stdcall;

//somewhere in the implementation section:
function DispatchAPICall; external 'wininet.dll';

//somewhere in your code:
DispatchAPICall(GetDesktopWindow(), GetModuleHandle('wininet.dll'), '3', SW_NORMAL);

Finally! I achieved!

I used the excellent API Monitor , to monitor the whole Internet Options dialog and I managed to discover what the "Clear SSL State" button do. It executes only two API calls SslEmptyCache and IncrementUrlCacheHeaderData , in that order.

API监视器,在“清除SSL状态”按钮下方显示两个API调用

After discover this I was able to implement the following code, executed BEFORE my request:

type
    TSslEmptyCache = function (pszTargetName: LPSTR; dwFlags: DWORD): BOOL; WINAPI;
    TIncrementUrlCacheHeaderData = function (nIdx: DWORD; lpdwData: LPDWORD): BOOL; WINAPI;

var
    SchannelDLLHandle, WinInetHandle: HMODULE;
    SslEmptyCache: TSslEmptyCache;
    IncrementUrlCacheHeaderData: TIncrementUrlCacheHeaderData;

SchannelDLLHandle := LoadLibrary('schannel.dll');
WinInetHandle := LoadLibrary('wininet.dll');

if (SchannelDLLHandle > 0) and (WinInetHandle > 0) then
    try
        SslEmptyCache := GetProcAddress(SchannelDLLHandle,'SslEmptyCacheW');
        IncrementUrlCacheHeaderData := GetProcAddress(WinInetHandle,'IncrementUrlCacheHeaderData');

        if Assigned(SslEmptyCache) and Assigned(IncrementUrlCacheHeaderData) then
        begin
            SslEmptyCache(nil,0);
            IncrementUrlCacheHeaderData(14,@buffer);
        end;
    finally
        FreeLibrary(SchannelDLLHandle);
        FreeLibrary(WinInetHandle);
    end;

Of course, this is a pseudo code, but It is complete ;)

The SslEmptyCache function has documentation at MSDN, but the IncrementUrlCacheHeaderData function not, so I had to research a little more to discover that the second paramenter must be a PDWORD, wich receives, when the function returns, an increment number, wich is persistent between calls at different processes (different applications).

For more information you can access this article where I explain all my saga. The text is in portuguese, but the site have a good translatin tool.

I wish to thank you all for the help

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM