1995 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1995 lines
		
	
	
		
			47 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //+-------------------------------------------------------------------------
 | |
| //
 | |
| //  Microsoft Windows
 | |
| //
 | |
| //  Copyright (C) Microsoft Corporation, 1995 - 1999
 | |
| //
 | |
| //  File:       verify.cpp
 | |
| //
 | |
| //--------------------------------------------------------------------------
 | |
| 
 | |
| #include <pch.cpp>
 | |
| 
 | |
| #pragma hdrstop
 | |
| 
 | |
| #include "cscsp.h"
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| VerifyKeyAuthority(
 | |
|     CERT_NAME_BLOB const *pIssuer,
 | |
|     CERT_INFO const *pCertInfoCA,
 | |
|     BYTE const *pbData,
 | |
|     DWORD cbData,
 | |
|     BOOL *pfKeyAuthorityMatch)
 | |
| {
 | |
|     CERT_AUTHORITY_KEY_ID2_INFO const *pcaki = NULL;
 | |
|     DWORD cbcaki;
 | |
|     HRESULT hr = S_OK;
 | |
|     BOOL fDisplayIssuer = g_fVerbose;
 | |
|     CERT_NAME_BLOB const *pAuthorityCertIssuerName = NULL;
 | |
|     BYTE *pbHash = NULL;
 | |
|     DWORD cbHash;
 | |
| 
 | |
|     *pfKeyAuthorityMatch = TRUE;
 | |
| 
 | |
|     if (!myDecodeKeyAuthority2(
 | |
| 			    X509_ASN_ENCODING,
 | |
| 			    pbData,
 | |
| 			    cbData,
 | |
| 			    CERTLIB_USE_LOCALALLOC,
 | |
| 			    &pcaki,
 | |
| 			    &cbcaki))
 | |
|     {
 | |
| 	hr = myHLastError();
 | |
| 	_JumpError(hr, error, "myDecodeKeyAuthority(IssuerKey)");
 | |
|     }
 | |
|     if (0 != pcaki->KeyId.cbData)
 | |
|     {
 | |
| 	//DumpHex(DH_NOTABPREFIX | 4, pcaki->KeyId.pbData, pcaki->KeyId.cbData);
 | |
| 	hr = myGetPublicKeyHash(
 | |
| 			pCertInfoCA,
 | |
| 			&pCertInfoCA->SubjectPublicKeyInfo,
 | |
| 			&pbHash,
 | |
| 			&cbHash);
 | |
| 	_JumpIfError(hr, error, "myGetPublicKeyHash");
 | |
| 
 | |
| 	//DumpHex(DH_NOTABPREFIX | 4, pbHash, cbHash);
 | |
| 
 | |
| 	if (cbHash == pcaki->KeyId.cbData &&
 | |
| 	    0 == memcmp(pbHash, pcaki->KeyId.pbData, cbHash))
 | |
| 	{
 | |
| 	    wprintf(myLoadResourceString(IDS_KEYID_IS_KEYAUTHORITY)); // "CA Key Id matches Key Id"
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	    wprintf(wszNewLine);
 | |
| 	    wprintf(myLoadResourceString(IDS_ERR_KEYID_NOT_KEYAUTHORITY)); // "ERROR: CA Key Id does not match Key Id"
 | |
| 	    wprintf(wszNewLine);
 | |
| 	    *pfKeyAuthorityMatch = FALSE;
 | |
| 	}
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	wprintf(myLoadResourceString(IDS_NO_KEYID)); // "No Key Id"
 | |
|     }
 | |
|     wprintf(wszNewLine);
 | |
| 
 | |
|     if (1 == pcaki->AuthorityCertIssuer.cAltEntry &&
 | |
| 	CERT_ALT_NAME_DIRECTORY_NAME ==
 | |
| 	    pcaki->AuthorityCertIssuer.rgAltEntry[0].dwAltNameChoice)
 | |
|     {
 | |
| 
 | |
| 	pAuthorityCertIssuerName = &pcaki->AuthorityCertIssuer.rgAltEntry[0].DirectoryName;
 | |
| 
 | |
| 	// The Issuer's Issuer name and the Issuer's SerialNumber combined
 | |
| 	// should uniquely identify the Issuer cert.
 | |
| 
 | |
| 	// Verify Issuer's Issuer name:
 | |
| 	//        -------- ------ ----
 | |
| 
 | |
| 	if (!CertCompareCertificateName(
 | |
| 		    X509_ASN_ENCODING,
 | |
| 		    const_cast<CERT_NAME_BLOB *>(&pCertInfoCA->Issuer),
 | |
| 		    const_cast<CERT_NAME_BLOB *>(pAuthorityCertIssuerName)))
 | |
| 	{
 | |
| 	    // This API doesn't set LastError
 | |
| 	    hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
 | |
| 
 | |
| 	    wprintf(wszNewLine);
 | |
| 	    wprintf(
 | |
| 		myLoadResourceString(IDS_ERR_FORMAT_ISSUER_NOT_KEYAUTHORITY), // "ERROR: CA Issuer name does not match Key Authority name (%x)"
 | |
| 		hr);
 | |
| 
 | |
| 	    hr = S_OK;
 | |
| 	    fDisplayIssuer = TRUE;
 | |
| 	    *pfKeyAuthorityMatch = FALSE;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	    wprintf(myLoadResourceString(IDS_ISSUER_IS_KEYAUTHORITY)); // "CA Issuer name matches Key Authority name"
 | |
| 	}
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	wprintf(myLoadResourceString(IDS_NO_KEYAUTHORITY)); // "No Key Authority name"
 | |
|     }
 | |
|     wprintf(wszNewLine);
 | |
| 
 | |
|     if (0 != pcaki->AuthorityCertSerialNumber.cbData)
 | |
|     {
 | |
| 	if (pCertInfoCA->SerialNumber.cbData !=
 | |
| 		pcaki->AuthorityCertSerialNumber.cbData ||
 | |
| 	    0 != memcmp(
 | |
| 		    pCertInfoCA->SerialNumber.pbData,
 | |
| 		    pcaki->AuthorityCertSerialNumber.pbData,
 | |
| 		    pcaki->AuthorityCertSerialNumber.cbData))
 | |
| 	{
 | |
| 	    wprintf(wszNewLine);
 | |
| 	    wprintf(myLoadResourceString(IDS_SERIAL_NOT_KEYAUTHORITY)); // "ERROR: Issuer serial number does not match Key Authority"
 | |
| 	    wprintf(wszNewLine);
 | |
| 
 | |
| 	    fDisplayIssuer = TRUE;
 | |
| 	    *pfKeyAuthorityMatch = FALSE;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	    wprintf(myLoadResourceString(IDS_SERIAL_IS_KEYAUTHORITY)); // "Issuer serial number matches Key Authority"
 | |
| 	}
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	wprintf(myLoadResourceString(IDS_NO_KEYAUTHORITYSERIAL)); // "No Key Authority serial number"
 | |
|     }
 | |
|     wprintf(wszNewLine);
 | |
| 
 | |
|     if (fDisplayIssuer)
 | |
|     {
 | |
| 	hr = cuDisplayCertName(
 | |
| 			TRUE,
 | |
| 			NULL,
 | |
| 			myLoadResourceString(IDS_ISSUERNAME), // "Issuer Name"
 | |
| 			g_wszPad4,
 | |
| 			pIssuer);
 | |
| 	_JumpIfError(hr, error, "cuDisplayCertName(Issuer)");
 | |
| 
 | |
| 	if (NULL != pAuthorityCertIssuerName)
 | |
| 	{
 | |
| 	    hr = cuDisplayCertName(
 | |
| 			    TRUE,
 | |
| 			    NULL,
 | |
| 			    myLoadResourceString(IDS_KEYAUTHORITYNAME), // "KeyAuthority
 | |
| 			    g_wszPad4,
 | |
| 			    pAuthorityCertIssuerName);
 | |
| 	    _JumpIfError(hr, error, "cuDisplayCertName(KeyAuthority)");
 | |
| 	}
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(myLoadResourceString(IDS_KEYID)); // "KeyId:"
 | |
| 	wprintf(wszNewLine);
 | |
| 
 | |
| 	DumpHex(DH_NOTABPREFIX | 4, pcaki->KeyId.pbData, pcaki->KeyId.cbData);
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
| 
 | |
| 	hr = cuDumpSerial(
 | |
| 		    NULL,
 | |
| 		    IDS_KEYAUTHORITYSERIAL,
 | |
| 		    &pcaki->AuthorityCertSerialNumber);
 | |
| 	_JumpIfError(hr, error, "cuDumpSerial");
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
| 
 | |
| 	hr = cuDumpSerial(NULL, IDS_CASERIAL, &pCertInfoCA->SerialNumber);
 | |
| 	_JumpIfError(hr, error, "cuDumpSerial");
 | |
|     }
 | |
| 
 | |
| error:
 | |
|     if (NULL != pcaki)
 | |
|     {
 | |
| 	LocalFree(const_cast<CERT_AUTHORITY_KEY_ID2_INFO *>(pcaki));
 | |
|     }
 | |
|     if (NULL != pbHash)
 | |
|     {
 | |
| 	LocalFree(pbHash);
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| static DWORD s_adwProvType[] =
 | |
| {
 | |
|     PROV_RSA_FULL,
 | |
|     PROV_RSA_SIG,
 | |
|     PROV_DSS,
 | |
|     PROV_FORTEZZA,
 | |
|     PROV_MS_EXCHANGE,
 | |
|     PROV_SSL,
 | |
|     PROV_RSA_SCHANNEL,
 | |
|     PROV_DSS_DH,
 | |
|     PROV_EC_ECDSA_SIG,
 | |
|     PROV_EC_ECNRA_SIG,
 | |
|     PROV_EC_ECDSA_FULL,
 | |
|     PROV_EC_ECNRA_FULL,
 | |
|     PROV_DH_SCHANNEL,
 | |
|     PROV_SPYRUS_LYNKS,
 | |
|     PROV_RNG,
 | |
|     PROV_INTEL_SEC,
 | |
| };
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| cuLoadKeys(
 | |
|     OPTIONAL IN WCHAR const *pwszProvName,
 | |
|     IN OUT DWORD *pdwProvType,
 | |
|     IN WCHAR const *pwszKeyContainerName,
 | |
|     IN BOOL fMachineKeyset,
 | |
|     IN BOOL fSoftFail,
 | |
|     OPTIONAL OUT HCRYPTPROV *phProv,
 | |
|     OPTIONAL OUT CERT_PUBLIC_KEY_INFO **ppPubKeyInfo,
 | |
|     OPTIONAL OUT CERT_PUBLIC_KEY_INFO **ppPubKeyInfoXchg)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     HRESULT hr2;
 | |
|     HCRYPTPROV hProv = NULL;
 | |
|     DWORD cb;
 | |
|     DWORD *pdwProvTypeT = pdwProvType;
 | |
|     DWORD *pdwProvTypeEnd = &pdwProvTypeT[1];
 | |
|     DWORD dwSilent = g_fCryptSilent? CRYPT_SILENT : 0;
 | |
|     CERT_PUBLIC_KEY_INFO *pPubKeyInfo = NULL;
 | |
|     CERT_PUBLIC_KEY_INFO *pPubKeyInfoXchg = NULL;
 | |
| 
 | |
|     if (NULL != phProv)
 | |
|     {
 | |
| 	*phProv = NULL;
 | |
|     }
 | |
|     if (NULL != ppPubKeyInfo)
 | |
|     {
 | |
| 	*ppPubKeyInfo = NULL;
 | |
|     }
 | |
|     if (NULL != ppPubKeyInfoXchg)
 | |
|     {
 | |
| 	*ppPubKeyInfoXchg = NULL;
 | |
|     }
 | |
| 
 | |
|     // If no provider type was specified, try them all
 | |
| 
 | |
|     if (0 == *pdwProvTypeT)
 | |
|     {
 | |
| 	pdwProvTypeT = s_adwProvType;
 | |
| 	pdwProvTypeEnd = &s_adwProvType[ARRAYSIZE(s_adwProvType)];
 | |
|     }
 | |
| 
 | |
|     hr = S_OK;
 | |
|     for ( ; pdwProvTypeT < pdwProvTypeEnd; pdwProvTypeT++)
 | |
|     {
 | |
| 	DBGPRINT((
 | |
| 	    DBG_SS_CERTUTILI,
 | |
| 	    "myCertSrvCryptAcquireContext(%ws, t=%x, f=%x, m=%x)\n",
 | |
| 	    pwszKeyContainerName,
 | |
| 	    *pdwProvTypeT,
 | |
| 	    dwSilent,
 | |
| 	    fMachineKeyset));
 | |
| 
 | |
| 	if (myCertSrvCryptAcquireContext(
 | |
| 			    &hProv,
 | |
| 			    pwszKeyContainerName,
 | |
| 			    pwszProvName,
 | |
| 			    *pdwProvTypeT,
 | |
| 			    dwSilent,		// dwFlags
 | |
| 			    fMachineKeyset))
 | |
| 	{
 | |
| 	    hr = S_OK;
 | |
| 	    break;
 | |
| 	}
 | |
| 	hr2 = myHLastError();
 | |
| 	if (S_OK == hr ||
 | |
| 	    (NTE_BAD_PROV_TYPE != hr2 &&
 | |
| 	     NTE_PROV_TYPE_NOT_DEF != hr2 &&
 | |
| 	     NTE_BAD_KEYSET != hr2))
 | |
| 	{
 | |
| 	    hr = hr2;
 | |
| 	}
 | |
| 	_PrintErrorStr2(
 | |
| 		hr2,
 | |
| 		"myCertSrvCryptAcquireContext",
 | |
| 		pwszKeyContainerName,
 | |
| 		hr2);
 | |
| 	if (NTE_BAD_FLAGS == hr2 &&
 | |
| 	    PROV_MS_EXCHANGE == *pdwProvTypeT &&
 | |
| 	    ((CRYPT_SILENT & dwSilent) || fMachineKeyset))
 | |
| 	{
 | |
| 	    DBGPRINT((
 | |
| 		DBG_SS_CERTUTILI,
 | |
| 		"myCertSrvCryptAcquireContext(%ws, t=%x, f=%x, m=%x)\n",
 | |
| 		pwszKeyContainerName,
 | |
| 		*pdwProvTypeT,
 | |
| 		0,
 | |
| 		FALSE));
 | |
| 
 | |
| 	    if (myCertSrvCryptAcquireContext(
 | |
| 				&hProv,
 | |
| 				pwszKeyContainerName,
 | |
| 				pwszProvName,
 | |
| 				*pdwProvTypeT,
 | |
| 				0,		// dwFlags
 | |
| 				FALSE))
 | |
| 	    {
 | |
| 		hr = S_OK;
 | |
| 		break;
 | |
| 	    }
 | |
| 	    hr2 = myHLastError();
 | |
| 	    _PrintErrorStr2(
 | |
| 		    hr2,
 | |
| 		    "myCertSrvCryptAcquireContext",
 | |
| 		    pwszKeyContainerName,
 | |
| 		    hr2);
 | |
| 	}
 | |
|     }
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	cuPrintErrorAndString(
 | |
| 			L"CryptAcquireContext",
 | |
| 			0,
 | |
| 			hr,
 | |
| 			pwszKeyContainerName);
 | |
| 	goto error;
 | |
|     }
 | |
| 
 | |
|     // export the public key blob
 | |
| 
 | |
|     if (NULL != ppPubKeyInfo &&
 | |
| 	!myCryptExportPublicKeyInfo(
 | |
| 				hProv,
 | |
| 				AT_SIGNATURE,
 | |
| 				CERTLIB_USE_LOCALALLOC,
 | |
| 				&pPubKeyInfo,
 | |
| 				&cb))
 | |
|     {
 | |
| 	hr = myHLastError();
 | |
| 	if (!fSoftFail)
 | |
| 	{
 | |
| 	    cuPrintErrorAndString(
 | |
| 			    L"CryptExportPublicKeyInfo",
 | |
| 			    0,
 | |
| 			    hr,
 | |
| 			    L"AT_SIGNATURE");
 | |
| 	    goto error;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     if (NULL != ppPubKeyInfoXchg &&
 | |
| 	!myCryptExportPublicKeyInfo(
 | |
| 				hProv,
 | |
| 				AT_KEYEXCHANGE,
 | |
| 				CERTLIB_USE_LOCALALLOC,
 | |
| 				&pPubKeyInfoXchg,
 | |
| 				&cb))
 | |
|     {
 | |
| 	hr = myHLastError();
 | |
| 	if (!fSoftFail)
 | |
| 	{
 | |
| 	    cuPrintErrorAndString(
 | |
| 			    L"CryptExportPublicKeyInfo",
 | |
| 			    0,
 | |
| 			    hr,
 | |
| 			    L"AT_KEYEXCHANGE");
 | |
| 	    goto error;
 | |
| 	}
 | |
|     }
 | |
|     *pdwProvType = *pdwProvTypeT;
 | |
|     if (NULL != phProv)
 | |
|     {
 | |
| 	*phProv = hProv;
 | |
| 	hProv = NULL;
 | |
|     }
 | |
|     if (NULL != ppPubKeyInfo)
 | |
|     {
 | |
| 	*ppPubKeyInfo = pPubKeyInfo;
 | |
| 	pPubKeyInfo = NULL;
 | |
|     }
 | |
|     if (NULL != ppPubKeyInfoXchg)
 | |
|     {
 | |
| 	*ppPubKeyInfoXchg = pPubKeyInfoXchg;
 | |
| 	pPubKeyInfoXchg = NULL;
 | |
|     }
 | |
|     hr = S_OK;
 | |
| 
 | |
| error:
 | |
|     if (NULL != pPubKeyInfo)
 | |
|     {
 | |
| 	LocalFree(pPubKeyInfo);
 | |
|     }
 | |
|     if (NULL != pPubKeyInfoXchg)
 | |
|     {
 | |
| 	LocalFree(pPubKeyInfoXchg);
 | |
|     }
 | |
|     if (NULL != hProv)
 | |
|     {
 | |
| 	CryptReleaseContext(hProv, 0);
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| VerifyPrivateKey(
 | |
|     IN CERT_CONTEXT const *pCertContextCA,
 | |
|     IN WCHAR const *pwszSanitizedCA,
 | |
|     IN WCHAR const *pwszKeyContainerName,
 | |
|     OUT BOOL *pfMatchFailed)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     DWORD dwProvType;
 | |
|     WCHAR *pwszProvName = NULL;
 | |
|     ALG_ID idAlg;
 | |
|     BOOL fMachineKeyset;
 | |
| 
 | |
|     *pfMatchFailed = TRUE;
 | |
| 
 | |
|     // get provider name
 | |
| 
 | |
|     hr = myGetCertSrvCSP(
 | |
| 		    FALSE,		// fEncryptionCSP
 | |
| 		    pwszSanitizedCA,
 | |
| 		    &dwProvType,
 | |
| 		    &pwszProvName,
 | |
| 		    &idAlg,
 | |
| 		    &fMachineKeyset,
 | |
| 		    NULL);		// pdwKeySize
 | |
|     _JumpIfError(hr, error, "myGetCertSrvCSP");
 | |
| 
 | |
|     hr = myValidateHashForSigning(
 | |
| 		    pwszKeyContainerName,
 | |
| 		    pwszProvName,
 | |
| 		    dwProvType,
 | |
| 		    fMachineKeyset,
 | |
| 		    &pCertContextCA->pCertInfo->SubjectPublicKeyInfo,
 | |
| 		    idAlg);
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	_PrintError(hr, "myValidateHashForSigning");
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	*pfMatchFailed = FALSE;
 | |
|     }
 | |
|     hr = S_OK;
 | |
| 
 | |
| error:
 | |
|     if (NULL != pwszProvName)
 | |
|     {
 | |
| 	LocalFree(pwszProvName);
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| VerifyCAKeys(
 | |
|     IN CERT_CONTEXT const *pCertContextCA,
 | |
|     IN WCHAR const *pwszSanitizedCA,
 | |
|     IN WCHAR const *pwszCertNameCA,
 | |
|     IN WCHAR const *pwszKeyContainerName)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     CERT_PUBLIC_KEY_INFO *pPubKeyInfo = NULL;
 | |
|     BOOL fMatchFailed = FALSE;
 | |
|     BOOL fSignatureFailed = FALSE;
 | |
|     WCHAR *pwszRevert = NULL;
 | |
|     DWORD dwNameId;
 | |
|     CRYPT_KEY_PROV_INFO kpi;
 | |
|     CRYPT_KEY_PROV_INFO *pkpi = NULL;
 | |
|     DWORD cbkpi;
 | |
| 
 | |
|     ZeroMemory(&kpi, sizeof(kpi));
 | |
|     hr = myGetNameId(pCertContextCA, &dwNameId);
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	_PrintError(hr, "myGetNameId");
 | |
| 	dwNameId = MAXDWORD;
 | |
|     }
 | |
|     hr = myRevertSanitizeName(pwszKeyContainerName, &pwszRevert);
 | |
|     _JumpIfError(hr, error, "myRevertSanitizeName");
 | |
| 
 | |
|     if (!myCertGetCertificateContextProperty(
 | |
| 			pCertContextCA,
 | |
| 			CERT_KEY_PROV_INFO_PROP_ID,
 | |
| 			CERTLIB_USE_LOCALALLOC,
 | |
| 			(VOID **) &pkpi,
 | |
| 			&cbkpi))
 | |
|     {
 | |
| 	hr = myHLastError();
 | |
| 	_PrintError(hr, "myCertGetCertificateContextProperty");
 | |
| 
 | |
| 	kpi.pwszContainerName = const_cast<WCHAR *>(pwszKeyContainerName);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	kpi = *pkpi;
 | |
| 	if (0 != lstrcmp(pwszKeyContainerName, pkpi->pwszContainerName))
 | |
| 	{
 | |
| 	    wprintf(
 | |
| 		L"%ws --> %ws\n",
 | |
| 		pwszKeyContainerName,
 | |
| 		pkpi->pwszContainerName);
 | |
| 
 | |
| 	    kpi.pwszContainerName = pkpi->pwszContainerName;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     // Load public key
 | |
| 
 | |
|     hr = cuLoadKeys(
 | |
| 		kpi.pwszProvName,
 | |
| 		&kpi.dwProvType,
 | |
| 		kpi.pwszContainerName,
 | |
| 		TRUE,			// fMachineKeyset
 | |
| 		FALSE,			// fSoftFail
 | |
| 		NULL,			// phProv
 | |
| 		&pPubKeyInfo,
 | |
| 		NULL);
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	cuPrintError(IDS_ERR_FORMAT_LOADKEYS, hr);
 | |
| 	goto error;
 | |
|     }
 | |
| 
 | |
|     // see if the public key matches the certificate's public key
 | |
| 
 | |
|     if (!CertComparePublicKeyInfo(
 | |
| 			    X509_ASN_ENCODING,
 | |
| 			    pPubKeyInfo,
 | |
| 			    &pCertContextCA->pCertInfo->SubjectPublicKeyInfo))
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(myLoadResourceString(IDS_ERR_PUBLICKEY_MISMATCH)); // "ERROR: Certificate public key does NOT match stored keyset"
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 
 | |
| 	fMatchFailed = TRUE;
 | |
|     }
 | |
| 
 | |
|     if (!fMatchFailed)
 | |
|     {
 | |
| 	hr = VerifyPrivateKey(
 | |
| 			pCertContextCA,
 | |
| 			pwszSanitizedCA,
 | |
| 			kpi.pwszContainerName,
 | |
| 			&fSignatureFailed);
 | |
| 	_JumpIfError(hr, error, "VerifyPrivateKey");
 | |
|     }
 | |
| 
 | |
|     if (g_fVerbose || fMatchFailed)
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(myLoadResourceString(IDS_CONTAINER_PUBLIC_KEY)); // "Container Public Key:"
 | |
| 	wprintf(wszNewLine);
 | |
| 	DumpHex(
 | |
| 	    DH_NOTABPREFIX | 4,
 | |
| 	    pPubKeyInfo->PublicKey.pbData,
 | |
| 	    pPubKeyInfo->PublicKey.cbData);
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(myLoadResourceString(IDS_CERT_PUBLIC_KEY)); // "Certificate Public Key:"
 | |
| 	wprintf(wszNewLine);
 | |
| 	DumpHex(
 | |
| 	    DH_NOTABPREFIX | 4,
 | |
| 	    pCertContextCA->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData,
 | |
| 	    pCertContextCA->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData);
 | |
|     }
 | |
| 
 | |
| error:
 | |
|     if (S_OK == hr)
 | |
|     {
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(
 | |
| 		fMatchFailed?
 | |
| 		    IDS_FORMAT_KEY_NOT_VERIFY : // "%ws does NOT verify as the public key in %ws"
 | |
| 		    IDS_FORMAT_KEY_IS_VERIFY),  // "%ws verifies as the public key in %ws"
 | |
| 	    pwszRevert,
 | |
| 	    pwszCertNameCA);
 | |
| 
 | |
| 	if (MAXDWORD != dwNameId)
 | |
| 	{
 | |
| 	    wprintf(
 | |
| 		L" V%u.%u",
 | |
| 		CANAMEIDTOICERT(dwNameId),
 | |
| 		CANAMEIDTOIKEY(dwNameId));
 | |
| 	}
 | |
| 
 | |
| 	if (fMatchFailed || fSignatureFailed)
 | |
| 	{
 | |
| 	    hr = E_INVALIDARG;
 | |
| 	    if (fSignatureFailed)
 | |
| 	    {
 | |
| 		wprintf(L" -- ");
 | |
| 		wprintf(myLoadResourceString(IDS_SIGNATURE_BAD)); // "Signature test FAILED"
 | |
| 	    }
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	    wprintf(L" -- ");
 | |
| 	    wprintf(myLoadResourceString(IDS_SIGNATURE_OK)); // "Signature test passed"
 | |
| 	}
 | |
| 	wprintf(wszNewLine);
 | |
|     }
 | |
|     if (NULL != pwszRevert)
 | |
|     {
 | |
| 	LocalFree(pwszRevert);
 | |
|     }
 | |
|     if (NULL != pPubKeyInfo)
 | |
|     {
 | |
| 	LocalFree(pPubKeyInfo);
 | |
|     }
 | |
|     if (NULL != pkpi)
 | |
|     {
 | |
| 	LocalFree(pkpi);
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| VerifyAllCAKeys(
 | |
|     IN WCHAR const *pwszCA,
 | |
|     IN WCHAR const *pwszSanitizedCA)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     WCHAR *pwszCertName = NULL;
 | |
|     DWORD cCACerts;
 | |
|     DWORD iHash;
 | |
|     HCERTSTORE hMyStore = NULL;
 | |
|     CERT_CONTEXT const *pccCA = NULL;
 | |
|     CRYPT_KEY_PROV_INFO *pkpi = NULL;
 | |
|     DWORD cbkpi;
 | |
| 
 | |
|     hr = myGetCARegHashCount(pwszSanitizedCA, CSRH_CASIGCERT, &cCACerts);
 | |
|     if (S_OK == hr && 0 == cCACerts)
 | |
|     {
 | |
| 	hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
 | |
|     }
 | |
|     _JumpIfError(hr, error, "myGetCARegHashCount");
 | |
| 
 | |
|     // open MY store
 | |
| 
 | |
|     hMyStore = CertOpenStore(
 | |
| 		       CERT_STORE_PROV_SYSTEM_W,
 | |
| 		       X509_ASN_ENCODING,
 | |
| 		       NULL,			// hProv
 | |
| 		       CERT_SYSTEM_STORE_LOCAL_MACHINE,
 | |
| 		       wszMY_CERTSTORE);
 | |
|     if (NULL == hMyStore)
 | |
|     {
 | |
|         hr = myHLastError();
 | |
|         _JumpError(hr, error, "CertOpenStore");
 | |
|     }
 | |
| 
 | |
|     for (iHash = 0; iHash < cCACerts; iHash++)
 | |
|     {
 | |
| 	DWORD NameId;
 | |
| 	
 | |
| 	hr = myFindCACertByHashIndex(
 | |
| 				hMyStore,
 | |
| 				pwszSanitizedCA,
 | |
| 				CSRH_CASIGCERT,
 | |
| 				iHash,
 | |
| 				&NameId,
 | |
| 				&pccCA);
 | |
| 	if (S_FALSE == hr)
 | |
| 	{
 | |
| 	    continue;
 | |
| 	}
 | |
| 	_JumpIfError(hr, error, "myFindCACertByHashIndex");
 | |
| 
 | |
| 	// get the private key provider info
 | |
| 
 | |
| 	if (!myCertGetCertificateContextProperty(
 | |
| 			    pccCA,
 | |
| 			    CERT_KEY_PROV_INFO_PROP_ID,
 | |
| 			    CERTLIB_USE_LOCALALLOC,
 | |
| 			    (VOID **) &pkpi,
 | |
| 			    &cbkpi))
 | |
| 	{
 | |
| 	    hr = myHLastError();
 | |
| 	    _JumpError(hr, error, "myCertGetCertificateContextProperty");
 | |
| 	}
 | |
| 
 | |
| 	if (MAXDWORD == NameId)
 | |
| 	{
 | |
| 	    NameId = MAKECANAMEID(iHash, iHash);
 | |
| 	}
 | |
| 	hr = myAllocIndexedName(
 | |
| 			pwszCA,
 | |
| 			CANAMEIDTOICERT(NameId),
 | |
| 			&pwszCertName);
 | |
| 	_JumpIfError(hr, error, "myAllocIndexedName");
 | |
| 
 | |
| 	hr = VerifyCAKeys(
 | |
| 		    pccCA,
 | |
| 		    pwszSanitizedCA,
 | |
| 		    pwszCertName,
 | |
| 		    pkpi->pwszContainerName);
 | |
| 	_JumpIfError(hr, error, "VerifyCAKeys");
 | |
| 
 | |
| 	CertFreeCertificateContext(pccCA);
 | |
| 	pccCA = NULL;
 | |
| 
 | |
| 	LocalFree(pkpi);
 | |
| 	pkpi = NULL;
 | |
| 
 | |
| 	LocalFree(pwszCertName);
 | |
| 	pwszCertName = NULL;
 | |
|     }
 | |
| 
 | |
| error:
 | |
|     if (NULL != pkpi)
 | |
|     {
 | |
| 	LocalFree(pkpi);
 | |
|     }
 | |
|     if (NULL != pccCA)
 | |
|     {
 | |
| 	CertFreeCertificateContext(pccCA);
 | |
|     }
 | |
|     if (NULL != hMyStore)
 | |
|     {
 | |
|         CertCloseStore(hMyStore, CERT_CLOSE_STORE_CHECK_FLAG);
 | |
|     }
 | |
|     if (NULL != pwszCertName)
 | |
|     {
 | |
| 	LocalFree(pwszCertName);
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| verbVerifyKeys(
 | |
|     IN WCHAR const *pwszOption,
 | |
|     OPTIONAL IN WCHAR const *pwszKeyContainerName,
 | |
|     OPTIONAL IN WCHAR const *pwszfnCertCA,
 | |
|     OPTIONAL IN WCHAR const *pwszArg3,
 | |
|     OPTIONAL IN WCHAR const *pwszArg4)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     CERT_CONTEXT const *pCertContextCA = NULL;
 | |
|     WCHAR *pwszCA = NULL;
 | |
|     WCHAR *pwszSanitizedCA = NULL;
 | |
|     WCHAR *pwszRevertContainer = NULL;
 | |
|     WCHAR *pwszSanitizedContainer = NULL;
 | |
| 
 | |
|     hr = cuGetLocalCANameFromConfig(NULL, &pwszCA);
 | |
|     _JumpIfError(hr, error, "GetLocalCANameFromConfig");
 | |
| 
 | |
|     hr = mySanitizeName(pwszCA, &pwszSanitizedCA);
 | |
|     _JumpIfError(hr, error, "mySanitizeName");
 | |
| 
 | |
|     if (NULL == pwszfnCertCA)
 | |
|     {
 | |
| 	if (NULL != pwszKeyContainerName)
 | |
| 	{
 | |
| 	    hr = E_INVALIDARG;
 | |
| 	    _JumpError(hr, error, "extra arg");
 | |
| 	}
 | |
| 
 | |
| 	hr = VerifyAllCAKeys(pwszCA, pwszSanitizedCA);
 | |
| 	_JumpIfError(hr, error, "VerifyAllCAKeys");
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	hr = myRevertSanitizeName(pwszKeyContainerName, &pwszRevertContainer);
 | |
| 	_JumpIfError(hr, error, "myRevertSanitizeName");
 | |
| 
 | |
| 	hr = cuSanitizeNameWithSuffix(
 | |
| 			    pwszRevertContainer,
 | |
| 			    &pwszSanitizedContainer);
 | |
| 	_JumpIfError(hr, error, "cuSanitizeNameWithSuffix");
 | |
| 
 | |
| 	// Load and decode CA certificate
 | |
| 
 | |
| 	hr = cuLoadCert(pwszfnCertCA, &pCertContextCA);
 | |
| 	if (S_OK != hr)
 | |
| 	{
 | |
| 	    cuPrintError(IDS_ERR_FORMAT_LOADCACERT, hr);
 | |
| 	    goto error;
 | |
| 	}
 | |
| 
 | |
| 	hr = VerifyCAKeys(
 | |
| 		    pCertContextCA,
 | |
| 		    pwszSanitizedCA,
 | |
| 		    pwszfnCertCA,
 | |
| 		    pwszSanitizedContainer);
 | |
| 	_JumpIfError(hr, error, "VerifyCAKeys");
 | |
|     }
 | |
| 
 | |
| error:
 | |
|     cuUnloadCert(&pCertContextCA);
 | |
|     if (NULL != pwszSanitizedCA)
 | |
|     {
 | |
| 	LocalFree(pwszSanitizedCA);
 | |
|     }
 | |
|     if (NULL != pwszCA)
 | |
|     {
 | |
| 	LocalFree(pwszCA);
 | |
|     }
 | |
|     if (NULL != pwszSanitizedContainer)
 | |
|     {
 | |
| 	LocalFree(pwszSanitizedContainer);
 | |
|     }
 | |
|     if (NULL != pwszRevertContainer)
 | |
|     {
 | |
| 	LocalFree(pwszRevertContainer);
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| VOID
 | |
| cuDumpPolicies(
 | |
|     IN UINT idMsg,
 | |
|     IN WCHAR const *pwszzPolicies)
 | |
| {
 | |
|     if (NULL != pwszzPolicies)
 | |
|     {
 | |
| 	wprintf(L"%ws:\n", myLoadResourceString(idMsg));
 | |
| 
 | |
| 	for ( ;
 | |
| 	     L'\0' != *pwszzPolicies;
 | |
| 	     pwszzPolicies += wcslen(pwszzPolicies) + 1)
 | |
| 	{
 | |
| 	    wprintf(g_wszPad4);
 | |
| 	    cuDumpOIDAndDescription(pwszzPolicies);
 | |
| 	    wprintf(wszNewLine);
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| cuVerifyCertContext(
 | |
|     IN CERT_CONTEXT const *pCert,
 | |
|     OPTIONAL IN HCERTSTORE hStoreCA,
 | |
|     OPTIONAL IN char *apszPolicies[],
 | |
|     IN DWORD cPolicies,
 | |
|     OUT DWORD *pVerifyState)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     DWORD idMsg;
 | |
|     WCHAR *pwszMissingIssuer = NULL;
 | |
|     WCHAR *pwszzIssuancePolicies = NULL;
 | |
|     WCHAR *pwszzApplicationPolicies = NULL;
 | |
|     DWORD Flags;
 | |
|     char *apszEnrollOids[] = { szOID_ENROLLMENT_AGENT };
 | |
| 
 | |
|     *pVerifyState = 0;
 | |
|     if (CertCompareCertificateName(
 | |
| 		    X509_ASN_ENCODING,
 | |
| 		    &pCert->pCertInfo->Issuer,
 | |
| 		    &pCert->pCertInfo->Subject))
 | |
|     {
 | |
| 	*pVerifyState |= VS_ROOT;
 | |
| #if 0
 | |
| 	hr = cuVerifySignature(
 | |
| 			pCert->pbCertEncoded,
 | |
| 			pCert->cbCertEncoded,
 | |
| 			&pCert->pCertInfo->SubjectPublicKeyInfo,
 | |
| 			FALSE);
 | |
| 	if (S_OK == hr)
 | |
| 	{
 | |
| 	    *pVerifyState |= VS_ROOTSIGOK;
 | |
| 	}
 | |
| 	_PrintIfError(hr, "cuVerifySignature");
 | |
| #endif
 | |
|     }
 | |
| 
 | |
|     // Verify the cert and chain:
 | |
|     Flags = 0;
 | |
|     if (g_fEnterpriseRegistry)
 | |
|     {
 | |
| 	Flags |= CA_VERIFY_FLAGS_NT_AUTH;
 | |
| 	if (NULL == apszPolicies || 0 == cPolicies)
 | |
| 	{
 | |
| 	    apszPolicies = apszEnrollOids;
 | |
| 	    cPolicies = ARRAYSIZE(apszEnrollOids);
 | |
| 	}
 | |
|     }
 | |
|     if (g_fForce)
 | |
|     {
 | |
| 	Flags |= CA_VERIFY_FLAGS_IGNORE_OFFLINE |
 | |
| 		    CA_VERIFY_FLAGS_ALLOW_UNTRUSTED_ROOT;
 | |
| 	if (1 < g_fForce)
 | |
| 	{
 | |
| 	    Flags |= CA_VERIFY_FLAGS_NO_REVOCATION;
 | |
| 	}
 | |
|     }
 | |
|     if (!g_fQuiet)
 | |
|     {
 | |
| 	Flags |= CA_VERIFY_FLAGS_DUMP_CHAIN;
 | |
|     }
 | |
|     if (g_fSplitASN)
 | |
|     {
 | |
| 	Flags |= CA_VERIFY_FLAGS_SAVE_CHAIN;
 | |
|     }
 | |
| 
 | |
|     hr = myVerifyCertContextEx(
 | |
| 			pCert,
 | |
|                         Flags,
 | |
| 			cPolicies,
 | |
| 			apszPolicies,
 | |
| 			g_fUserRegistry? HCCE_CURRENT_USER : HCCE_LOCAL_MACHINE,
 | |
| 			NULL,			// pft
 | |
| 			hStoreCA,		// hAdditionalStore
 | |
| 			&pwszMissingIssuer,
 | |
| 			&pwszzIssuancePolicies,
 | |
| 			&pwszzApplicationPolicies);
 | |
| 
 | |
|     cuDumpPolicies(IDS_ISSUANCE_POLICIES, pwszzIssuancePolicies);
 | |
|     cuDumpPolicies(IDS_APPLICATION_POLICIES, pwszzApplicationPolicies);
 | |
| 
 | |
|     idMsg = 0;
 | |
|     if (CRYPT_E_REVOKED == hr)
 | |
|     {
 | |
| 	idMsg = IDS_REVOKED_CERT;	// "Certificate is REVOKED"
 | |
| 	*pVerifyState |= VS_REVOKED;
 | |
|     }
 | |
|     else if (CERT_E_UNTRUSTEDROOT == hr)
 | |
|     {
 | |
| 	idMsg = IDS_UNTRUSTED_ROOT;	// "Verifies against UNTRUSTED root"
 | |
| 	*pVerifyState |= VS_UNTRUSTEDROOT;
 | |
|     }
 | |
|     else if (CERT_E_CHAINING == hr)
 | |
|     {
 | |
| 	idMsg = IDS_INCOMPLETE_CHAIN;	// "Incomplete certificate chain"
 | |
| 	*pVerifyState |= VS_INCOMPLETECHAIN;
 | |
|     }
 | |
|     else if (CERT_E_EXPIRED == hr)
 | |
|     {
 | |
| 	idMsg = IDS_EXPIRED_CERT;	// "Expired certificate"
 | |
| 	*pVerifyState |= VS_EXPIRED;
 | |
|     }
 | |
|     else if (CRYPT_E_REVOCATION_OFFLINE == hr)
 | |
|     {
 | |
| 	idMsg = IDS_REVOCATION_OFFLINE;	// "Revocation check skipped -- server offline"
 | |
| 	*pVerifyState |= VS_REVOCATIONOFFLINE;
 | |
|     }
 | |
|     else if (CRYPT_E_NO_REVOCATION_CHECK == hr)
 | |
|     {
 | |
| 	idMsg = IDS_NO_REVOCATION_CHECK; // "Revocation check skipped -- no revocation information available"
 | |
| 	*pVerifyState |= VS_NOREVOCATIONCHECK;
 | |
|     }
 | |
|     if (0 != idMsg)
 | |
|     {
 | |
| 	wprintf(myLoadResourceString(idMsg));
 | |
| 	wprintf(wszNewLine);
 | |
| 	if (NULL != pwszMissingIssuer)
 | |
| 	{
 | |
| 	    wprintf(myLoadResourceString(IDS_MISSING_CERT));
 | |
| 	    wprintf(L"\n    %ws\n", pwszMissingIssuer);
 | |
| 	}
 | |
| 	hr = S_OK;
 | |
|     }
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	*pVerifyState |= VS_OTHERERROR;
 | |
|     }
 | |
|     _JumpIfError(hr, error, "cuVerifyCertContext");
 | |
| 
 | |
| error:
 | |
|     if (NULL != pwszMissingIssuer)
 | |
|     {
 | |
| 	LocalFree(pwszMissingIssuer);
 | |
|     }
 | |
|     if (NULL != pwszzIssuancePolicies)
 | |
|     {
 | |
| 	LocalFree(pwszzIssuancePolicies);
 | |
|     }
 | |
|     if (NULL != pwszzApplicationPolicies)
 | |
|     {
 | |
| 	LocalFree(pwszzApplicationPolicies);
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| #define RS_INCOMPLETE	0
 | |
| #define RS_PASS		1
 | |
| #define RS_FAIL		2
 | |
| #define RS_REVOKED	3
 | |
| 
 | |
| DWORD
 | |
| VerifyRevocation(
 | |
|     IN CERT_CONTEXT const *pCertContext,
 | |
|     OPTIONAL IN CERT_CONTEXT const *pCertContextCA)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     CERT_REVOCATION_PARA crp;
 | |
|     CERT_REVOCATION_STATUS crs;
 | |
|     DWORD RevState;
 | |
| 
 | |
|     ZeroMemory(&crp, sizeof(crp));
 | |
|     crp.cbSize = sizeof(crp);
 | |
|     crp.pIssuerCert = pCertContextCA;
 | |
| 
 | |
|     ZeroMemory(&crs, sizeof(crs));
 | |
|     crs.cbSize = sizeof(crs);
 | |
| 
 | |
|     if (!CertVerifyRevocation(
 | |
| 			X509_ASN_ENCODING,
 | |
| 			CERT_CONTEXT_REVOCATION_TYPE,
 | |
| 			1,				// cContext
 | |
| 			(VOID **) &pCertContext,	// rgpContext
 | |
| 			0,				// dwFlags
 | |
| 			&crp,
 | |
| 			&crs))
 | |
|     {
 | |
| 	hr = myHLastError();
 | |
| 	if (CRYPT_E_REVOKED == hr)
 | |
| 	{
 | |
| 	    wprintf(
 | |
| 		myLoadResourceString(IDS_FORMAT_IS_REVOKED), // "Certificate is REVOKED (Reason=%x)"
 | |
| 		crs.dwReason);
 | |
| 	    wprintf(wszNewLine);
 | |
| 	    RevState = RS_REVOKED;
 | |
| 	    goto error;
 | |
| 	}
 | |
| 	if (CRYPT_E_NO_REVOCATION_CHECK != hr)
 | |
| 	{
 | |
| 	    wprintf(wszNewLine);
 | |
| 	    cuPrintError(IDS_ERR_FORMAT_VERIFY_REVSTATUS, hr); // "ERROR: Verify Revocation Status returned %ws"
 | |
| 	    cuPrintErrorMessageText(hr);
 | |
| 	    wprintf(wszNewLine);
 | |
| 
 | |
| 	    RevState = RS_FAIL;
 | |
| 	    goto error;
 | |
| 	}
 | |
| 	wprintf(myLoadResourceString(IDS_CANNOT_CHECK_REVSTATUS));  // "Cannot check revocation status"
 | |
| 	wprintf(wszNewLine);
 | |
| 
 | |
| 	RevState = RS_INCOMPLETE;
 | |
| 	goto error;
 | |
|     }
 | |
|     wprintf(myLoadResourceString(IDS_REVSTATUS_OK)); // "Revocation check passed"
 | |
|     wprintf(wszNewLine);
 | |
|     RevState = RS_PASS;
 | |
| 
 | |
| error:
 | |
|     return(RevState);
 | |
| }
 | |
| 
 | |
| 
 | |
| #define CAS_UNKNOWN	0
 | |
| #define CAS_CA		1
 | |
| #define CAS_ENDENTITY	2
 | |
| 
 | |
| VOID
 | |
| VerifyCACert(
 | |
|     IN CERT_INFO const *pCertInfo,
 | |
|     IN BOOL fCA,
 | |
|     OUT DWORD *pState)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     CERT_EXTENSION *pExt;
 | |
|     UINT id = 0;
 | |
| 
 | |
|     *pState = CAS_UNKNOWN;
 | |
| 
 | |
|     pExt = CertFindExtension(
 | |
| 			szOID_BASIC_CONSTRAINTS2,
 | |
| 			pCertInfo->cExtension,
 | |
| 			pCertInfo->rgExtension);
 | |
|     if (NULL == pExt)
 | |
|     {
 | |
| 	// This API doesn't set LastError
 | |
| 	//hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
 | |
| 	//_PrintError(hr, "CertFindExtension");
 | |
| 
 | |
| 	if (fCA)
 | |
| 	{
 | |
| 	    id = IDS_NOBASICCONSTRAINTS2_ERROR; // "ERROR: CA Cert has no Basic Constraints2 Extension"
 | |
| 	}
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	DWORD cb;
 | |
| 	CERT_BASIC_CONSTRAINTS2_INFO Constraints;
 | |
| 
 | |
| 	cb = sizeof(Constraints);
 | |
| 	if (!CryptDecodeObject(
 | |
| 			    X509_ASN_ENCODING,
 | |
| 			    X509_BASIC_CONSTRAINTS2,
 | |
| 			    pExt->Value.pbData,
 | |
| 			    pExt->Value.cbData,
 | |
| 			    0,
 | |
| 			    &Constraints,
 | |
| 			    &cb))
 | |
| 	{
 | |
| 	    hr = myHLastError();
 | |
| 	    _PrintError(hr, "CryptDecodeObject");
 | |
| 
 | |
| 	    id = IDS_CANNOTDECODEBASICCONSTRAINTS2_ERROR; // "ERROR: Cannot decode CA Cert Basic Constraints2 Extension"
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	    *pState = Constraints.fCA? CAS_CA : CAS_ENDENTITY;
 | |
| 	    if (!Constraints.fCA)
 | |
| 	    {
 | |
| 		id = IDS_ENDENTITYCACERT_ERROR; // "ERROR: CA Cert is an End Entity certificate"
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
|     if (fCA && 0 != id)
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(myLoadResourceString(id));
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
|     }
 | |
|     if (!fCA)
 | |
|     {
 | |
| 	switch (*pState)
 | |
| 	{
 | |
| 	    case CAS_CA:
 | |
| 		wprintf(myLoadResourceString(IDS_CACERT)); // "Cert is a CA certificate"
 | |
| 		wprintf(wszNewLine);
 | |
| 		break;
 | |
| 
 | |
| 	    case CAS_ENDENTITY:
 | |
| 		wprintf(myLoadResourceString(IDS_ENDENTITYCERT)); // "Cert is an End Entity certificate"
 | |
| 		wprintf(wszNewLine);
 | |
| 		break;
 | |
| 	}
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| VerifyCertAgainstChain(
 | |
|     IN WCHAR const *pwszfnCert)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     CERT_CONTEXT const *pCertContext = NULL;
 | |
|     DWORD VerifyState;
 | |
|     DWORD CertState;
 | |
|     DWORD RevState;
 | |
| 
 | |
|     // Load and decode certificates
 | |
| 
 | |
|     hr = cuLoadCert(pwszfnCert, &pCertContext);
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	cuPrintError(IDS_FORMAT_LOADTESTCERT, hr);
 | |
| 	goto error;
 | |
|     }
 | |
| 
 | |
|     // Display name info:
 | |
| 
 | |
|     hr = cuDisplayCertNames(TRUE, NULL, pCertContext->pCertInfo);
 | |
|     _JumpIfError(hr, error, "cuDisplayCertNames(Cert)");
 | |
| 
 | |
|     cuDumpSerial(NULL, IDS_CERT_SERIAL, &pCertContext->pCertInfo->SerialNumber);
 | |
|     wprintf(wszNewLine);
 | |
| 
 | |
|     hr = cuVerifyCertContext(
 | |
| 			pCertContext,	// pCert
 | |
| 			NULL,		// hStoreCA
 | |
| 			NULL,		// apszPolicies
 | |
| 			0,		// cPolicies
 | |
| 			&VerifyState);
 | |
|     _JumpIfError(hr, error, "cuVerifyCertContext");
 | |
| 
 | |
|     VerifyCACert(pCertContext->pCertInfo, FALSE, &CertState);
 | |
| 
 | |
|     if (!g_fCryptSilent)
 | |
|     {
 | |
| 	RevState = VerifyRevocation(pCertContext, NULL);
 | |
|     }
 | |
| 
 | |
| error:
 | |
|     cuUnloadCert(&pCertContext);
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| VerifyCertAgainstParent(
 | |
|     IN WCHAR const *pwszfnCert,
 | |
|     IN WCHAR const *pwszfnCertCA,
 | |
|     OUT BOOL *pfCertLoaded)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     CERT_INFO const *pCertInfo;
 | |
|     CERT_INFO const *pCertInfoCA;
 | |
|     CERT_CONTEXT const *pCertContext = NULL;
 | |
|     CERT_CONTEXT const *pCertContextCA = NULL;
 | |
|     DWORD dwFlags;
 | |
|     BOOL fDisplayCANames = g_fVerbose;
 | |
|     DWORD i;
 | |
|     BOOL fCertInvalid = FALSE;
 | |
|     DWORD RevState = RS_INCOMPLETE;
 | |
|     BOOL fCheckRevocation = FALSE;
 | |
|     SYSTEMTIME st;
 | |
|     FILETIME ft;
 | |
|     DWORD CAState;
 | |
|     DWORD CertState;
 | |
| 
 | |
|     // Load and decode certificates
 | |
| 
 | |
|     *pfCertLoaded = FALSE;
 | |
|     hr = cuLoadCert(pwszfnCert, &pCertContext);
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	if (CRYPT_E_ASN1_BADTAG != hr)
 | |
| 	{
 | |
| 	    cuPrintError(IDS_FORMAT_LOADTESTCERT, hr);
 | |
| 	}
 | |
| 	goto error;
 | |
|     }
 | |
|     *pfCertLoaded = TRUE;
 | |
|     pCertInfo = pCertContext->pCertInfo;
 | |
| 
 | |
|     hr = cuLoadCert(pwszfnCertCA, &pCertContextCA);
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	cuPrintError(IDS_FORMAT_LOADCACERT, hr);
 | |
| 	goto error;
 | |
|     }
 | |
|     pCertInfoCA = pCertContextCA->pCertInfo;
 | |
| 
 | |
|     // Display name info:
 | |
| 
 | |
|     hr = cuDisplayCertNames(
 | |
| 			TRUE,
 | |
| 			myLoadResourceString(IDS_CERT), // "Cert"
 | |
| 			pCertInfo);
 | |
|     _JumpIfError(hr, error, "cuDisplayCertNames(Cert)");
 | |
| 
 | |
|     hr = cuDisplayCertNames(
 | |
| 			TRUE,
 | |
| 			myLoadResourceString(IDS_CA), // "CA"
 | |
| 			pCertInfoCA);
 | |
|     _JumpIfError(hr, error, "cuDisplayCertNames(CA)");
 | |
| 
 | |
|     if (g_fVerbose)
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	cuDumpSerial(NULL, IDS_CERT_SERIAL, &pCertInfo->SerialNumber);
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
| 	cuDumpSerial(NULL, IDS_ROOT_SERIAL, &pCertInfoCA->SerialNumber);
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
|     }
 | |
| 
 | |
|     if (!CertCompareCertificateName(
 | |
| 		    X509_ASN_ENCODING,
 | |
| 		    const_cast<CERT_NAME_BLOB *>(&pCertInfoCA->Issuer),
 | |
| 		    const_cast<CERT_NAME_BLOB *>(&pCertInfoCA->Subject)))
 | |
|     {
 | |
| 	// This API doesn't set LastError
 | |
| 	hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
 | |
| 
 | |
| 	wprintf(myLoadResourceString(IDS_FORMAT_CA_NOT_ROOT)); // "CA is not a root: Subject name does not match Issuer"
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	hr = S_OK;
 | |
|     }
 | |
|     if (fDisplayCANames)
 | |
|     {
 | |
| 	hr = cuDisplayCertNames(
 | |
| 			    TRUE,
 | |
| 			    myLoadResourceString(IDS_CA), // "CA"
 | |
| 			    pCertInfoCA);
 | |
| 	_JumpIfError(hr, error, "cuDisplayCertNames(CA)");
 | |
|     }
 | |
| 
 | |
|     if (!CertCompareCertificateName(
 | |
| 			X509_ASN_ENCODING,
 | |
| 			const_cast<CERT_NAME_BLOB *>(&pCertInfo->Issuer),
 | |
| 			const_cast<CERT_NAME_BLOB *>(&pCertInfoCA->Subject)))
 | |
|     {
 | |
| 	// This API doesn't set LastError
 | |
| 	hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_FORMAT_CA_SUBJECT_NOT_ISSUER), // "ERROR: CA Subject name does not match Cert Issuer (%x)"
 | |
| 	    hr);
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	hr = S_OK;
 | |
| 	fCertInvalid = TRUE;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	wprintf(myLoadResourceString(IDS_CA_SUBJECT_IS_ISSUER)); // "CA Subject name matches Cert Issuer"
 | |
| 	wprintf(wszNewLine);
 | |
|     }
 | |
| 
 | |
|     GetSystemTime(&st);
 | |
|     if (!SystemTimeToFileTime(&st, &ft))
 | |
|     {
 | |
| 	hr = myHLastError();
 | |
| 	_JumpError(hr, error, "SystemTimeToFileTime");
 | |
|     }
 | |
|     if (0 < CompareFileTime(&pCertInfo->NotBefore, &ft))
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_NOWNOTBEFORE_ERROR)); // "ERROR: Cert is not yet valid"
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	fCertInvalid = TRUE;
 | |
|     }
 | |
