In an earlier post, I showed you how to select a personal certificate from a user's "My" store. Now you need to know what to do with the certificate. In my case, I need to supply a certificate to a web site that requires personal certificates.
TCP/IP communications are a little tricky, in that you cannot supply the certificate when you make the request. You need to call OpenRequest, and then wait for the INTERNET_STATUS_REQUEST_COMPLETE signal in your Callback routine. You can then check the returned error, looking for ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED in the INTERNET_ASYNC_RESULT struct. When you get the error, you need to use InternetSetOpen on your OpenRequest handle to supply the certificate and then repeat the OpenRequest. It's really pretty simple. It's just that the docs and samples leave out a lot of the error checking an recovery work that you will need to code. It helps to have a server setup with a valid SSL certificate and require personal certificates in order to connect.
case INTERNET_STATUS_REQUEST_COMPLETE:
{
//check for errors
if(ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED == pRes->dwError)
{
// The server requires a certificate
// Save dwError so we can act on it.
cpMainDlg->m_dwError = pRes->dwError;
sMsg.Format("%s: CLIENT_AUTH_CERT_NEEDED (%d)", cpMainDlg->m_szMemo, pRes->dwError);
// Check that we have a certificate pointer,
// otherwise, it's time to fall over dead.
if(cpMainDlg->m_pHSCertContext == NULL)
{
//write the callback information to the buffer
sMsg += _T(" No cert provided by user");
}
else
{
// We have a pointer (there's no guarantee it's valid)
// We have to be careful and check all returns for errors
// as the pointer could point to la-la land if someone in
// a different thread has closed the certificate store.
// Attempt to set the option
if (!::InternetSetOption( cpMainDlg->hRequest,
INTERNET_OPTION_CLIENT_CERT_CONTEXT ,
(LPVOID) cpMainDlg->m_pHSCertContext,
sizeof(CERT_CONTEXT) ))
{
// Display the error.
CString sErrMsg;
cpMainDlg->GetErrorMessage(GetLastError(), &sErrMsg);
sMsg += _T(" ");
sMsg += sErrMsg;
}
}
} // end if (ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED == dwError)
...
}
Diary of a husband, father and programmer.
Sunday, April 6, 2008
Supplying a Personal Certificate on a WinInet handle
Subscribe to:
Post Comments (Atom)

0 comments:
Post a Comment