//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1995 - 1999 // // File: verify.cpp // //-------------------------------------------------------------------------- #include #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(&pCertInfoCA->Issuer), const_cast(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(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(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(&pCertInfoCA->Issuer), const_cast(&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(&pCertInfo->Issuer), const_cast(&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(&pCertInfoCA->Issuer), const_cast(&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(&pCRLInfo->Issuer), const_cast(&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(pbEncoded), cbEncoded, const_cast(pcpki))) { hr = myHLastError(); if (E_INVALIDARG == hr) { CRYPT_DATA_BLOB Blob; Blob.cbData = cbEncoded; Blob.pbData = const_cast(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); }