|     if (0 > CompareFileTime(&pCertInfo->NotAfter, &ft))
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_NOWNOTAFTER_ERROR)); // "ERROR: Cert has expired"
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	fCertInvalid = TRUE;
 | |
|     }
 | |
| 
 | |
|     if (0 < CompareFileTime(&pCertInfoCA->NotBefore, &pCertInfo->NotBefore))
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_CANOTBEFORE_ERROR)); // "ERROR: Cert Valid before CA Cert Valid"
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	//fCertInvalid = TRUE;
 | |
|     }
 | |
|     if (0 > CompareFileTime(&pCertInfoCA->NotAfter, &pCertInfo->NotAfter))
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_CANOTAFTER_ERROR)); // "ERROR: Cert Expires after CA Cert Expires"
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	//fCertInvalid = TRUE;
 | |
|     }
 | |
| 
 | |
|     VerifyCACert(pCertInfoCA, TRUE, &CAState);
 | |
|     VerifyCACert(pCertInfo, FALSE, &CertState);
 | |
| 
 | |
|     hr = S_OK;
 | |
| 
 | |
|     dwFlags =
 | |
| 	CERT_STORE_SIGNATURE_FLAG |
 | |
| 	CERT_STORE_TIME_VALIDITY_FLAG;
 | |
