I'm writing some WinHttp code in C. I'm sending requests over SSL, and in order to handle SSL errors, I'm registering a WINHTTP_STATUS_CALLBACK function, via a call to WinHttpSetStatusCallback with dwNotificationFlags set to WINHTTP_CALLBACK_STATUS_SECURE_FAILURE.
The documentation for WINHTTP_STATUS_CALLBACK says, that when the callback is invoked with dwInternetStatus
= WINHTTP_CALLBACK_STATUS_SECURE_FAILURE, it indicates that
One or more errors were encountered while retrieving a Secure Sockets Layer (SSL) certificate from the server. The lpvStatusInformation parameter contains a flag. For more information, see the description for lpvStatusInformation.
Now, the lpvStatusInformation
parameter is typed as a LPVOID. But I take it from that statement in the documentation that it isn't treated as a pointer in the case of WINHTTP_CALLBACK_STATUS_SECURE_FAILURE.
The doc for lpvStatusInformation
says:
If the dwInternetStatus parameter is WINHTTP_CALLBACK_STATUS_SECURE_FAILURE, this parameter can be one of the following values.
...And those values are one of these hex values: 1,2,4,8,10,20,40. (See WinHttp.h)
This seems pretty clear to me. I shouldn't de-reference the pointer to get the value. the lpvStatusInformation
holds the hex value, not a pointer.
Am I interpreting this correctly?
I've written my code that way, and it has worked in the past. I think! However now I am getting a lpvStatusInformation
of 0x0104f288. That is nothing like any of those hex values. It's also not possible to create that value through OR'ing the possible values (though the doc says nothing about multiple status items in the same DWORD). It sure looks like a pointer to me. And when I de-ref the pointer, I get 0x8, which corresponds to WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA
, which at least makes sense.
The question is, Should I de-reference that pointer, or not?
Here's the callback code:
void CALLBACK Iirf_WinHttpSslStatusCallback( HINTERNET hInternet,
DWORD_PTR context,
DWORD code,
void * pInfo,
DWORD infoLength)
{
if (code == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE) {
ConfigInfo * cfg = (ConfigInfo *) context; // app-specific structure
DWORD details = (DWORD) pInfo; // do not de-reference??
CHAR buffer[32];
CHAR * statusDescription = NULL;
switch (details) {
case WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED:
statusDescription = "CERT_REV_FAILED";
break;
case WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT:
statusDescription = "INVALID_CERT";
break;
case WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED:
statusDescription = "CERT_REVOKED";
break;
case WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA:
statusDescription = "INVALID_CA";
break;
case WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID:
statusDescription = "CERT_CN_INVALID";
break;
case WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID:
statusDescription = "CERT_DATE_INVALID";
break;
case WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR:
statusDescription = "SECURITY_CHANNEL_ERROR";
break;
default:
statusDescription = buffer;
sprintf_s(buffer, 32, "stat(0x%08X) len(%d)",
details, infoLength);
break;
}
LogMessage(cfg, 1, "SslStatusCallback: %s", statusDescription);
}
}
The docs are a little misleading. lpvStatusInformation
is a pointer to the flags value. We've been casting it to a DWORD* and dereferencing it, and the values we get match up with the flag values in the docs.