Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3203 lines
70 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 2001
//
// File: url.cpp
//
//--------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#define __dwFILE__ __dwFILE_CERTUTIL_URL_CPP__
#define MAX_MSG_LEN 256
#define MAX_URL_LEN 1024
#define LIST_STATUS_SUBITEM 1
#define LIST_TYPE_SUBITEM 2
#define LIST_URL_SUBITEM 3
#define LIST_TIME_SUBITEM 4
#define DEF_TIMEOUT 15
#define wszCERTIFICATE L"Certificate"
#define wszBASE_CRL_ITEM_TYPE L"Base CRL"
#define wszDELTA_CRL_ITEM_TYPE L"Delta CRL"
#define OBJECT_TYPE_CERT 0x00000001
#define OBJECT_TYPE_CRL 0x00000002
#define OBJECT_TYPE_MSG 0x00000003
#define MAX_ULTOW_BUFFER_SIZE 40
typedef struct _tagOBJECT_INFO
{
DWORD dwType;
union
{
CERT_CONTEXT const *pCert;
CRL_CONTEXT const *pCRL;
WCHAR wszErrInfo[MAX_MSG_LEN];
};
} OBJECT_INFO;
CERT_CONTEXT const *g_pCert;
WCHAR *g_pwszFile = NULL;
CRL_CONTEXT const *g_pCRL;
DWORD g_dwTimeout;
WCHAR const *g_pwszUrl;
DWORD g_dwRetrievalFlags;
static int s_majorURL = 0;
static int s_levelURL = 1;
class CUrlFetch {
public:
virtual ~CUrlFetch() = 0;
virtual int AddListItem(
IN WCHAR const *pwszURL,
IN WCHAR const *pwszStatus,
IN WCHAR const *pwszType,
IN DWORD dwInterval) = 0;
virtual HRESULT UpdateListItemStatus(
IN int nItem,
IN WCHAR const *pwszStatus) = 0;
virtual HRESULT UpdateListItemParam(
IN int nItem,
IN LPARAM lParam) = 0;
virtual HRESULT UpdateListItemTime(
IN int nItem,
IN DWORD dwInterval) = 0;
virtual HRESULT UpdateListItem(
IN int nItem,
IN WCHAR const *pwszURL,
IN WCHAR const *pwszStatus,
IN WCHAR const *pwszType,
IN DWORD dwInterval) = 0;
virtual int DisplayMessageBox(
IN HWND hWnd,
IN LPCWSTR lpText,
IN LPCWSTR lpCaption,
IN UINT uType) = 0;
virtual HCURSOR SetCursor(
IN HCURSOR hCursor) = 0;
virtual VOID Display() = 0;
};
CUrlFetch::~CUrlFetch() {}
class CUrlFetchDialog : CUrlFetch {
public:
CUrlFetchDialog(
IN HWND hwndList)
{
m_hwndList = hwndList;
}
~CUrlFetchDialog() {}
int AddListItem(
IN WCHAR const *pwszURL,
IN WCHAR const *pwszStatus,
IN WCHAR const *pwszType,
IN DWORD dwInterval);
HRESULT UpdateListItemStatus(
IN int nItem,
IN WCHAR const *pwszStatus);
HRESULT UpdateListItemParam(
IN int nItem,
IN LPARAM lParam);
HRESULT UpdateListItemTime(
IN int nItem,
IN DWORD dwInterval);
HRESULT UpdateListItem(
IN int nItem,
IN WCHAR const *pwszURL,
IN WCHAR const *pwszStatus,
IN WCHAR const *pwszType,
IN DWORD dwInterval);
int DisplayMessageBox(
IN HWND hWnd,
IN LPCWSTR lpText,
IN LPCWSTR lpCaption,
IN UINT uType);
HCURSOR SetCursor(
IN HCURSOR hCursor)
{
return(::SetCursor(hCursor));
}
VOID Display() {}
private:
HWND m_hwndList;
};
#define CII_URL 0
#define CII_TYPE 1
#define CII_STATUS 2
#define CII_MESSAGE 3
#define CII_MAX 4
class CConsoleItem {
public:
CConsoleItem()
{
ZeroMemory(&m_apwsz, sizeof(m_apwsz));
m_dwInterval = 0;
}
~CConsoleItem()
{
DWORD i;
for (i = 0; i < CII_MAX; i++)
{
if (NULL != m_apwsz[i])
{
LocalFree(m_apwsz[i]);
}
}
}
HRESULT UpdateString(
IN DWORD iString,
IN WCHAR const *pwszNew);
HRESULT UpdateInterval(
IN DWORD dwInterval)
{
m_dwInterval = dwInterval;
return(S_OK);
}
VOID DisplayItem();
private:
WCHAR *m_apwsz[CII_MAX];
DWORD m_dwInterval;
};
HRESULT
CConsoleItem::UpdateString(
IN DWORD iString,
IN WCHAR const *pwszNew)
{
HRESULT hr;
WCHAR *pwsz;
if (iString >= CII_MAX)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "iString");
}
if (NULL != pwszNew)
{
hr = myDupString(pwszNew, &pwsz);
_JumpIfError(hr, error, "myDupString");
if (NULL != m_apwsz[iString])
{
LocalFree(m_apwsz[iString]);
}
m_apwsz[iString] = pwsz;
}
hr = S_OK;
error:
return(hr);
}
VOID
CConsoleItem::DisplayItem()
{
wprintf(
L" %ws \"%ws\" %ws %u\n",
NULL == m_apwsz[CII_STATUS]? L"???" : m_apwsz[CII_STATUS],
NULL == m_apwsz[CII_TYPE]? L"???" : m_apwsz[CII_TYPE],
myLoadResourceString(IDS_TIME_COLON), // "Time:"
m_dwInterval);
if (NULL != m_apwsz[CII_MESSAGE])
{
wprintf(L" %ws\n", m_apwsz[CII_MESSAGE]);
}
if (NULL != m_apwsz[CII_URL])
{
wprintf(L" %ws\n\n", m_apwsz[CII_URL]);
}
}
class CUrlFetchConsole : CUrlFetch {
public:
CUrlFetchConsole()
{
m_cItem = 0;
m_rgpItem = NULL;
}
~CUrlFetchConsole()
{
if (NULL != m_rgpItem)
{
int i;
for (i = 0; i < m_cItem; i++)
{
delete m_rgpItem[i];
}
LocalFree(m_rgpItem);
}
}
int AddListItem(
IN WCHAR const *pwszURL,
IN WCHAR const *pwszStatus,
IN WCHAR const *pwszType,
IN DWORD dwInterval);
HRESULT UpdateListItemStatus(
IN int nItem,
IN WCHAR const *pwszStatus);
HRESULT UpdateListItemParam(
IN int nItem,
IN LPARAM lParam);
HRESULT UpdateListItemTime(
IN int nItem,
IN DWORD dwInterval);
HRESULT UpdateListItem(
IN int nItem,
IN WCHAR const *pwszURL,
IN WCHAR const *pwszStatus,
IN WCHAR const *pwszType,
IN DWORD dwInterval);
int DisplayMessageBox(
IN HWND hWnd,
IN LPCWSTR lpText,
IN LPCWSTR lpCaption,
IN UINT uType);
HCURSOR SetCursor(
IN HCURSOR hCursor)
{
return(hCursor);
}
VOID Display()
{
if (NULL != m_rgpItem)
{
int i;
for (i = 0; i < m_cItem; i++)
{
if (NULL != m_rgpItem[i])
{
m_rgpItem[i]->DisplayItem();
}
}
}
}
private:
int m_cItem;
CConsoleItem **m_rgpItem;
};
class THREAD_INFO
{
public:
~THREAD_INFO()
{
delete m_pUrl;
}
CERT_CONTEXT const *m_pCert;
CRL_CONTEXT const *m_pCRL;
CUrlFetch *m_pUrl;
};
HRESULT
GetSimpleName(
OPTIONAL IN CERT_CONTEXT const *pCert,
OPTIONAL IN CRL_CONTEXT const *pCRL,
OUT WCHAR **ppwszSimpleName)
{
HRESULT hr;
CERT_CONTEXT Cert;
CERT_INFO CertInfo;
BYTE Zero;
*ppwszSimpleName = NULL;
if (NULL == pCert)
{
if (NULL == pCRL)
{
hr = E_POINTER;
_JumpError(hr, error, "GetSimpleName NULL parm");
}
ZeroMemory(&Cert, sizeof(Cert));
ZeroMemory(&CertInfo, sizeof(CertInfo));
Cert.dwCertEncodingType = X509_ASN_ENCODING;
//Cert.pbCertEncoded = NULL;
//Cert.cbCertEncoded = NULL;
Cert.pCertInfo = &CertInfo;
Zero = 0;
CertInfo.dwVersion = CERT_V3;
CertInfo.SerialNumber.pbData = &Zero;
CertInfo.SerialNumber.cbData = sizeof(Zero);
CertInfo.SignatureAlgorithm = pCRL->pCrlInfo->SignatureAlgorithm;
CertInfo.Issuer = pCRL->pCrlInfo->Issuer;
CertInfo.NotBefore = pCRL->pCrlInfo->ThisUpdate;
CertInfo.NotAfter = pCRL->pCrlInfo->NextUpdate;
CertInfo.Subject = pCRL->pCrlInfo->Issuer;
//CertInfo.SubjectPublicKeyInfo;
//CertInfo.IssuerUniqueId;
//CertInfo.SubjectUniqueId;
CertInfo.cExtension = pCRL->pCrlInfo->cExtension;
CertInfo.rgExtension = pCRL->pCrlInfo->rgExtension;
pCert = &Cert;
}
hr = myCertGetNameString(
pCert,
CERT_NAME_SIMPLE_DISPLAY_TYPE,
ppwszSimpleName);
_JumpIfError(hr, error, "myCertGetNameString");
error:
return(hr);
}
BOOL
ViewCertificate(
IN CERT_CONTEXT const *pCert,
IN WCHAR const *pwszTitle)
{
CRYPTUI_VIEWCERTIFICATE_STRUCT CertViewInfo;
ZeroMemory(&CertViewInfo, sizeof(CertViewInfo));
CertViewInfo.dwSize = sizeof(CertViewInfo);
CertViewInfo.hwndParent = NULL;
CertViewInfo.szTitle = pwszTitle;
CertViewInfo.pCertContext = pCert;
return CryptUIDlgViewCertificate(&CertViewInfo, NULL);
#if 0
Removed due to incompatibility with Win2k.
CryptUIDlgViewContext(
CERT_STORE_CERTIFICATE_CONTEXT,
(VOID const *) pObjInfo->pCert,
hDlg,
myLoadResourceString(IDS_CERTIFICATE), // "Certificate"
0,
NULL);
#endif
}
BOOL
ViewCrl(
IN CRL_CONTEXT const *pCRL,
IN WCHAR const *pwszTitle)
{
CRYPTUI_VIEWCRL_STRUCT CRLViewInfo;
ZeroMemory(&CRLViewInfo, sizeof(CRLViewInfo));
CRLViewInfo.dwSize = sizeof(CRLViewInfo);
CRLViewInfo.hwndParent = NULL;
CRLViewInfo.szTitle = pwszTitle;
CRLViewInfo.pCRLContext = pCRL;
return CryptUIDlgViewCRL(&CRLViewInfo);
#if 0
Removed due to incompatibility with Win2k.
CryptUIDlgViewContext(
CERT_STORE_CRL_CONTEXT,
(VOID const *) pObjInfo->pCRL,
hDlg,
myLoadResourceString(IDS_CRL), // "CRL"
0,
NULL);
#endif
}
HRESULT
ReadCertOrCRLFromFile(
IN WCHAR const *pwszFile,
OUT CERT_CONTEXT const **ppCert,
OUT CRL_CONTEXT const **ppCRL)
{
HRESULT hr;
CERT_BLOB Blob;
*ppCert = NULL;
*ppCRL = NULL;
Blob.pbData = NULL;
hr = DecodeFileW(pwszFile, &Blob.pbData, &Blob.cbData, CRYPT_STRING_ANY);
if (S_OK != hr)
{
cuPrintError(IDS_ERR_FORMAT_DECODEFILE, hr);
goto error;
}
*ppCert = CertCreateCertificateContext(
X509_ASN_ENCODING,
Blob.pbData,
Blob.cbData);
if (NULL == *ppCert)
{
hr = myHLastError();
_PrintError2(hr, "CertCreateCertificateContext", hr);
*ppCRL = CertCreateCRLContext(
X509_ASN_ENCODING,
Blob.pbData,
Blob.cbData);
if (NULL == *ppCRL)
{
hr = myHLastError();
_JumpError(hr, error, "CertCreateCRLContext");
}
}
s_majorURL++;
s_levelURL = 1;
hr = cuSaveAsnToFile(
Blob.pbData,
Blob.cbData,
s_majorURL,
s_levelURL,
0, // iElement
NULL != *ppCert? L".crt" : L".crl");
_PrintIfError(hr, "cuSaveAsnToFile");
hr = S_OK;
error:
if (NULL != Blob.pbData)
{
LocalFree(Blob.pbData);
}
return(hr);
}
BOOL
RetrieveCRLStore(
IN WCHAR const *pwszURL,
OUT HCERTSTORE *phStore)
{
return(CryptRetrieveObjectByUrl(
pwszURL,
CONTEXT_OID_CRL,
CRYPT_WIRE_ONLY_RETRIEVAL |
CRYPT_RETRIEVE_MULTIPLE_OBJECTS |
g_dwRetrievalFlags,
g_dwTimeout,
(VOID **) phStore,
NULL,
NULL,
NULL,
NULL));
}
BOOL
RetrieveCertStore(
IN WCHAR const *pwszURL,
OUT HCERTSTORE *phStore)
{
return(CryptRetrieveObjectByUrl(
pwszURL,
CONTEXT_OID_CERTIFICATE,
CRYPT_WIRE_ONLY_RETRIEVAL |
CRYPT_RETRIEVE_MULTIPLE_OBJECTS |
g_dwRetrievalFlags,
g_dwTimeout,
(VOID **) phStore,
NULL,
NULL,
NULL,
NULL));
}
int
CUrlFetchDialog::AddListItem(
IN WCHAR const *pwszURL,
IN WCHAR const *pwszStatus,
IN WCHAR const *pwszType,
IN DWORD dwInterval)
{
LVITEM item;
LRESULT lMsg = 0;
WCHAR wszInterval[MAX_ULTOW_BUFFER_SIZE];
int nListCount = 0;
// Get the list count so we can append to it
nListCount = ListView_GetItemCount(m_hwndList);
ZeroMemory(&item, sizeof(item));
item.iItem = nListCount;
// Add the item
item.mask = 0;
item.iSubItem = 0;
lMsg = SendMessage(m_hwndList, LVM_INSERTITEM, 0, (LPARAM) &item);
// Add the status
item.mask = LVIF_TEXT;
item.iSubItem = LIST_STATUS_SUBITEM - 1;
item.pszText = const_cast<WCHAR *>(pwszStatus);
lMsg = SendMessage(m_hwndList, LVM_SETITEMTEXT, nListCount, (LPARAM) &item);
// Add the type
item.iSubItem = LIST_TYPE_SUBITEM - 1;
item.pszText = const_cast<WCHAR *>(pwszType);
lMsg = SendMessage(m_hwndList, LVM_SETITEMTEXT, nListCount, (LPARAM) &item);
// Add the URL
item.iSubItem = LIST_URL_SUBITEM - 1;
item.pszText = const_cast<WCHAR *>(pwszURL);
lMsg = SendMessage(m_hwndList, LVM_SETITEMTEXT, nListCount, (LPARAM) &item);
// Add the interval
item.iSubItem = LIST_TIME_SUBITEM - 1;
_ultow(dwInterval, wszInterval, 10);
item.pszText = wszInterval;
lMsg = SendMessage(m_hwndList, LVM_SETITEMTEXT, nListCount, (LPARAM) &item);
return nListCount;
}
HRESULT
CUrlFetchDialog::UpdateListItemStatus(
IN int nItem,
IN WCHAR const *pwszStatus)
{
LVITEM item;
ZeroMemory(&item, sizeof(item));
item.mask = LVIF_TEXT;
item.iItem = nItem;
item.iSubItem = LIST_STATUS_SUBITEM - 1;
item.pszText = const_cast<WCHAR *>(pwszStatus);
SendMessage(m_hwndList, LVM_SETITEMTEXT, nItem, (LPARAM) &item);
return(S_OK);
}
HRESULT
CUrlFetchDialog::UpdateListItemParam(
IN int nItem,
IN LPARAM lParam)
{
LVITEM item;
ZeroMemory(&item, sizeof(item));
item.iItem = nItem;
item.mask = LVIF_PARAM;
item.lParam = lParam;
SendMessage(m_hwndList, LVM_SETITEM, nItem, (LPARAM) &item);
return(S_OK);
}
HRESULT
CUrlFetchDialog::UpdateListItemTime(
IN int nItem,
IN DWORD dwInterval)
{
LVITEM item;
WCHAR wszInterval[MAX_ULTOW_BUFFER_SIZE];
ZeroMemory(&item, sizeof(item));
item.iItem = nItem;
item.mask = LVIF_TEXT;
item.iSubItem = LIST_TIME_SUBITEM - 1;
item.pszText = wszInterval;
_ultow(dwInterval, wszInterval, 10);
SendMessage(m_hwndList, LVM_SETITEMTEXT, nItem, (LPARAM) &item);
return(S_OK);
}
HRESULT
CUrlFetchDialog::UpdateListItem(
IN int nItem,
IN WCHAR const *pwszURL,
IN WCHAR const *pwszStatus,
IN WCHAR const *pwszType,
IN DWORD dwInterval)
{
LVITEM item;
LRESULT lMsg = 0;
WCHAR wszInterval[MAX_ULTOW_BUFFER_SIZE];
ZeroMemory(&item, sizeof(item));
item.iItem = nItem;
// Update the status
item.mask = LVIF_TEXT;
item.iSubItem = LIST_STATUS_SUBITEM - 1;
item.pszText = const_cast<WCHAR *>(pwszStatus);
lMsg = SendMessage(m_hwndList, LVM_SETITEMTEXT, nItem, (LPARAM) &item);
// Update the type
item.iSubItem = LIST_TYPE_SUBITEM - 1;
item.pszText = const_cast<WCHAR *>(pwszType);
lMsg = SendMessage(m_hwndList, LVM_SETITEMTEXT, nItem, (LPARAM) &item);
// Update the URL
item.iSubItem = LIST_URL_SUBITEM - 1;
item.pszText = const_cast<WCHAR *>(pwszURL);
lMsg = SendMessage(m_hwndList, LVM_SETITEMTEXT, nItem, (LPARAM) &item);
// Update the interval
item.iSubItem = LIST_TIME_SUBITEM - 1;
_ultow(dwInterval, wszInterval, 10);
item.pszText = wszInterval;
lMsg = SendMessage(m_hwndList, LVM_SETITEMTEXT, nItem, (LPARAM) &item);
return(S_OK);
}
int
CUrlFetchDialog::DisplayMessageBox(
IN HWND hWnd,
IN LPCWSTR lpText,
IN LPCWSTR lpCaption,
IN UINT uType)
{
return(::MessageBox(hWnd, lpText, lpCaption, uType));
}
int
CUrlFetchConsole::AddListItem(
IN WCHAR const *pwszURL,
IN WCHAR const *pwszStatus,
IN WCHAR const *pwszType,
IN DWORD dwInterval)
{
HRESULT hr;
DWORD cb = (m_cItem + 1) * sizeof(*m_rgpItem);
CConsoleItem **rgpItem;
int nItem;
#if 0
wprintf(
L"CUrlFetchConsole::AddListItem(%u: %ws, %ws, %u)\n%ws\n\n",
m_cItem,
pwszStatus,
pwszType,
dwInterval,
pwszURL);
#endif
if (0 == m_cItem)
{
rgpItem = (CConsoleItem **) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
cb);
}
else
{
rgpItem = (CConsoleItem **) LocalReAlloc(
m_rgpItem,
cb,
LMEM_MOVEABLE);
}
if (NULL == rgpItem)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc/ReAlloc");
}
m_rgpItem = rgpItem;
nItem = m_cItem++;
m_rgpItem[nItem] = new CConsoleItem;
if (NULL == m_rgpItem[nItem])
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "new");
}
hr = UpdateListItem(nItem, pwszURL, pwszStatus, pwszType, dwInterval);
_JumpIfError(hr, error, "UpdateListItem");
error:
return(nItem);
}
HRESULT
CUrlFetchConsole::UpdateListItemStatus(
IN int nItem,
IN WCHAR const *pwszStatus)
{
HRESULT hr;
#if 0
wprintf(
L"CUrlFetchConsole::UpdateListItemStatus(%u: %ws)\n",
nItem,
pwszStatus);
#endif
if (nItem >= m_cItem || NULL == m_rgpItem[nItem])
{
hr = E_INVALIDARG;
_JumpError(hr, error, "new");
}
hr = m_rgpItem[nItem]->UpdateString(CII_STATUS, pwszStatus);
_JumpIfError(hr, error, "UpdateString");
error:
return(hr);
}
HRESULT
CUrlFetchConsole::UpdateListItemParam(
IN int nItem,
IN LPARAM lParam)
{
HRESULT hr;
OBJECT_INFO *pObjInfo = (OBJECT_INFO *) lParam;
#if 0
wprintf(
L"CUrlFetchConsole::UpdateListItemParam(%u: %p): ",
nItem,
lParam);
#endif
if (nItem >= m_cItem || NULL == m_rgpItem[nItem])
{
hr = E_INVALIDARG;
_JumpError(hr, error, "new");
}
switch (pObjInfo->dwType)
{
case OBJECT_TYPE_CERT:
#if 0
wprintf(L"OBJECT_TYPE_CERT\n");
#endif
break;
case OBJECT_TYPE_CRL:
#if 0
wprintf(L"OBJECT_TYPE_CRL\n");
#endif
break;
case OBJECT_TYPE_MSG:
#if 0
wprintf(L"OBJECT_TYPE_MSG\n%ws\n", pObjInfo->wszErrInfo);
#endif
hr = m_rgpItem[nItem]->UpdateString(
CII_MESSAGE,
pObjInfo->wszErrInfo);
_JumpIfError(hr, error, "UpdateString");
break;
default:
#if 0
wprintf(L"???\n");
#endif
break;
}
hr = S_OK;
error:
delete pObjInfo;
return(hr);
}
HRESULT
CUrlFetchConsole::UpdateListItemTime(
IN int nItem,
IN DWORD dwInterval)
{
HRESULT hr;
#if 0
wprintf(
L"CUrlFetchConsole::UpdateListItemTime(%u: %u)\n",
nItem,
dwInterval);
#endif
if (nItem >= m_cItem || NULL == m_rgpItem[nItem])
{
hr = E_INVALIDARG;
_JumpError(hr, error, "new");
}
hr = m_rgpItem[nItem]->UpdateInterval(dwInterval);
_JumpIfError(hr, error, "UpdateInterval");
error:
return(hr);
}
HRESULT
CUrlFetchConsole::UpdateListItem(
IN int nItem,
IN WCHAR const *pwszURL,
IN WCHAR const *pwszStatus,
IN WCHAR const *pwszType,
IN DWORD dwInterval)
{
HRESULT hr;
#if 0
wprintf(
L"CUrlFetchConsole::UpdateListItem(%u: %ws, %ws, %u)\n%ws\n\n",
nItem,
pwszStatus,
pwszType,
dwInterval,
pwszURL);
#endif
if (nItem >= m_cItem || NULL == m_rgpItem[nItem])
{
hr = E_INVALIDARG;
_JumpError(hr, error, "new");
}
hr = m_rgpItem[nItem]->UpdateInterval(dwInterval);
_JumpIfError(hr, error, "UpdateInterval");
hr = m_rgpItem[nItem]->UpdateString(CII_URL, pwszURL);
_JumpIfError(hr, error, "UpdateString");
hr = m_rgpItem[nItem]->UpdateString(CII_STATUS, pwszStatus);
_JumpIfError(hr, error, "UpdateString");
hr = m_rgpItem[nItem]->UpdateString(CII_TYPE, pwszType);
_JumpIfError(hr, error, "UpdateString");
error:
return(hr);
}
int
CUrlFetchConsole::DisplayMessageBox(
IN HWND hWnd,
IN LPCWSTR lpText,
IN LPCWSTR lpCaption,
IN UINT uType)
{
wprintf(L"%ws: %ws\n", lpCaption, lpText);
return(IDOK);
}
BOOL
cuVerifyAKI(
IN DWORD cExt,
IN CERT_EXTENSION const *rgExt,
IN CERT_NAME_BLOB const *pIssuer,
IN CERT_CONTEXT const *pCertIssuer)
{
BOOL fVerified = FALSE;
CERT_EXTENSION const *pExt;
pExt = CertFindExtension(
szOID_AUTHORITY_KEY_IDENTIFIER2,
cExt,
const_cast<CERT_EXTENSION *>(rgExt));
if (NULL != pExt)
{
HRESULT hr;
hr = cuVerifyKeyAuthority(
pIssuer,
pCertIssuer->pCertInfo,
pExt->Value.pbData,
pExt->Value.cbData,
TRUE,
&fVerified);
_JumpIfError(hr, error, "cuVerifyKeyAuthority");
}
else
{
fVerified = TRUE; // no penalty if missing the AKI extension
}
error:
return(fVerified);
}
WCHAR const *
wszCertStatus(
OPTIONAL IN CERT_CONTEXT const *pCert,
IN CERT_CONTEXT const *pCertIssuer)
{
HRESULT hr;
WCHAR const *pwsz;
CERT_REVOCATION_PARA crp;
CERT_REVOCATION_STATUS crs;
UINT ids;
ZeroMemory(&crp, sizeof(crp));
crp.cbSize = sizeof(crp);
ZeroMemory(&crs, sizeof(crs));
crs.cbSize = sizeof(crs);
// verify cert signature with the Issuer Cert public key
if (NULL != pCert)
{
if (!CryptVerifyCertificateSignature(
NULL,
X509_ASN_ENCODING,
pCert->pbCertEncoded,
pCert->cbCertEncoded,
&pCertIssuer->pCertInfo->SubjectPublicKeyInfo))
{
hr = myHLastError();
_PrintError2(hr, "CryptVerifyCertificateSignature", hr);
ids = IDS_STATUS_WRONG_ISSUER; // "Wrong Issuer"
goto error;
}
}
if (0 != CertVerifyTimeValidity(NULL, pCertIssuer->pCertInfo))
{
ids = IDS_STATUS_EXPIRED; // "Expired"
goto error;
}
if (NULL != pCert &&
!cuVerifyAKI(
pCert->pCertInfo->cExtension,
pCert->pCertInfo->rgExtension,
&pCert->pCertInfo->Issuer,
pCertIssuer))
{
ids = IDS_STATUS_BAD_AKI; // "Bad Authority Key Id"
goto error;
}
crp.hCrlStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM_W,
X509_ASN_ENCODING,
NULL, // hProv
cuGetSystemStoreFlags() | CERT_STORE_READONLY_FLAG,
wszCA_CERTSTORE);
if (NULL == crp.hCrlStore)
{
hr = myHLastError();
_JumpError(hr, error, "CertOpenStore");
}
if (!CertVerifyRevocation(
X509_ASN_ENCODING,
CERT_CONTEXT_REVOCATION_TYPE,
1, // cContext
(VOID **) &pCertIssuer, // rgpContext
0, // dwFlags
&crp,
&crs))
{
hr = myHLastError();
_PrintError(hr, "CertVerifyRevocation");
if (CRYPT_E_REVOKED == hr || CERT_E_REVOKED == hr)
{
ids = IDS_STATUS_REVOKED; // "Revoked"
}
else
if (CRYPT_E_NO_REVOCATION_CHECK != hr)
{
ids = IDS_STATUS_CANNOT_CHECK_REVOCATION; // "Revocation Check Failed"
}
else
{
ids = IDS_STATUS_NO_CRL; // "No CRL"
}
goto error;
}
ids = NULL != pCert?
IDS_STATUS_VERIFIED : // "Verified"
IDS_STATUS_OK; // "OK"
error:
if (NULL != crp.hCrlStore)
{
CertCloseStore(crp.hCrlStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
pwsz = myLoadResourceString(ids);
if (NULL == pwsz)
{
pwsz = L"???";
}
return(pwsz);
}
BOOL
cuVerifyMinimumBaseCRL(
IN CRL_CONTEXT const *pCRLBase,
IN CRL_CONTEXT const *pCRLDelta)
{
BOOL fVerified = FALSE;
DWORD CRLNumber;
CRLNumber = myCRLNumber(pCRLBase);
if (0 != CRLNumber)
{
CERT_EXTENSION const *pExt;
pExt = CertFindExtension(
szOID_DELTA_CRL_INDICATOR,
pCRLDelta->pCrlInfo->cExtension,
pCRLDelta->pCrlInfo->rgExtension);
if (NULL != pExt)
{
DWORD MinBase;
DWORD cb;
cb = sizeof(MinBase);
MinBase = 0;
if (CryptDecodeObject(
X509_ASN_ENCODING,
X509_INTEGER,
pExt->Value.pbData,
pExt->Value.cbData,
0,
&MinBase,
&cb))
{
if (CRLNumber >= MinBase)
{
fVerified = TRUE;
}
}
}
}
return(fVerified);
}
HRESULT
GetObjectUrl(
IN char const *pszUrlOid,
IN VOID *pvPara,
IN DWORD dwFlags,
OUT CRYPT_URL_ARRAY **ppUrlArray,
OUT DWORD *pcbUrlArray)
{
HRESULT hr;
CRYPT_URL_ARRAY *pUrlArray = NULL;
DWORD cbUrlArray;
*ppUrlArray = NULL;
if (!CryptGetObjectUrl(
pszUrlOid,
pvPara,
dwFlags,
NULL,
&cbUrlArray,
NULL,
NULL,
NULL))
{
hr = myHLastError();
_PrintError2(hr, "CryptGetObjectUrl", hr);
if (CRYPT_E_NOT_FOUND == hr)
{
hr = S_OK;
goto error;
}
_JumpError(hr, error, "CryptGetObjectUrl");
}
pUrlArray = (CRYPT_URL_ARRAY *) LocalAlloc(LMEM_FIXED, cbUrlArray);
if (NULL == pUrlArray)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
if (!CryptGetObjectUrl(
pszUrlOid,
pvPara,
dwFlags,
pUrlArray,
&cbUrlArray,
NULL,
NULL,
NULL))
{
hr = myHLastError();
_JumpError(hr, error, "CryptGetObjectUrl");
}
*ppUrlArray = pUrlArray;
pUrlArray = NULL;
*pcbUrlArray = cbUrlArray;
hr = S_OK;
error:
if (NULL != pUrlArray)
{
LocalFree(pUrlArray);
}
return(hr);
}
BOOL
cuVerifyIDP(
IN CERT_CONTEXT const *pCertSubject,
IN CRL_CONTEXT const *pCRL)
{
HRESULT hr;
BOOL fVerified = TRUE;
CERT_EXTENSION const *pExtCDP;
CRL_DIST_POINTS_INFO *pCDP = NULL;
CERT_EXTENSION const *pExtIDP;
CRL_ISSUING_DIST_POINT *pIDP = NULL;
DWORD cb;
DWORD iDistPoint;
DWORD i;
// Find the cert CDP extension:
pExtCDP = CertFindExtension(
szOID_CRL_DIST_POINTS,
pCertSubject->pCertInfo->cExtension,
pCertSubject->pCertInfo->rgExtension);
if (NULL == pExtCDP)
{
hr = CRYPT_E_NOT_FOUND;
_JumpIfError2(hr, error, "CertFindExtension", hr);
}
// Find the CRL IDP extension:
pExtIDP = CertFindExtension(
szOID_ISSUING_DIST_POINT,
pCRL->pCrlInfo->cExtension,
pCRL->pCrlInfo->rgExtension);
if (NULL == pExtIDP)
{
hr = CRYPT_E_NOT_FOUND;
_JumpIfError2(hr, error, "CertFindExtension", hr);
}
fVerified = FALSE;
// Decode the cert CDP extension:
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_CRL_DIST_POINTS,
pExtCDP->Value.pbData,
pExtCDP->Value.cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pCDP,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "myDecodeObject");
}
// Decode the CRL IDP extension:
if (!myDecodeObject(
X509_ASN_ENCODING,
X509_ISSUING_DIST_POINT,
pExtIDP->Value.pbData,
pExtIDP->Value.cbData,
CERTLIB_USE_LOCALALLOC,
(VOID **) &pIDP,
&cb))
{
hr = myHLastError();
_JumpError(hr, error, "myDecodeObject");
}
if (CRL_DIST_POINT_FULL_NAME != pIDP->DistPointName.dwDistPointNameChoice)
{
hr = CRYPT_E_NOT_FOUND;
_JumpIfError2(hr, error, "dwDistPointNameChoice", hr);
}
for (iDistPoint = 0; iDistPoint < pCDP->cDistPoint; iDistPoint++)
{
CERT_ALT_NAME_INFO *pAltNameEntry;
if (CRL_DIST_POINT_FULL_NAME !=
pCDP->rgDistPoint[iDistPoint].DistPointName.dwDistPointNameChoice)
{
continue;
}
pAltNameEntry = &pCDP->rgDistPoint[iDistPoint].DistPointName.FullName;
for (i = 0; i < pIDP->DistPointName.FullName.cAltEntry; i++)
{
DWORD j;
CERT_ALT_NAME_ENTRY const *pIDPAlt =
&pIDP->DistPointName.FullName.rgAltEntry[i];
for (j = 0; j < pAltNameEntry->cAltEntry; j++)
{
CERT_ALT_NAME_ENTRY const *pCDPAlt = &pAltNameEntry->rgAltEntry[j];
BOOL fMatch;
if (pIDPAlt->dwAltNameChoice != pCDPAlt->dwAltNameChoice)
{
continue;
}
fMatch = FALSE;
switch (pIDPAlt->dwAltNameChoice)
{
case CERT_ALT_NAME_OTHER_NAME:
fMatch = 0 == strcmp(
pIDPAlt->pOtherName->pszObjId,
pCDPAlt->pOtherName->pszObjId) &&
myAreBlobsSame(
pIDPAlt->pOtherName->Value.pbData,
pIDPAlt->pOtherName->Value.cbData,
pCDPAlt->pOtherName->Value.pbData,
pCDPAlt->pOtherName->Value.cbData);
break;
case CERT_ALT_NAME_RFC822_NAME:
fMatch = 0 == lstrcmp(
pIDPAlt->pwszRfc822Name,
pCDPAlt->pwszRfc822Name);
break;
case CERT_ALT_NAME_DNS_NAME:
fMatch = 0 == lstrcmp(
pIDPAlt->pwszDNSName,
pCDPAlt->pwszDNSName);
break;
case CERT_ALT_NAME_DIRECTORY_NAME:
fMatch = 0 == lstrcmp(
pIDPAlt->pwszRfc822Name,
pCDPAlt->pwszRfc822Name);
break;
case CERT_ALT_NAME_URL:
fMatch = 0 == lstrcmp(pIDPAlt->pwszURL, pCDPAlt->pwszURL);
break;
case CERT_ALT_NAME_IP_ADDRESS:
fMatch = myAreBlobsSame(
pIDPAlt->IPAddress.pbData,
pIDPAlt->IPAddress.cbData,
pCDPAlt->IPAddress.pbData,
pCDPAlt->IPAddress.cbData);
break;
case CERT_ALT_NAME_REGISTERED_ID:
fMatch = 0 == strcmp(
pIDPAlt->pszRegisteredID,
pCDPAlt->pszRegisteredID);
break;
//case CERT_ALT_NAME_X400_ADDRESS:
//case CERT_ALT_NAME_EDI_PARTY_NAME:
default:
continue;
}
if (fMatch)
{
fVerified = TRUE;
break;
}
}
if (fVerified)
{
break;
}
}
if (fVerified)
{
break;
}
}
error:
if (NULL != pCDP)
{
LocalFree(pCDP);
}
if (NULL != pIDP)
{
LocalFree(pIDP);
}
return(fVerified);
}
WCHAR const *
wszCRLStatus(
OPTIONAL IN CERT_CONTEXT const *pCertIssuer,
OPTIONAL IN CERT_CONTEXT const *pCertSubject,
OPTIONAL IN CRL_CONTEXT const *pCRLBase,
IN CRL_CONTEXT const *pCRL)
{
HRESULT hr;
WCHAR const *pwsz;
UINT ids;
// verify CRL signature with the Issuer Cert public key
if (NULL == pCertIssuer && NULL != pCertSubject)
{
// if the Subject cert is a root, use Subject cert for Issuer cert
hr = cuVerifySignature(
pCertSubject->pbCertEncoded,
pCertSubject->cbCertEncoded,
&pCertSubject->pCertInfo->SubjectPublicKeyInfo,
TRUE,
TRUE);
if (S_OK == hr)
{
pCertIssuer = pCertSubject;
}
}
if (NULL != pCertIssuer)
{
if (!CryptVerifyCertificateSignature(
NULL,
X509_ASN_ENCODING,
pCRL->pbCrlEncoded,
pCRL->cbCrlEncoded,
&pCertIssuer->pCertInfo->SubjectPublicKeyInfo))
{
hr = myHLastError();
_PrintError2(hr, "CryptVerifyCertificateSignature", hr);
ids = IDS_STATUS_WRONG_ISSUER; // "Wrong Issuer"
goto error;
}
}
if (0 != CertVerifyCRLTimeValidity(NULL, pCRL->pCrlInfo))
{
ids = IDS_STATUS_EXPIRED; // "Expired"
goto error;
}
if (NULL != pCRLBase &&
!cuVerifyMinimumBaseCRL(pCRLBase, pCRL))
{
ids = IDS_STATUS_OLD_BASE_CRL; // "Old Base CRL"
goto error;
}
if (NULL != pCertIssuer)
{
if (!CertCompareCertificateName(
X509_ASN_ENCODING,
&pCRL->pCrlInfo->Issuer,
&pCertSubject->pCertInfo->Issuer))
{
ids = IDS_STATUS_BAD_CERT_ISSUER; // "Bad Cert Issuer"
goto error;
}
if (!CertCompareCertificateName(
X509_ASN_ENCODING,
&pCRL->pCrlInfo->Issuer,
&pCertIssuer->pCertInfo->Subject))
{
ids = IDS_STATUS_BAD_CA_CERT_SUBJECT; // "Bad CA Cert Subject"
goto error;
}
if (!cuVerifyAKI(
pCRL->pCrlInfo->cExtension,
pCRL->pCrlInfo->rgExtension,
&pCRL->pCrlInfo->Issuer,
pCertIssuer))
{
ids = IDS_STATUS_BAD_AKI; // "Bad Authority Key Id"
goto error;
}
}
if (NULL != pCertSubject &&
NULL == pCRLBase &&
!cuVerifyIDP(pCertSubject, pCRL))
{
ids = IDS_STATUS_BAD_IDP; // "No IDP Intersection"
goto error;
}
ids = NULL != pCertIssuer?
IDS_STATUS_VERIFIED : // "Verified"
IDS_STATUS_OK; // "OK"
error:
pwsz = myLoadResourceString(ids);
if (NULL == pwsz)
{
pwsz = L"???";
}
return(pwsz);
}
DWORD
GetCertNumber(
IN CERT_CONTEXT const *pCert,
OPTIONAL IN OUT BYTE **ppbHashes,
OPTIONAL IN OUT DWORD *pcHashes)
{
HRESULT hr;
DWORD CertNumber = MAXDWORD;
DWORD i;
BYTE abHash[CBMAX_CRYPT_HASH_LEN];
DWORD cbHash;
i = MAXDWORD;
cbHash = sizeof(abHash);
if (!CertGetCertificateContextProperty(
pCert,
CERT_SHA1_HASH_PROP_ID,
abHash,
&cbHash))
{
hr = myHLastError();
_JumpError(hr, error, "CertGetCertificateContextProperty");
}
if (cbHash != sizeof(abHash))
{
_JumpError(E_INVALIDARG, error, "cbHash");
}
if (NULL != ppbHashes && NULL != pcHashes)
{
for (i = 0; i < *pcHashes; i++)
{
if (0 == memcmp(
abHash,
&(*ppbHashes)[i * sizeof(abHash)],
sizeof(abHash)))
{
break;
}
}
if (i == *pcHashes)
{
if (0 == *pcHashes)
{
*ppbHashes = (BYTE *) LocalAlloc(LMEM_FIXED, sizeof(abHash));
if (NULL == *ppbHashes)
{
_JumpError(E_OUTOFMEMORY, error, "LocalAlloc");
}
}
else
{
BYTE *pb;
pb = (BYTE *) LocalReAlloc(
*ppbHashes,
(i + 1) * sizeof(abHash),
LMEM_MOVEABLE);
if (NULL == pb)
{
_JumpError(E_OUTOFMEMORY, error, "LocalAlloc");
}
*ppbHashes = pb;
}
memcpy(
&(*ppbHashes)[i * sizeof(abHash)],
abHash,
sizeof(abHash));
(*pcHashes)++;
}
}
CertNumber = i;
error:
return(CertNumber);
}
VOID
FillErrorText(
IN UINT idsFmt,
IN WCHAR const *pwszFmt2,
OUT WCHAR *pwsz,
IN DWORD cwc,
IN HRESULT hr)
{
WCHAR const *pwszFmt;
WCHAR const *pwszMsg = myGetErrorMessageText(hr, TRUE);
pwszFmt = myLoadResourceString(idsFmt);
if (NULL == pwszFmt)
{
pwszFmt = pwszFmt2;
}
_snwprintf(pwsz, cwc, pwszFmt, pwszMsg);
pwsz[cwc - 1] = L'\0';
if (NULL != pwszMsg)
{
LocalFree(const_cast<WCHAR *>(pwszMsg));
}
}
VOID
FillErrorTextRetrieve(
OUT WCHAR *pwsz,
IN DWORD cwc,
IN HRESULT hr)
{
FillErrorText(
IDS_FORMAT_URL_RETRIEVE_ERROR, // "Error retrieving URL: %ws"
L"Error retrieving URL: %ws",
pwsz,
cwc,
hr);
}
VOID
FillErrorTextExtract(
OUT WCHAR *pwsz,
IN DWORD cwc,
IN HRESULT hr)
{
FillErrorText(
IDS_FORMAT_URL_EXTRACT_ERROR, // "No URLs found: %ws"
L"No URLs found: %ws",
pwsz,
cwc,
hr);
}
BOOL
RetrieveAndAddAIAUrlToList(
IN CUrlFetch *pUrl,
OPTIONAL IN CERT_CONTEXT const *pCert,
IN WCHAR const *pwszUrl,
IN DWORD iURL,
OPTIONAL IN OUT BYTE **ppbHashes,
OPTIONAL IN OUT DWORD *pcHashes)
{
HRESULT hr = S_OK;
BOOL fRet = FALSE;
int iItem = 0;
HCERTSTORE hStore = NULL;
CERT_CONTEXT const *pAIACert = NULL;
WCHAR wszUrl[MAX_URL_LEN];
DWORD cert = 0;
DWORD dwIntStart = 0;
DWORD dwIntEnd = 0;
DWORD dwInterval = 0;
OBJECT_INFO *pObjInfo = NULL;
HCURSOR hPrevCur;
WCHAR const *pwszTypeCert;
WCHAR *pwszTypeBuffer = NULL;
s_levelURL++;
// Add the url to the list view with RETRIEVING status
iItem = pUrl->AddListItem(
pwszUrl,
myLoadResourceString(IDS_STATUS_RETRIEVING), // "Retrieving"
myLoadResourceString(IDS_AIA_ITEM_TYPE), // "AIA"
0);
// Attempt to retrieve the url
hPrevCur = pUrl->SetCursor(LoadCursor(NULL, IDC_WAIT));
dwIntStart = GetTickCount();
if (!RetrieveCertStore(pwszUrl, &hStore) || NULL == hStore)
{
hr = myHLastError();
pUrl->SetCursor(hPrevCur);
_PrintErrorStr(hr, "RetrieveCertStore", pwszUrl);
// Modify the status of this URL on the list to FAILED
pUrl->UpdateListItemStatus(
iItem,
myLoadResourceString(IDS_STATUS_FAILURE)); // "Failed"
pObjInfo = new OBJECT_INFO;
if (NULL == pObjInfo)
{
_PrintError(E_OUTOFMEMORY, "new");
}
else
{
pObjInfo->dwType = OBJECT_TYPE_MSG;
pObjInfo->wszErrInfo[0] = L'\0';
FillErrorTextRetrieve(
pObjInfo->wszErrInfo,
ARRAYSIZE(pObjInfo->wszErrInfo),
hr);
pUrl->UpdateListItemParam(iItem, (LPARAM) pObjInfo);
}
// Retrieve the next item
goto error;
}
pUrl->SetCursor(hPrevCur);
// Calculate and update the retrieval interval
dwIntEnd = GetTickCount();
dwInterval = (dwIntEnd - dwIntStart) / 1000;
pUrl->UpdateListItemTime(iItem, dwInterval);
// Modify the status of this URL on the list to SUCCESS.
pUrl->UpdateListItemStatus(
iItem,
myLoadResourceString(IDS_STATUS_SUCCESS)); // "Success"
// Add the certificate context to the items
pwszTypeCert = myLoadResourceString(IDS_CERT_ITEM_TYPE);
if (NULL == pwszTypeCert)
{
pwszTypeCert = wszCERTIFICATE;
}
pwszTypeBuffer = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pwszTypeCert) + 2 + cwcDWORDSPRINTF + 2) *
sizeof(WCHAR));
if (NULL == pwszTypeBuffer)
{
_JumpError(E_OUTOFMEMORY, error, "LocalAlloc");
}
cert = 0;
while (TRUE)
{
WCHAR const *pwszStatus;
DWORD CertNumber;
pAIACert = CertEnumCertificatesInStore(hStore, pAIACert);
if (NULL == pAIACert)
{
break;
}
// Add the cert to the list, initially as OK
_snwprintf(
wszUrl,
ARRAYSIZE(wszUrl),
L"[%d.%d] %ws",
iURL,
cert,
pwszUrl);
wszUrl[ARRAYSIZE(wszUrl) - 1] = L'\0';
hr = cuSaveAsnToFile(
pAIACert->pbCertEncoded,
pAIACert->cbCertEncoded,
s_majorURL,
s_levelURL,
cert,
L".crt");
_PrintIfError(hr, "cuSaveAsnToFile");
CertNumber = GetCertNumber(pAIACert, ppbHashes, pcHashes);
wcscpy(pwszTypeBuffer, pwszTypeCert);
if (MAXDWORD != CertNumber)
{
wsprintf(
&pwszTypeBuffer[wcslen(pwszTypeCert)],
L" (%u)",
CertNumber);
}
if (0 == cert)
{
pUrl->UpdateListItem(
iItem,
wszUrl,
myLoadResourceString(IDS_STATUS_VERIFYING), // "Verifying"
pwszTypeBuffer,
dwInterval);
}
else
{
iItem = pUrl->AddListItem(
wszUrl,
myLoadResourceString(IDS_STATUS_VERIFYING), // "Verifying"
pwszTypeBuffer,
dwInterval);
}
// Check the validity
hPrevCur = pUrl->SetCursor(LoadCursor(NULL, IDC_WAIT));
pwszStatus = wszCertStatus(pCert, pAIACert);
pUrl->SetCursor(hPrevCur);
pUrl->UpdateListItemStatus(iItem, pwszStatus);
pObjInfo = new OBJECT_INFO;
if (NULL == pObjInfo)
{
_PrintError(E_OUTOFMEMORY, "new");
}
else
{
ZeroMemory(pObjInfo, sizeof(*pObjInfo));
pObjInfo->dwType = OBJECT_TYPE_CERT;
pObjInfo->pCert = CertDuplicateCertificateContext(pAIACert);
pUrl->UpdateListItemParam(iItem, (LPARAM) pObjInfo);
}
cert++;
}
fRet = TRUE;
error:
if (NULL != pwszTypeBuffer)
{
LocalFree(pwszTypeBuffer);
}
return fRet;
}
BOOL
RetrieveAndAddCDPUrlToList(
IN CUrlFetch *pUrl,
IN WCHAR const *pwszUrl,
IN DWORD iURL,
IN CERT_CONTEXT const *pCertIn,
OPTIONAL IN CERT_CONTEXT const *pCertIssuer,
IN CRL_CONTEXT const *pCRLIn)
{
HRESULT hr = S_OK;
BOOL fRet = FALSE;
int iItem = 0;
int iDCrlItem = 0;
HCERTSTORE hStore = NULL;
HCERTSTORE hDeltaStore = NULL;
CRL_CONTEXT const *pCRL = NULL;
CRL_CONTEXT const *pDCRL = NULL;
WCHAR wszUrl[MAX_URL_LEN];
WCHAR wszMsg[MAX_MSG_LEN];
DWORD cCRL;
DWORD cDCRL;
DWORD cURL;
DWORD dwIntStart;
DWORD dwIntEnd;
DWORD dwInterval;
OBJECT_INFO *pObjInfo = NULL;
CERT_CRL_CONTEXT_PAIR ContextPair;
CRYPT_URL_ARRAY *pCRLUrlArray = NULL;
DWORD cbCRLUrlArray;
OSVERSIONINFO OSInfo;
WCHAR const *pwszType;
WCHAR const *pwszTypeDelta;
DWORD iElement = 0;
HCURSOR hPrevCur;
DWORD cwc;
DWORD cwcDelta;
WCHAR *pwszTypeBuffer = NULL;
// Add the url to the list view with RETRIEVING status
s_levelURL++;
iItem = pUrl->AddListItem(
pwszUrl,
myLoadResourceString(IDS_STATUS_RETRIEVING), // "Retrieving"
myLoadResourceString(IDS_CDP_ITEM_TYPE), // "CDP"
0);
// Attempt to retrieve the url
hPrevCur = pUrl->SetCursor(LoadCursor(NULL, IDC_WAIT));
dwIntStart = GetTickCount();
if (!RetrieveCRLStore(pwszUrl, &hStore) || NULL == hStore)
{
hr = myHLastError();
pUrl->SetCursor(hPrevCur);
_PrintErrorStr(hr, "RetrieveCRLStore", pwszUrl);
// Modify the status of this URL on the list to FAILED
pUrl->UpdateListItemStatus(iItem, myLoadResourceString(IDS_STATUS_FAILURE)); // "Failed"
pObjInfo = new OBJECT_INFO;
if (NULL == pObjInfo)
{
_PrintError(E_OUTOFMEMORY, "new");
}
else
{
pObjInfo->dwType = OBJECT_TYPE_MSG;
pObjInfo->wszErrInfo[0] = L'\0';
FillErrorTextRetrieve(
pObjInfo->wszErrInfo,
ARRAYSIZE(pObjInfo->wszErrInfo),
hr);
pUrl->UpdateListItemParam(iItem, (LPARAM) pObjInfo);
}
// Retrieve the next item
goto error;
}
pUrl->SetCursor(hPrevCur);
// Calculate and update the interval
dwIntEnd = GetTickCount();
dwInterval = (dwIntEnd - dwIntStart) / 1000; // Interval in seconds
pUrl->UpdateListItemTime(iItem, dwInterval);
// Modify the status of this URL on the list to SUCCESS.
pUrl->UpdateListItemStatus(
iItem,
myLoadResourceString(IDS_STATUS_SUCCESS)); // "Success"
// If the CRL was successfully retrieved, then check it for
// a freshness distribution point extension either on the
// certificate or on the CRL
ZeroMemory(&ContextPair, sizeof(ContextPair));
ContextPair.pCertContext = pCertIn;
pwszType = myLoadResourceString(IDS_BASE_CRL_ITEM_TYPE); // "Base CRL"
if (NULL == pwszType)
{
pwszType = wszBASE_CRL_ITEM_TYPE;
}
pwszTypeDelta = myLoadResourceString(IDS_DELTA_CRL_ITEM_TYPE); // "Delta CRL"
if (NULL == pwszTypeDelta)
{
pwszTypeDelta = wszDELTA_CRL_ITEM_TYPE;
}
cwc = wcslen(pwszType);
cwcDelta = wcslen(pwszTypeDelta);
if (cwc < cwcDelta)
{
cwc = cwcDelta;
}
pwszTypeBuffer = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(cwc + 2 + cwcDWORDSPRINTF + 2) * sizeof(WCHAR));
if (NULL == pwszTypeBuffer)
{
_JumpError(E_OUTOFMEMORY, error, "LocalAlloc");
}
cCRL = 0;
while (TRUE)
{
WCHAR const *pwszStatus;
BOOL fDelta;
DWORD CRLNumber;
pCRL = CertEnumCRLsInStore(hStore, pCRL);
if (NULL == pCRL)
{
break;
}
hr = cuSaveAsnToFile(
pCRL->pbCrlEncoded,
pCRL->cbCrlEncoded,
s_majorURL,
s_levelURL,
iElement++,
L".crl");
_PrintIfError(hr, "cuSaveAsnToFile");
hr = myIsDeltaCRL(pCRL, &fDelta);
_PrintIfError(hr, "myIsDeltaCRL");
if (S_OK != hr)
{
fDelta = NULL != pCRLIn;
}
// Add the CRL to the list, initially as OK
_snwprintf(
wszUrl,
ARRAYSIZE(wszUrl),
L"[%d.%d] %ws",
iURL,
cCRL,
pwszUrl);
wszUrl[ARRAYSIZE(wszUrl) - 1] = L'\0';
wcscpy(pwszTypeBuffer, fDelta? pwszTypeDelta : pwszType);
CRLNumber = myCRLNumber(pCRL);
if (0 != CRLNumber)
{
wsprintf(
&pwszTypeBuffer[wcslen(pwszTypeBuffer)],
L" (%u)",
CRLNumber);
}
if (0 == cCRL)
{
pUrl->UpdateListItem(
iItem,
wszUrl,
myLoadResourceString(IDS_STATUS_VERIFYING), // "Verifying"
pwszTypeBuffer,
dwInterval);
}
else
{
iItem = pUrl->AddListItem(
wszUrl,
myLoadResourceString(IDS_STATUS_VERIFYING), // "Verifying"
pwszTypeBuffer,
dwInterval);
}
// Check the CRL
hPrevCur = pUrl->SetCursor(LoadCursor(NULL, IDC_WAIT));
pwszStatus = wszCRLStatus(pCertIssuer, pCertIn, NULL, pCRL);
pUrl->SetCursor(hPrevCur);
pUrl->UpdateListItemStatus(iItem, pwszStatus);
// Add the CRL to this param
pObjInfo = new OBJECT_INFO;
if (NULL == pObjInfo)
{
_PrintError(E_OUTOFMEMORY, "new");
}
else
{
ZeroMemory(pObjInfo, sizeof(*pObjInfo));
pObjInfo->dwType = OBJECT_TYPE_CRL;
pObjInfo->pCRL = CertDuplicateCRLContext(pCRL);
pUrl->UpdateListItemParam(iItem, (LPARAM) pObjInfo);
}
// Get any URLs from this CRL
ContextPair.pCrlContext = pCRL;
hr = GetObjectUrl(
URL_OID_CRL_FRESHEST_CRL, // Freshest CRL URLs: cert+CRL
(VOID *) &ContextPair,
CRYPT_GET_URL_FROM_EXTENSION,
&pCRLUrlArray,
&cbCRLUrlArray);
if (S_OK != hr)
{
_PrintError(hr, "GetObjectUrl");
// If this is Win2k, it does not support the freshest CRL
// extension, so we shouldn't return a failure.
ZeroMemory(&OSInfo, sizeof(OSInfo));
OSInfo.dwOSVersionInfoSize = sizeof(OSInfo);
if (GetVersionEx(&OSInfo))
{
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr &&
OSInfo.dwMajorVersion == 5 &&
OSInfo.dwMinorVersion == 0)
{
// ERROR_FILE_NOT_FOUND is returned when the ASN.1 handler
// for an extension does not exist.
continue;
}
}
FillErrorTextExtract(wszMsg, ARRAYSIZE(wszMsg), hr);
pUrl->DisplayMessageBox(
NULL,
wszMsg,
myLoadResourceString(IDS_GET_OBJECT_URL), // "GetObjectUrl"
MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
pUrl->AddListItem(
NULL,
myLoadResourceString(IDS_STATUS_ERROR), // "Error"
myLoadResourceString(IDS_NO_ITEM_TYPE), // "None
0);
goto error;
}
if (NULL == pCRLUrlArray)
{
continue; // No delta CRLs to retrieve
}
for (cURL = 0; cURL < pCRLUrlArray->cUrl; cURL++)
{
// Add this CRL to the list with proper index with
// RETRIEVING status
_snwprintf(
wszUrl,
ARRAYSIZE(wszUrl),
L"[%d.%d.%d] %ws",
iURL,
cURL,
cCRL,
pCRLUrlArray->rgwszUrl[cURL]);
wszUrl[ARRAYSIZE(wszUrl) - 1] = L'\0';
iDCrlItem = pUrl->AddListItem(
wszUrl,
myLoadResourceString(IDS_STATUS_RETRIEVING), // "Retrieving"
myLoadResourceString(IDS_CDP_ITEM_TYPE), // "CDP"
0);
// Now attempt to retrieve the delta CRLs
hPrevCur = pUrl->SetCursor(LoadCursor(NULL, IDC_WAIT));
dwIntStart = GetTickCount();
if (!RetrieveCRLStore(pCRLUrlArray->rgwszUrl[cURL], &hDeltaStore))
{
hr = myHLastError();
pUrl->SetCursor(hPrevCur);
_PrintErrorStr(hr, "RetrieveCRLStore", pCRLUrlArray->rgwszUrl[cURL]);
// Modify the status of this URL on the list to FAILED
pUrl->UpdateListItemStatus(
iDCrlItem,
myLoadResourceString(IDS_STATUS_FAILURE)); // "Failed"
pObjInfo = new OBJECT_INFO;
if (NULL == pObjInfo)
{
_PrintError(E_OUTOFMEMORY, "new");
}
else
{
pObjInfo->dwType = OBJECT_TYPE_MSG;
pObjInfo->wszErrInfo[0] = L'\0';
FillErrorTextRetrieve(
pObjInfo->wszErrInfo,
ARRAYSIZE(pObjInfo->wszErrInfo),
hr);
pUrl->UpdateListItemParam(iDCrlItem, (LPARAM) pObjInfo);
}
// Retrieve the next item
continue;
}
pUrl->SetCursor(hPrevCur);
// Calculate the retrieval interval and update the list view
dwIntEnd = GetTickCount();
dwInterval = (dwIntEnd - dwIntStart) / 1000;
pUrl->UpdateListItemTime(iDCrlItem, dwInterval);
// Update the list with SUCCESS status
pUrl->UpdateListItemStatus(
iDCrlItem,
myLoadResourceString(IDS_STATUS_SUCCESS)); // "Success"
// Update the individual items
cDCRL = 0;
while (TRUE)
{
DWORD CRLNumberDelta;
pDCRL = CertEnumCRLsInStore(hDeltaStore, pDCRL);
if (NULL == pDCRL)
{
break;
}
hr = cuSaveAsnToFile(
pDCRL->pbCrlEncoded,
pDCRL->cbCrlEncoded,
s_majorURL,
s_levelURL,
iElement++,
L".crl");
_PrintIfError(hr, "cuSaveAsnToFile");
// Add the CRL to the list, initially as OK
_snwprintf(
wszUrl,
ARRAYSIZE(wszUrl),
L"[%d.%d.%d] %ws",
iURL,
cDCRL,
cURL,
pCRLUrlArray->rgwszUrl[cURL]);
wszUrl[ARRAYSIZE(wszUrl) - 1] = L'\0';
wcscpy(pwszTypeBuffer, pwszTypeDelta);
CRLNumber = myCRLNumber(pCRL);
if (0 != CRLNumber)
{
wsprintf(&pwszTypeBuffer[cwcDelta], L" (%u)", CRLNumber);
}
if (0 == cDCRL)
{
pUrl->UpdateListItem(
iDCrlItem,
wszUrl,
myLoadResourceString(IDS_STATUS_VERIFYING), // "Verifying"
pwszTypeBuffer,
dwInterval);
}
else
{
iDCrlItem = pUrl->AddListItem(
wszUrl,
myLoadResourceString(IDS_STATUS_VERIFYING), // "Verifying"
pwszTypeBuffer,
dwInterval);
}
// Check the CRL
hPrevCur = pUrl->SetCursor(LoadCursor(NULL, IDC_WAIT));
pwszStatus = wszCRLStatus(pCertIssuer, pCertIn, pCRL, pDCRL);
pUrl->SetCursor(hPrevCur);
pUrl->UpdateListItemStatus(iDCrlItem, pwszStatus);
// Re-using the same object, but that's OK since
// we store it in the list
pObjInfo = new OBJECT_INFO;
if (NULL == pObjInfo)
{
_PrintError(E_OUTOFMEMORY, "new");
}
else
{
ZeroMemory(pObjInfo, sizeof(*pObjInfo));
pObjInfo->dwType = OBJECT_TYPE_CRL;
pObjInfo->pCRL = CertDuplicateCRLContext(pDCRL);
pUrl->UpdateListItemParam(iDCrlItem, (LPARAM) pObjInfo);
}
cDCRL++;
}
}
cCRL++;
}
fRet = TRUE;
error:
if (NULL != pwszTypeBuffer)
{
LocalFree(pwszTypeBuffer);
}
if (NULL != pCRLUrlArray)
{
LocalFree(pCRLUrlArray);
}
return(fRet);
}
DWORD WINAPI
CDPThreadProc(
IN VOID *pvParam)
{
HRESULT hr;
DWORD dwRet = 0;
CRYPT_URL_ARRAY *pUrlArray = NULL;
DWORD cbUrlArray;
DWORD cURL;
WCHAR wszMsg[MAX_MSG_LEN];
THREAD_INFO *pThreadInfo = (THREAD_INFO *) pvParam;
CERT_CONTEXT const *pCertIssuer;
CERT_CHAIN_PARA ChainParams;
CERT_CHAIN_CONTEXT const *pChainContext = NULL;
HCURSOR hPrevCur;
CUrlFetch *pUrl = pThreadInfo->m_pUrl;
// First retrieve the base URLs
if (NULL != pThreadInfo->m_pCRL)
{
CERT_CRL_CONTEXT_PAIR ContextPair;
// Get any URLs from this CRL
ContextPair.pCertContext = pThreadInfo->m_pCert;
ContextPair.pCrlContext = pThreadInfo->m_pCRL;
hr = GetObjectUrl(
URL_OID_CRL_FRESHEST_CRL, // Freshest CRL URLs: cert+CRL
(VOID *) &ContextPair,
CRYPT_GET_URL_FROM_EXTENSION,
&pUrlArray,
&cbUrlArray);
_PrintIfError(hr, "GetObjectUrl");
}
else
{
hr = GetObjectUrl(
URL_OID_CERTIFICATE_CRL_DIST_POINT, // CDP URLs: cert
(VOID *) pThreadInfo->m_pCert,
CRYPT_GET_URL_FROM_EXTENSION,
&pUrlArray,
&cbUrlArray);
_PrintIfError(hr, "GetObjectUrl");
}
if (S_OK != hr)
{
FillErrorTextExtract(wszMsg, ARRAYSIZE(wszMsg), hr);
pUrl->DisplayMessageBox(
NULL,
wszMsg,
myLoadResourceString(IDS_GET_OBJECT_URL), // "GetObjectUrl"
MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
pUrl->AddListItem(
NULL,
myLoadResourceString(IDS_STATUS_ERROR), // "Error"
myLoadResourceString(IDS_NO_ITEM_TYPE), // "None"
0);
_JumpError(hr, error, "GetObjectUrl");
}
if (NULL == pUrlArray)
{
dwRet = 1; // Nothing to retrieve
pUrl->AddListItem(
NULL,
myLoadResourceString(IDS_STATUS_NO_RETRIEVAL), // "No URLs"
myLoadResourceString(IDS_NO_ITEM_TYPE), // "None"
0);
goto error;
}
// Build the chain to get the issuer cert
ZeroMemory(&ChainParams, sizeof(ChainParams));
ChainParams.cbSize = sizeof(ChainParams);
hPrevCur = pUrl->SetCursor(LoadCursor(NULL, IDC_WAIT));
pCertIssuer = NULL;
if (NULL != pThreadInfo->m_pCert)
{
if (!CertGetCertificateChain(
HCCE_LOCAL_MACHINE,
pThreadInfo->m_pCert, // pCertContext
NULL, // pTime
NULL, // hAdditionalStore
&ChainParams, // pChainPara
0, // dwFlags
NULL, // pvReserved
&pChainContext)) // ppChainContext
{
hr = myHLastError();
_PrintError(hr, "CertGetCertificateChain");
}
else
if (0 < pChainContext->cChain &&
1 < pChainContext->rgpChain[0]->cElement)
{
pCertIssuer = pChainContext->rgpChain[0]->rgpElement[1]->pCertContext;
}
}
pUrl->SetCursor(hPrevCur);
for (cURL = 0; cURL < pUrlArray->cUrl; cURL++)
{
if (!RetrieveAndAddCDPUrlToList(
pThreadInfo->m_pUrl,
pUrlArray->rgwszUrl[cURL],
cURL,
pThreadInfo->m_pCert,
pCertIssuer,
pThreadInfo->m_pCRL))
{
// Do nothing right now
}
}
dwRet = 1;
error:
pThreadInfo->m_pUrl->Display();
if (NULL != pChainContext)
{
CertFreeCertificateChain(pChainContext);
}
if (NULL != pUrlArray)
{
LocalFree(pUrlArray);
}
delete pThreadInfo; // Because it was allocated
return(dwRet);
}
DWORD WINAPI
CertThreadProc(
IN VOID *pvParam)
{
HRESULT hr;
DWORD dwRet = 0;
CRYPT_URL_ARRAY *pCertUrlArray = NULL;
DWORD cbCertUrlArray = 0;
DWORD cURL;
WCHAR wszMsg[MAX_MSG_LEN];
THREAD_INFO *pThreadInfo = (THREAD_INFO *) pvParam;
BYTE *pbHashes = NULL;
DWORD cHashes;
CUrlFetch *pUrl = pThreadInfo->m_pUrl;
// First retrieve the AIA URLs
hr = GetObjectUrl(
URL_OID_CERTIFICATE_ISSUER, // AIA URLs: Cert
(VOID *) pThreadInfo->m_pCert,
CRYPT_GET_URL_FROM_EXTENSION,
&pCertUrlArray,
&cbCertUrlArray);
if (S_OK != hr)
{
FillErrorTextExtract(wszMsg, ARRAYSIZE(wszMsg), hr);
pUrl->DisplayMessageBox(
NULL,
wszMsg,
myLoadResourceString(IDS_GET_OBJECT_URL), // "GetObjectUrl"
MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
pUrl->AddListItem(
NULL,
myLoadResourceString(IDS_STATUS_ERROR), // "Error"
myLoadResourceString(IDS_NO_ITEM_TYPE), // "None"
0);
_JumpError(hr, error, "GetObjectUrl");
}
if (NULL == pCertUrlArray)
{
dwRet = 1; // Nothing to retrieve
pUrl->AddListItem(
NULL,
myLoadResourceString(IDS_STATUS_NO_RETRIEVAL), // "No URLs"
myLoadResourceString(IDS_NO_ITEM_TYPE), // "None"
0);
goto error;
}
cHashes = 0;
for (cURL = 0; cURL < pCertUrlArray->cUrl; cURL++)
{
if (!RetrieveAndAddAIAUrlToList(
pThreadInfo->m_pUrl,
pThreadInfo->m_pCert,
pCertUrlArray->rgwszUrl[cURL],
cURL,
&pbHashes,
&cHashes))
{
// Do nothing right now
}
}
dwRet = 1;
error:
pThreadInfo->m_pUrl->Display();
if (NULL != pbHashes)
{
LocalFree(pbHashes);
}
if (NULL != pCertUrlArray)
{
LocalFree(pCertUrlArray);
}
delete pThreadInfo; // Because it was allocated in the calling thread
return dwRet;
}
VOID
RetrieveCDPUrlsFromCertOrCRL(
OPTIONAL IN CERT_CONTEXT const *pCert,
OPTIONAL IN CRL_CONTEXT const *pCRL,
IN HWND hwndList)
{
HRESULT hr;
DWORD dwThreadId;
HANDLE hThread = NULL;
THREAD_INFO *pThreadInfo = NULL;
pThreadInfo = new THREAD_INFO;
if (NULL == pThreadInfo)
{
_JumpError(E_OUTOFMEMORY, error, "new");
}
ZeroMemory(pThreadInfo, sizeof(*pThreadInfo));
pThreadInfo->m_pCert = pCert;
pThreadInfo->m_pCRL = pCRL;
pThreadInfo->m_pUrl = (CUrlFetch *) new CUrlFetchDialog(hwndList);
if (NULL == pThreadInfo->m_pUrl)
{
_JumpError(E_OUTOFMEMORY, error, "new");
}
hThread = CreateThread(
NULL,
0,
CDPThreadProc,
(VOID *) pThreadInfo,
0,
&dwThreadId);
if (NULL == hThread)
{
hr = myHLastError();
_JumpError(hr, error, "CreateThread");
}
pThreadInfo = NULL;
error:
delete pThreadInfo;
return;
}
VOID
RetrieveAIAUrlsFromCert(
IN CERT_CONTEXT const *pCert,
IN HWND hwndList)
{
HRESULT hr;
DWORD dwThreadId;
HANDLE hThread = NULL;
THREAD_INFO *pThreadInfo = NULL;
pThreadInfo = new THREAD_INFO;
if (NULL == pThreadInfo)
{
_JumpError(E_OUTOFMEMORY, error, "new");
}
ZeroMemory(pThreadInfo, sizeof(*pThreadInfo));
pThreadInfo->m_pCert = pCert;
pThreadInfo->m_pUrl = (CUrlFetch *) new CUrlFetchDialog(hwndList);
if (NULL == pThreadInfo->m_pUrl)
{
_JumpError(E_OUTOFMEMORY, error, "new");
}
hThread = CreateThread(
NULL,
0,
CertThreadProc,
(VOID *) pThreadInfo,
0,
&dwThreadId);
if (NULL == hThread)
{
hr = myHLastError();
_JumpError(hr, error, "CreateThread");
}
pThreadInfo = NULL;
error:
delete pThreadInfo;
return;
}
VOID
cuDisplayCDPUrlsFromCertOrCRL(
OPTIONAL IN CERT_CONTEXT const *pCert,
OPTIONAL IN CRL_CONTEXT const *pCRL)
{
HRESULT hr;
DWORD dwThreadId;
HANDLE hThread = NULL;
THREAD_INFO *pThreadInfo = NULL;
s_majorURL++;
s_levelURL = 1;
pThreadInfo = new THREAD_INFO;
if (NULL == pThreadInfo)
{
_JumpError(E_OUTOFMEMORY, error, "new");
}
ZeroMemory(pThreadInfo, sizeof(*pThreadInfo));
pThreadInfo->m_pCert = pCert;
pThreadInfo->m_pCRL = pCRL;
pThreadInfo->m_pUrl = (CUrlFetch *) new CUrlFetchConsole();
if (NULL == pThreadInfo->m_pUrl)
{
_JumpError(E_OUTOFMEMORY, error, "new");
}
CDPThreadProc(pThreadInfo);
pThreadInfo = NULL;
error:
delete pThreadInfo;
return;
}
VOID
cuDisplayAIAUrlsFromCert(
IN CERT_CONTEXT const *pCert)
{
HRESULT hr;
DWORD dwThreadId;
HANDLE hThread = NULL;
THREAD_INFO *pThreadInfo = NULL;
s_majorURL++;
s_levelURL = 1;
pThreadInfo = new THREAD_INFO;
if (NULL == pThreadInfo)
{
_JumpError(E_OUTOFMEMORY, error, "new");
}
ZeroMemory(pThreadInfo, sizeof(*pThreadInfo));
pThreadInfo->m_pCert = pCert;
pThreadInfo->m_pUrl = (CUrlFetch *) new CUrlFetchConsole();
if (NULL == pThreadInfo->m_pUrl)
{
_JumpError(E_OUTOFMEMORY, error, "new");
}
CertThreadProc(pThreadInfo);
pThreadInfo = NULL;
error:
delete pThreadInfo;
return;
}
// Update the certificate or CRL name
VOID
UpdateCertOrCRLState(
IN HWND hDlg,
OPTIONAL IN CERT_CONTEXT const *pCert,
OPTIONAL IN CRL_CONTEXT const *pCRL)
{
HRESULT hr;
WCHAR *pwszSimpleName = NULL;
WCHAR const *pwszType;
hr = GetSimpleName(pCert, pCRL, &pwszSimpleName);
_PrintIfError(hr, "GetSimpleName");
if (NULL != pCRL)
{
pwszType = myLoadResourceString(IDS_BASE_CRL_ISSUER); // "Base CRL Issuer"
if (NULL != CertFindExtension(
szOID_DELTA_CRL_INDICATOR,
pCRL->pCrlInfo->cExtension,
pCRL->pCrlInfo->rgExtension))
{
pwszType = myLoadResourceString(IDS_DELTA_CRL_ISSUER); // "Delta CRL Issuer"
}
}
else
{
pwszType = myLoadResourceString(IDS_CERT_SUBJECT); // "Certificate Subject"
}
SetDlgItemText(hDlg, IDC_SUBJECTTYPE, pwszType);
SetDlgItemText(hDlg, IDC_SIMPLENAME, pwszSimpleName);
if (NULL != pCRL)
{
SendMessage(
GetDlgItem(hDlg, IDC_RETRIEVECRLS),
BM_SETCHECK,
(WPARAM) TRUE,
(LPARAM) 0);
SendMessage(
GetDlgItem(hDlg, IDC_RETRIEVECERTS),
BM_SETCHECK,
(WPARAM) FALSE,
(LPARAM) 0);
}
EnableWindow(GetDlgItem(hDlg, IDC_RETRIEVECERTS), NULL == pCRL);
// Enable the retrieve button
EnableWindow(GetDlgItem(hDlg, IDC_RETRIEVE), TRUE);
if (NULL != pwszSimpleName)
{
LocalFree(pwszSimpleName);
}
}
INT_PTR CALLBACK
DlgProc(
HWND hDlg,
UINT msg,
WPARAM wParam,
LPARAM lParam)
{
HRESULT hr;
HWND hwndList = NULL;
HWND hwndView = NULL;
NMHDR *lpnm = NULL;
LVCOLUMN col;
LVITEM item;
OBJECT_INFO *pObjInfo = NULL;
WCHAR wszUrl[MAX_URL_LEN];
switch (msg)
{
case WM_INITDIALOG:
// Initialize the controls
hwndList = GetDlgItem(hDlg, IDC_URLLIST);
ListView_DeleteAllItems(hwndList);
ZeroMemory(&col, sizeof(col));
// Add the status column
col.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH |
LVCF_ORDER;
col.fmt = LVCFMT_LEFT;
col.pszText = const_cast<WCHAR *>(myLoadResourceString(IDS_STATUS_COLUMN)); // "Status"
col.iSubItem = LIST_STATUS_SUBITEM;
col.cx = 60;
col.iOrder = LIST_STATUS_SUBITEM - 1;
ListView_InsertColumn(hwndList, 0, &col);
// Add the type column
col.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH |
LVCF_ORDER;
col.fmt = LVCFMT_LEFT;
col.pszText = const_cast<WCHAR *>(myLoadResourceString(IDS_TYPE_COLUMN)); // "Type"
col.iSubItem = LIST_TYPE_SUBITEM;
col.cx = 80;
col.iOrder = LIST_TYPE_SUBITEM - 1;
ListView_InsertColumn(hwndList, 1, &col);
// Add the url column
col.mask = LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH | LVCF_ORDER;
col.pszText = const_cast<WCHAR *>(myLoadResourceString(IDS_URL_COLUMN)); // "Url"
col.iSubItem = LIST_URL_SUBITEM;
col.cx = 350;
col.iOrder = LIST_URL_SUBITEM - 1;
ListView_InsertColumn(hwndList, 2, &col);
// Add the retrieval time column
col.mask = LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH | LVCF_ORDER;
col.pszText = const_cast<WCHAR *>(myLoadResourceString(IDS_TIME_COLUMN)); // "Retrieval Time"
col.iSubItem = LIST_TIME_SUBITEM;
col.cx = 80;
col.iOrder = LIST_TIME_SUBITEM - 1;
ListView_InsertColumn(hwndList, 3, &col);
// Update the certificate name
SetDlgItemText(hDlg, IDC_SIMPLENAME, myLoadResourceString(IDS_NO_SELECTION)); // "No Selection"
// Set the control style
SendDlgItemMessageA(
hDlg,
IDC_URLLIST,
LVM_SETEXTENDEDLISTVIEWSTYLE,
0,
LVS_EX_FULLROWSELECT);
// Set the default retrieval option to CRLs
CheckDlgButton(hDlg, IDC_RETRIEVECRLS, BST_CHECKED);
// Disable the cross-cert radio button
EnableWindow(GetDlgItem(hDlg, IDC_RETRIEVECROSSCERTS), FALSE);
// Disable the retrieval button until a cert is selected
EnableWindow(GetDlgItem(hDlg, IDC_RETRIEVE), FALSE);
// Set the default timeout value
SetDlgItemInt(hDlg, IDC_TIMEOUT, DEF_TIMEOUT, FALSE);
// Clear the LDAP_SIGN flag
CheckDlgButton(hDlg, IDC_CHK_LDAPSIGN, BST_UNCHECKED);
// If an ULR was specified, set the text
if (NULL != g_pwszUrl)
{
SetDlgItemText(hDlg, IDC_DOWNLOADURL, g_pwszUrl);
}
// If a certificate was specified, update the dialog
SetDlgItemText(hDlg, IDC_SUBJECTTYPE, L"");
if (NULL != g_pCert || NULL != g_pCRL)
{
// Update the certificate or CRL name
UpdateCertOrCRLState(hDlg, g_pCert, g_pCRL);
}
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hDlg, 0);
break;
case IDC_SELECT:
if (NULL != g_pwszFile)
{
LocalFree(g_pwszFile);
g_pwszFile = NULL;
}
hr = myGetOpenFileName(
hDlg,
NULL, // hInstance
IDS_URL_OPEN_TITLE,
IDS_URL_FILE_FILTER,
IDS_URL_DEFAULT_EXT,
OFN_PATHMUSTEXIST |
OFN_FILEMUSTEXIST |
OFN_HIDEREADONLY,
NULL, // no default file
&g_pwszFile);
_PrintIfError(hr, "myGetOpenFileName");
if (S_OK == hr && NULL == g_pwszFile)
{
// canceled: see public\sdk\inc\cderr.h for real
// CommDlgExtendedError errors
hr = myHError(CommDlgExtendedError());
if (S_OK == hr)
{
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
}
_PrintIfError(hr, "myGetOpenFileName");
if (S_OK == hr)
{
// Load the cert or CRL into memory
if (NULL != g_pCert || NULL != g_pCRL)
{
if (NULL != g_pCert)
{
CertFreeCertificateContext(g_pCert);
g_pCert = NULL;
}
if (NULL != g_pCRL)
{
CertFreeCRLContext(g_pCRL);
g_pCRL = NULL;
}
ListView_DeleteAllItems(
GetDlgItem(hDlg, IDC_URLLIST));
SetDlgItemText(
hDlg,
IDC_SIMPLENAME,
myLoadResourceString(IDS_NO_CERT_SELECTED)); // "No Certificate Selected"
}
hr = ReadCertOrCRLFromFile(
g_pwszFile,
&g_pCert,
&g_pCRL);
if (S_OK != hr)
{
MessageBox(
hDlg,
myLoadResourceString(IDS_OPEN_FILE_ERROR), // "Error Opening Certificate or CRL File"
myLoadResourceString(IDS_SELECT_CERT_OR_CRL), // "Select Certificate or CRL"
MB_OK | MB_ICONEXCLAMATION | MB_APPLMODAL);
break;
}
// Update the certificate or CRL name
UpdateCertOrCRLState(hDlg, g_pCert, g_pCRL);
}
break;
case IDC_RETRIEVE:
if (BN_CLICKED == HIWORD(wParam))
{
// Clear the list
ListView_DeleteAllItems(GetDlgItem(hDlg, IDC_URLLIST));
s_majorURL++;
s_levelURL = 1;
// Set the current timeout
g_dwTimeout = (DWORD) (GetDlgItemInt(
hDlg,
IDC_TIMEOUT,
NULL,
FALSE) * 1000);
// Get the currently selected item
if (IsDlgButtonChecked(hDlg, IDC_RETRIEVECERTS))
{
// Retrieve URLs from the cert
if (NULL != g_pCert)
{
// Retrieve the list of URLs
RetrieveAIAUrlsFromCert(
g_pCert,
GetDlgItem(hDlg, IDC_URLLIST));
}
// Or simply retrieve one URL
if (0 != GetDlgItemText(
hDlg,
IDC_DOWNLOADURL,
wszUrl,
ARRAYSIZE(wszUrl)))
{
CUrlFetch *pUrl = (CUrlFetch *) new CUrlFetchDialog(GetDlgItem(hDlg, IDC_URLLIST));
if (NULL == pUrl)
{
_PrintError(E_OUTOFMEMORY, "new");
}
else
{
RetrieveAndAddAIAUrlToList(
pUrl,
NULL,
wszUrl,
0,
NULL,
NULL);
delete pUrl;
}
}
}
else if (IsDlgButtonChecked(hDlg, IDC_RETRIEVECRLS))
{
// Retrieve URLs from the cert
if (NULL != g_pCert || NULL != g_pCRL)
{
// Retrieve the list of URLs
RetrieveCDPUrlsFromCertOrCRL(
g_pCert,
g_pCRL,
GetDlgItem(hDlg, IDC_URLLIST));
}
// Or simply retrieve one URL
if (0 != GetDlgItemText(
hDlg,
IDC_DOWNLOADURL,
wszUrl,
ARRAYSIZE(wszUrl)))
{
CUrlFetch *pUrl = (CUrlFetch *) new CUrlFetchDialog(GetDlgItem(hDlg, IDC_URLLIST));
if (NULL == pUrl)
{
_PrintError(E_OUTOFMEMORY, "new");
}
else
{
RetrieveAndAddCDPUrlToList(
pUrl,
wszUrl,
0,
g_pCert,
NULL,
g_pCRL);
delete pUrl;
}
}
}
}
break;
case IDC_DOWNLOADURL:
if (EN_CHANGE == HIWORD(wParam))
{
if (0 != GetDlgItemText(
hDlg,
IDC_DOWNLOADURL,
wszUrl,
ARRAYSIZE(wszUrl)))
{
EnableWindow(GetDlgItem(hDlg, IDC_RETRIEVE), TRUE);
}
else
{
if (NULL == g_pCert && NULL == g_pCRL)
{
EnableWindow(
GetDlgItem(hDlg, IDC_RETRIEVE),
FALSE);
}
}
}
break;
case IDC_CHK_LDAPSIGN:
if (IsDlgButtonChecked(hDlg, IDC_CHK_LDAPSIGN))
{
g_dwRetrievalFlags |= CRYPT_LDAP_SIGN_RETRIEVAL;
}
else if (g_dwRetrievalFlags != 0)
{
g_dwRetrievalFlags &= ~CRYPT_LDAP_SIGN_RETRIEVAL;
}
break;
default:
break;
}
case WM_NOTIFY:
switch (wParam)
{
case IDC_URLLIST:
lpnm = (NMHDR *) lParam;
switch (lpnm->code)
{
case LVN_ITEMACTIVATE:
// Display it
ZeroMemory(&item, sizeof(item));
item.mask = LVIF_PARAM;
item.iItem = ((NMITEMACTIVATE *) lParam)->iItem;
if (ListView_GetItem(
((NMITEMACTIVATE *) lParam)->hdr.hwndFrom,
&item))
{
if (NULL != item.lParam)
{
pObjInfo = (OBJECT_INFO *) item.lParam;
switch (pObjInfo->dwType)
{
case OBJECT_TYPE_CERT:
ViewCertificate(
pObjInfo->pCert,
myLoadResourceString(IDS_CERTIFICATE)); // "Certificate"
break;
case OBJECT_TYPE_CRL:
ViewCrl(pObjInfo->pCRL, myLoadResourceString(IDS_CRL)); // "CRL"
break;
case OBJECT_TYPE_MSG:
MessageBox(
hDlg,
pObjInfo->wszErrInfo,
myLoadResourceString(IDS_ERROR_INFO), // "Error Information"
MB_OK);
break;
}
}
}
break;
case LVN_DELETEITEM:
ZeroMemory(&item, sizeof(item));
item.mask = LVIF_PARAM;
item.iItem = ((NMLISTVIEW *) lParam)->iItem;
if (ListView_GetItem(
((NMLISTVIEW *) lParam)->hdr.hwndFrom,
&item))
{
if (NULL != item.lParam)
{
pObjInfo = (OBJECT_INFO *) item.lParam;
switch (pObjInfo->dwType)
{
case OBJECT_TYPE_CERT:
CertFreeCertificateContext(pObjInfo->pCert);
break;
case OBJECT_TYPE_CRL:
CertFreeCRLContext(pObjInfo->pCRL);
break;
}
delete pObjInfo;
}
}
break;
default:
break;
}
break;
default:
break;
}
break;
default:
break;
}
return FALSE;
}
//+-------------------------------------------------------------------------
//
// IsInternetUrlProtocol -- Checks the protocol portion of the URL and returns
// TRUE if the protocol is an Internet protocol (http, https, ftp, ldap,
// mailto, file) and FALSE if it is not.
//
//--------------------------------------------------------------------------
BOOL
IsInternetUrlProtocol(
IN WCHAR const *pwszUrl)
{
BOOL fRet = FALSE;
// If NULL, just return FALSE
if (NULL == pwszUrl)
{
goto error;
}
// Compare the first few characters to see if they pertain to an Internet
// protocol
if (0 == _wcsnicmp(pwszUrl, L"http:", wcslen(L"http:")) ||
0 == _wcsnicmp(pwszUrl, L"https:", wcslen(L"https:")) ||
0 == _wcsnicmp(pwszUrl, L"ftp:", wcslen(L"ftp:")) ||
0 == _wcsnicmp(pwszUrl, L"ldap:", wcslen(L"ldap:")) ||
0 == _wcsnicmp(pwszUrl, L"mailto:", wcslen(L"mailto:")) ||
0 == _wcsnicmp(pwszUrl, L"file:", wcslen(L"file:")))
{
// It's an allowable Internet URL protocol
fRet = TRUE;
}
error:
return fRet;
}
HRESULT
verbURL(
IN WCHAR const *pwszOption,
IN WCHAR const *pwszFileOrURL,
IN WCHAR const *pwszArg2,
IN WCHAR const *pwszArg3,
IN WCHAR const *pwszArg4)
{
HRESULT hr;
INT_PTR nDlg = 0;
INITCOMMONCONTROLSEX Init;
HINSTANCE hInstance = (HINSTANCE) GetModuleHandle(NULL);
// Initialize the listview common controls
ZeroMemory(&Init, sizeof(Init));
Init.dwSize = sizeof(Init);
Init.dwICC = ICC_LISTVIEW_CLASSES;
if (!InitCommonControlsEx(&Init))
{
hr = myHLastError();
_JumpError(hr, error, "InitCommonControlsEx");
}
// If pwszFileOrURL is NULL, just call the dialog box,
// else determine if it's a file or URL
if (NULL != pwszFileOrURL)
{
// If it's a file, then we need to open it
if (!IsInternetUrlProtocol(pwszFileOrURL))
{
hr = ReadCertOrCRLFromFile(pwszFileOrURL, &g_pCert, &g_pCRL);
_JumpIfError(hr, error, "ReadCertOrCRLFromFile");
}
else // Otherwise just pass it in to the dialog
{
g_pwszUrl = pwszFileOrURL;
}
}
nDlg = DialogBox(
hInstance,
MAKEINTRESOURCE(IDD_URLTESTDLG),
NULL,
DlgProc);
hr = S_OK;
error:
if (NULL != g_pwszFile)
{
LocalFree(g_pwszFile);
g_pwszFile = NULL;
}
if (NULL != g_pCert)
{
CertFreeCertificateContext(g_pCert);
g_pCert = NULL;
}
if (NULL != g_pCRL)
{
CertFreeCRLContext(g_pCRL);
g_pCRL = NULL;
}
return(hr);
}