| 	//CERT_STORE_REVOCATION_FLAG;
 | |
| 
 | |
|     if (g_fVerbose)
 | |
|     {
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_FORMAT_CERTVERIFYSUBJECTCERTIFICATECONTEXT_FLAGS), // "CertVerifySubjectCertificateContext Flags = %x --> "
 | |
| 	    dwFlags);
 | |
|     }
 | |
| 
 | |
|     if (!CertVerifySubjectCertificateContext(
 | |
| 				pCertContext,
 | |
| 				pCertContextCA,
 | |
| 				&dwFlags))
 | |
|     {
 | |
| 	hr = myHLastError();
 | |
| 	if (g_fVerbose)
 | |
| 	{
 | |
| 	    wprintf(wszNewLine);
 | |
| 	    fflush(stdout);
 | |
| 	}
 | |
| 	_JumpError(hr, error, "CertVerifySubjectCertificateContext");
 | |
|     }
 | |
|     if (g_fVerbose)
 | |
|     {
 | |
| 	wprintf(L"%x\n", dwFlags);
 | |
|     }
 | |
|     if (0 != dwFlags)
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_ERR_FORMAT_VALIDATION), // "ERROR: Certificate validation failure: %x"
 | |
| 	    dwFlags);
 | |
| 	wprintf(wszNewLine);
 | |
