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.
2719 lines
66 KiB
2719 lines
66 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
//
|
|
// File: verify.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
#include "cscsp.h"
|
|
|
|
#define __dwFILE__ __dwFILE_CERTUTIL_VERIFY_CPP__
|
|
|
|
|
|
HRESULT
|
|
cuVerifyKeyAuthority(
|
|
IN CERT_NAME_BLOB const *pIssuer,
|
|
IN CERT_INFO const *pCertInfoCA,
|
|
IN BYTE const *pbData,
|
|
IN DWORD cbData,
|
|
IN BOOL fQuiet,
|
|
OUT BOOL *pfKeyAuthorityMatch)
|
|
{
|
|
CERT_AUTHORITY_KEY_ID2_INFO const *pcaki = NULL;
|
|
DWORD cbcaki;
|
|
HRESULT hr = S_OK;
|
|
BOOL fDisplayIssuer = !fQuiet && 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))
|
|
{
|
|
if (!fQuiet)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_KEYID_IS_KEYAUTHORITY)); // "CA Key Id matches Key Id"
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!fQuiet)
|
|
{
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_ERR_KEYID_NOT_KEYAUTHORITY)); // "ERROR: CA Key Id does not match Key Id"
|
|
wprintf(wszNewLine);
|
|
}
|
|
*pfKeyAuthorityMatch = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!fQuiet)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_NO_KEYID)); // "No Key Id"
|
|
}
|
|
}
|
|
if (!fQuiet)
|
|
{
|
|
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);
|
|
|
|
if (!fQuiet)
|
|
{
|
|
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
|
|
{
|
|
if (!fQuiet)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_ISSUER_IS_KEYAUTHORITY)); // "CA Issuer name matches Key Authority name"
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!fQuiet)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_NO_KEYAUTHORITY)); // "No Key Authority name"
|
|
}
|
|
}
|
|
if (!fQuiet)
|
|
{
|
|
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))
|
|
{
|
|
if (!fQuiet)
|
|
{
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_SERIAL_NOT_KEYAUTHORITY)); // "ERROR: Issuer serial number does not match Key Authority"
|
|
wprintf(wszNewLine);
|
|
|
|
fDisplayIssuer = TRUE;
|
|
}
|
|
*pfKeyAuthorityMatch = FALSE;
|
|
}
|
|
else
|
|
{
|
|
if (!fQuiet)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_SERIAL_IS_KEYAUTHORITY)); // "Issuer serial number matches Key Authority"
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!fQuiet)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_NO_KEYAUTHORITYSERIAL)); // "No Key Authority serial number"
|
|
}
|
|
}
|
|
if (!fQuiet)
|
|
{
|
|
wprintf(wszNewLine);
|
|
}
|
|
|
|
if (!fQuiet && fDisplayIssuer)
|
|
{
|
|
hr = cuDisplayCertName(
|
|
TRUE,
|
|
NULL,
|
|
myLoadResourceString(IDS_ISSUERNAME), // "Issuer Name"
|
|
g_wszPad4,
|
|
pIssuer,
|
|
NULL);
|
|
_JumpIfError(hr, error, "cuDisplayCertName(Issuer)");
|
|
|
|
if (NULL != pAuthorityCertIssuerName)
|
|
{
|
|
hr = cuDisplayCertName(
|
|
TRUE,
|
|
NULL,
|
|
myLoadResourceString(IDS_KEYAUTHORITYNAME), // "KeyAuthority
|
|
g_wszPad4,
|
|
pAuthorityCertIssuerName,
|
|
NULL);
|
|
_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,
|
|
OUT BOOL *pfSigningTestAttempted,
|
|
OUT BOOL *pfKeyUsageCountSupported,
|
|
OUT BOOL *pfKeyUsageCountEnabled,
|
|
OUT ULARGE_INTEGER *puliKeyUsageCount)
|
|
{
|
|
HRESULT hr;
|
|
HCRYPTPROV hProv = NULL;
|
|
DWORD dwProvType;
|
|
WCHAR *pwszProvName = NULL;
|
|
ALG_ID idAlg;
|
|
BOOL fMachineKeyset;
|
|
|
|
*pfMatchFailed = TRUE;
|
|
*pfSigningTestAttempted = FALSE;
|
|
*pfKeyUsageCountSupported = FALSE;
|
|
*pfKeyUsageCountEnabled = FALSE;
|
|
puliKeyUsageCount->QuadPart = 0;
|
|
|
|
// get provider name
|
|
|
|
hr = myGetCertSrvCSP(
|
|
FALSE, // fEncryptionCSP
|
|
pwszSanitizedCA,
|
|
&dwProvType,
|
|
&pwszProvName,
|
|
&idAlg,
|
|
&fMachineKeyset,
|
|
NULL); // pdwKeySize
|
|
_JumpIfError(hr, error, "myGetCertSrvCSP");
|
|
|
|
hr = myValidateSigningKey(
|
|
pwszKeyContainerName,
|
|
pwszProvName,
|
|
dwProvType,
|
|
g_fCryptSilent,
|
|
fMachineKeyset,
|
|
g_fForce, // fForceSignatureTest
|
|
pCertContextCA,
|
|
NULL, // pPublicKeyInfo
|
|
idAlg,
|
|
pfSigningTestAttempted,
|
|
&hProv);
|
|
_JumpIfError(hr, error, "myValidateSigningKey");
|
|
|
|
*pfMatchFailed = FALSE;
|
|
hr = myGetSigningKeyUsageCount(
|
|
hProv,
|
|
pfKeyUsageCountSupported,
|
|
pfKeyUsageCountEnabled,
|
|
puliKeyUsageCount);
|
|
_JumpIfError(hr, error, "myGetSigningKeyUsageCount");
|
|
|
|
error:
|
|
if (NULL != hProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
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 fSigningTestFailed = FALSE;
|
|
BOOL fSigningTestAttempted = FALSE;
|
|
BOOL fKeyUsageCountSupported = FALSE;
|
|
BOOL fKeyUsageCountEnabled = FALSE;
|
|
ULARGE_INTEGER uliKeyUsageCount;
|
|
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);
|
|
_JumpError(hr, error, "cuLoadKeys");
|
|
}
|
|
|
|
// 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 (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);
|
|
}
|
|
|
|
if (!fMatchFailed)
|
|
{
|
|
hr = VerifyPrivateKey(
|
|
pCertContextCA,
|
|
pwszSanitizedCA,
|
|
kpi.pwszContainerName,
|
|
&fSigningTestFailed,
|
|
&fSigningTestAttempted,
|
|
&fKeyUsageCountSupported,
|
|
&fKeyUsageCountEnabled,
|
|
&uliKeyUsageCount);
|
|
_PrintIfError(hr, "VerifyPrivateKey");
|
|
}
|
|
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);
|
|
wprintf(wszNewLine);
|
|
|
|
if (MAXDWORD != dwNameId)
|
|
{
|
|
wprintf(
|
|
L" V%u.%u\n",
|
|
CANAMEIDTOICERT(dwNameId),
|
|
CANAMEIDTOIKEY(dwNameId));
|
|
}
|
|
if (fSigningTestAttempted)
|
|
{
|
|
wprintf(
|
|
L" %ws\n",
|
|
myLoadResourceString(
|
|
fSigningTestFailed?
|
|
IDS_SIGNATURE_BAD : // "Signature test FAILED"
|
|
IDS_SIGNATURE_OK)); // "Signature test passed"
|
|
}
|
|
|
|
if (fKeyUsageCountEnabled)
|
|
{
|
|
wprintf(
|
|
L" %ws: %I64u (0x%I64x)\n",
|
|
myLoadResourceString(IDS_KEY_USAGE_COUNT), // "Key usage count:"
|
|
uliKeyUsageCount.QuadPart,
|
|
uliKeyUsageCount.QuadPart);
|
|
}
|
|
else if (g_fVerbose)
|
|
{
|
|
wprintf(
|
|
L" %ws: %ws\n",
|
|
myLoadResourceString(IDS_KEY_USAGE_COUNT), // "Key usage count:"
|
|
myLoadResourceString(
|
|
fKeyUsageCountSupported?
|
|
IDS_KEY_USAGE_COUNT_DISABLED : // "Disabled"
|
|
IDS_KEY_USAGE_COUNT_NOTSUPPORTED)); // "Not supported"
|
|
}
|
|
wprintf(wszNewLine);
|
|
|
|
if (fMatchFailed || fSigningTestFailed)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "fMatchFailed || fSigningTestFailed");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
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;
|
|
HRESULT hr2;
|
|
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 |
|
|
CERT_STORE_READONLY_FLAG,
|
|
wszMY_CERTSTORE);
|
|
if (NULL == hMyStore)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertOpenStore");
|
|
}
|
|
|
|
hr2 = S_OK;
|
|
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),
|
|
MAXDWORD, // IndexTarget
|
|
&pwszCertName);
|
|
_JumpIfError(hr, error, "myAllocIndexedName");
|
|
|
|
hr = VerifyCAKeys(
|
|
pccCA,
|
|
pwszSanitizedCA,
|
|
pwszCertName,
|
|
pkpi->pwszContainerName);
|
|
_PrintIfError(hr, "VerifyCAKeys");
|
|
if (S_OK == hr2)
|
|
{
|
|
hr2 = hr;
|
|
}
|
|
CertFreeCertificateContext(pccCA);
|
|
pccCA = NULL;
|
|
|
|
LocalFree(pkpi);
|
|
pkpi = NULL;
|
|
|
|
LocalFree(pwszCertName);
|
|
pwszCertName = NULL;
|
|
}
|
|
hr = hr2;
|
|
|
|
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)
|
|
{
|
|
wprintf(L"%ws:", myLoadResourceString(idMsg));
|
|
if (NULL == pwszzPolicies)
|
|
{
|
|
wprintf(L" %ws\n", myLoadResourceString(IDS_ALL_POLICIES));
|
|
}
|
|
else if (L'\0' == *pwszzPolicies)
|
|
{
|
|
wprintf(L" %ws\n", myLoadResourceString(IDS_NO_POLICIES));
|
|
}
|
|
else
|
|
{
|
|
wprintf(wszNewLine);
|
|
for ( ;
|
|
L'\0' != *pwszzPolicies;
|
|
pwszzPolicies += wcslen(pwszzPolicies) + 1)
|
|
{
|
|
wprintf(g_wszPad4);
|
|
cuDumpOIDAndDescription(pwszzPolicies);
|
|
wprintf(wszNewLine);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
FNSIMPLECHAINELEMENTCALLBACK cuSimpleChainElementCallback;
|
|
|
|
VOID
|
|
cuSimpleChainElementCallback(
|
|
IN DWORD dwFlags,
|
|
IN DWORD iElement,
|
|
IN CERT_SIMPLE_CHAIN const *pChain)
|
|
{
|
|
CERT_CHAIN_ELEMENT const *pElement = pChain->rgpElement[iElement];
|
|
CERT_REVOCATION_INFO *pRevocationInfo;
|
|
WCHAR const *pwszFmtHeader = L" ----------------%ws%ws%ws----------------\n";
|
|
|
|
CSASSERT(iElement < pChain->cElement);
|
|
pElement = pChain->rgpElement[iElement];
|
|
|
|
wprintf(
|
|
pwszFmtHeader,
|
|
g_wszPad2,
|
|
myLoadResourceString(IDS_CERT_AIA), // "Certificate AIA"
|
|
g_wszPad2);
|
|
cuDisplayAIAUrlsFromCert(pElement->pCertContext);
|
|
|
|
wprintf(
|
|
pwszFmtHeader,
|
|
g_wszPad2,
|
|
myLoadResourceString(IDS_CERT_CDP), // "Certificate CDP"
|
|
g_wszPad2);
|
|
cuDisplayCDPUrlsFromCertOrCRL(pElement->pCertContext, NULL);
|
|
|
|
pRevocationInfo = pElement->pRevocationInfo;
|
|
|
|
if (NULL != pRevocationInfo &&
|
|
CCSIZEOF_STRUCT(CERT_REVOCATION_INFO, pCrlInfo) <=
|
|
pRevocationInfo->cbSize &&
|
|
NULL != pRevocationInfo->pCrlInfo)
|
|
{
|
|
CERT_REVOCATION_CRL_INFO *pCrlInfo;
|
|
|
|
pCrlInfo = pRevocationInfo->pCrlInfo;
|
|
if (NULL != pCrlInfo)
|
|
{
|
|
if (NULL != pCrlInfo->pBaseCrlContext)
|
|
{
|
|
wprintf(
|
|
pwszFmtHeader,
|
|
g_wszPad2,
|
|
myLoadResourceString(IDS_BASECRL_CDP), // "Base CRL CDP"
|
|
g_wszPad2);
|
|
cuDisplayCDPUrlsFromCertOrCRL(NULL, pCrlInfo->pBaseCrlContext);
|
|
}
|
|
//if (NULL != pCrlInfo->pDeltaCrlContext)
|
|
}
|
|
}
|
|
wprintf(
|
|
pwszFmtHeader,
|
|
g_wszEmpty,
|
|
g_wszEmpty,
|
|
g_wszEmpty);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
cuVerifyCertContext(
|
|
IN CERT_CONTEXT const *pCert,
|
|
OPTIONAL IN HCERTSTORE hStoreCA,
|
|
IN DWORD cApplicationPolicies,
|
|
OPTIONAL IN char const * const *apszApplicationPolicies,
|
|
IN DWORD cIssuancePolicies,
|
|
OPTIONAL IN char const * const *apszIssuancePolicies,
|
|
IN BOOL fNTAuth,
|
|
OUT DWORD *pVerifyState)
|
|
{
|
|
HRESULT hr;
|
|
DWORD idMsg;
|
|
WCHAR *pwszMissingIssuer = NULL;
|
|
WCHAR *pwszzIssuancePolicies = NULL;
|
|
WCHAR *pwszzApplicationPolicies = NULL;
|
|
WCHAR *pwszExtendedErrorInfo = NULL;
|
|
DWORD Flags;
|
|
|
|
*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,
|
|
FALSE);
|
|
if (S_OK == hr)
|
|
{
|
|
*pVerifyState |= VS_ROOTSIGOK;
|
|
}
|
|
_PrintIfError(hr, "cuVerifySignature");
|
|
#endif
|
|
}
|
|
|
|
// Verify the cert and chain:
|
|
Flags = 0;
|
|
if (fNTAuth || g_fEnterpriseRegistry)
|
|
{
|
|
Flags |= CA_VERIFY_FLAGS_NT_AUTH;
|
|
}
|
|
if (g_fForce)
|
|
{
|
|
Flags |= CA_VERIFY_FLAGS_FULL_CHAIN_REVOCATION;
|
|
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,
|
|
g_dwmsTimeout,
|
|
cApplicationPolicies,
|
|
apszApplicationPolicies,
|
|
cIssuancePolicies,
|
|
apszIssuancePolicies,
|
|
g_fUserRegistry? HCCE_CURRENT_USER : HCCE_LOCAL_MACHINE,
|
|
NULL, // pft
|
|
hStoreCA, // hAdditionalStore
|
|
g_fURLFetch? cuSimpleChainElementCallback : NULL,
|
|
&pwszMissingIssuer,
|
|
&pwszzIssuancePolicies,
|
|
&pwszzApplicationPolicies,
|
|
&pwszExtendedErrorInfo,
|
|
NULL); // pTrustStatus
|
|
|
|
if (S_OK == hr &&
|
|
(NULL != pwszzIssuancePolicies ||
|
|
NULL != pwszzApplicationPolicies ||
|
|
IsWhistler()))
|
|
{
|
|
// Suppress misleading "All Policies" display on Windows 2000.
|
|
|
|
cuDumpPolicies(IDS_ISSUANCE_POLICIES, pwszzIssuancePolicies);
|
|
cuDumpPolicies(IDS_APPLICATION_POLICIES, pwszzApplicationPolicies);
|
|
}
|
|
if (NULL != pwszExtendedErrorInfo)
|
|
{
|
|
wprintf(L"%ws\n", pwszExtendedErrorInfo);
|
|
}
|
|
|
|
idMsg = 0;
|
|
if (CRYPT_E_REVOKED == hr || CERT_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);
|
|
}
|
|
if (NULL != pwszExtendedErrorInfo)
|
|
{
|
|
LocalFree(pwszExtendedErrorInfo);
|
|
}
|
|
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 = RS_INCOMPLETE;
|
|
|
|
ZeroMemory(&crp, sizeof(crp));
|
|
crp.cbSize = sizeof(crp);
|
|
crp.pIssuerCert = pCertContextCA;
|
|
|
|
ZeroMemory(&crs, sizeof(crs));
|
|
crs.cbSize = sizeof(crs);
|
|
|
|
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 **) &pCertContext, // rgpContext
|
|
0, // dwFlags
|
|
&crp,
|
|
&crs))
|
|
{
|
|
hr = myHLastError();
|
|
if (CRYPT_E_REVOKED == hr || CERT_E_REVOKED == hr)
|
|
{
|
|
wprintf(
|
|
myLoadResourceString(IDS_FORMAT_IS_REVOKED), // "Leaf 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: Verifying leaf certificate revocation status returned %ws"
|
|
cuPrintErrorMessageText(hr);
|
|
wprintf(wszNewLine);
|
|
|
|
RevState = RS_FAIL;
|
|
goto error;
|
|
}
|
|
wprintf(myLoadResourceString(IDS_CANNOT_CHECK_REVSTATUS)); // "Cannot check leaf certificate revocation status"
|
|
wprintf(wszNewLine);
|
|
|
|
RevState = RS_INCOMPLETE;
|
|
goto error;
|
|
}
|
|
wprintf(myLoadResourceString(IDS_REVSTATUS_OK)); // "Leaf certificate revocation check passed"
|
|
wprintf(wszNewLine);
|
|
RevState = RS_PASS;
|
|
|
|
error:
|
|
if (NULL != crp.hCrlStore)
|
|
{
|
|
CertCloseStore(crp.hCrlStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
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,
|
|
IN DWORD cApplicationPolicies,
|
|
OPTIONAL IN char const * const *apszApplicationPolicies,
|
|
IN DWORD cIssuancePolicies,
|
|
OPTIONAL IN char const * const *apszIssuancePolicies)
|
|
{
|
|
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
|
|
cApplicationPolicies,
|
|
apszApplicationPolicies,
|
|
cIssuancePolicies,
|
|
apszIssuancePolicies,
|
|
FALSE, // fNTAuth
|
|
&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,
|
|
OPTIONAL IN WCHAR const *pwszfnCertCACrossed,
|
|
OUT BOOL *pfCertLoaded)
|
|
{
|
|
HRESULT hr;
|
|
CERT_INFO const *pCertInfo;
|
|
CERT_INFO const *pCertInfoCA;
|
|
CERT_INFO const *pCertInfoCACrossed;
|
|
CERT_CONTEXT const *pCertContext = NULL;
|
|
CERT_CONTEXT const *pCertContextCA = NULL;
|
|
CERT_CONTEXT const *pCertContextCACrossed = 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;
|
|
BYTE *pbKeyId = NULL;
|
|
DWORD cbKeyId;
|
|
BYTE *pbKeyIdCACrossed = NULL;
|
|
DWORD cbKeyIdCACrossed;
|
|
|
|
// 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;
|
|
|
|
if (NULL != pwszfnCertCACrossed)
|
|
{
|
|
hr = cuLoadCert(pwszfnCertCACrossed, &pCertContextCACrossed);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintError(IDS_FORMAT_LOADCACERT, hr);
|
|
goto error;
|
|
}
|
|
pCertInfoCACrossed = pCertContextCACrossed->pCertInfo;
|
|
}
|
|
|
|
// Display name info:
|
|
|
|
hr = cuDisplayCertNames(
|
|
TRUE,
|
|
myLoadResourceString(IDS_CERT), // "Cert"
|
|
pCertInfo);
|
|
_JumpIfError(hr, error, "cuDisplayCertNames(Cert)");
|
|
|
|
hr = cuDisplayCertNames(
|
|
TRUE,
|
|
myLoadResourceString(IDS_ISSUINGCACERT), // "Issuing CA Cert"
|
|
pCertInfoCA);
|
|
_JumpIfError(hr, error, "cuDisplayCertNames(CA)");
|
|
|
|
if (NULL != pwszfnCertCACrossed)
|
|
{
|
|
hr = cuDisplayCertNames(
|
|
TRUE,
|
|
myLoadResourceString(IDS_CROSSEDCACERT), // "Crossed CA Cert"
|
|
pCertInfoCACrossed);
|
|
_JumpIfError(hr, error, "cuDisplayCertNames(CrossedCA)");
|
|
|
|
}
|
|
|
|
if (g_fVerbose)
|
|
{
|
|
wprintf(wszNewLine);
|
|
cuDumpSerial(NULL, IDS_CERT_SERIAL, &pCertInfo->SerialNumber);
|
|
|
|
wprintf(wszNewLine);
|
|
cuDumpSerial(NULL, IDS_ISSUINGCACERT_SERIAL, &pCertInfoCA->SerialNumber);
|
|
|
|
if (NULL != pwszfnCertCACrossed)
|
|
{
|
|
wprintf(wszNewLine);
|
|
cuDumpSerial(NULL, IDS_CROSSEDCACERT_SERIAL, &pCertInfoCACrossed->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
|
|
|
|
wprintf(myLoadResourceString(IDS_ISSUINGCA_NOT_ROOT)); // "Issuing CA is not a root: Subject name does not match Issuer"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
hr = S_OK;
|
|
}
|
|
|
|
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
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(
|
|
myLoadResourceString(IDS_ISSUINGCA_SUBJECT_NOT_ISSUER)); // "ERROR: Issuing CA Subject name does not match Cert Issuer"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
hr = S_OK;
|
|
fCertInvalid = TRUE;
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_ISSUINGCA_SUBJECT_IS_ISSUER)); // "Issuing CA Subject name matches Cert Issuer"
|
|
wprintf(wszNewLine);
|
|
}
|
|
if (NULL != pwszfnCertCACrossed)
|
|
{
|
|
if (!CertCompareCertificateName(
|
|
X509_ASN_ENCODING,
|
|
const_cast<CERT_NAME_BLOB *>(&pCertInfo->Subject),
|
|
const_cast<CERT_NAME_BLOB *>(&pCertInfoCACrossed->Subject)))
|
|
{
|
|
// This API doesn't set LastError
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(
|
|
myLoadResourceString(IDS_CROSSEDCA_SUBJECT_NOT_SUBJECT)); // "ERROR: Crossed CA Subject name does not match Cert Subject"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
hr = S_OK;
|
|
fCertInvalid = TRUE;
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_CROSEDGCA_SUBJECT_IS_SUBJECT)); // "Crossed CA Subject name matches Cert Subject"
|
|
wprintf(wszNewLine);
|
|
}
|
|
|
|
// see if the public key matches the certificate's public key
|
|
|
|
if (!CertComparePublicKeyInfo(
|
|
X509_ASN_ENCODING,
|
|
const_cast<CERT_PUBLIC_KEY_INFO *>(&pCertInfo->SubjectPublicKeyInfo),
|
|
const_cast<CERT_PUBLIC_KEY_INFO *>(&pCertInfoCACrossed->SubjectPublicKeyInfo)))
|
|
{
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_CROSEDGCA_NOT_PUBLICKEY)); // "ERROR: Certificate public key does NOT match Cert key"
|
|
wprintf(wszNewLine);
|
|
fCertInvalid = TRUE;
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_CROSEDGCA_NOT_IS_PUBLICKEY)); // "Crossed CA public key matches Cert key"
|
|
}
|
|
wprintf(wszNewLine);
|
|
|
|
hr = myGetPublicKeyHash(
|
|
pCertInfo,
|
|
&pCertInfo->SubjectPublicKeyInfo,
|
|
&pbKeyId,
|
|
&cbKeyId);
|
|
_JumpIfError(hr, error, "myGetPublicKeyHash");
|
|
|
|
hr = myGetPublicKeyHash(
|
|
pCertInfoCACrossed,
|
|
&pCertInfoCACrossed->SubjectPublicKeyInfo,
|
|
&pbKeyIdCACrossed,
|
|
&cbKeyIdCACrossed);
|
|
_JumpIfError(hr, error, "myGetPublicKeyHash");
|
|
|
|
if (cbKeyId == cbKeyIdCACrossed &&
|
|
0 == memcmp(pbKeyId, pbKeyIdCACrossed, cbKeyId))
|
|
{
|
|
wprintf(myLoadResourceString(IDS_CROSSEDKEYID_IS_KEYID)); // "Crossed CA Key Id matches Key Id"
|
|
}
|
|
else
|
|
{
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_CROSSEDKEYID_NOT_KEYID)); // "ERROR: Crossed CA Key Id does not match Key Id"
|
|
wprintf(wszNewLine);
|
|
fCertInvalid = TRUE;
|
|
}
|
|
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 issuing 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 issuing 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(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_ERR_CA_SIG_NOT_ISSUER)); // "ERROR: CA did not issue Certificate: Signature check failed"
|
|
wprintf(wszNewLine);
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_CERT_SIG_OK)); // "Certificate signature is valid"
|
|
}
|
|
wprintf(wszNewLine);
|
|
|
|
if (CERT_STORE_TIME_VALIDITY_FLAG & dwFlags)
|
|
{
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_ERR_EXPIRED)); // "ERROR: Certificate has expired"
|
|
wprintf(wszNewLine);
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_CERT_CURRENT)); // "Certificate is current"
|
|
}
|
|
wprintf(wszNewLine);
|
|
|
|
if (0 != dwFlags)
|
|
{
|
|
wprintf(wszNewLine);
|
|
fCertInvalid = TRUE;
|
|
}
|
|
|
|
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 = cuVerifyKeyAuthority(
|
|
&pCertInfo->Issuer,
|
|
pCertInfoCA,
|
|
pce->Value.pbData,
|
|
pce->Value.cbData,
|
|
FALSE,
|
|
&fKeyAuthorityMatch);
|
|
_JumpIfError(hr, error, "cuVerifyKeyAuthority");
|
|
|
|
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 (NULL != pbKeyId)
|
|
{
|
|
LocalFree(pbKeyId);
|
|
}
|
|
if (NULL != pbKeyIdCACrossed)
|
|
{
|
|
LocalFree(pbKeyIdCACrossed);
|
|
}
|
|
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,
|
|
OPTIONAL IN WCHAR const *pwszfnCertEE, // or delta CRL
|
|
OUT BOOL *pfCRLLoaded)
|
|
{
|
|
HRESULT hr;
|
|
CRL_CONTEXT const *pCRLContext = NULL;
|
|
CRL_CONTEXT const *pCRLContextDelta = NULL;
|
|
CERT_CONTEXT const *pCertContextCA = NULL;
|
|
CERT_CONTEXT const *pCertContextEE = NULL;
|
|
CRL_INFO const *pCRLInfo;
|
|
CRL_INFO const *pCRLInfoDelta;
|
|
CERT_INFO const *pCertInfoCA;
|
|
CERT_INFO const *pCertInfoEE;
|
|
BOOL fDisplayCANames = g_fVerbose;
|
|
DWORD i;
|
|
BOOL fCRLInvalid = FALSE;
|
|
SYSTEMTIME st;
|
|
FILETIME ft;
|
|
DWORD dwNameIdCRL;
|
|
DWORD dwNameIdCert;
|
|
|
|
// Load and decode CRL and certificate
|
|
|
|
*pfCRLLoaded = FALSE;
|
|
hr = cuLoadCRL(pwszfnCRL, &pCRLContext);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintError(IDS_FORMAT_LOADTESTCRL, hr);
|
|
goto error;
|
|
}
|
|
*pfCRLLoaded = TRUE;
|
|
pCRLInfo = pCRLContext->pCrlInfo;
|
|
|
|
hr = cuLoadCert(pwszfnCertCA, &pCertContextCA);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintError(IDS_FORMAT_LOADCACERT, hr);
|
|
goto error;
|
|
}
|
|
pCertInfoCA = pCertContextCA->pCertInfo;
|
|
if (NULL != pwszfnCertEE)
|
|
{
|
|
hr = cuLoadCert(pwszfnCertEE, &pCertContextEE);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = cuLoadCRL(pwszfnCertEE, &pCRLContextDelta);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintError(IDS_FORMAT_LOADTESTCERT, hr);
|
|
goto error;
|
|
}
|
|
pCRLInfoDelta = pCRLContextDelta->pCrlInfo;
|
|
}
|
|
else
|
|
{
|
|
pCertInfoEE = pCertContextEE->pCertInfo;
|
|
}
|
|
}
|
|
|
|
// Display name info:
|
|
|
|
hr = cuDisplayCertName(
|
|
TRUE,
|
|
myLoadResourceString(IDS_CRL), // "CRL"
|
|
myLoadResourceString(IDS_ISSUER), // "Issuer"
|
|
g_wszPad4,
|
|
&pCRLInfo->Issuer,
|
|
NULL);
|
|
_JumpIfError(hr, error, "cuDisplayCertName(CRL Issuer)");
|
|
|
|
hr = cuDisplayCertNames(
|
|
TRUE,
|
|
myLoadResourceString(IDS_ISSUINGCACERT), // "Issuing CA Cert"
|
|
pCertInfoCA);
|
|
_JumpIfError(hr, error, "cuDisplayCertNames(CA)");
|
|
|
|
if (g_fVerbose)
|
|
{
|
|
wprintf(wszNewLine);
|
|
cuDumpSerial(NULL, IDS_ISSUINGCACERT_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
|
|
|
|
wprintf(myLoadResourceString(IDS_ISSUINGCA_NOT_ROOT)); // "Issuing CA is not a root: Subject name does not match Issuer"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
}
|
|
if (fDisplayCANames)
|
|
{
|
|
hr = cuDisplayCertNames(
|
|
TRUE,
|
|
myLoadResourceString(IDS_ISSUINGCACERT), // "Issuing CA Cert"
|
|
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
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(
|
|
myLoadResourceString(IDS_ISSUINGCA_CRLSUBJECT_NOT_ISSUER)); // "ERROR: Issuing CA Subject name does not match CRL Issuer"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
fCRLInvalid = TRUE;
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_ISSUINGCA_CRLSUBJECT_IS_ISSUER)); // "Issuing 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 issuing 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 issuing 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(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_ERR_CA_SIG_NOT_CRLISSUER)); // "ERROR: CA did not issue CRL: Signature check failed"
|
|
wprintf(wszNewLine);
|
|
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 = cuVerifyKeyAuthority(
|
|
&pCRLInfo->Issuer,
|
|
pCertInfoCA,
|
|
pce->Value.pbData,
|
|
pce->Value.cbData,
|
|
FALSE,
|
|
&fKeyAuthorityMatch);
|
|
_JumpIfError(hr, error, "cuVerifyKeyAuthority");
|
|
|
|
if (!fKeyAuthorityMatch)
|
|
{
|
|
fCRLInvalid = TRUE;
|
|
}
|
|
}
|
|
}
|
|
hr = myGetCRLNameId(pCRLContext, &dwNameIdCRL);
|
|
_PrintIfError(hr, "myGetCRLNameId");
|
|
|
|
hr = myGetNameId(pCertContextCA, &dwNameIdCert);
|
|
_PrintIfError(hr, "myGetNameId");
|
|
|
|
if (MAXDWORD != dwNameIdCRL &&
|
|
MAXDWORD != dwNameIdCert &&
|
|
dwNameIdCRL != dwNameIdCert)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_CRLNAMEID_NOT_CERTNAMEID)); // "WARNING: CRL CA Version does not match Cert CA Version"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
//fCRLInvalid = TRUE;
|
|
}
|
|
|
|
if (NULL != pCertContextEE)
|
|
{
|
|
BOOL fCertLoaded;
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_VERIFYING_ISSUED_CERT)); // "Verifying Issued Certificate:"
|
|
wprintf(wszNewLine);
|
|
hr = VerifyCertAgainstParent(
|
|
pwszfnCertEE,
|
|
pwszfnCertCA,
|
|
NULL, // pwszfnCertCACrossed
|
|
&fCertLoaded);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "VerifyCertAgainstParent");
|
|
fCRLInvalid = TRUE;
|
|
}
|
|
wprintf(wszNewLine);
|
|
|
|
if (!CertCompareCertificateName(
|
|
X509_ASN_ENCODING,
|
|
const_cast<CERT_NAME_BLOB *>(&pCertInfoEE->Issuer),
|
|
const_cast<CERT_NAME_BLOB *>(&pCRLInfo->Issuer)))
|
|
{
|
|
// This API doesn't set LastError
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_CRLISSUER_NOT_EEISSUER)); // "ERROR: CRL Issuer does not match Cert Issuer"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
fCRLInvalid = TRUE;
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_CRLISSUER_IS_EEISSUER)); // "CRL Issuer matches Cert Issuer"
|
|
wprintf(wszNewLine);
|
|
}
|
|
if (!cuVerifyIDP(pCertContextEE, pCRLContext))
|
|
{
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_CRL_IDP_MISMATCH)); // "ERROR: CRL IDP extension does not match Cert CDP"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
fCRLInvalid = TRUE;
|
|
}
|
|
}
|
|
else if (NULL != pCRLContextDelta)
|
|
{
|
|
BOOL fCRLLoaded;
|
|
BOOL fDelta;
|
|
DWORD dwNameIdDelta;
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_VERIFYING_DELTA_CRL)); // "Verifying Delta CRL:"
|
|
wprintf(wszNewLine);
|
|
hr = VerifyCRLAgainstCACert(
|
|
pwszfnCertEE, // pwszfnCRL
|
|
pwszfnCertCA,
|
|
NULL, // pwszfnCertEE
|
|
&fCRLLoaded);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "VerifyCRLAgainstCACert");
|
|
fCRLInvalid = TRUE;
|
|
}
|
|
wprintf(wszNewLine);
|
|
|
|
if (!CertCompareCertificateName(
|
|
X509_ASN_ENCODING,
|
|
const_cast<CERT_NAME_BLOB *>(&pCRLInfoDelta->Issuer),
|
|
const_cast<CERT_NAME_BLOB *>(&pCRLInfo->Issuer)))
|
|
{
|
|
// This API doesn't set LastError
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_CRLISSUER_NOT_DELTAISSUER)); // "ERROR: CRL Issuer does not match Delta CRL Issuer"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
fCRLInvalid = TRUE;
|
|
}
|
|
else
|
|
{
|
|
wprintf(myLoadResourceString(IDS_CRLISSUER_IS_DELTAISSUER)); // "CRL Issuer matches Delta CRL Issuer"
|
|
wprintf(wszNewLine);
|
|
}
|
|
hr = myIsDeltaCRL(pCRLContext, &fDelta);
|
|
_JumpIfError(hr, error, "myIsDeltaCRL");
|
|
|
|
if (fDelta)
|
|
{
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_CRL_NOT_BASE)); // "ERROR: CRL is not a Base CRL"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
fCRLInvalid = TRUE;
|
|
}
|
|
|
|
hr = myIsDeltaCRL(pCRLContextDelta, &fDelta);
|
|
_JumpIfError(hr, error, "myIsDeltaCRL");
|
|
|
|
if (!fDelta)
|
|
{
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_CRL_NOT_DELTA)); // "ERROR: CRL is not a Delta CRL"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
fCRLInvalid = TRUE;
|
|
}
|
|
hr = myGetCRLNameId(pCRLContextDelta, &dwNameIdDelta);
|
|
_PrintIfError(hr, "myGetCRLNameId");
|
|
|
|
if (MAXDWORD != dwNameIdCRL &&
|
|
MAXDWORD != dwNameIdDelta &&
|
|
dwNameIdCRL != dwNameIdDelta)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_CRLNAMEID_NOT_DELTANAMEID)); // "WARNING: CRL CA Version does not match Delta CRL CA Version"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
//fCRLInvalid = TRUE;
|
|
}
|
|
if (fDelta && !cuVerifyMinimumBaseCRL(pCRLContext, pCRLContextDelta))
|
|
{
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_CRL_MINBASE_MISMATCH)); // "ERROR: CRL Number less than Delta CRL Minimum Base"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
fCRLInvalid = TRUE;
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
cuUnloadCRL(&pCRLContext);
|
|
cuUnloadCert(&pCertContextCA);
|
|
cuUnloadCert(&pCertContextEE);
|
|
if (S_OK == hr)
|
|
{
|
|
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
|
|
VerifyBlobAgainstCACert(
|
|
IN WCHAR const *pwszfnBlob,
|
|
IN WCHAR const *pwszfnCertCA)
|
|
{
|
|
HRESULT hr;
|
|
CERT_CONTEXT const *pCertContextCA = NULL;
|
|
CERT_INFO const *pCertInfoCA;
|
|
BYTE *pbBlob = NULL;
|
|
DWORD cbBlob;
|
|
CERT_SIGNED_CONTENT_INFO *pcsci = NULL;
|
|
DWORD cbcsci;
|
|
BOOL fSigInvalid = FALSE;
|
|
|
|
// Load blob and load and decode certificate
|
|
|
|
hr = DecodeFileW(pwszfnBlob, &pbBlob, &cbBlob, CRYPT_STRING_ANY);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintError(IDS_ERR_FORMAT_DECODEFILE, hr);
|
|
goto error;
|
|
}
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT,
|
|
pbBlob,
|
|
cbBlob,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pcsci,
|
|
&cbcsci))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError3(
|
|
hr,
|
|
"myDecodeObject",
|
|
CRYPT_E_ASN1_BADTAG,
|
|
CRYPT_E_ASN1_EOD);
|
|
}
|
|
|
|
hr = cuLoadCert(pwszfnCertCA, &pCertContextCA);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintError(IDS_FORMAT_LOADCACERT, hr);
|
|
goto error;
|
|
}
|
|
pCertInfoCA = pCertContextCA->pCertInfo;
|
|
|
|
hr = cuDumpAsnBinary(pbBlob, cbBlob, MAXDWORD);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintError(IDS_ERR_FORMAT_CANNOT_DECODE, hr);
|
|
goto error;
|
|
}
|
|
|
|
// Display name info:
|
|
|
|
hr = cuDisplayCertNames(
|
|
TRUE,
|
|
myLoadResourceString(IDS_ISSUINGCACERT), // "Issuing CA Cert"
|
|
pCertInfoCA);
|
|
_JumpIfError(hr, error, "cuDisplayCertNames(CA)");
|
|
|
|
if (g_fVerbose)
|
|
{
|
|
wprintf(wszNewLine);
|
|
cuDumpSerial(NULL, IDS_ISSUINGCACERT_SERIAL, &pCertInfoCA->SerialNumber);
|
|
|
|
wprintf(wszNewLine);
|
|
}
|
|
|
|
// verify blob signature with the CA Cert public key
|
|
|
|
if (CryptVerifyCertificateSignature(
|
|
NULL,
|
|
X509_ASN_ENCODING,
|
|
pbBlob,
|
|
cbBlob,
|
|
&pCertContextCA->pCertInfo->SubjectPublicKeyInfo))
|
|
{
|
|
wprintf(myLoadResourceString(IDS_CRL_SIG_OK)); // "CRL signature is valid"
|
|
wprintf(wszNewLine);
|
|
}
|
|
else
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError(hr, "CryptVerifyCertificateSignature");
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_ERR_CA_SIG_NOT_CRLISSUER)); // "ERROR: CA did not issue CRL: Signature check failed"
|
|
wprintf(wszNewLine);
|
|
wprintf(wszNewLine);
|
|
fSigInvalid = TRUE;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pcsci)
|
|
{
|
|
LocalFree(pcsci);
|
|
}
|
|
if (NULL != pbBlob)
|
|
{
|
|
LocalFree(pbBlob);
|
|
}
|
|
cuUnloadCert(&pCertContextCA);
|
|
if (S_OK == hr)
|
|
{
|
|
wprintf(wszNewLine);
|
|
wprintf(
|
|
myLoadResourceString(
|
|
fSigInvalid?
|
|
IDS_FORMAT_NOT_VERIFY : // "%ws does NOT verify as issued by %ws"
|
|
IDS_FORMAT_IS_VERIFY), // "%ws verifies as issued by %ws"
|
|
pwszfnBlob,
|
|
pwszfnCertCA);
|
|
wprintf(wszNewLine);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
cuParseOIDList(
|
|
IN WCHAR const *pwszIn,
|
|
OUT DWORD *pcOut,
|
|
OUT char ***pppszOut)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR **ppwszOID = NULL;
|
|
char **ppszOID = NULL;
|
|
DWORD cOID;
|
|
DWORD i;
|
|
|
|
hr = cuParseStrings(pwszIn, FALSE, NULL, NULL, &ppwszOID, NULL);
|
|
_JumpIfError2(hr, error, "cuParseStrings", hr);
|
|
|
|
for (i = 0; NULL != ppwszOID[i]; i++)
|
|
{
|
|
hr = myVerifyObjId(ppwszOID[i]);
|
|
_JumpIfErrorStr2(hr, error, "myVerifyObjId", ppwszOID[i], hr);
|
|
}
|
|
if (0 == i)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "No OIDs");
|
|
}
|
|
cOID = i;
|
|
|
|
ppszOID = (char **) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
(cOID + 1) * sizeof(*ppszOID));
|
|
if (NULL == ppszOID)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
for (i = 0; NULL != ppwszOID[i]; i++)
|
|
{
|
|
if (!myConvertWszToSz(&ppszOID[i], ppwszOID[i], -1))
|
|
{
|
|
_JumpError(hr, error, "myConvertWszToSz");
|
|
}
|
|
}
|
|
*pcOut = cOID;
|
|
*pppszOut = ppszOID;
|
|
ppszOID = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
cuFreeStringArray(ppwszOID);
|
|
cuFreeStringArrayA(ppszOID);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbVerifyCert(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszfnCert,
|
|
IN WCHAR const *pwszfnCertCA,
|
|
IN WCHAR const *pwszfnCertCACrossed,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cApplicationPolicies;
|
|
char **ppszApplicationPolicies = NULL;
|
|
DWORD cIssuancePolicies;
|
|
char **ppszIssuancePolicies = NULL;
|
|
|
|
// First check for Application and Issuance policy OID lists
|
|
|
|
cApplicationPolicies = 0;
|
|
cIssuancePolicies = 0;
|
|
if (NULL != pwszfnCertCA)
|
|
{
|
|
hr = S_OK;
|
|
if (!myIsMinusSignString(pwszfnCertCA))
|
|
{
|
|
hr = cuParseOIDList(
|
|
pwszfnCertCA,
|
|
&cApplicationPolicies,
|
|
&ppszApplicationPolicies);
|
|
_PrintIfErrorStr2(hr, "cuParseOIDList", L"Application", hr);
|
|
}
|
|
if (S_OK == hr)
|
|
{
|
|
if (NULL != pwszfnCertCACrossed)
|
|
{
|
|
hr = cuParseOIDList(
|
|
pwszfnCertCACrossed,
|
|
&cIssuancePolicies,
|
|
&ppszIssuancePolicies);
|
|
_JumpIfErrorStr2(hr, error, "cuParseOIDList", L"Issuance", hr);
|
|
|
|
pwszfnCertCACrossed = NULL;
|
|
}
|
|
pwszfnCertCA = NULL;
|
|
}
|
|
}
|
|
if (NULL != pwszfnCertCA)
|
|
{
|
|
BOOL fCertLoaded;
|
|
|
|
hr = VerifyCertAgainstParent(
|
|
pwszfnCert,
|
|
pwszfnCertCA,
|
|
pwszfnCertCACrossed,
|
|
&fCertLoaded);
|
|
if (S_OK != hr && !fCertLoaded)
|
|
{
|
|
BOOL fCRLLoaded;
|
|
|
|
hr = VerifyCRLAgainstCACert(
|
|
pwszfnCert,
|
|
pwszfnCertCA,
|
|
pwszfnCertCACrossed,
|
|
&fCRLLoaded);
|
|
if (S_OK != hr && !fCRLLoaded)
|
|
{
|
|
hr = VerifyBlobAgainstCACert(pwszfnCert, pwszfnCertCA);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = VerifyCertAgainstChain(
|
|
pwszfnCert,
|
|
cApplicationPolicies,
|
|
ppszApplicationPolicies,
|
|
cIssuancePolicies,
|
|
ppszIssuancePolicies);
|
|
}
|
|
|
|
error:
|
|
cuFreeStringArrayA(ppszApplicationPolicies);
|
|
cuFreeStringArrayA(ppszIssuancePolicies);
|
|
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 fSuppressSuccess,
|
|
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;
|
|
if (!fSuppressSuccess)
|
|
{
|
|
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;
|
|
if (!fSuppressSuccess)
|
|
{
|
|
id = IDS_SIGNATUREMATCHES; // "Signature matches Public Key"
|
|
}
|
|
}
|
|
if (0 != id)
|
|
{
|
|
wprintf(myLoadResourceString(id), hr);
|
|
wprintf(wszNewLine);
|
|
}
|
|
return(hr);
|
|
}
|