Wininet SSL client authenticates oddity

I have a crawler that switches to Wininet for HTTP.

This usually works well, but for the website I get the error ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED

Code example:

vErrorNone := HttpSendRequest(HttpOpen_Request, nil, 0, nil, 0); if vErrorNone = False then begin vErrorID := GetLastError; if (vErrorID = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) then begin // this error end ; end ; 

Then I tried an experiment with:

  TmpFakePointer := nil; vErrorNone := InternetErrorDlg( GetDesktopWindow() , HttpOpen_Request , ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED , 0 or FLAGS_ERROR_UI_FILTER_FOR_ERRORS or FLAGS_ERROR_UI_FLAGS_GENERATE_DATA or FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS , TmpFakePointer ) = ERROR_SUCCESS ; if vErrorNone then begin vErrorNone := HttpSendRequest(HttpOpen_Request, nil, 0, nil, 0); end ; 

However, two things are odd here:

  • 1) The dialog box does not appear
  • 2) It works
  • 2.1) Error in the second HttpSendRequest
  • 2.2) Valid data

He finds the combination above very strange and contradicts the documentation. Since the user did not select any certificate, why does this work? If Wininet returns to an anonymous client authentication certificate when the dialog cannot be shown (I assume I gave it the wrong handle to display the dialog? Although these are errors if I explicitly give it the wrong handle) is there a way to select this directly without calling InternetErrorDlg?

+1
source share
1 answer

Well

There are two things you can do:

1: Show the certificate error to the user and allow him to decide whether or not to continue.
2: Ignore any certificate errors you receive.

I will show you how to make the second option:

When you get ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED or any other certificate error, you need to call InternetSetOptions to tell wininet that it should ignore the error and continue. After that you need to resend the request.

 function SetToIgnoreCerticateErrors(var aErrorMsg: string): Boolean; var vDWFlags: DWord; vDWFlagsLen: DWord; begin Result := False; try vDWFlagsLen := SizeOf(vDWFlags); if not InternetQueryOptionA(oRequestHandle, INTERNET_OPTION_SECURITY_FLAGS, @vDWFlags, vDWFlagsLen) then begin aErrorMsg := 'Internal error in SetToIgnoreCerticateErrors when trying to get wininet flags.' + GetWininetError; Exit; end; vDWFlags := vDWFlags or SECURITY_FLAG_IGNORE_UNKNOWN_CA or SECURITY_FLAG_IGNORE_CERT_DATE_INVALID or SECURITY_FLAG_IGNORE_CERT_CN_INVALID or SECURITY_FLAG_IGNORE_REVOCATION; if not InternetSetOptionA(oRequestHandle, INTERNET_OPTION_SECURITY_FLAGS, @vDWFlags, vDWFlagsLen) then begin aErrorMsg := 'Internal error in SetToIgnoreCerticateErrors when trying to set wininet INTERNET_OPTION_SECURITY_FLAGS flag .' + GetWininetError; Exit; end; Result := True; except on E: Exception do begin aErrorMsg := 'Unknown error in SetToIgnoreCerticateErrors.' + E.Message; end; end; end; vErrorNone := HttpSendRequest(HttpOpen_Request, nil, 0, nil, 0); if vErrorNone = False then begin vErrorID := GetLastError; if (vErrorID = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED) then begin //call SetToIgnoreCerticateErrors //re-send the request end end end; 

I extracted SetToIgnoreCerticateErrors from my wininet API and cannot compile it accurately.

These are the following steps:

1 - Get an error
2 - Check if the error is a certificate error
3 - If this is a certificate error, they call InternetSetOption, just like me.
4 - Resubmit the request.

I don’t know how to implement the first option "Show the certificate error to the user and let him decide whether or not to continue." because I never had to do this.

Also check this out: How to handle a certificate authority error using WinInet

Hope this helps you.

+2
source

Source: https://habr.com/ru/post/1276048/


All Articles