| 	if (CERT_STORE_SIGNATURE_FLAG & dwFlags)
 | |
| 	{
 | |
| 	    wprintf(myLoadResourceString(IDS_ERR_CA_SIG_NOT_ISSUER)); // "ERROR: CA did not issue Certificate: Signature check failed"
 | |
| 	    wprintf(wszNewLine);
 | |
| 	}
 | |
| 	if (CERT_STORE_TIME_VALIDITY_FLAG & dwFlags)
 | |
| 	{
 | |
| 	    wprintf(myLoadResourceString(IDS_ERR_EXPIRED)); // "ERROR: Certificate has expired"
 | |
| 	    wprintf(wszNewLine);
 | |
| 	}
 | |
| 	wprintf(wszNewLine);
 | |
| 	//hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
 | |
| 	fCertInvalid = TRUE;
 | |
| 	//goto error;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	wprintf(myLoadResourceString(IDS_CURRENT_SIG_OK)); // "Certificate is current and signature is valid"
 | |
| 	wprintf(wszNewLine);
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < pCertInfo->cExtension; i++)
 | |
|     {
 | |
| 	CERT_EXTENSION *pce;
 | |
| 
 | |
| 	pce = &pCertInfo->rgExtension[i];
 | |
| 	//wprintf(L"%d: %hs: %d, %x (%x)\n", i, pce->pszObjId, pce->fCritical, pce->Value.pbData, pce->Value.cbData);
 | |
| 	if (0 == strcmp(pce->pszObjId, szOID_AUTHORITY_KEY_IDENTIFIER2))
 | |
| 	{
 | |
| 	    BOOL fKeyAuthorityMatch;
 | |
| 
 | |
| 	    //wprintf(L"%d: %ws\n", i, L"szOID_AUTHORITY_KEY_IDENTIFIER2");
 | |
| 	    hr = VerifyKeyAuthority(
 | |
| 			    &pCertInfo->Issuer,
 | |
| 			    pCertInfoCA,
 | |
| 			    pce->Value.pbData,
 | |
| 			    pce->Value.cbData,
 | |
| 			    &fKeyAuthorityMatch);
 | |
| 	    _JumpIfError(hr, error, "VerifyKeyAuthority");
 | |
| 
 | |
| 	    if (!fKeyAuthorityMatch)
 | |
| 	    {
 | |
| 		fCertInvalid = TRUE;
 | |
| 	    }
 | |
| 	}
 | |
| 	else
 | |
| 	if (0 == strcmp(pce->pszObjId, szOID_KEY_ATTRIBUTES))
 | |
| 	{
 | |
| 	    //wprintf(L"%d: %ws\n", i, L"szOID_KEY_ATTRIBUTES");
 | |
| 	}
 | |
| 	else
 | |
| 	if (0 == strcmp(pce->pszObjId, szOID_CRL_DIST_POINTS))
 | |
| 	{
 | |
| 	    //wprintf(L"%d: %ws\n", i, L"szOID_CRL_DIST_POINTS");
 | |
| 	    wprintf(myLoadResourceString(IDS_CRL_DIST_POINTS)); // "Contains CRL_DIST_POINTS revocation-check extension"
 | |
| 	    wprintf(wszNewLine);
 | |
| 	    fCheckRevocation = TRUE;
 | |
| 	}
 | |
| 	else
 | |
| 	if (0 == strcmp(pce->pszObjId, szOID_NETSCAPE_REVOCATION_URL))
 | |
| 	{
 | |
| 	    //wprintf(L"%d: %ws\n", i, L"szOID_NETSCAPE_REVOCATION_URL");
 | |
| 	    wprintf(myLoadResourceString(IDS_NETSCAPE_REVOCATION_URL)); // "Contains NETSCAPE_REVOCATION_URL revocation-check extension"
 | |
| 	    wprintf(wszNewLine);
 | |
| 	    fCheckRevocation = TRUE;
 | |
| 	}
 | |
|     }
 | |
