If you are developing a client to a server service that communicates over SSL such as a Web Service then it is your job to ensure your server is the "real deal" and not some rouge server or man-in-the-middle. How do you do that? Validate the server's certificate. Make sure the certificate is for the domain you are accessing, make sure the certificate chain is valid, and make sure the certificate is signed by a trusted certificate authority (CA). Sound like a pain? Well it isn't. You get a lot for a little with the right API calls.
WinHttpReceiveResponse in C++ will return FALSE if the certificate has one of the following errors:
WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED
Certification
revocation checking has been enabled, but the revocation check failed to verify
whether a certificate has been revoked. The server used to check for revocation
might be unreachable.
WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT
SSL certificate is invalid.
WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED
SSL certificate was revoked.
WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA
The function is unfamiliar with the Certificate Authority that generated the server's certificate.
WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID
SSL certificate common name (host name field) is incorrect, for example, if you entered www.microsoft.com and the common name on the certificate says www.msn.com.
WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID
SSL certificate date that was received from the server is bad. The certificate is expired.
WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR
The application experienced an internal error loading the SSL libraries.
However, WinHttpReceiveResponse does not return these errors directly as a call to GetLastError() will only return ERROR_WINHTTP_SECURE_FAILURE if there is a problem with the server's certificate. You must use the CallBack WINHTTP_STATUS_CALLBACK to access the specific errors listed above.
public WINHTTP_STATUS_CALLBACK myOwnAsyncCallback( __in HINTERNET hInternet,
__in DWORD_PTR dwContext,
__in DWORD dwInternetStatus,
__in LPVOID lpvStatusInformation,
__in DWORD dwStatusInformationLength)
{
if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_SECURE_FAILURE)
// We have a certificate issue but which one? Take action before each break. This function must be thread safe and reentrant.
switch(*(DWORD*)lpvStatusInformation)
{
case WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED:
break;
case WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT:
break;
case WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED:
break;
case WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA:
break;
case WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID:
break;
case WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID:
break;
case WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR:
break;
}
}
HINTERNET hSession = WinHttpOpen(L"A WinHTTP Example Program/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
WINHTTP_STATUS_CALLBACK isCallback = WinHttpSetStatusCallback( hSession, WINHTTP_STATUS_CALLBACK)myOwnAsyncCallback,WINHTTP_CALLBACK_FLAG_SECURE_FAILURE,
NULL);
//The rest of your code including call WinHttpReceiveResponse
For more information see
http://msdn.microsoft.com/en-us/library/cc185684(VS.85).aspx
http://msdn.microsoft.com/en-us/library/aa383917(VS.85).aspx
http://msdn.microsoft.com/en-us/library/aa384266(VS.85).aspx
http://msdn.microsoft.com/en-us/library/aa384115(VS.85).aspx