|     if (fCheckRevocation)
 | |
|     {
 | |
| 	if (!g_fCryptSilent)
 | |
| 	{
 | |
| 	    RevState = VerifyRevocation(pCertContext, pCertContextCA);
 | |
| 	}
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	wprintf(myLoadResourceString(IDS_NO_REVCHECKEXTENSION)); // "Certificate has no revocation-check extension"
 | |
| 	wprintf(wszNewLine);
 | |
| 	RevState = RS_INCOMPLETE;
 | |
|     }
 | |
| 
 | |
| error:
 | |
|     cuUnloadCert(&pCertContext);
 | |
|     cuUnloadCert(&pCertContextCA);
 | |
|     if (S_OK == hr)
 | |
|     {
 | |
| 	DWORD msgid;
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(
 | |
| 		    fCertInvalid?
 | |
| 			IDS_FORMAT_NOT_VERIFY : // "%ws does NOT verify as issued by %ws"
 | |
| 			IDS_FORMAT_IS_VERIFY), // "%ws verifies as issued by %ws"
 | |
| 	    pwszfnCert,
 | |
| 	    pwszfnCertCA);
 | |
| 
 | |
| 	switch (RevState)
 | |
| 	{
 | |
| 	    case RS_FAIL:
 | |
| 		msgid = IDS_FORMAT_REVCHECK_FAIL;	// " -- Revocation check FAILED."
 | |
| 		break;
 | |
| 
 | |
| 	    case RS_PASS:
 | |
| 		msgid = IDS_FORMAT_REVCHECK_PASS;	// " -- Revocation check passed."
 | |
| 		break;
 | |
| 
 | |
| 	    case RS_REVOKED:
 | |
| 		msgid = IDS_FORMAT_REVCHECK_REVOKED;	// " -- Revocation check: REVOKED."
 | |
| 		break;
 | |
| 
 | |
| 	    default:
 | |
| 		msgid = IDS_FORMAT_REVCHECK_SKIPPED;	// " -- Revocation check skipped."
 | |
| 		break;
 | |
| 	}
 | |
| 	wprintf(myLoadResourceString(msgid));
 | |
| 	wprintf(wszNewLine);
 | |
| 	if (fCertInvalid)
 | |
| 	{
 | |
| 	    hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
 | |
| 	}
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| VerifyCRLAgainstCACert(
 | |
|     IN WCHAR const *pwszfnCRL,
 | |
|     IN WCHAR const *pwszfnCertCA)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     CRL_CONTEXT const *pCRLContext = NULL;
 | |
|     CERT_CONTEXT const *pCertContextCA = NULL;
 | |
|     CRL_INFO const *pCRLInfo;
 | |
|     CERT_INFO const *pCertInfoCA;
 | |
|     BOOL fDisplayCANames = g_fVerbose;
 | |
|     DWORD i;
 | |
|     BOOL fCRLInvalid = FALSE;
 | |
|     SYSTEMTIME st;
 | |
|     FILETIME ft;
 | |
| 
 | |
|     // Load and decode CRL and certificate
 | |
| 
 | |
|     hr = cuLoadCRL(pwszfnCRL, &pCRLContext);
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	cuPrintError(IDS_FORMAT_LOADTESTCRL, hr);
 | |
| 	goto error;
 | |
|     }
 | |
|     pCRLInfo = pCRLContext->pCrlInfo;
 | |
| 
 | |
|     hr = cuLoadCert(pwszfnCertCA, &pCertContextCA);
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	cuPrintError(IDS_FORMAT_LOADCACERT, hr);
 | |
| 	goto error;
 | |
|     }
 | |
|     pCertInfoCA = pCertContextCA->pCertInfo;
 | |
| 
 | |
|     // Display name info:
 | |
| 
 | |
|     hr = cuDisplayCertName(
 | |
| 			TRUE,
 | |
| 			myLoadResourceString(IDS_CRL), // "CRL"
 | |
| 			myLoadResourceString(IDS_ISSUER), // "Issuer"
 | |
| 			g_wszPad4,
 | |
| 			&pCRLInfo->Issuer);
 | |
|     _JumpIfError(hr, error, "cuDisplayCertName(CRL Issuer)");
 | |
| 
 | |
|     hr = cuDisplayCertNames(
 | |
| 			TRUE,
 | |
| 			myLoadResourceString(IDS_CA), // "CA"
 | |
| 			pCertInfoCA);
 | |
|     _JumpIfError(hr, error, "cuDisplayCertNames(CA)");
 | |
| 
 | |
|     if (g_fVerbose)
 | |
|     {
 | |
| 	//wprintf(wszNewLine);
 | |
| 	//cuDumpSerial(NULL, IDS_CERT_SERIAL, &pCRLInfo->SerialNumber);
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
| 	cuDumpSerial(NULL, IDS_ROOT_SERIAL, &pCertInfoCA->SerialNumber);
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
|     }
 | |
| 
 | |
|     if (!CertCompareCertificateName(
 | |
| 			X509_ASN_ENCODING,
 | |
| 			const_cast<CERT_NAME_BLOB *>(&pCertInfoCA->Issuer),
 | |
| 			const_cast<CERT_NAME_BLOB *>(&pCertInfoCA->Subject)))
 | |
|     {
 | |
| 	// This API doesn't set LastError
 | |
| 	hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
 | |
| 
 | |
| 	wprintf(myLoadResourceString(IDS_FORMAT_CA_NOT_ROOT)); // "CA is not a root: Subject name does not match Issuer"
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	hr = S_OK;
 | |
|     }
 | |
|     if (fDisplayCANames)
 | |
|     {
 | |
| 	hr = cuDisplayCertNames(
 | |
| 			    TRUE,
 | |
| 			    myLoadResourceString(IDS_CA), // "CA"
 | |
| 			    pCertInfoCA);
 | |
| 	_JumpIfError(hr, error, "cuDisplayCertNames(CA)");
 | |
|     }
 | |
| 
 | |
|     if (!CertCompareCertificateName(
 | |
| 			X509_ASN_ENCODING,
 | |
| 			const_cast<CERT_NAME_BLOB *>(&pCRLInfo->Issuer),
 | |
| 			const_cast<CERT_NAME_BLOB *>(&pCertInfoCA->Subject)))
 | |
|     {
 | |
| 	// This API doesn't set LastError
 | |
| 	hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_FORMAT_CA_CRLSUBJECT_NOT_ISSUER), // "ERROR: CA Subject name does not match CRL Issuer (%x)"
 | |
| 	    hr);
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	hr = S_OK;
 | |
| 	fCRLInvalid = TRUE;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	wprintf(myLoadResourceString(IDS_CA_CRLSUBJECT_IS_ISSUER)); // "CA Subject name matches CRL Issuer"
 | |
| 	wprintf(wszNewLine);
 | |
|     }
 | |
| 
 | |
|     GetSystemTime(&st);
 | |
|     if (!SystemTimeToFileTime(&st, &ft))
 | |
|     {
 | |
| 	hr = myHLastError();
 | |
| 	_JumpError(hr, error, "SystemTimeToFileTime");
 | |
|     }
 | |
|     if (0 < CompareFileTime(&pCRLInfo->ThisUpdate, &ft))
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_NOWNOTBEFORECRL_ERROR)); // "ERROR: CRL is not yet valid"
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	fCRLInvalid = TRUE;
 | |
|     }
 | |
|     if ((0 != pCRLInfo->NextUpdate.dwLowDateTime ||
 | |
| 	 0 != pCRLInfo->NextUpdate.dwHighDateTime) &&
 | |
| 	0 > CompareFileTime(&pCRLInfo->NextUpdate, &ft))
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_NOWNOTAFTERCRL_ERROR)); // "ERROR: CRL has expired"
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	fCRLInvalid = TRUE;
 | |
|     }
 | |
| 
 | |
|     if (0 < CompareFileTime(&pCertInfoCA->NotBefore, &pCRLInfo->ThisUpdate))
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_CANOTBEFORECRL_ERROR)); // "ERROR: CRL Valid before CA Cert Valid"
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	//fCRLInvalid = TRUE;
 | |
|     }
 | |
|     if ((0 != pCRLInfo->NextUpdate.dwLowDateTime ||
 | |
| 	 0 != pCRLInfo->NextUpdate.dwHighDateTime) &&
 | |
| 	0 > CompareFileTime(&pCertInfoCA->NotAfter, &pCRLInfo->NextUpdate))
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_CANOTAFTERCRL_ERROR)); // "ERROR: CRL Expires after CA Cert Expires"
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(wszNewLine);
 | |
| 	//fCRLInvalid = TRUE;
 | |
|     }
 | |
| 
 | |
|     // verify CRL signature with the CA Cert public key
 | |
| 
 | |
|     if (CryptVerifyCertificateSignature(
 | |
| 			NULL,
 | |
| 			X509_ASN_ENCODING,
 | |
| 			pCRLContext->pbCrlEncoded,
 | |
| 			pCRLContext->cbCrlEncoded,
 | |
| 			&pCertContextCA->pCertInfo->SubjectPublicKeyInfo))
 | |
|     {
 | |
| 	wprintf(myLoadResourceString(IDS_CRL_SIG_OK)); // "CRL signature is valid"
 | |
| 	wprintf(wszNewLine);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	hr = myHLastError();
 | |
| 	_PrintError(hr, "CryptVerifyCertificateSignature");
 | |
| 	wprintf(myLoadResourceString(IDS_ERR_CA_SIG_NOT_CRLISSUER)); // "ERROR: CA did not issue CRL: Signature check failed"
 | |
| 	wprintf(wszNewLine);
 | |
| 	fCRLInvalid = TRUE;
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < pCRLInfo->cExtension; i++)
 | |
|     {
 | |
| 	CERT_EXTENSION *pce;
 | |
| 
 | |
| 	pce = &pCRLInfo->rgExtension[i];
 | |
| 	//wprintf(L"%d: %hs: %d, %x (%x)\n", i, pce->pszObjId, pce->fCritical, pce->Value.pbData, pce->Value.cbData);
 | |
| 	if (0 == strcmp(pce->pszObjId, szOID_AUTHORITY_KEY_IDENTIFIER2))
 | |
| 	{
 | |
| 	    BOOL fKeyAuthorityMatch;
 | |
| 
 | |
| 	    //wprintf(L"%d: %ws\n", i, L"szOID_AUTHORITY_KEY_IDENTIFIER2");
 | |
| 
 | |
| 	    hr = VerifyKeyAuthority(
 | |
| 			    &pCRLInfo->Issuer,
 | |
| 			    pCertInfoCA,
 | |
| 			    pce->Value.pbData,
 | |
| 			    pce->Value.cbData,
 | |
| 			    &fKeyAuthorityMatch);
 | |
| 	    _JumpIfError(hr, error, "VerifyKeyAuthority");
 | |
| 
 | |
| 	    if (!fKeyAuthorityMatch)
 | |
| 	    {
 | |
| 		fCRLInvalid = TRUE;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
| error:
 | |
|     cuUnloadCRL(&pCRLContext);
 | |
|     cuUnloadCert(&pCertContextCA);
 | |
|     if (S_OK == hr)
 | |
|     {
 | |
| 	DWORD msgid;
 | |
| 
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(
 | |
| 		    fCRLInvalid?
 | |
| 			IDS_FORMAT_NOT_VERIFY : // "%ws does NOT verify as issued by %ws"
 | |
| 			IDS_FORMAT_IS_VERIFY), // "%ws verifies as issued by %ws"
 | |
| 	    pwszfnCRL,
 | |
| 	    pwszfnCertCA);
 | |
| 	wprintf(wszNewLine);
 | |
| 	if (fCRLInvalid)
 | |
| 	{
 | |
| 	    hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
 | |
| 	}
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| verbVerifyCert(
 | |
|     IN WCHAR const *pwszOption,
 | |
|     IN WCHAR const *pwszfnCert,
 | |
|     IN WCHAR const *pwszfnCertCA,
 | |
|     IN WCHAR const *pwszArg3,
 | |
|     IN WCHAR const *pwszArg4)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     BOOL fCertLoaded;
 | |
| 
 | |
|     if (NULL != pwszfnCertCA)
 | |
|     {
 | |
| 	hr = VerifyCertAgainstParent(pwszfnCert, pwszfnCertCA, &fCertLoaded);
 | |
| 	if (S_OK != hr && !fCertLoaded)
 | |
| 	{
 | |
| 	    hr = VerifyCRLAgainstCACert(pwszfnCert, pwszfnCertCA);
 | |
| 	}
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	hr = VerifyCertAgainstChain(pwszfnCert);
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| DWORD amsgidState[CHECK7F_COUNT] = {
 | |
|     //IDS_CHECK7F_FIELD_UNKNOWN,		// "???"
 | |
|     IDS_CHECK7F_FIELD_NONE,			// "None"
 | |
|     IDS_CHECK7F_FIELD_OTHER,			// "Other"
 | |
|     IDS_CHECK7F_FIELD_ISSUER,			// "Issuer"
 | |
|     IDS_CHECK7F_FIELD_ISSUERRDN,		// "IssuerRDN"
 | |
|     IDS_CHECK7F_FIELD_ISSUERRDNATTRIBUTE,	// "IssuerRDNAttribute"
 | |
|     IDS_CHECK7F_FIELD_ISSUERRDNSTRING,		// "IssuerRDNString"
 | |
|     IDS_CHECK7F_FIELD_SUBJECT,			// "Subject"
 | |
|     IDS_CHECK7F_FIELD_SUBJECTRDN,		// "SubjectRDN"
 | |
|     IDS_CHECK7F_FIELD_SUBJECTRDNATTRIBUTE,	// "SubjectRDNAttribute"
 | |
|     IDS_CHECK7F_FIELD_SUBJECTRDNSTRING,		// "SubjectRDNString"
 | |
|     IDS_CHECK7F_FIELD_EXTENSIONS,		// "Extensions"
 | |
|     IDS_CHECK7F_FIELD_EXTENSIONARRAY,		// "ExtensionArray"
 | |
|     IDS_CHECK7F_FIELD_EXTENSION,		// "Extension"
 | |
|     IDS_CHECK7F_FIELD_EXTENSIONVALUE,		// "ExtensionValue"
 | |
|     IDS_CHECK7F_FIELD_EXTENSIONVALUERAW,	// "ExtensionValueRaw"
 | |
| };
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| verbCheck7f(
 | |
|     IN WCHAR const *pwszOption,
 | |
|     IN WCHAR const *pwszfnCert,
 | |
|     IN WCHAR const *pwszArg2,
 | |
|     IN WCHAR const *pwszArg3,
 | |
|     IN WCHAR const *pwszArg4)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     CERT_CONTEXT const *pCertContext = NULL;
 | |
|     CERT_INFO const *pCertInfo;
 | |
|     WCHAR const *pwszObjectIdDescription = NULL;
 | |
|     DWORD i;
 | |
|     DWORD dwLen;
 | |
|     DWORD index;
 | |
|     DWORD index2;
 | |
|     DWORD state;
 | |
|     DWORD cwcField;
 | |
|     DWORD cwcObjectId;
 | |
|     WCHAR wszField[128];
 | |
|     WCHAR wszObjectId[40];
 | |
| 
 | |
|     // Load and decode certificates
 | |
| 
 | |
|     hr = cuLoadCert(pwszfnCert, &pCertContext);
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	cuPrintError(IDS_FORMAT_LOADTESTCERT, hr);
 | |
| 	goto error;
 | |
|     }
 | |
|     pCertInfo = pCertContext->pCertInfo;
 | |
| 
 | |
|     if (g_fVerbose)
 | |
|     {
 | |
| 	wprintf(wszNewLine);
 | |
| 	wprintf(myLoadResourceString(IDS_CERTCOLON)); // "Cert:"
 | |
| 	wprintf(wszNewLine);
 | |
| 	DumpHex(0, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
 | |
| 
 | |
| 	// Display name info:
 | |
| 
 | |
| 	hr = cuDisplayCertNames(
 | |
| 			    TRUE,
 | |
| 			    myLoadResourceString(IDS_CERT), // "Cert"
 | |
| 			    pCertInfo);
 | |
| 	_JumpIfError(hr, error, "cuDisplayCertNames(Cert)");
 | |
|     }
 | |
| 
 | |
|     cwcField = sizeof(wszField)/sizeof(wszField[0]);
 | |
|     cwcObjectId = sizeof(wszObjectId)/sizeof(wszObjectId[0]);
 | |
|     hr = myCheck7f(
 | |
| 		pCertContext->pbCertEncoded,
 | |
| 		pCertContext->cbCertEncoded,
 | |
| 		g_fVerbose,
 | |
| 		&state,
 | |
| 		&index,
 | |
| 		&index2,
 | |
| 		&cwcField,
 | |
| 		wszField,
 | |
| 		&cwcObjectId,
 | |
| 		wszObjectId,
 | |
| 		&pwszObjectIdDescription);
 | |
|     _JumpIfError(hr, error, "myCheck7f");
 | |
| 
 | |
|     if (CHECK7F_NONE != state)
 | |
|     {
 | |
| 	DWORD msgid = IDS_CHECK7F_FIELD_UNKNOWN; // "???"
 | |
| 	
 | |
| 	CSASSERT(0 != amsgidState[CHECK7F_COUNT - 1]);
 | |
| 	if (CHECK7F_COUNT > state)
 | |
| 	{
 | |
| 	    msgid = amsgidState[state];
 | |
| 	}
 | |
| 	CSASSERT(0 != msgid);
 | |
| 	wprintf(myLoadResourceString(IDS_FORMAT_SUSPECT_LENGTH)); // "Suspect length in"
 | |
| 	wprintf(myLoadResourceString(msgid));
 | |
| 	if (0 != index)
 | |
| 	{
 | |
| 	    wprintf(
 | |
| 		0 != index2? L"[%u,%u]" : L"[%u]",
 | |
| 		index - 1,
 | |
| 		index2 - 1);
 | |
| 	}
 | |
| 	wprintf(L": field=%ws", wszField);
 | |
| 	wprintf(
 | |
| 	    myLoadResourceString(IDS_FORMAT_FIELD), // ": field=%ws"
 | |
| 	    wszField);
 | |
| 	if (0 != index)
 | |
| 	{
 | |
| 	    wprintf(
 | |
| 		0 != index2? L"[%u,%u]" : L"[%u]",
 | |
| 		index - 1,
 | |
| 		index2 - 1);
 | |
| 	}
 | |
| 	if (L'\0' != wszObjectId[0])
 | |
| 	{
 | |
| 	    wprintf(
 | |
| 		myLoadResourceString(IDS_FORMAT_OID), // ", oid=%ws"
 | |
| 		wszObjectId);
 | |
| 	}
 | |
| 	if (NULL != pwszObjectIdDescription)
 | |
| 	{
 | |
| 	    wprintf(L" (%ws)", pwszObjectIdDescription);
 | |
| 	}
 | |
| 	wprintf(wszNewLine);
 | |
| 	hr = CERTSRV_E_ENCODING_LENGTH;
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < pCertInfo->cExtension; i++)
 | |
|     {
 | |
| 	CERT_EXTENSION *pce;
 | |
| 	WCHAR const *pwszDescriptiveName;
 | |
| 
 | |
| 	pce = &pCertInfo->rgExtension[i];
 | |
| 	if (g_fVerbose)
 | |
| 	{
 | |
| 	    wprintf(wszNewLine);
 | |
| 	    wprintf(
 | |
| 		myLoadResourceString(IDS_FORMAT_EXTENSION_OID), // "Extension %d: oid=""%hs"" fcrit=%u length=%x"
 | |
| 		i,
 | |
| 		pce->pszObjId,
 | |
| 		pce->fCritical,
 | |
| 		pce->Value.cbData);
 | |
| 		
 | |
| 	    pwszDescriptiveName = cuGetOIDNameA(pce->pszObjId);
 | |
| 	    if (NULL != pwszDescriptiveName)
 | |
| 	    {
 | |
| 		wprintf(L" (%ws)", pwszDescriptiveName);
 | |
| 	    }
 | |
| 	    wprintf(wszNewLine);
 | |
| 	    DumpHex(0, pce->Value.pbData, pce->Value.cbData);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
| error:
 | |
|     cuUnloadCert(&pCertContext);
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| cuVerifySignature(
 | |
|     IN BYTE const *pbEncoded,
 | |
|     IN DWORD cbEncoded,
 | |
|     IN CERT_PUBLIC_KEY_INFO const *pcpki,
 | |
|     IN BOOL fSuppressError)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     DWORD id = 0;
 | |
| 
 | |
|     // verify with the passed public key
 | |
|     if (!CryptVerifyCertificateSignature(
 | |
| 			    NULL,
 | |
| 			    X509_ASN_ENCODING,
 | |
| 			    const_cast<BYTE *>(pbEncoded),
 | |
| 			    cbEncoded,
 | |
| 			    const_cast<CERT_PUBLIC_KEY_INFO *>(pcpki)))
 | |
|     {
 | |
| 	hr = myHLastError();
 | |
| 	if (E_INVALIDARG == hr)
 | |
| 	{
 | |
| 	    CRYPT_DATA_BLOB Blob;
 | |
| 
 | |
| 	    Blob.cbData = cbEncoded;
 | |
| 	    Blob.pbData = const_cast<BYTE *>(pbEncoded);
 | |
| 	    if (!CryptVerifyCertificateSignatureEx(
 | |
| 				    NULL,	// hCryptProv
 | |
| 				    X509_ASN_ENCODING,
 | |
| 				    CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB,
 | |
| 				    &Blob,
 | |
| 				    CRYPT_VERIFY_CERT_SIGN_ISSUER_NULL,
 | |
| 				    NULL,	// pvIssuer
 | |
| 				    0,		// dwFlags
 | |
| 				    NULL))	// pvReserved
 | |
| 	    {
 | |
| 		HRESULT hr2 = myHLastError();
 | |
| 
 | |
| 		_PrintError(hr2, "CryptVerifyCertificateSignatureEx");
 | |
| 	    }
 | |
| 	    else
 | |
| 	    {
 | |
| 		hr = S_OK;
 | |
| 		id = IDS_NULL_SIGNATUREMATCHES; // "NULL signature verifies"
 | |
| 	    }
 | |
| 	}
 | |
| 	if (S_OK != hr && !fSuppressError)
 | |
| 	{
 | |
| 	    id = IDS_ERR_FORMAT_NO_SIGNATUREMATCHES; // "Signature does not match Public key: %x"
 | |
| 	}
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	hr = S_OK;
 | |
| 	id = IDS_SIGNATUREMATCHES;	// "Signature matches Public Key"
 | |
|     }
 | |
|     if (0 != id)
 | |
|     {
 | |
| 	wprintf(myLoadResourceString(id), hr);
 | |
| 	wprintf(wszNewLine);
 | |
|     }
 | |
|     return(hr);
 | |
| }
 |