//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1995 - 1999 // // File: dump.cpp // //-------------------------------------------------------------------------- #include #pragma hdrstop #include "csprop.h" #include "cscsp.h" #include "csber.h" #define __dwFILE__ __dwFILE_CERTUTIL_DUMP_CPP__ #if DBG #define wszCERTUTIL L"(certutil)" #else #define wszCERTUTIL L"" #endif WCHAR const g_wszCertUtil[] = wszCERTUTIL; DWORD s_DbgSsRecoveryTrace = DBG_SS_CERTUTILI; HRESULT DumpAttributes( IN CRYPT_ATTRIBUTE const *rgAttr, IN DWORD cAttr, IN BOOL fQuiet, IN DWORD Type, // FOT_* OPTIONAL IN HCERTSTORE hStore, OPTIONAL OUT BYTE *pbHashUserCert, OPTIONAL IN OUT DWORD *pcbHashUserCert, OPTIONAL IN OUT CERT_EXTENSIONS **ppExtInfo); WCHAR const * wszRDNValueType( IN DWORD dwValueType) { WCHAR const *pwsz; switch (CERT_RDN_TYPE_MASK & dwValueType) { case CERT_RDN_ANY_TYPE: pwsz = L"CERT_RDN_ANY_TYPE"; break; case CERT_RDN_ENCODED_BLOB: pwsz = L"CERT_RDN_ENCODED_BLOB"; break; case CERT_RDN_OCTET_STRING: pwsz = L"CERT_RDN_OCTET_STRING"; break; case CERT_RDN_NUMERIC_STRING: pwsz = L"CERT_RDN_NUMERIC_STRING"; break; case CERT_RDN_PRINTABLE_STRING: pwsz = L"CERT_RDN_PRINTABLE_STRING"; break; case CERT_RDN_TELETEX_STRING: pwsz = L"CERT_RDN_TELETEX_STRING"; break; //case CERT_RDN_T61_STRING: //pwsz = L"CERT_RDN_T61_STRING"; //break; case CERT_RDN_VIDEOTEX_STRING: pwsz = L"CERT_RDN_VIDEOTEX_STRING"; break; case CERT_RDN_IA5_STRING: pwsz = L"CERT_RDN_IA5_STRING"; break; case CERT_RDN_GRAPHIC_STRING: pwsz = L"CERT_RDN_GRAPHIC_STRING"; break; //case CERT_RDN_VISIBLE_STRING: //pwsz = L"CERT_RDN_VISIBLE_STRING"; //break; case CERT_RDN_ISO646_STRING: pwsz = L"CERT_RDN_ISO646_STRING"; break; case CERT_RDN_GENERAL_STRING: pwsz = L"CERT_RDN_GENERAL_STRING"; break; case CERT_RDN_UNIVERSAL_STRING: pwsz = L"CERT_RDN_UNIVERSAL_STRING"; break; //case CERT_RDN_INT4_STRING: //pwsz = L"CERT_RDN_INT4_STRING"; //break; //case CERT_RDN_BMP_STRING: //pwsz = L"CERT_RDN_BMP_STRING"; //break; case CERT_RDN_UNICODE_STRING: pwsz = L"CERT_RDN_UNICODE_STRING"; break; case CERT_RDN_UTF8_STRING: pwsz = L"CERT_RDN_UTF8_STRING"; break; default: pwsz = myLoadResourceString(IDS_QUESTIONMARKS); // "???" break; } return(pwsz); } VOID cuPrintCRLFString( IN WCHAR const *pwszPrefix, IN WCHAR const *pwszIn) { if (NULL == pwszPrefix) { pwszPrefix = g_wszEmpty; } while (L'\0' != *pwszIn) { DWORD i; WCHAR const *pwc; pwc = pwszIn++; i = wcscspn(pwszIn, L"\r\n"); wprintf( L"%.1ws%ws%.*ws", pwc, L'\n' == *pwc? pwszPrefix : g_wszEmpty, i, pwszIn); pwszIn += i; if (L'\r' == *pwszIn) { pwszIn++; } } } VOID cuPrintPossibleObjectIdName( IN WCHAR const *pwszObjId) { HRESULT hr; if (iswdigit(*pwszObjId)) { hr = myVerifyObjId(pwszObjId); if (S_OK == hr) { WCHAR const *pwszName = cuGetOIDName(pwszObjId); if (NULL != pwszName && L'\0' != *pwszName) { wprintf(L" %ws", pwszName); } } } } WCHAR const * cuGetOIDNameA( IN char const *pszObjId) { HRESULT hr; WCHAR const *pwszName1 = g_wszEmpty; WCHAR const *pwszName2; char *pszT = NULL; static WCHAR s_wszName[512]; pszT = (char *) LocalAlloc(LMEM_FIXED, 1 + strlen(pszObjId) + 1); if (NULL == pszT) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } strcpy(&pszT[1], pszObjId); *pszT = '+'; pwszName1 = myGetOIDNameA(pszT); // Group OID lookup *pszT = '-'; pwszName2 = myGetOIDNameA(pszT); // Generic OID lookup if (0 == mylstrcmpiL(pwszName1, pwszName2)) { pwszName2 = g_wszEmpty; // display only one if they're the same } if (L'\0' == *pwszName1) { pwszName1 = pwszName2; pwszName2 = g_wszEmpty; } if (L'\0' != *pwszName2 && ARRAYSIZE(s_wszName) > wcslen(pwszName1) + wcslen(pwszName2) + 3) { wcscpy(s_wszName, pwszName1); wcscat(s_wszName, L" " wszLPAREN); wcscat(s_wszName, pwszName2); wcscat(s_wszName, wszRPAREN); pwszName1 = s_wszName; } error: if (NULL != pszT) { LocalFree(pszT); } return(pwszName1); } WCHAR const * cuGetOIDName( IN WCHAR const *pwszObjId) { HRESULT hr; char *pszObjId = NULL; WCHAR const *pwszName = g_wszEmpty; if (!myConvertWszToSz(&pszObjId, pwszObjId, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertWszToSz"); } pwszName = cuGetOIDNameA(pszObjId); error: if (NULL != pszObjId) { LocalFree(pszObjId); } return(pwszName); } VOID cuDumpOIDAndDescriptionA( IN char const *pszObjId) { WCHAR const *pwsz; wprintf(L"%hs", pszObjId); pwsz = cuGetOIDNameA(pszObjId); if (NULL != pwsz && L'\0' != *pwsz) { wprintf(L" %ws", pwsz); } } VOID cuDumpOIDAndDescription( IN WCHAR const *pwszObjId) { WCHAR const *pwsz; wprintf(L"%ws", pwszObjId); pwsz = cuGetOIDName(pwszObjId); if (NULL != pwsz && L'\0' != *pwsz) { wprintf(L" %ws", pwsz); } } HRESULT cuCertNameToStr( IN BOOL fMultiLine, IN CERT_NAME_BLOB const *pNameBlob, OUT WCHAR **ppwszCertName) { HRESULT hr; DWORD Flags = CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG | CERT_NAME_STR_NO_QUOTING_FLAG; *ppwszCertName = NULL; if (fMultiLine) { Flags |= CERT_NAME_STR_CRLF_FLAG; } hr = myCertNameToStr( X509_ASN_ENCODING, pNameBlob, Flags, ppwszCertName); _JumpIfError(hr, error, "myCertNameToStr"); error: return(hr); } typedef struct _RDNTABLE { CHAR const *pszObjId; DWORD cchMax; } RDNTABLE; RDNTABLE const g_RdnTable[] = { { szOID_COUNTRY_NAME, cchCOUNTRYNAMEMAX }, { szOID_ORGANIZATION_NAME, cchORGANIZATIONNAMEMAX }, { szOID_ORGANIZATIONAL_UNIT_NAME, cchORGANIZATIONALUNITNAMEMAX }, { szOID_COMMON_NAME, cchCOMMONNAMEMAX }, { szOID_LOCALITY_NAME, cchLOCALITYMANAMEMAX }, { szOID_STATE_OR_PROVINCE_NAME, cchSTATEORPROVINCENAMEMAX }, { szOID_TITLE, cchTITLEMAX }, { szOID_GIVEN_NAME, cchGIVENNAMEMAX }, { szOID_INITIALS, cchINITIALSMAX }, { szOID_SUR_NAME, cchSURNAMEMAX }, { szOID_DOMAIN_COMPONENT, cchDOMAINCOMPONENTMAX }, { szOID_RSA_emailAddr, cchEMAILMAX }, { szOID_STREET_ADDRESS, cchSTREETADDRESSMAX }, { szOID_RSA_unstructName, cchUNSTRUCTUREDNAMEMAX }, { szOID_RSA_unstructAddr, cchUNSTRUCTUREDADDRESSMAX }, { szOID_DEVICE_SERIAL_NUMBER, cchDEVICESERIALNUMBERMAX }, { NULL, 0 }, }; DWORD cwcRDNMax( IN char const *pszObjId) { RDNTABLE const *pRdnTable; DWORD cwcMax = MAXDWORD; for (pRdnTable = g_RdnTable; NULL != pRdnTable->pszObjId; pRdnTable++) { if (0 == strcmp(pszObjId, pRdnTable->pszObjId)) { cwcMax = pRdnTable->cchMax; break; } } return(cwcMax); } HRESULT cuDisplayCertNameValue( OPTIONAL IN char const *pszObjId, OPTIONAL IN WCHAR const *pwszChoice, IN DWORD dwValueType, IN CRYPT_DATA_BLOB const *pValueW, IN CRYPT_DATA_BLOB const *pValueA) { HRESULT hr; DWORD cwc; DWORD cwcMax = MAXDWORD; CRYPT_DATA_BLOB ValueUTF8; ValueUTF8.pbData = NULL; cwc = pValueW->cbData / sizeof(WCHAR); if (NULL != pszObjId) { cwcMax = cwcRDNMax(pszObjId); } if (CERT_RDN_UTF8_STRING == dwValueType) { if (myConvertWszToUTF8( (char **) &ValueUTF8.pbData, (WCHAR const *) pValueW->pbData, pValueW->cbData / sizeof(WCHAR))) { ValueUTF8.cbData = strlen((CHAR const *) ValueUTF8.pbData); pValueA = &ValueUTF8; } } wprintf( L"%ws, %ws = %u", wszRDNValueType(dwValueType), myLoadResourceString(IDS_LENGTH), // "Length" pValueA->cbData); if (MAXDWORD != cwcMax || CERT_RDN_OCTET_STRING != dwValueType) { wprintf( L" " wszLPAREN L"%ws%ws%u", cwc <= cwcMax? g_wszEmpty : myLoadResourceString(IDS_OVERFLOW), // "OVERFLOW:" cwc <= cwcMax? g_wszEmpty : L" ", cwc); if (NULL != pszObjId && MAXDWORD != cwcMax) { wprintf(L"/%u", cwcMax); } wprintf( L" %ws" wszRPAREN, myLoadResourceString(IDS_CHARS)); // "Characters" } wprintf(wszNewLine); wprintf(g_wszPad8); if (NULL != pszObjId) { cuDumpOIDAndDescriptionA(pszObjId); wprintf(L"="); } else if (NULL != pwszChoice) { wprintf(L"%ws=", pwszChoice); } if (CERT_RDN_OCTET_STRING != dwValueType) { wprintf(L"\"%ws\"\n", pValueW->pbData); } wprintf(wszNewLine); DumpHex( DH_NOADDRESS | DH_NOTABPREFIX | 8, pValueA->pbData, pValueA->cbData); if (pValueA->cbData != pValueW->cbData || 0 != memcmp(pValueA->pbData, pValueW->pbData, pValueW->cbData)) { wprintf(wszNewLine); DumpHex( DH_NOADDRESS | DH_NOTABPREFIX | 8, pValueW->pbData, pValueW->cbData); } hr = S_OK; //error: if (NULL != ValueUTF8.pbData) { LocalFree(ValueUTF8.pbData); } return(hr); } HRESULT cuDisplayCertName( IN BOOL fMultiLine, OPTIONAL IN WCHAR const *pwszNamePrefix, OPTIONAL IN WCHAR const *pwszName, IN WCHAR const *pwszPad, IN CERT_NAME_BLOB const *pNameBlob, OPTIONAL IN CERT_INFO const *pCertInfo) { WCHAR *pwszCertName = NULL; DWORD i; HRESULT hr = S_OK; CERT_NAME_INFO *pNameInfoA = NULL; CERT_NAME_INFO *pNameInfoW = NULL; WCHAR *pwszAltName = NULL; DWORD cb; hr = cuCertNameToStr(fMultiLine, pNameBlob, &pwszCertName); _JumpIfError(hr, error, "cuCertNameToStr"); if (NULL != pwszNamePrefix) { wprintf(pwszNamePrefix); } if (NULL != pwszName) { wprintf(L"%ws:", pwszName); } wprintf(fMultiLine? L"\n%ws" : L" ", pwszPad); cuPrintCRLFString(pwszPad, pwszCertName); if (L'\0' == *pwszCertName) { wprintf(L"%ws", myLoadResourceString(IDS_PROP_EMPTY)); // "EMPTY" if (NULL != pCertInfo) { CERT_EXTENSION const *pExt; pExt = CertFindExtension( szOID_SUBJECT_ALT_NAME2, pCertInfo->cExtension, pCertInfo->rgExtension); if (NULL != pExt) { if (!CryptFormatObject( X509_ASN_ENCODING, 0, CRYPT_FORMAT_STR_NO_HEX, NULL, pExt->pszObjId, pExt->Value.pbData, pExt->Value.cbData, NULL, &cb)) { hr = myHLastError(); _PrintError(hr, "CryptFormatObject"); if (S_OK == hr) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); } } else { pwszAltName = (WCHAR *) LocalAlloc(LMEM_FIXED, cb); if (NULL == pwszAltName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (!CryptFormatObject( X509_ASN_ENCODING, 0, CRYPT_FORMAT_STR_NO_HEX, NULL, pExt->pszObjId, pExt->Value.pbData, pExt->Value.cbData, pwszAltName, &cb)) { hr = myHLastError(); _JumpError(hr, error, "CryptFormatObject"); } wprintf(L" (%ws)", pwszAltName); } } } } wprintf(wszNewLine); if (1 < g_fVerbose) { DumpHex( DH_NOTABPREFIX | 4, pNameBlob->pbData, pNameBlob->cbData); wprintf(wszNewLine); } if (!myDecodeName( X509_ASN_ENCODING, X509_UNICODE_NAME, pNameBlob->pbData, pNameBlob->cbData, CERTLIB_USE_LOCALALLOC, &pNameInfoW, &cb)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeName"); } if (!myDecodeName( X509_ASN_ENCODING, X509_NAME, pNameBlob->pbData, pNameBlob->cbData, CERTLIB_USE_LOCALALLOC, &pNameInfoA, &cb)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeName"); } if (g_fVerbose) { for (i = 0; i < pNameInfoW->cRDN; i++) { CERT_RDN const *prdnA; CERT_RDN const *prdnW; DWORD j; prdnA = &pNameInfoA->rgRDN[i]; prdnW = &pNameInfoW->rgRDN[i]; for (j = 0; j < prdnW->cRDNAttr; j++) { CERT_RDN_ATTR const *prdnaA; CERT_RDN_ATTR const *prdnaW; prdnaA = &prdnA->rgRDNAttr[j]; prdnaW = &prdnW->rgRDNAttr[j]; wprintf(L" [%u,%u]: ", i, j); hr = cuDisplayCertNameValue( prdnaW->pszObjId, NULL, prdnaW->dwValueType, &prdnaW->Value, &prdnaA->Value); _PrintIfError(hr, "cuDisplayCertNameValue"); wprintf(wszNewLine); } } } error: if (NULL != pwszCertName) { LocalFree(pwszCertName); } if (NULL != pwszAltName) { LocalFree(pwszAltName); } if (NULL != pNameInfoW) { LocalFree(pNameInfoW); } if (NULL != pNameInfoA) { LocalFree(pNameInfoA); } return(hr); } HRESULT cuDisplayCertNames( IN BOOL fMultiLine, OPTIONAL IN WCHAR const *pwszNamePrefix, IN CERT_INFO const *pCertInfo) { HRESULT hr; hr = cuDisplayCertName( fMultiLine, pwszNamePrefix, myLoadResourceString(IDS_ISSUER), // "Issuer" g_wszPad4, &pCertInfo->Issuer, NULL); _JumpIfError(hr, error, "cuDisplayCertName(Issuer)"); hr = cuDisplayCertName( fMultiLine, pwszNamePrefix, myLoadResourceString(IDS_SUBJECT), // "Subject" g_wszPad4, &pCertInfo->Subject, pCertInfo); _JumpIfError(hr, error, "cuDisplayCertName(Subject)"); error: return(hr); } #define POLICY_MASK \ (EXTENSION_POLICY_MASK & ~(EXTENSION_CRITICAL_FLAG | EXTENSION_DISABLE_FLAG)) #define EXTRA_MASK (~(EXTENSION_POLICY_MASK | EXTENSION_ORIGIN_MASK)) WCHAR const * cuwszFromExtFlags( DWORD ExtFlags) { static WCHAR awc[MAX_PATH]; WCHAR const *pwszComma; WCHAR const *pwszSep = wszLPAREN; DWORD msgid; WCHAR const *pwszT; awc[0] = L'\0'; pwszComma = myLoadResourceString(IDS_SEPARATOR); // ", " if (NULL == pwszComma) { pwszComma = L", "; } if (EXTENSION_CRITICAL_FLAG & ExtFlags) { wcscat(awc, pwszSep); pwszSep = pwszComma; pwszT = myLoadResourceString(IDS_CRITICAL); // "Critical" if (NULL != pwszT) { wcscat(awc, pwszT); } } if (~EXTENSION_CRITICAL_FLAG & ExtFlags) { if (EXTENSION_DISABLE_FLAG & ExtFlags) { wcscat(awc, pwszSep); pwszSep = pwszComma; pwszT = myLoadResourceString(IDS_DISABLED); // "Disabled" if (NULL != pwszT) { wcscat(awc, pwszT); } } if (POLICY_MASK & ExtFlags) { wcscat(awc, pwszSep); pwszSep = pwszComma; pwszT = myLoadResourceString(IDS_FORMAT_POLICYFLAGS); // "PolicyFlags=%x" if (NULL == pwszT) { pwszT = L"PolicyFlags=%x"; } wsprintf(&awc[wcslen(awc)], pwszT, POLICY_MASK & ExtFlags); } switch (EXTENSION_ORIGIN_MASK & ExtFlags) { case EXTENSION_ORIGIN_REQUEST: msgid = IDS_REQUEST; // "Request" break; case EXTENSION_ORIGIN_POLICY: msgid = IDS_POLICY; // "Policy" break; case EXTENSION_ORIGIN_ADMIN: msgid = IDS_ADMIN; // "Admin" break; case EXTENSION_ORIGIN_SERVER: msgid = IDS_SERVER; // "Server" break; case EXTENSION_ORIGIN_RENEWALCERT: msgid = IDS_RENEWALCERT; // "Renewal Cert" break; case EXTENSION_ORIGIN_IMPORTEDCERT: msgid = IDS_IMPORTEDCERT; // "Imported Cert" break; case EXTENSION_ORIGIN_PKCS7: msgid = IDS_PKCS7ATTRIBUTE; // "PKCS7 Attribute" break; case EXTENSION_ORIGIN_CMC: msgid = IDS_CMCATTRIBUTE; // "CMC Attribute" break; case EXTENSION_ORIGIN_CACERT: msgid = IDS_CACERTEXT; // "CA Cert" break; default: msgid = IDS_UNKNOWN; // "UNKNOWN" break; } wcscat(awc, pwszSep); pwszSep = pwszComma; pwszT = myLoadResourceString(IDS_FORMAT_ORIGIN); // "Origin=%ws" if (NULL == pwszT) { pwszT = L"Origin=%ws"; } wsprintf(&awc[wcslen(awc)], pwszT, myLoadResourceString(msgid)); if (EXTRA_MASK & ExtFlags) { wcscat(awc, pwszSep); pwszT = myLoadResourceString(IDS_FORMAT_UNKNOWN_HEX); // "???=%x" if (NULL == pwszT) { pwszT = L"???=%x"; } wsprintf(&awc[wcslen(awc)], pwszT, EXTRA_MASK & ExtFlags); } } if (L'\0' != awc[0]) { wcscat(awc, wszRPAREN); } return(awc); } VOID PrintStringWithPrefix( IN WCHAR const *pwszPrefix, IN WCHAR const *pwszIn) { while (L'\0' != *pwszIn) { DWORD i; DWORD j; WCHAR const *pwszNewLine; pwszNewLine = g_wszEmpty; j = 0; i = wcscspn(pwszIn, L"\n"); if (L'\n' == pwszIn[i]) { pwszNewLine = L"\n"; j++; if (0 < i && L'\r' == pwszIn[i - 1]) { i--; j++; } } wprintf(L"%ws%.*ws%ws", pwszPrefix, i, pwszIn, pwszNewLine); pwszIn += i + j; } } WCHAR const * wszAltNameChoice( IN LONG Choice) { WCHAR const *pwsz; switch (Choice) { case CERT_ALT_NAME_OTHER_NAME: pwsz = L"CERT_ALT_NAME_OTHER_NAME"; break; case CERT_ALT_NAME_RFC822_NAME: pwsz = L"CERT_ALT_NAME_RFC822_NAME"; break; case CERT_ALT_NAME_DNS_NAME: pwsz = L"CERT_ALT_NAME_DNS_NAME"; break; case CERT_ALT_NAME_X400_ADDRESS: pwsz = L"CERT_ALT_NAME_X400_ADDRESS"; break; case CERT_ALT_NAME_DIRECTORY_NAME: pwsz = L"CERT_ALT_NAME_DIRECTORY_NAME"; break; case CERT_ALT_NAME_EDI_PARTY_NAME: pwsz = L"CERT_ALT_NAME_EDI_PARTY_NAME"; break; case CERT_ALT_NAME_URL: pwsz = L"CERT_ALT_NAME_URL"; break; case CERT_ALT_NAME_IP_ADDRESS: pwsz = L"CERT_ALT_NAME_IP_ADDRESS"; break; case CERT_ALT_NAME_REGISTERED_ID: pwsz = L"CERT_ALT_NAME_REGISTERED_ID"; break; default: pwsz = myLoadResourceString(IDS_QUESTIONMARKS); // "???" break; } return(pwsz); } HRESULT DumpIPAddress( IN WCHAR const *pwszPad, IN UINT idsMsg, IN BYTE const *pb, IN DWORD cb) { HRESULT hr; if (CB_IPV6ADDRESS != cb && CB_IPV4ADDRESS != cb) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "IPAddress size"); } wprintf(L"%ws %ws = ", pwszPad, myLoadResourceString(idsMsg)); if (CB_IPV6ADDRESS == cb) { BYTE abZero[CB_IPV6ADDRESS - CB_IPV4ADDRESS]; ZeroMemory(abZero, sizeof(abZero)); if (0 == memcmp(abZero, pb, sizeof(abZero))) { wprintf(L"::"); pb += sizeof(abZero); cb = CB_IPV4ADDRESS; CSASSERT(CB_IPV6ADDRESS - sizeof(abZero) == cb); } else { DWORD j; WCHAR const *pwsz = L""; BOOL fZeroSeen = FALSE; BOOL fZero = FALSE; for (j = 0; j < cb / sizeof(USHORT); j++) { USHORT us = (pb[sizeof(USHORT) * j] << 8) | pb[sizeof(USHORT) * j + 1]; if (0 == us && (fZero || !fZeroSeen)) { fZero = TRUE; fZeroSeen = TRUE; pwsz = L"::"; } else { wprintf(L"%ws%04x", pwsz, us); pwsz = L":"; fZero = FALSE; } } if (fZero) { wprintf(L"%ws", pwsz); CSASSERT(0 == lstrcmp(pwsz, L"::")); } } } if (CB_IPV4ADDRESS == cb) { wprintf( L"%u.%u.%u.%u", pb[0], pb[1], pb[2], pb[3]); } wprintf(wszNewLine); hr = S_OK; error: return(hr); } HRESULT DumpAltName( IN WCHAR const *pwszPad, IN DWORD dwSubtreeIndex, IN BYTE const *pbExtension, IN DWORD cbExtension) { HRESULT hr; BSTR strExtension = NULL; BSTR strObjId = NULL; BSTR strName = NULL; ICertEncodeAltName *pAltName = NULL; CRYPT_DATA_BLOB *pBlob = NULL; LONG Count; LONG Choice; LONG i; DWORD cb; hr = CoCreateInstance( CLSID_CCertEncodeAltName, NULL, // pUnkOuter CLSCTX_INPROC_SERVER, IID_ICertEncodeAltName, (VOID **) &pAltName); _JumpIfError(hr, error, "CoCreateInstance"); if (!ConvertWszToBstr( &strExtension, (WCHAR const *) pbExtension, cbExtension)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToBstr"); } hr = pAltName->Decode(strExtension); _JumpIfError(hr, error, "Decode"); hr = pAltName->GetNameCount(&Count); _JumpIfError(hr, error, "GetNameCount"); if (MAXDWORD == dwSubtreeIndex) { wprintf(pwszPad); wprintf( myLoadResourceString(IDS_FORMAT_ALTNAMECOUNT), // "AltName: %u entries:" Count); wprintf(wszNewLine); } for (i = 0; i < Count; i++) { BOOL fHex = FALSE; BOOL fNameBlob = FALSE; hr = pAltName->GetNameChoice(i, &Choice); _JumpIfError(hr, error, "GetNameChoice"); if (NULL != strName) { SysFreeString(strName); strName = NULL; } hr = pAltName->GetName(i, &strName); _JumpIfError(hr, error, "GetName"); myRegisterMemAlloc(strName, -1, CSM_SYSALLOC); wprintf(pwszPad); if (MAXDWORD == dwSubtreeIndex) { wprintf( L"%ws[%u] ", myLoadResourceString(IDS_ALTNAME), // "AltName" i); } wprintf(L"%ws:", wszAltNameChoice(Choice)); if (CERT_ALT_NAME_DIRECTORY_NAME == Choice) { fNameBlob = TRUE; // Name is encoded as a blob } else if (CERT_ALT_NAME_IP_ADDRESS == Choice) { BYTE const *pb = (BYTE const *) strName; cb = SysStringByteLen(strName); wprintf(wszNewLine); if (2 * CB_IPV6ADDRESS == cb || 2 * CB_IPV4ADDRESS == cb) { DumpIPAddress(pwszPad, IDS_IPADDRESS, pb, cb / 2); DumpIPAddress(pwszPad, IDS_MASK, &pb[cb / 2], cb / 2); } else { fHex = TRUE; } } else if (CERT_ALT_NAME_OTHER_NAME == Choice) { if (NULL != strObjId) { SysFreeString(strObjId); strObjId = NULL; } hr = pAltName->GetName(EAN_NAMEOBJECTID | i, &strObjId); _JumpIfError(hr, error, "GetName"); myRegisterMemAlloc(strObjId, -1, CSM_SYSALLOC); wprintf(L" "); cuDumpOIDAndDescription(strObjId); wprintf(L": "); if (0 == lstrcmp(TEXT(szOID_NT_PRINCIPAL_NAME), strObjId) || BER_UTF8_STRING == *(BYTE const *) strName || BER_UNICODE_STRING == *(BYTE const *) strName) { CERT_NAME_VALUE *pNameValueA = NULL; CERT_NAME_VALUE *pNameValueW = NULL; if (!myDecodeObject( X509_ASN_ENCODING, X509_ANY_STRING, (BYTE *) strName, SysStringByteLen(strName), CERTLIB_USE_LOCALALLOC, (VOID **) &pNameValueA, &cb)) { hr = myHLastError(); _PrintError(hr, "myDecodeObject"); CSASSERT(NULL == pNameValueA); } if (!myDecodeObject( X509_ASN_ENCODING, X509_UNICODE_ANY_STRING, (BYTE *) strName, SysStringByteLen(strName), CERTLIB_USE_LOCALALLOC, (VOID **) &pNameValueW, &cb)) { hr = myHLastError(); _PrintError(hr, "myDecodeObject"); CSASSERT(NULL == pNameValueW); } if (NULL != pNameValueA && NULL != pNameValueW) { wprintf(wszNewLine); wprintf(L"%ws ", pwszPad); hr = cuDisplayCertNameValue( NULL, NULL, // wszAltNameChoice(Choice), pNameValueW->dwValueType, &pNameValueW->Value, &pNameValueA->Value); _PrintIfError(hr, "cuDisplayCertNameValue"); wprintf(wszNewLine); } if (NULL != pNameValueA) { LocalFree(pNameValueA); } if (NULL != pNameValueW) { LocalFree(pNameValueW); } } else if (0 == lstrcmp(TEXT(szOID_NTDS_REPLICATION), strObjId) || BER_OCTET_STRING == *(BYTE const *) strName) { fHex = TRUE; if (myDecodeObject( X509_ASN_ENCODING, X509_OCTET_STRING, (BYTE const *) strName, SysStringByteLen(strName), CERTLIB_USE_LOCALALLOC, (VOID **) &pBlob, &cb)) { if (0 == lstrcmp(TEXT(szOID_NTDS_REPLICATION), strObjId) && pBlob->cbData == sizeof(GUID)) { WCHAR *pwsz; hr = myCLSIDToWsz((CLSID const *) pBlob->pbData, &pwsz); if (S_OK == hr) { wprintf(L"\n%ws %ws\n", pwszPad, pwsz); LocalFree(pwsz); fHex = FALSE; } } if (fHex) { wprintf(wszNewLine); DumpHex( DH_NOTABPREFIX | 8, pBlob->pbData, pBlob->cbData); wprintf(wszNewLine); fHex = FALSE; } } } else { fHex = TRUE; } } else { wprintf(L" \"%ws\"\n", strName); } if (fNameBlob) { CERT_NAME_BLOB Name; Name.pbData = (BYTE *) strName; Name.cbData = SysStringByteLen(strName); hr = cuDisplayCertName( TRUE, NULL, NULL, // wszAltNameChoice(Choice) g_wszPad8, &Name, NULL); _PrintIfError(hr, "cuDisplayCertName(DirectoryName)"); if (S_OK != hr) { fHex = TRUE; } } if (fHex) { wprintf(wszNewLine); DumpHex( DH_NOTABPREFIX | 8, (BYTE *) strName, SysStringByteLen(strName)); wprintf(wszNewLine); } } error: if (NULL != pBlob) { LocalFree(pBlob); } if (NULL != strObjId) { SysFreeString(strObjId); } if (NULL != strName) { SysFreeString(strName); } if (NULL != strExtension) { SysFreeString(strExtension); } if (NULL != pAltName) { pAltName->Release(); } return(hr); } HRESULT DumpGeneralSubTree( IN UINT idsMsg, IN DWORD cSubtree, IN CERT_GENERAL_SUBTREE const *rgSubtree) { HRESULT hr; HRESULT hr2; DWORD i; CERT_ALT_NAME_INFO cani; BYTE *pb = NULL; DWORD cb; wprintf(L" %ws:\n", myLoadResourceString(idsMsg)); hr = S_OK; for (i = 0; i < cSubtree; i++) { wprintf( L" %ws[%u]: " wszLPAREN L"%u...", myLoadResourceString(IDS_SUBTREE), i, rgSubtree[i].dwMinimum); wprintf( rgSubtree[i].fMaximum? L"%u" : L"Max", rgSubtree[i].dwMaximum); wprintf(wszRPAREN L"\n"); cani.cAltEntry = 1; cani.rgAltEntry = const_cast(&rgSubtree[i].Base); if (!myEncodeObject( X509_ASN_ENCODING, X509_ALTERNATE_NAME, &cani, 0, CERTLIB_USE_LOCALALLOC, &pb, // pbEncoded &cb)) { hr = myHLastError(); _JumpError(hr, error, "myEncodeObject"); } hr2 = DumpAltName(g_wszPad6, i, pb, cb); _PrintIfError(hr2, "DumpAltName"); if (S_OK == hr) { hr = hr2; } LocalFree(pb); pb = NULL; } _JumpIfError(hr, error, "DumpAltName"); error: if (NULL != pb) { LocalFree(pb); } return(hr); } HRESULT DumpNameConstraints( IN BYTE const *pbExtension, IN DWORD cbExtension) { HRESULT hr; HRESULT hr2; CERT_NAME_CONSTRAINTS_INFO *pnci = NULL; DWORD cb; if (!myDecodeObject( X509_ASN_ENCODING, X509_NAME_CONSTRAINTS, pbExtension, cbExtension, CERTLIB_USE_LOCALALLOC, (VOID **) &pnci, &cb)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeObject"); } hr = DumpGeneralSubTree( IDS_PERMITTED, pnci->cPermittedSubtree, pnci->rgPermittedSubtree); _PrintIfError(hr, "DumpGeneralSubTree"); hr2 = DumpGeneralSubTree( IDS_EXCLUDED, pnci->cExcludedSubtree, pnci->rgExcludedSubtree); _PrintIfError(hr2, "DumpGeneralSubTree"); if (S_OK == hr) { hr = hr2; } _JumpIfError(hr, error, "DumpGeneralSubTree"); error: if (NULL != pnci) { LocalFree(pnci); } return(hr); } HRESULT DumpOctetHash( IN WCHAR const *pwszPad, IN UINT idsDescription, OPTIONAL IN WCHAR const *pwszCertutil, IN BYTE const *pbIn, IN DWORD cbIn, OPTIONAL OUT BYTE *pbOut, OPTIONAL IN OUT DWORD *pcbOut) { HRESULT hr; CRYPT_DATA_BLOB aBlob[1 + BLOB_ROUND(CBMAX_CRYPT_HASH_LEN)]; DWORD cb; BSTR strHash = NULL; cb = sizeof(aBlob); if (CryptDecodeObject( X509_ASN_ENCODING, X509_OCTET_STRING, pbIn, cbIn, 0, aBlob, &cb)) { if (NULL == pbOut) { wprintf( L"%ws%ws%ws:\n", pwszPad, 0 != idsDescription? myLoadResourceString(idsDescription) : g_wszEmpty, NULL != pwszCertutil? pwszCertutil : g_wszEmpty); hr = MultiByteIntegerToBstr( TRUE, aBlob[0].cbData, aBlob[0].pbData, &strHash); _JumpIfError(hr, error, "MultiByteIntegerToBstr"); wprintf(L" %ws\n", strHash); } else { if (NULL == pcbOut) { hr = E_INVALIDARG; _JumpError(hr, error, "NULL parm"); } cb = *pcbOut; *pcbOut = aBlob[0].cbData; CopyMemory(pbOut, aBlob[0].pbData, min(cb, aBlob[0].cbData)); if (cb < aBlob[0].cbData) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); _JumpError(hr, error, "buffer too small"); } } } hr = S_OK; error: if (NULL != strHash) { SysFreeString(strHash); } return(hr); } HRESULT DumpHash( OPTIONAL IN WCHAR const *pwszPrefix, OPTIONAL IN DWORD idMessage, OPTIONAL IN WCHAR const *pwszHashNamePrefix, IN WCHAR const *pwszHashName, IN BYTE const *pbHash, IN DWORD cbHash) { HRESULT hr; BSTR strHash = NULL; WCHAR *pwsz = NULL; if (NULL != pbHash) { hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strHash); _JumpIfError(hr, error, "MultiByteIntegerToBstr"); if (NULL != pwszPrefix) { wprintf(pwszPrefix); } if (0 != idMessage) { if (NULL != pwszHashNamePrefix) { DWORD cwc; cwc = wcslen(pwszHashNamePrefix) + 1 + wcslen(pwszHashName); pwsz = (WCHAR *) LocalAlloc( LMEM_FIXED, (cwc + 1) * sizeof(WCHAR)); if (NULL == pwsz) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwsz, pwszHashNamePrefix); wcscat(pwsz, L" "); wcscat(pwsz, pwszHashName); CSASSERT(wcslen(pwsz) == cwc); pwszHashName = pwsz; } wprintf(myLoadResourceString(idMessage), pwszHashName, strHash); } else { wprintf(strHash); } wprintf(wszNewLine); if (1 < g_fVerbose) { DumpHex(DH_NOTABPREFIX | 4, pbHash, cbHash); wprintf(wszNewLine); } } hr = S_OK; error: if (NULL != pwsz) { LocalFree(pwsz); } if (NULL != strHash) { SysFreeString(strHash); } return(hr); } #define FOT_EXTENSION 0 #define FOT_ATTRIBUTE 1 #define FOT_PROPERTY 2 BOOL DumpFormattedObject( IN char const *pszObjId, IN DWORD Type, // FOT_* IN BYTE const *pbObject, IN DWORD cbObject) { HRESULT hr; BOOL fDisplayed = FALSE; WCHAR *pwszFormatted = NULL; DWORD cbFormatted; CRYPT_DATA_BLOB *pBlobProp = NULL; DWORD cbBlobProp; WCHAR const *pwszPrefix0 = g_wszPad4; WCHAR const *pwszPrefix1 = g_wszPad8; WCHAR const *pwszDescriptiveName; // format the object using the installed formatting function hr = S_OK; if (!CryptFormatObject( X509_ASN_ENCODING, 0, CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX, NULL, pszObjId, pbObject, cbObject, NULL, &cbFormatted)) { hr = myHLastError(); _PrintErrorStr2(hr, pszObjId, L"CryptFormatObject", hr); if (S_OK == hr) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); } } if (S_OK != hr) { if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr && CRYPT_E_ASN1_BADTAG != hr && CRYPT_E_ASN1_CORRUPT != hr) { _JumpError(hr, error, "CryptFormatObject"); } if (FOT_PROPERTY == Type) { if (!myDecodeObject( X509_ASN_ENCODING, X509_OCTET_STRING, pbObject, cbObject, CERTLIB_USE_LOCALALLOC, (VOID **) &pBlobProp, &cbBlobProp)) { hr = myHLastError(); _PrintError(hr, "myDecodeObject"); } else { hr = cuDumpFormattedProperty( MAXDWORD, pszObjId, pBlobProp->pbData, pBlobProp->cbData); _PrintIfError(hr, "cuDumpFormattedProperty"); if (S_OK == hr) { fDisplayed = TRUE; } } } if (S_OK != hr && !g_fQuiet) { PrintStringWithPrefix( pwszPrefix0, myLoadResourceString(FOT_ATTRIBUTE == Type? IDS_UNKNOWN_ATTRIBUTE : // "Unknown Attribute type" (FOT_EXTENSION == Type? IDS_UNKNOWN_EXTENSION : // "Unknown Extension type" IDS_UNKNOWN_PROPERTY))); // "Unknown Property" wprintf(wszNewLine); } } else { pwszFormatted = (WCHAR *) LocalAlloc(LMEM_FIXED, cbFormatted); if (NULL == pwszFormatted) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } if (!CryptFormatObject( X509_ASN_ENCODING, 0, CRYPT_FORMAT_STR_MULTI_LINE | CRYPT_FORMAT_STR_NO_HEX, NULL, pszObjId, pbObject, cbObject, pwszFormatted, &cbFormatted)) { hr = myHLastError(); _JumpErrorStr(hr, error, pszObjId, L"CryptFormatObject"); } PrintStringWithPrefix(g_fQuiet? g_wszEmpty : pwszPrefix1, pwszFormatted); fDisplayed = TRUE; } if (g_fVerbose) { if (0 == strcmp(szOID_SUBJECT_ALT_NAME, pszObjId) || 0 == strcmp(szOID_SUBJECT_ALT_NAME2, pszObjId) || 0 == strcmp(szOID_ISSUER_ALT_NAME, pszObjId) || 0 == strcmp(szOID_ISSUER_ALT_NAME2, pszObjId)) { DumpAltName(g_wszPad4, MAXDWORD, pbObject, cbObject); } else if (0 == strcmp(szOID_NAME_CONSTRAINTS, pszObjId)) { DumpNameConstraints(pbObject, cbObject); } } error: if (NULL != pBlobProp) { LocalFree(pBlobProp); } if (NULL != pwszFormatted) { LocalFree(pwszFormatted); } return(fDisplayed); } HRESULT cuDumpUsage( OPTIONAL IN WCHAR const *pwszPrefix, IN DWORD idMessage, IN CTL_USAGE const *pUsage) { HRESULT hr; DWORD i; if (NULL == pwszPrefix) { pwszPrefix = L""; } wprintf(L"%ws", pwszPrefix); wprintf(myLoadResourceString(idMessage)); wprintf(L" %u\n", pUsage->cUsageIdentifier); for (i = 0; i < pUsage->cUsageIdentifier; i++) { wprintf( L"%ws%ws[%d] ", pwszPrefix, g_wszPad2, i); cuDumpOIDAndDescriptionA(pUsage->rgpszUsageIdentifier[i]); wprintf(wszNewLine); } hr = S_OK; //error: return(hr); } #ifndef XENROLL_PASS_THRU_PROP_ID #define XENROLL_PASS_THRU_PROP_ID (CERT_FIRST_USER_PROP_ID + 0x100) #endif #ifndef XENROLL_RENEWAL_CERTIFICATE_PROP_ID #define XENROLL_RENEWAL_CERTIFICATE_PROP_ID (CERT_FIRST_USER_PROP_ID + 0x101) #endif typedef struct _DUMPPROP { DWORD dwPropId; WCHAR const *pwszDescription; } DUMPPROP; #define _DFPROP(def) { (def), L#def } DUMPPROP s_apwszPropIds[] = { _DFPROP(CERT_KEY_PROV_HANDLE_PROP_ID), _DFPROP(CERT_KEY_PROV_INFO_PROP_ID), _DFPROP(CERT_SHA1_HASH_PROP_ID), _DFPROP(CERT_MD5_HASH_PROP_ID), _DFPROP(CERT_KEY_CONTEXT_PROP_ID), _DFPROP(CERT_KEY_SPEC_PROP_ID), _DFPROP(CERT_IE30_RESERVED_PROP_ID), _DFPROP(CERT_PUBKEY_HASH_RESERVED_PROP_ID), _DFPROP(CERT_ENHKEY_USAGE_PROP_ID), _DFPROP(CERT_NEXT_UPDATE_LOCATION_PROP_ID), _DFPROP(CERT_FRIENDLY_NAME_PROP_ID), _DFPROP(CERT_PVK_FILE_PROP_ID), _DFPROP(CERT_DESCRIPTION_PROP_ID), _DFPROP(CERT_ACCESS_STATE_PROP_ID), _DFPROP(CERT_SIGNATURE_HASH_PROP_ID), _DFPROP(CERT_SMART_CARD_DATA_PROP_ID), _DFPROP(CERT_EFS_PROP_ID), _DFPROP(CERT_FORTEZZA_DATA_PROP_ID), _DFPROP(CERT_ARCHIVED_PROP_ID), _DFPROP(CERT_KEY_IDENTIFIER_PROP_ID), _DFPROP(CERT_AUTO_ENROLL_PROP_ID), _DFPROP(CERT_PUBKEY_ALG_PARA_PROP_ID), _DFPROP(CERT_CROSS_CERT_DIST_POINTS_PROP_ID), _DFPROP(CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID), _DFPROP(CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID), _DFPROP(CERT_ENROLLMENT_PROP_ID), _DFPROP(CERT_DATE_STAMP_PROP_ID), _DFPROP(CERT_ISSUER_SERIAL_NUMBER_MD5_HASH_PROP_ID), _DFPROP(CERT_SUBJECT_NAME_MD5_HASH_PROP_ID), _DFPROP(CERT_EXTENDED_ERROR_INFO_PROP_ID), _DFPROP(XENROLL_PASS_THRU_PROP_ID), _DFPROP(XENROLL_RENEWAL_CERTIFICATE_PROP_ID), }; HRESULT cuDecodeBool( IN BYTE const *pbIn, IN DWORD cbIn, OUT BOOL *pfWriteToDS) { HRESULT hr; hr = E_INVALIDARG; if (3 == cbIn && BER_BOOL == pbIn[0] && 1 == pbIn[1]) { *pfWriteToDS = FALSE; if (0 != pbIn[2]) { if (0xff != pbIn[2]) { _PrintError(hr, "BER_BOOL"); } *pfWriteToDS = TRUE; } hr = S_OK; } return(hr); } HRESULT DecodeRequestFlags( IN BYTE const *pbIn, IN DWORD cbIn, OUT BOOL *pfWriteToCSP, OUT BOOL *pfWriteToDS, OUT DWORD *popenFlags) { HRESULT hr; CRYPT_SEQUENCE_OF_ANY *pSeq = NULL; DWORD cb; hr = cuDecodeSequence(pbIn, cbIn, 3, &pSeq); _JumpIfError(hr, error, "cuDecodeSequence"); hr = cuDecodeBool( pSeq->rgValue[0].pbData, pSeq->rgValue[0].cbData, pfWriteToCSP); _JumpIfError(hr, error, "cuDecodeBool"); hr = cuDecodeBool( pSeq->rgValue[1].pbData, pSeq->rgValue[1].cbData, pfWriteToDS); _JumpIfError(hr, error, "cuDecodeBool"); cb = sizeof(*popenFlags); *popenFlags = 0; if (!CryptDecodeObject( X509_ASN_ENCODING, X509_INTEGER, pSeq->rgValue[2].pbData, pSeq->rgValue[2].cbData, 0, popenFlags, &cb)) { hr = myHLastError(); _JumpError(hr, error, "CryptDecodeObject"); } hr = S_OK; error: if (NULL != pSeq) { LocalFree(pSeq); } return(hr); } HRESULT cuDumpFormattedProperty( IN DWORD dwPropId, OPTIONAL IN char const *pszObjId, IN BYTE const *pb, IN DWORD cb) { HRESULT hr; char szObjId[sizeof(szOID_CERT_PROP_ID_PREFIX) + 20]; WCHAR const *pwszDescriptiveName; BOOL fDisplayed; DWORD i; CSASSERT(NULL == pszObjId || MAXDWORD == dwPropId); hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); if (NULL != pszObjId) { char const *psz; if (0 != strncmp( szOID_CERT_PROP_ID_PREFIX, pszObjId, ARRAYSIZE(szOID_CERT_PROP_ID_PREFIX) - 1)) { _JumpError(hr, error, "Not a property ObjId"); } psz = &pszObjId[ARRAYSIZE(szOID_CERT_PROP_ID_PREFIX) - 1]; dwPropId = atol(psz); while ('\0' != *psz) { if (!isdigit(*psz)) { _JumpError(hr, error, "Bad property ObjId suffix"); } psz++; } } wprintf(wszNewLine); for (i = 0; ; i++) { if (i >= ARRAYSIZE(s_apwszPropIds)) { pwszDescriptiveName = myLoadResourceString(IDS_UNKNOWN_PROPERTY); // "Unknown Property" break; } if (s_apwszPropIds[i].dwPropId == dwPropId) { pwszDescriptiveName = s_apwszPropIds[i].pwszDescription; break; } } wprintf(L" %ws", pwszDescriptiveName); if (NULL != pszObjId) { wprintf(L"(%hs)", pszObjId); } else { wprintf(L"(%u)", dwPropId); } sprintf(szObjId, "%hs%u", szOID_CERT_PROP_ID_PREFIX, dwPropId); pwszDescriptiveName = cuGetOIDNameA(szObjId); if (NULL != pwszDescriptiveName && L'\0' != *pwszDescriptiveName) { wprintf(L" %ws", pwszDescriptiveName); } wprintf(L":\n"); #if 0 fDisplayed = DumpFormattedObject(szObjId, FOT_PROPERTY, pb, cb); #else fDisplayed = FALSE; #endif if (!fDisplayed) { if (IS_CERT_HASH_PROP_ID(dwPropId) || IS_PUBKEY_HASH_PROP_ID(dwPropId) || IS_CHAIN_HASH_PROP_ID(dwPropId) || CERT_KEY_IDENTIFIER_PROP_ID == dwPropId) { wprintf(g_wszPad4); hr = DumpHash(NULL, 0, NULL, g_wszEmpty, pb, cb); _JumpIfError(hr, error, "DumpHash"); fDisplayed = TRUE; } else if (CERT_FRIENDLY_NAME_PROP_ID == dwPropId || CERT_DESCRIPTION_PROP_ID == dwPropId) { wprintf(L"%ws%ws\n", g_wszPad4, pb); fDisplayed = TRUE; } else if (CERT_KEY_PROV_INFO_PROP_ID == dwPropId) { hr = cuDumpCertKeyProviderInfo( g_wszPad4, NULL, (CRYPT_KEY_PROV_INFO *) pb, NULL); _JumpIfError(hr, error, "cuDumpCertKeyProviderInfo"); fDisplayed = TRUE; } else if (CERT_AUTO_ENROLL_PROP_ID == dwPropId) { wprintf( L"%ws%ws = %.*ws\n", g_wszPad4, myLoadResourceString(IDS_PROP_AUTOENROLL), // "AutoEnroll Property" cb / sizeof(WCHAR), pb); fDisplayed = TRUE; } else if (CERT_ENROLLMENT_PROP_ID == dwPropId) { BYTE const *pbTmp = pb; DWORD cbTmp = cb; DWORD cwc; if (sizeof(LONG) <= cbTmp) { // RequestId: wprintf( L"%ws%ws = %u\n", g_wszPad4, myLoadResourceString(IDS_REQUESTID), // "RequestId" *(LONG *) pbTmp); pbTmp += sizeof(LONG); cbTmp -= sizeof(LONG); if (sizeof(cwc) <= cbTmp) { // CA DNS name: cwc = *(DWORD *) pbTmp; pbTmp += sizeof(cwc); // skip count of next field cbTmp -= sizeof(cwc); wprintf( L"%ws%ws = %.*ws\\", g_wszPad4, myLoadResourceString(IDS_CADNSNAME), // "Authority" min(cwc, cbTmp / sizeof(WCHAR)), pbTmp); pbTmp += cwc * sizeof(WCHAR); cbTmp -= cwc * sizeof(WCHAR); if (sizeof(cwc) <= cbTmp) { // CA name: cwc = *(DWORD UNALIGNED *) pbTmp; pbTmp += sizeof(cwc); // skip count of next field cbTmp -= sizeof(cwc); wprintf( L"%.*ws\n", min(cwc, cbTmp / sizeof(WCHAR)), pbTmp); pbTmp += cwc * sizeof(WCHAR); cbTmp -= cwc * sizeof(WCHAR); if (sizeof(cwc) <= cbTmp) { // friendly name: cwc = *(DWORD UNALIGNED *) pbTmp; pbTmp += sizeof(cwc); // skip count of next field cbTmp -= sizeof(cwc); wprintf( L"%ws%ws = %.*ws\n", g_wszPad4, myLoadResourceString(IDS_FRIENDLYNAME), // "Friendly Name" min(cwc, cbTmp / sizeof(WCHAR)), pbTmp); pbTmp += cwc * sizeof(WCHAR); cbTmp -= cwc * sizeof(WCHAR); fDisplayed = TRUE; } } } } } else if (CERT_CTL_USAGE_PROP_ID == dwPropId) { CTL_USAGE *pUsage; if (!myDecodeObject( X509_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, pb, cb, CERTLIB_USE_LOCALALLOC, (VOID **) &pUsage, &cb)) { hr = myHLastError(); _PrintError(hr, "myDecodeObject"); } else { hr = cuDumpUsage(g_wszPad2, IDS_USAGEENTRIES, pUsage); _JumpIfError(hr, error, "cuDumpUsage"); fDisplayed = TRUE; } } else if (CERT_PUBKEY_ALG_PARA_PROP_ID == dwPropId) { CERT_DSS_PARAMETERS *pDssParms; if (!myDecodeObject( X509_ASN_ENCODING, X509_DSS_PARAMETERS, pb, cb, CERTLIB_USE_LOCALALLOC, (VOID **) &pDssParms, &cb)) { hr = myHLastError(); _PrintError(hr, "myDecodeObject"); } else { wprintf( myLoadResourceString(IDS_FORMAT_DSSKEY_LENGTH), // "DSS Key Length: %u bits" pDssParms->p.cbData * 8); wprintf(L" DSS P:\n"); DumpHex( DH_NOADDRESS | DH_NOTABPREFIX | 4, pDssParms->p.pbData, pDssParms->p.cbData); wprintf(L" DSS Q:\n"); DumpHex( DH_NOADDRESS | DH_NOTABPREFIX | 4, pDssParms->q.pbData, pDssParms->q.cbData); wprintf(L" DSS G:\n"); DumpHex( DH_NOADDRESS | DH_NOTABPREFIX | 4, pDssParms->g.pbData, pDssParms->g.cbData); LocalFree(pDssParms); fDisplayed = TRUE; } } else if (XENROLL_PASS_THRU_PROP_ID == dwPropId) { BOOL fWriteToCSP; BOOL fWriteToDS; DWORD openFlags; hr = DecodeRequestFlags( pb, cb, &fWriteToCSP, &fWriteToDS, &openFlags); _PrintIfError(hr, "DecodeRequestFlags"); if (S_OK == hr) { wprintf(L" fWriteToCSP: %u\n", fWriteToCSP); wprintf(L" fWriteToDS: %u\n", fWriteToDS); wprintf(L" openFlags: 0x%x\n", openFlags); fDisplayed = TRUE; } } else if (XENROLL_RENEWAL_CERTIFICATE_PROP_ID == dwPropId) { wprintf(myLoadResourceString(IDS_RENEWAL_CERT)); // "Renewal Certificate:" wprintf(wszNewLine); hr = cuDumpAsnBinary(pb, cb, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); } } if (!fDisplayed || g_fVerbose) { DumpHex(DH_NOADDRESS | DH_NOTABPREFIX | 4, pb, cb); } hr = S_OK; error: return(hr); } //+------------------------------------------------------------------------- // cuDecodeObjId -- decode an ASN.1 encoded ObjectId // // Construct an ASN.1 encoded PKCS_ATTRIBUTE with an array of empty values, // to trick CryptDecodeObject into decoding the passed in encoded Object Id. //-------------------------------------------------------------------------- HRESULT cuDecodeObjId( IN BYTE const *pbData, IN DWORD cbData, OUT char **ppszObjId) { HRESULT hr; CRYPT_ATTRIBUTE *pAttr = NULL; BYTE *pbAlloc = NULL; DWORD cbAlloc; BYTE *pb; DWORD cb; //DumpHex(DH_NOTABPREFIX | 2, pbData, cbData); cbAlloc = 2 + cbData + 2; pbAlloc = (BYTE *) LocalAlloc(LMEM_FIXED, cbAlloc); if (NULL == pbAlloc) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } pb = pbAlloc; *pb++ = BER_SEQUENCE; // PKCS_ATTRIBUTE sequence CSASSERT(0x7f >= cbData + 2); *pb++ = (BYTE ) (cbData + 2); // overall length CopyMemory(pb, pbData, cbData); // copy encoded Object Id pb += cbData; *pb++ = BER_SET; // empty array of attribute values *pb = 0; // zero length array of values //DumpHex(DH_NOTABPREFIX | 2, pbAlloc, cbAlloc); if (!myDecodeObject( X509_ASN_ENCODING, PKCS_ATTRIBUTE, pbAlloc, cbAlloc, CERTLIB_USE_LOCALALLOC, (VOID **) &pAttr, &cb)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeObject"); } hr = myDupStringA(pAttr->pszObjId, ppszObjId); _JumpIfError(hr, error, "myDupStringA"); error: if (NULL != pbAlloc) { LocalFree(pbAlloc); } if (NULL != pAttr) { LocalFree(pAttr); } return(hr); } //+------------------------------------------------------------------------- // cuEncodeObjId -- decode an ASN.1 encoded ObjectId // // Construct an ASN.1 encoded PKCS_ATTRIBUTE with an array of empty values, // to trick CryptEncodeObject into decoding the passed in encoded Object Id. //-------------------------------------------------------------------------- HRESULT cuEncodeObjId( IN char const *pszObjId, OUT BYTE **ppbData, OUT DWORD *pcbData) { HRESULT hr; CRYPT_ATTRIBUTE Attr; BYTE *pbAttr = NULL; DWORD cbAttr; *ppbData = NULL; ZeroMemory(&Attr, sizeof(Attr)); Attr.pszObjId = const_cast(pszObjId); if (!myEncodeObject( X509_ASN_ENCODING, PKCS_ATTRIBUTE, &Attr, 0, CERTLIB_USE_LOCALALLOC, &pbAttr, // pbEncoded &cbAttr)) { hr = myHLastError(); _JumpError(hr, error, "myEncodeObject"); } if (cbAttr <= 2 + 2 + 2 || BER_SEQUENCE != pbAttr[0] || cbAttr != pbAttr[1] + 2 || BER_OBJECT_ID != pbAttr[2] || cbAttr != pbAttr[3] + 2 + 2 + 2 || BER_SET != pbAttr[cbAttr - 2] || 0 != pbAttr[cbAttr - 1]) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "bad Attr"); } *pcbData = cbAttr - 4; *ppbData = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbData); if (NULL == *ppbData) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(*ppbData, &pbAttr[2], *pcbData); hr = S_OK; error: if (NULL != pbAttr) { LocalFree(pbAttr); } return(hr); } // UnicodeDecode() // // This function is responsible for decoding unicode crypt data blobs from // various certificate fields. The returned WCHAR * must be freed by LocalFree // // Params: // // pBlob - IN CRYPT_DATA_BLOB to be decoded, expected UNICODE // // Returns: // // WCHAR * to decoded string, to be freed using LocalFree HRESULT UnicodeDecode( IN CRYPT_DATA_BLOB const *pBlob, OUT WCHAR **ppwszOut) { HRESULT hr; CERT_NAME_VALUE *pName = NULL; DWORD cb; *ppwszOut = NULL; if (!myDecodeObject( X509_ASN_ENCODING, X509_UNICODE_ANY_STRING, pBlob->pbData, pBlob->cbData, CERTLIB_USE_LOCALALLOC, (VOID **) &pName, &cb)) { CSASSERT(NULL == pName); hr = myHLastError(); _JumpError(hr, error, "myDecodeObject"); } hr = myDupString((WCHAR const *) pName->Value.pbData, ppwszOut); _JumpIfError(hr, error, "myDupString"); error: if (NULL != pName) { LocalFree(pName); } return(hr); } BOOL cuDumpFormattedExtension( IN WCHAR const *pwszName, IN BYTE const *pbObject, IN DWORD cbObject) { HRESULT hr; BOOL fDisplayed = FALSE; char *pszObjId = NULL; BSTR strHash = NULL; WCHAR const *pwszDescriptiveName; DWORD cb; WCHAR const *pwszPad = g_fQuiet? g_wszEmpty : g_wszPad4; if (!ConvertWszToSz(&pszObjId, pwszName, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertWszToSz"); } pwszDescriptiveName = cuGetOIDName(pwszName); if (NULL != pwszDescriptiveName && L'\0' != *pwszDescriptiveName) { PrintStringWithPrefix(pwszPad, pwszDescriptiveName); if (g_fQuiet) { wprintf(L": "); } else { wprintf(wszNewLine); } } if (0 == cbObject) { if (!g_fQuiet) { wprintf( L"%ws%ws\n", g_wszPad8, myLoadResourceString(IDS_PROP_EMPTY)); // "EMPTY" } fDisplayed = TRUE; } else { fDisplayed = DumpFormattedObject( pszObjId, FOT_EXTENSION, pbObject, cbObject); if (!fDisplayed) { if (0 == strcmp(pszObjId, szOID_CERTSRV_CA_VERSION)) { DWORD NameId; cb = sizeof(NameId); NameId = 0; if (CryptDecodeObject( X509_ASN_ENCODING, X509_INTEGER, pbObject, cbObject, 0, &NameId, &cb)) { wprintf( L"%ws%ws%ws: %u.%u\n", pwszPad, myLoadResourceString(IDS_CAVERSION), g_wszCertUtil, CANAMEIDTOICERT(NameId), CANAMEIDTOIKEY(NameId)); fDisplayed = TRUE; } } else if (0 == strcmp(pszObjId, szOID_CERTSRV_CROSSCA_VERSION)) { DWORD CrossCAVersion; cb = sizeof(CrossCAVersion); CrossCAVersion = 0; if (CryptDecodeObject( X509_ASN_ENCODING, X509_INTEGER, pbObject, cbObject, 0, &CrossCAVersion, &cb)) { wprintf( L"%ws%ws%ws: (%u-%u)\n", pwszPad, myLoadResourceString(IDS_CAVERSION), g_wszCertUtil, CROSSCAVERSIONTOSOURCE(CrossCAVersion), CROSSCAVERSIONTOTARGET(CrossCAVersion)); fDisplayed = TRUE; } } else if (0 == strcmp(pszObjId, szOID_CERTSRV_PREVIOUS_CERT_HASH)) { hr = DumpOctetHash( pwszPad, IDS_PREVIOUS_CA_CERT_HASH, g_wszCertUtil, pbObject, cbObject, NULL, NULL); if (S_OK == hr) { fDisplayed = TRUE; } } else if (0 == strcmp(pszObjId, szOID_CRL_NUMBER)) { DWORD CRLNumber; cb = sizeof(CRLNumber); CRLNumber = 0; if (CryptDecodeObject( X509_ASN_ENCODING, X509_INTEGER, pbObject, cbObject, 0, &CRLNumber, &cb)) { wprintf( L"%ws%ws%ws: %u\n", pwszPad, myLoadResourceString(IDS_CRL_NUMBER), g_wszCertUtil, CRLNumber); fDisplayed = TRUE; } } else if (0 == strcmp(pszObjId, szOID_DELTA_CRL_INDICATOR)) { DWORD CRLNumber; cb = sizeof(CRLNumber); CRLNumber = 0; if (CryptDecodeObject( X509_ASN_ENCODING, X509_INTEGER, pbObject, cbObject, 0, &CRLNumber, &cb)) { wprintf( L"%ws%ws%ws: %u\n", pwszPad, myLoadResourceString(IDS_MINIMUM_BASE_CRL_NUMBER), g_wszCertUtil, CRLNumber); fDisplayed = TRUE; } } else if (0 == strcmp(pszObjId, szOID_CRL_VIRTUAL_BASE)) { DWORD CRLNumber; cb = sizeof(CRLNumber); CRLNumber = 0; if (CryptDecodeObject( X509_ASN_ENCODING, X509_INTEGER, pbObject, cbObject, 0, &CRLNumber, &cb)) { wprintf( L"%ws%ws%ws: %u\n", pwszPad, myLoadResourceString(IDS_VIRTUAL_BASE_CRL_NUMBER), g_wszCertUtil, CRLNumber); fDisplayed = TRUE; } } else if (0 == strcmp(pszObjId, szOID_CRL_NEXT_PUBLISH) || 0 == strcmp(pszObjId, szOID_RSA_signingTime)) { FILETIME ft; cb = sizeof(ft); if (CryptDecodeObject( X509_ASN_ENCODING, X509_CHOICE_OF_TIME, pbObject, cbObject, 0, &ft, &cb)) { wprintf( L"%ws%ws%ws: ", pwszPad, myLoadResourceString( 0 == strcmp(pszObjId, szOID_CRL_NEXT_PUBLISH)? IDS_CRL_NEXT_PUBLISH : IDS_SIGNING_TIME), g_wszCertUtil); hr = cuDumpFileTime(0, NULL, &ft); _JumpIfError(hr, error, "cuDumpFileTime"); fDisplayed = TRUE; } } else if (0 == strcmp(pszObjId, szOID_FRESHEST_CRL)) { wprintf( L"%ws%ws%ws:\n", pwszPad, myLoadResourceString(IDS_FRESHEST_CRL_CDP), g_wszCertUtil); cuDumpFormattedExtension( TEXT(szOID_CRL_DIST_POINTS), pbObject, cbObject); fDisplayed = TRUE; } else if (0 == strcmp(pszObjId, szOID_CRL_SELF_CDP)) { wprintf( L"%ws%ws%ws:\n", pwszPad, myLoadResourceString(IDS_CRL_SELF_CDP), g_wszCertUtil); cuDumpFormattedExtension( TEXT(szOID_CRL_DIST_POINTS), pbObject, cbObject); fDisplayed = TRUE; } else if (0 == strcmp(pszObjId, szOID_PKIX ".2")) { // Exchange policy module intended to use szOID_PKIX_CA_ISSUERS, // but the ".48.2" suffix was instead written as ".2". // // szOID_PKIX_CA_ISSUERS was wrong anyway -- it should have // used szOID_AUTHORITY_INFO_ACCESS instead. wprintf( L"%ws%ws%ws:\n", pwszPad, myLoadResourceString(IDS_EXCHANGEAIA), // "Exchange Authority Information Access" g_wszCertUtil); cuDumpFormattedExtension( TEXT(szOID_AUTHORITY_INFO_ACCESS), pbObject, cbObject); fDisplayed = TRUE; } else if (0 == strcmp(pszObjId, szOID_ISSUER_ALT_NAME)) { // Exchange policy module overloaded this OID and stored the // file version information for expolicy.dll and certsrv.exe. typedef struct _CUVER { USHORT usMajor; USHORT usMinor; USHORT usBuild; USHORT usBuildMinor; } CUVER; CUVER const *pVer; CRYPT_INTEGER_BLOB aBlob[1 + BLOB_ROUND(2 * sizeof(*pVer))]; cb = sizeof(aBlob); if (CryptDecodeObject( X509_ASN_ENCODING, X509_MULTI_BYTE_INTEGER, pbObject, cbObject, 0, aBlob, &cb)) { if (2 * sizeof(*pVer) == aBlob[0].cbData) { wprintf( L"%ws%ws%ws:\n", pwszPad, myLoadResourceString(IDS_EXCHANGEVERSION), // "Exchange Version" g_wszCertUtil); pVer = (CUVER const *) aBlob[0].pbData; wprintf( L" expolicy.dll: %u.%u:%u.%u\n", pVer->usMajor, pVer->usMinor, pVer->usBuild, pVer->usBuildMinor); pVer++; wprintf( L" certsrv.exe: %u.%u:%u.%u\n", pVer->usMajor, pVer->usMinor, pVer->usBuild, pVer->usBuildMinor); fDisplayed = TRUE; } } else { hr = myHLastError(); _JumpError(hr, error, "CryptDecodeObject"); } } else if (0 == strcmp(pszObjId, szOID_APPLICATION_CERT_POLICIES)) { wprintf( L"%ws%ws%ws:\n", pwszPad, myLoadResourceString(IDS_APPLICATION_CERT_POLICIES), g_wszCertUtil); cuDumpFormattedExtension( TEXT(szOID_CERT_POLICIES), pbObject, cbObject); fDisplayed = TRUE; } else if (0 == strcmp(pszObjId, szOID_APPLICATION_POLICY_MAPPINGS)) { wprintf( L"%ws%ws%ws:\n", pwszPad, myLoadResourceString(IDS_APPLICATION_POLICY_MAPPINGS), g_wszCertUtil); cuDumpFormattedExtension( TEXT(szOID_POLICY_MAPPINGS), pbObject, cbObject); fDisplayed = TRUE; } else if (0 == strcmp(pszObjId, szOID_APPLICATION_POLICY_CONSTRAINTS)) { wprintf( L"%ws%ws%ws:\n", pwszPad, myLoadResourceString(IDS_APPLICATION_POLICY_CONSTRAINTS), g_wszCertUtil); cuDumpFormattedExtension( TEXT(szOID_POLICY_CONSTRAINTS), pbObject, cbObject); fDisplayed = TRUE; } else if (0 == strcmp(pszObjId, szOID_POLICY_MAPPINGS)) { CERT_POLICY_MAPPINGS_INFO *pPolicyMappings = NULL; DWORD i; if (!myDecodeObject( X509_ASN_ENCODING, X509_POLICY_MAPPINGS, pbObject, cbObject, CERTLIB_USE_LOCALALLOC, (VOID **) &pPolicyMappings, &cb)) { hr = myHLastError(); CSASSERT(NULL == pPolicyMappings); _JumpIfError(hr, error, "myDecodeObject"); } wprintf( L"%ws%ws%ws:\n", pwszPad, myLoadResourceString(IDS_POLICY_MAPPINGS), g_wszCertUtil); for (i = 0; i < pPolicyMappings->cPolicyMapping; i++) { wprintf(g_wszPad4); wprintf(myLoadResourceString(IDS_FORMAT_MAP_ARRAY_COLON), i); wprintf(wszNewLine); wprintf(g_wszPad8); wprintf(myLoadResourceString(IDS_ISSUER_DOMAIN_POLICY)); cuDumpOIDAndDescriptionA( pPolicyMappings->rgPolicyMapping[i].pszIssuerDomainPolicy); wprintf(wszNewLine); wprintf(g_wszPad8); wprintf(myLoadResourceString(IDS_SUBJECT_DOMAIN_POLICY)); cuDumpOIDAndDescriptionA( pPolicyMappings->rgPolicyMapping[i].pszSubjectDomainPolicy); wprintf(wszNewLine); } LocalFree(pPolicyMappings); fDisplayed = TRUE; } else if (0 == strcmp(pszObjId, szOID_POLICY_CONSTRAINTS)) { CERT_POLICY_CONSTRAINTS_INFO Constraints; cb = sizeof(Constraints); if (!CryptDecodeObject( X509_ASN_ENCODING, X509_POLICY_CONSTRAINTS, pbObject, cbObject, 0, &Constraints, &cb)) { hr = myHLastError(); _JumpError(hr, error, "CryptDecodeObject"); } wprintf( L"%ws%ws%ws:\n", pwszPad, myLoadResourceString(IDS_POLICY_CONSTRAINTS), g_wszCertUtil); if (Constraints.fRequireExplicitPolicy) { wprintf( L" dwRequireExplicitPolicySkipCerts: %u\n", Constraints.dwRequireExplicitPolicySkipCerts); } if (Constraints.fInhibitPolicyMapping) { wprintf( L" dwInhibitPolicyMappingSkipCerts: %u\n", Constraints.dwInhibitPolicyMappingSkipCerts); } fDisplayed = TRUE; } else if (0 == strcmp(pszObjId, szOID_REASON_CODE_HOLD)) { char *pszObjIdT; hr = cuDecodeObjId(pbObject, cbObject, &pszObjIdT); if (S_OK == hr) { wprintf(pwszPad); cuDumpOIDAndDescriptionA(pszObjIdT); wprintf(wszNewLine); LocalFree(pszObjIdT); fDisplayed = TRUE; } } else if (0 == strcmp(pszObjId, szOID_VERISIGN_ONSITE_JURISDICTION_HASH)) { CRYPT_DATA_BLOB Value; WCHAR *pwsz; Value.pbData = const_cast(pbObject); Value.cbData = cbObject; hr = UnicodeDecode(&Value, &pwsz); if (S_OK == hr) { wprintf(L"%ws%ws\n", pwszPad, pwsz); LocalFree(pwsz); fDisplayed = TRUE; } } } } error: if (NULL != strHash) { SysFreeString(strHash); } if (NULL != pszObjId) { LocalFree(pszObjId); } return(fDisplayed); } WCHAR const * const g_apwszFieldNames[] = { wszCONFIG_COMMONNAME, wszCONFIG_ORGUNIT, wszCONFIG_ORGANIZATION, wszCONFIG_LOCALITY, wszCONFIG_STATE, wszCONFIG_COUNTRY, wszCONFIG_CONFIG, wszCONFIG_EXCHANGECERTIFICATE, wszCONFIG_SIGNATURECERTIFICATE, wszCONFIG_DESCRIPTION, wszCONFIG_SERVER, wszCONFIG_AUTHORITY, wszCONFIG_SANITIZEDNAME, wszCONFIG_SHORTNAME, wszCONFIG_SANITIZEDSHORTNAME, wszCONFIG_FLAGS, }; #define CSTRING (sizeof(g_apwszFieldNames)/sizeof(g_apwszFieldNames[0])) WCHAR const *g_apwszDisplayNames[CSTRING]; LONG g_amsgidDisplayNames[CSTRING] = { IDS_CONFIGDISPLAY_COMMONNAME_COLON, IDS_CONFIGDISPLAY_ORGUNIT_COLON, IDS_CONFIGDISPLAY_ORG_COLON, IDS_CONFIGDISPLAY_LOCALITY_COLON, IDS_CONFIGDISPLAY_STATE_COLON, IDS_CONFIGDISPLAY_COUNTRY_COLON, IDS_CONFIGDISPLAY_CONFIG_COLON, IDS_CONFIGDISPLAY_EXCHANGECERT_COLON, IDS_CONFIGDISPLAY_SIGCERT_COLON, IDS_CONFIGDISPLAY_DESCRIPTION_COLON, IDS_CONFIGDISPLAY_SERVER_COLON, IDS_CONFIGDISPLAY_AUTHORITY_COLON, IDS_CONFIGDISPLAY_SANITIZEDNAME_COLON, IDS_CONFIGDISPLAY_SHORTNAME_COLON, IDS_CONFIGDISPLAY_SANITIZEDSHORTNAME_COLON, IDS_CONFIGDISPLAY_FLAGS_COLON, }; HRESULT cuConfigDump(VOID) { HRESULT hr; DWORD i; for (i = 0; i < CSTRING; i++) { g_apwszDisplayNames[i] = myLoadResourceString(g_amsgidDisplayNames[i]); } hr = ConfigDumpSetDisplayNames( g_apwszFieldNames, g_apwszDisplayNames, CSTRING); _JumpIfError(hr, error, "ConfigDumpSetDisplayNames"); hr = ConfigDump( g_DispatchFlags, myLoadResourceString(IDS_CONFIGDISPLAY_ENTRY), // "Entry" myLoadResourceString(IDS_CONFIGDISPLAY_LOCAL), // "(Local)" g_pwszDnsName, g_pwszOldName); _JumpIfError(hr, error, "ConfigDump"); error: return(hr); } typedef HRESULT (FNDUMP)( IN DWORD idMessage, IN BYTE const *pbIn, IN DWORD cbIn, IN BYTE const *pbDecoded, IN DWORD cbDecoded, IN CERT_SIGNED_CONTENT_INFO const *pcsci); FNDUMP dumpCert, dumpCRL, dumpRequest, dumpCMCRequest, dumpCMCResponse, dumpKeyGenRequest, dumpCertSequence, dumpCTL; typedef struct _ASNFORMATS { char const *pszFormat; FNDUMP *pfnDump; DWORD idMessage; WCHAR const *pwszExtension; } ASNFORMATS; ASNFORMATS g_aasn[] = { { X509_CERT_TO_BE_SIGNED, dumpCert, IDS_DUMP_CERT, L".crt", }, { X509_CERT_CRL_TO_BE_SIGNED, dumpCRL, IDS_DUMP_CRL, L".crl", }, { X509_CERT_REQUEST_TO_BE_SIGNED, dumpRequest, IDS_DUMP_REQUEST, L".p10", }, { CMC_DATA, dumpCMCRequest, IDS_DUMP_CMC, L".cmc", }, { CMC_RESPONSE, dumpCMCResponse, IDS_DUMP_CMCRESPONSE, L".res", }, { X509_KEYGEN_REQUEST_TO_BE_SIGNED, dumpKeyGenRequest, IDS_DUMP_KEYGEN, L".req", }, { PKCS_CONTENT_INFO_SEQUENCE_OF_ANY, dumpCertSequence, IDS_DUMP_CERTSEQ, L".seq", }, { PKCS_CTL, dumpCTL, IDS_DUMP_CTL, L".stl", }, }; #define CASNFORMATS (sizeof(g_aasn)/sizeof(g_aasn[0])) HRESULT dumpPKCS7( OPTIONAL IN HCERTSTORE hStoreWrapper, IN BYTE const *pbIn, IN DWORD cbIn); typedef struct _DUMPALGID { ALG_ID Algid; WCHAR const *pwszDescription; } DUMPALGID; #define _DFALGID(algid) { (algid), L#algid } DUMPALGID g_adfAlgids[] = { _DFALGID(CALG_MD2), _DFALGID(CALG_MD4), _DFALGID(CALG_MD5), //_DFALGID(CALG_SHA), same as CALG_SHA1 _DFALGID(CALG_SHA1), _DFALGID(CALG_MAC), _DFALGID(CALG_RSA_SIGN), _DFALGID(CALG_DSS_SIGN), _DFALGID(CALG_NO_SIGN), _DFALGID(CALG_RSA_KEYX), _DFALGID(CALG_DES), _DFALGID(CALG_3DES_112), _DFALGID(CALG_3DES), _DFALGID(CALG_DESX), _DFALGID(CALG_RC2), _DFALGID(CALG_RC4), _DFALGID(CALG_SEAL), _DFALGID(CALG_DH_SF), _DFALGID(CALG_DH_EPHEM), _DFALGID(CALG_AGREEDKEY_ANY), _DFALGID(CALG_KEA_KEYX), _DFALGID(CALG_HUGHES_MD5), _DFALGID(CALG_SKIPJACK), _DFALGID(CALG_TEK), _DFALGID(CALG_CYLINK_MEK), _DFALGID(CALG_SSL3_SHAMD5), _DFALGID(CALG_SSL3_MASTER), _DFALGID(CALG_SCHANNEL_MASTER_HASH), _DFALGID(CALG_SCHANNEL_MAC_KEY), _DFALGID(CALG_SCHANNEL_ENC_KEY), _DFALGID(CALG_PCT1_MASTER), _DFALGID(CALG_SSL2_MASTER), _DFALGID(CALG_TLS1_MASTER), _DFALGID(CALG_RC5), _DFALGID(CALG_HMAC), _DFALGID(CALG_TLS1PRF), _DFALGID(CALG_HASH_REPLACE_OWF), _DFALGID(CALG_AES_128), _DFALGID(CALG_AES_192), _DFALGID(CALG_AES_256), _DFALGID(CALG_AES), }; DUMPALGID g_adfClass[] = { _DFALGID(ALG_CLASS_ANY), _DFALGID(ALG_CLASS_SIGNATURE), _DFALGID(ALG_CLASS_MSG_ENCRYPT), _DFALGID(ALG_CLASS_DATA_ENCRYPT), _DFALGID(ALG_CLASS_HASH), _DFALGID(ALG_CLASS_KEY_EXCHANGE), }; DUMPALGID g_adfType[] = { _DFALGID(ALG_TYPE_ANY), _DFALGID(ALG_TYPE_DSS), _DFALGID(ALG_TYPE_RSA), _DFALGID(ALG_TYPE_BLOCK), _DFALGID(ALG_TYPE_STREAM), _DFALGID(ALG_TYPE_DH), _DFALGID(ALG_TYPE_SECURECHANNEL), }; // Generic sub-ids DUMPALGID g_adfSubIdAny[] = { _DFALGID(ALG_SID_ANY), }; // Some DSS sub-ids DUMPALGID g_adfSubIdDSS[] = { _DFALGID(ALG_SID_DSS_ANY), _DFALGID(ALG_SID_DSS_PKCS), _DFALGID(ALG_SID_DSS_DMS), }; // Some RSA sub-ids DUMPALGID g_adfSubIdRSA[] = { _DFALGID(ALG_SID_RSA_ANY), _DFALGID(ALG_SID_RSA_PKCS), _DFALGID(ALG_SID_RSA_MSATWORK), _DFALGID(ALG_SID_RSA_ENTRUST), _DFALGID(ALG_SID_RSA_PGP), }; // Block cipher sub ids DUMPALGID g_adfSubIdBlock[] = { // RC2 sub-ids _DFALGID(ALG_SID_RC2), // DES sub_ids _DFALGID(ALG_SID_DES), _DFALGID(ALG_SID_3DES), _DFALGID(ALG_SID_DESX), _DFALGID(ALG_SID_IDEA), _DFALGID(ALG_SID_CAST), _DFALGID(ALG_SID_SAFERSK64), _DFALGID(ALG_SID_SAFERSK128), _DFALGID(ALG_SID_3DES_112), _DFALGID(ALG_SID_CYLINK_MEK), _DFALGID(ALG_SID_RC5), _DFALGID(ALG_SID_AES_128), _DFALGID(ALG_SID_AES_192), _DFALGID(ALG_SID_AES_256), _DFALGID(ALG_SID_AES), // Fortezza sub-ids _DFALGID(ALG_SID_SKIPJACK), _DFALGID(ALG_SID_TEK), }; // Stream cipher sub-ids DUMPALGID g_adfSubIdStream[] = { _DFALGID(ALG_SID_RC4), _DFALGID(ALG_SID_SEAL), }; // Diffie-Hellman sub-ids DUMPALGID g_adfSubIdDH[] = { _DFALGID(ALG_SID_DH_SANDF), _DFALGID(ALG_SID_DH_EPHEM), _DFALGID(ALG_SID_AGREED_KEY_ANY), _DFALGID(ALG_SID_KEA), }; // secure channel sub ids DUMPALGID g_adfSubIdSecureChannel[] = { _DFALGID(ALG_SID_SSL3_MASTER), _DFALGID(ALG_SID_SCHANNEL_MASTER_HASH), _DFALGID(ALG_SID_SCHANNEL_MAC_KEY), _DFALGID(ALG_SID_PCT1_MASTER), _DFALGID(ALG_SID_SSL2_MASTER), _DFALGID(ALG_SID_TLS1_MASTER), _DFALGID(ALG_SID_SCHANNEL_ENC_KEY), }; // Hash sub ids DUMPALGID g_adfSubIdHash[] = { _DFALGID(ALG_SID_MD2), _DFALGID(ALG_SID_MD4), _DFALGID(ALG_SID_MD5), _DFALGID(ALG_SID_SHA1), _DFALGID(ALG_SID_MAC), _DFALGID(ALG_SID_RIPEMD), _DFALGID(ALG_SID_RIPEMD160), _DFALGID(ALG_SID_SSL3SHAMD5), _DFALGID(ALG_SID_HMAC), _DFALGID(ALG_SID_TLS1PRF), _DFALGID(ALG_SID_HASH_REPLACE_OWF), }; #if 0 // KP_MODE #define CRYPT_MODE_CBCI 6 // ANSI CBC Interleaved #define CRYPT_MODE_CFBP 7 // ANSI CFB Pipelined #define CRYPT_MODE_OFBP 8 // ANSI OFB Pipelined #define CRYPT_MODE_CBCOFM 9 // ANSI CBC + OF Masking #define CRYPT_MODE_CBCOFMI 10 // ANSI CBC + OFM Interleaved #endif typedef struct _DUMPSUBIDMAP { DWORD dwAlgType; DUMPALGID *adfSubId; DWORD cdfSubId; } DUMPSUBIDMAP; #define _DFARRAYANDSIZE(adf) (adf), ARRAYSIZE(adf) DUMPSUBIDMAP g_adfSubIdMap[] = { { ALG_TYPE_ANY, _DFARRAYANDSIZE(g_adfSubIdAny) }, { ALG_TYPE_DSS, _DFARRAYANDSIZE(g_adfSubIdDSS) }, { ALG_TYPE_RSA, _DFARRAYANDSIZE(g_adfSubIdRSA) }, { ALG_TYPE_BLOCK, _DFARRAYANDSIZE(g_adfSubIdBlock) }, { ALG_TYPE_STREAM, _DFARRAYANDSIZE(g_adfSubIdStream) }, { ALG_TYPE_DH, _DFARRAYANDSIZE(g_adfSubIdDH) }, { ALG_TYPE_SECURECHANNEL, _DFARRAYANDSIZE(g_adfSubIdSecureChannel) }, }; VOID cuDumpAlgid( IN DWORD Algid) { WCHAR const *pwsz; WCHAR const *pwszQuestionMarks; DUMPALGID *pda; DUMPALGID *pdaSubId; DWORD cdaSubId; DUMPSUBIDMAP *pdsm; DWORD AlgClass; DWORD AlgType; DWORD AlgSubId; pwszQuestionMarks = myLoadResourceString(IDS_QUESTIONMARKS); // "???" for (pda = g_adfAlgids; pda < &g_adfAlgids[ARRAYSIZE(g_adfAlgids)]; pda++) { if (Algid == pda->Algid) { wprintf(L" %ws\n", pda->pwszDescription); break; } } AlgClass = GET_ALG_CLASS(Algid); pwsz = pwszQuestionMarks; for (pda = g_adfClass; pda < &g_adfClass[ARRAYSIZE(g_adfClass)]; pda++) { if (AlgClass == pda->Algid) { pwsz = pda->pwszDescription; break; } } wprintf( L" %ws: 0x%x(%u) %ws\n", myLoadResourceString(IDS_ALGORITHM_CLASS), // "Algorithm Class" AlgClass, AlgClass >> 13, pwsz); AlgType = GET_ALG_TYPE(Algid); pwsz = pwszQuestionMarks; for (pda = g_adfType; pda < &g_adfType[ARRAYSIZE(g_adfType)]; pda++) { if (AlgType == pda->Algid) { pwsz = pda->pwszDescription; break; } } wprintf( L" %ws: 0x%x(%u) %ws\n", myLoadResourceString(IDS_ALGORITHM_TYPE), // "Algorithm Type" AlgType, AlgType >> 9, pwsz); pdaSubId = g_adfSubIdAny; cdaSubId = ARRAYSIZE(g_adfSubIdAny); for (pdsm = g_adfSubIdMap; pdsm < &g_adfSubIdMap[ARRAYSIZE(g_adfSubIdMap)]; pdsm++) { if (AlgType == pdsm->dwAlgType) { pdaSubId = pdsm->adfSubId; cdaSubId = pdsm->cdfSubId; break; } } if (ALG_CLASS_HASH == AlgClass && pdaSubId == g_adfSubIdAny) { pdaSubId = g_adfSubIdHash; cdaSubId = ARRAYSIZE(g_adfSubIdHash); } pwsz = pwszQuestionMarks; AlgSubId = GET_ALG_SID(Algid); for (pda = pdaSubId; pda < &pdaSubId[cdaSubId]; pda++) { if (AlgSubId == pda->Algid) { pwsz = pda->pwszDescription; break; } } wprintf( L" %ws: 0x%x(%u) %ws\n", myLoadResourceString(IDS_ALGORITHM_SUBID), // "Algorithm Sub-id" AlgSubId, AlgSubId >> 0, pwsz); } HRESULT cuDumpPrivateKeyBlob( IN BYTE const *pbKey, IN DWORD cbKey, IN BOOL fQuiet) { HRESULT hr; PUBLICKEYSTRUC const *pkey = (PUBLICKEYSTRUC const *) pbKey; WCHAR const *pwszType; if (sizeof(*pkey) >= cbKey) { //DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 2, pbKey, cbKey); hr = CRYPT_E_ASN1_BADTAG; _JumpError2(hr, error, "key check", hr); } switch (pkey->bType) { case SIMPLEBLOB: pwszType = L"SIMPLEBLOB"; break; case PUBLICKEYBLOB: pwszType = L"PUBLICKEYBLOB"; break; case PRIVATEKEYBLOB: pwszType = L"PRIVATEKEYBLOB"; break; case PLAINTEXTKEYBLOB: pwszType = L"PLAINTEXTKEYBLOB"; break; case OPAQUEKEYBLOB: pwszType = L"OPAQUEKEYBLOB"; break; case PUBLICKEYBLOBEX: pwszType = L"PUBLICKEYBLOBEX"; break; case SYMMETRICWRAPKEYBLOB: pwszType = L"SYMMETRICWRAPKEYBLOB"; break; default: //DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 2, pbKey, cbKey); hr = CRYPT_E_ASN1_BADTAG; _JumpError2(hr, error, "key check", hr); } if (fQuiet) { hr = S_OK; goto error; } wprintf(myLoadResourceString(IDS_PRIVATEKEY)); wprintf(wszNewLine); wprintf(L" %ws\n", pwszType); wprintf(g_wszPad2); wprintf( myLoadResourceString(IDS_FORMAT_VERSION), // "Version: %u" pkey->bVersion); wprintf(wszNewLine); wprintf(L" aiKeyAlg: 0x%x\n", pkey->aiKeyAlg); cuDumpAlgid(pkey->aiKeyAlg); DumpHex( DH_NOTABPREFIX | DH_PRIVATEDATA | 2, (BYTE const *) &pkey[1], cbKey - sizeof(*pkey)); hr = S_OK; error: return(hr); } HRESULT DisplayUniqueContainer(IN HCRYPTPROV hProv); HRESULT cuDumpPrivateKey( IN CERT_CONTEXT const *pCert, OPTIONAL OUT BOOL *pfSigningKey, OPTIONAL OUT BOOL *pfMatchingKey) { HRESULT hr; HCRYPTPROV hProv = NULL; HCRYPTKEY hKey = NULL; DWORD dwKeySpec; DWORD cb; CRYPT_BIT_BLOB PrivateKey; CERT_PUBLIC_KEY_INFO *pPublicKeyInfo = NULL; ZeroMemory(&PrivateKey, sizeof(PrivateKey)); if (NULL != pfSigningKey) { *pfSigningKey = FALSE; } if (NULL != pfMatchingKey) { *pfMatchingKey = FALSE; } if (!CryptAcquireCertificatePrivateKey( pCert, 0, // dwFlags NULL, // pvReserved &hProv, &dwKeySpec, NULL)) // pfCallerFreeProv { hr = myHLastError(); if (CRYPT_E_NO_KEY_PROPERTY == hr) { wprintf(myLoadResourceString(IDS_NO_KEY_PROPERTY)); // "No stored keyset property" wprintf(wszNewLine); hr = S_OK; _JumpError2( CRYPT_E_NO_KEY_PROPERTY, error, "CryptAcquireCertificatePrivateKey", CRYPT_E_NO_KEY_PROPERTY); } if (NTE_BAD_KEYSET == hr) { wprintf(myLoadResourceString(IDS_NO_KEY)); // "Missing stored keyset" wprintf(wszNewLine); hr = S_OK; _JumpError2( NTE_BAD_KEYSET, error, "CryptAcquireCertificatePrivateKey", NTE_BAD_KEYSET); } _JumpError(hr, error, "CryptAcquireCertificatePrivateKey"); } if (!g_fQuiet) { DisplayUniqueContainer(hProv); } if (NULL != pfSigningKey) { *pfSigningKey = AT_SIGNATURE == dwKeySpec; } if (!CryptGetUserKey(hProv, dwKeySpec, &hKey)) { hr = myHLastError(); _PrintError(hr, "CryptGetUserKey"); cuPrintError(IDS_ERR_FORMAT_LOADKEY, hr); goto error; } hr = myCryptExportPrivateKey( hKey, &PrivateKey.pbData, &PrivateKey.cbData); if (NTE_BAD_TYPE == hr || NTE_BAD_KEY_STATE == hr || NTE_PERM == hr) { wprintf(myLoadResourceString(IDS_PRIVATE_KEY_NOT_EXPORTABLE)); // "Private key is NOT exportable" wprintf(wszNewLine); } else { _JumpIfError(hr, error, "myCryptExportPrivateKey"); } if (!myCryptExportPublicKeyInfo( hProv, dwKeySpec, CERTLIB_USE_LOCALALLOC, &pPublicKeyInfo, &cb)) { hr = myHLastError(); _JumpError(hr, error, "myCryptExportPublicKeyInfo"); } if (!myCertComparePublicKeyInfo( X509_ASN_ENCODING, CERT_V1 == pCert->pCertInfo->dwVersion, pPublicKeyInfo, &pCert->pCertInfo->SubjectPublicKeyInfo)) { // by design, (my)CertComparePublicKeyInfo doesn't set last error! wprintf(myLoadResourceString(IDS_ERR_PUBLICKEY_MISMATCH)); // "ERROR: Certificate public key does NOT match stored keyset" wprintf(wszNewLine); } else { if (AT_SIGNATURE == dwKeySpec) { hr = myValidateKeyForSigning( hProv, &pCert->pCertInfo->SubjectPublicKeyInfo, CALG_SHA1); _PrintIfError(hr, "myValidateKeyForSigning"); } else { hr = myValidateKeyForEncrypting( hProv, &pCert->pCertInfo->SubjectPublicKeyInfo, CALG_RC4); _PrintIfError(hr, "myValidateKeyForEncrypting"); } if (S_OK != hr) { wprintf(myLoadResourceString(IDS_ERR_PRIVATEKEY_MISMATCH)); // "ERROR: Certificate public key does NOT match private key" wprintf(wszNewLine); hr = S_OK; } else if (NULL != pfMatchingKey) { *pfMatchingKey = TRUE; } if (!g_fQuiet && NULL != PrivateKey.pbData) { wprintf(wszNewLine); hr = cuDumpPrivateKeyBlob( PrivateKey.pbData, PrivateKey.cbData, FALSE); _JumpIfError(hr, error, "cuDumpPrivateKeyBlob"); } } error: if (NULL != PrivateKey.pbData) { SecureZeroMemory(PrivateKey.pbData, PrivateKey.cbData); // Key material LocalFree(PrivateKey.pbData); } if (NULL != pPublicKeyInfo) { LocalFree(pPublicKeyInfo); } if (NULL != hKey) { CryptDestroyKey(hKey); } if (NULL != hProv) { CryptReleaseContext(hProv, 0); } return(hr); } HRESULT cuDumpCertKeyProviderInfo( IN WCHAR const *pwszPrefix, OPTIONAL IN CERT_CONTEXT const *pCert, OPTIONAL IN CRYPT_KEY_PROV_INFO *pkpi, OPTIONAL OUT CRYPT_KEY_PROV_INFO **ppkpi) { HRESULT hr; CRYPT_KEY_PROV_INFO *pkpiT = NULL; DWORD i; if (NULL != ppkpi) { *ppkpi = NULL; } CSASSERT((NULL == pCert) ^ (NULL == pkpi)); if (NULL != pCert) { CSASSERT(NULL == pkpi); hr = myCertGetKeyProviderInfo(pCert, &pkpiT); if (S_OK != hr) { _PrintIfError2(hr, "myCertGetKeyProviderInfo", CRYPT_E_NOT_FOUND); if (CRYPT_E_NOT_FOUND != hr) { _JumpError(hr, error, "myCertGetKeyProviderInfo"); } // Ignore missing property if we're just dumping the key provider info wprintf(myLoadResourceString(IDS_NO_KEY_PROVIDER_INFO)); // "No key provider information" wprintf(wszNewLine); CSASSERT(NULL == pkpiT); hr = S_OK; goto error; } pkpi = pkpiT; } else { CSASSERT(NULL != pkpi); } wprintf(pwszPrefix); wprintf( myLoadResourceString(IDS_FORMAT_KEY_CONTAINER), pkpi->pwszContainerName); wprintf(wszNewLine); wprintf(pwszPrefix); wprintf( myLoadResourceString(IDS_FORMAT_PROVIDER_NAME), pkpi->pwszProvName); wprintf(wszNewLine); if (!g_fQuiet) { wprintf(pwszPrefix); wprintf( myLoadResourceString(IDS_FORMAT_PROVIDER_TYPE), pkpi->dwProvType); wprintf(wszNewLine); } if (!g_fQuiet) { wprintf(pwszPrefix); wprintf( myLoadResourceString(IDS_FORMAT_FLAGS), pkpi->dwFlags); wprintf(wszNewLine); if (NULL != pkpi->rgProvParam) { for (i = 0; i < pkpi->cProvParam; i++) { wprintf(pwszPrefix); wprintf( myLoadResourceString(IDS_FORMAT_PROVPARM), pkpi->rgProvParam[i].dwParam); wprintf(wszNewLine); DumpHex( DH_MULTIADDRESS | DH_NOTABPREFIX | 4, pkpi->rgProvParam[i].pbData, pkpi->rgProvParam[i].cbData); wprintf(pwszPrefix); wprintf( myLoadResourceString(IDS_FORMAT_PROVPARMFLAGS), pkpi->rgProvParam[i].dwFlags); wprintf(wszNewLine); } } wprintf(pwszPrefix); wprintf( myLoadResourceString(IDS_FORMAT_KEYSPEC), pkpi->dwKeySpec); wprintf(wszNewLine); } if (NULL != pkpiT && NULL != ppkpi) { *ppkpi = pkpiT; pkpiT = NULL; } hr = S_OK; error: if (NULL != pkpiT) { LocalFree(pkpiT); } return(hr); } VOID cuDumpAlgorithm( IN DWORD idMessage, IN CRYPT_ALGORITHM_IDENTIFIER const *pAlg) { wprintf(myLoadResourceString(idMessage)); wprintf(wszNewLine); wprintf(g_wszPad4); wprintf(myLoadResourceString(IDS_ALG_OID)); // "Algorithm ObjectId" wprintf(L": "); cuDumpOIDAndDescriptionA(pAlg->pszObjId); wprintf(wszNewLine); wprintf(g_wszPad4); wprintf(myLoadResourceString(IDS_ALG_PARAMETERS_COLON)); // "Algorithm Parameters:" if (NULL != pAlg->Parameters.pbData) { wprintf(wszNewLine); DumpHex( DH_MULTIADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 4, pAlg->Parameters.pbData, pAlg->Parameters.cbData); } else { wprintf(L" %ws\n", myLoadResourceString(IDS_NULL)); // "NULL" } } VOID cuDumpPublicKey( IN CERT_PUBLIC_KEY_INFO const *pKey) { cuDumpAlgorithm(IDS_PUBLICKEY_ALGORITHM, &pKey->Algorithm); wprintf( myLoadResourceString(IDS_FORMAT_PUBLICKEY_LENGTH), // "Public Key Length: %u bits" CertGetPublicKeyLength( X509_ASN_ENCODING, const_cast(pKey))); wprintf(wszNewLine); wprintf( myLoadResourceString(IDS_FORMAT_PUBLICKEY_UNUSEDBITS), // "Public Key: UnusedBits=%u" pKey->PublicKey.cUnusedBits); wprintf(wszNewLine); DumpHex( DH_NOTABPREFIX | DH_NOASCIIHEX | 4, pKey->PublicKey.pbData, pKey->PublicKey.cbData); } VOID cuDumpSignature( OPTIONAL IN CERT_SIGNED_CONTENT_INFO const *pcsci) { if (NULL == pcsci) { wprintf(myLoadResourceString(IDS_NO_SIGNATURE)); wprintf(wszNewLine); goto error; } if (1 < g_fVerbose) { DumpHex( DH_NOTABPREFIX | 4, pcsci->ToBeSigned.pbData, pcsci->ToBeSigned.cbData); } cuDumpAlgorithm(IDS_SIGNATURE_ALGORITHM, &pcsci->SignatureAlgorithm); wprintf( myLoadResourceString(IDS_FORMAT_SIGNATURE_UNUSEDBITS), // "Signature: UnusedBits=%u" pcsci->Signature.cUnusedBits); wprintf(wszNewLine); DumpHex( DH_NOTABPREFIX | DH_NOASCIIHEX | 4, pcsci->Signature.pbData, pcsci->Signature.cbData); error: ; } HRESULT cuSaveAsnToFile( IN BYTE const *pbIn, IN DWORD cbIn, IN int imajor, IN int ilevel, IN DWORD iElement, IN WCHAR const *pwszExtension) { HRESULT hr; WCHAR awc[MAX_PATH]; CSASSERT(0 < imajor); CSASSERT(0 < ilevel); wsprintf( awc, MAXDWORD == iElement? L"Blob%d_%d" : L"Blob%d_%d_%d", imajor - 1, ilevel - 1, iElement); if (wcslen(awc) + wcslen(pwszExtension) >= ARRAYSIZE(awc)) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); _JumpErrorStr(hr, error, "awc", pwszExtension); } wcscat(awc, pwszExtension); if (g_fSplitASN) { //wprintf(L"cuSaveAsnToFile: %d %d %d: %ws\n", imajor - 1, ilevel - 1, iElement, awc); hr = EncodeToFileW(awc, pbIn, cbIn, CRYPT_STRING_BINARY | g_EncodeFlags); _JumpIfError(hr, error, "EncodeToFileW"); } hr = S_OK; error: return(hr); } HRESULT DumpAsnBlob( OPTIONAL IN HCERTSTORE hStoreWrapper, IN BOOL fQuiet, IN BYTE const *pbIn, IN DWORD cbIn, IN DWORD iElement) { HRESULT hr; HRESULT hr2; ASNFORMATS *pasn; ASNFORMATS *pasnEnd; DWORD cbDecoded; BYTE *pbDecoded = NULL; HCERTSTORE hStorePFX = NULL; CERT_CONTEXT const *pCert = NULL; CRYPT_KEY_PROV_INFO *pkpi = NULL; CERT_SIGNED_CONTENT_INFO *pcsci = NULL; DWORD cbcsci; static int s_major = 0; static int s_level = 0; BOOL fSaved = FALSE; WCHAR wszPassword[MAX_PATH]; if (0 == s_level) { s_major++; } s_level++; if (1 < s_level) { wprintf(myLoadResourceString(IDS_FORMAT_DUMP_LEVEL_START), s_level - 1); wprintf(wszNewLine); } if (MAXDWORD != iElement) { wprintf(myLoadResourceString(IDS_FORMAT_ELEMENT), iElement); wprintf(wszNewLine); } if (1 < g_fVerbose) { wprintf(myLoadResourceString(IDS_FORMAT_ELEMENT_DUMP)); // "Embedded ASN.1 Element:" wprintf(wszNewLine); DumpHex(0, pbIn, cbIn); } pasnEnd = &g_aasn[CASNFORMATS]; for (pasn = g_aasn; pasn < pasnEnd; pasn++) { CSASSERT(NULL == pbDecoded); if (myDecodeObject( X509_ASN_ENCODING, pasn->pszFormat, pbIn, cbIn, CERTLIB_USE_LOCALALLOC, (VOID **) &pbDecoded, &cbDecoded)) { if (!myDecodeObject( X509_ASN_ENCODING, X509_CERT, pbIn, cbIn, CERTLIB_USE_LOCALALLOC, (VOID **) &pcsci, &cbcsci)) { hr = myHLastError(); _PrintError3( hr, "myDecodeObject", CRYPT_E_ASN1_BADTAG, CRYPT_E_ASN1_EOD); } hr = (*pasn->pfnDump)( pasn->idMessage, pbIn, cbIn, pbDecoded, cbDecoded, pcsci); if (S_OK != hr && dumpCertSequence == pasn->pfnDump) { LocalFree(pbDecoded); pbDecoded = NULL; CSASSERT(NULL == pcsci); continue; } hr2 = cuSaveAsnToFile( pbIn, cbIn, s_major, s_level, iElement, pasn->pwszExtension); _PrintIfError(hr2, "cuSaveAsnToFile"); fSaved = TRUE; _JumpIfError(hr, error, "(*pfnDump)"); break; } hr = myHLastError(); _PrintError2(hr, "myDecodeObject", hr); CSASSERT(S_OK != hr); } if (pasn >= pasnEnd) { CRYPT_DATA_BLOB pfx; CSASSERT(S_OK != hr); pfx.pbData = const_cast(pbIn); pfx.cbData = cbIn; if (PFXIsPFXBlob(&pfx)) { DWORD dwKeySpec; DWORD dwFlags; WCHAR const *pwszPassword; DWORD iCert; hr = cuGetPassword( 0, // idsPrompt NULL, // pwszfn g_pwszPassword, FALSE, // fVerify wszPassword, ARRAYSIZE(wszPassword), &pwszPassword); _JumpIfError(hr, error, "cuGetPassword"); hStorePFX = myPFXImportCertStore( &pfx, pwszPassword, CRYPT_EXPORTABLE); if (NULL == hStorePFX) { hr = myHLastError(); _JumpError(hr, error, "myPFXImportCertStore"); } hr = cuSaveAsnToFile(pbIn, cbIn, s_major, s_level, iElement, L".p12"); _PrintIfError(hr, "cuSaveAsnToFile"); fSaved = TRUE; for (iCert = 0; ; iCert++) { BOOL fSigningKey; BOOL fMatchingKey; BOOL fRepaired = FALSE; pCert = CertEnumCertificatesInStore(hStorePFX, pCert); if (NULL == pCert) { break; } hr = cuDumpAsnBinary( pCert->pbCertEncoded, pCert->cbCertEncoded, iCert); _JumpIfError(hr, error, "cuDumpAsnBinary"); while (TRUE) { if (NULL != pkpi) { LocalFree(pkpi); pkpi = NULL; } hr = cuDumpCertKeyProviderInfo( g_wszPad2, pCert, NULL, &pkpi); if (S_OK != hr) { if (CRYPT_E_NOT_FOUND != hr) { _JumpError(hr, error, "cuDumpCertKeyProviderInfo"); } } else if (NULL != pkpi) { // NT4 PFXImportCertStore doesn't set machine keyset hr = cuDumpPrivateKey( pCert, &fSigningKey, &fMatchingKey); _PrintIfError2( hr, "cuDumpPrivateKey", CRYPT_E_NO_KEY_PROPERTY); if (S_OK == hr && !fMatchingKey && !fRepaired && 0 == (CRYPT_MACHINE_KEYSET & pkpi->dwFlags)) { LocalFree(pkpi); pkpi = NULL; hr = myRepairCertKeyProviderInfo(pCert, TRUE, NULL); _JumpIfError(hr, error, "myRepairCertKeyProviderInfo"); fRepaired = TRUE; continue; } } break; } } hr = S_OK; } else { hr = dumpPKCS7(hStoreWrapper, pbIn, cbIn); if (S_OK == hr) { hr = cuSaveAsnToFile( pbIn, cbIn, s_major, s_level, iElement, L".p7b"); _PrintIfError(hr, "cuSaveAsnToFile"); fSaved = TRUE; } else { hr = cuDumpPrivateKeyBlob(pbIn, cbIn, fQuiet); if (S_OK == hr) { hr = cuSaveAsnToFile( pbIn, cbIn, s_major, s_level, iElement, L".key"); _PrintIfError(hr, "cuSaveAsnToFile"); fSaved = TRUE; } else { _PrintError2(hr, "dumpPKCS7", CRYPT_E_ASN1_BADTAG); if (!fQuiet) { DumpHex(DH_MULTIADDRESS | DH_NOTABPREFIX | 4, pbIn, cbIn); } } hr = S_OK; } } } error: SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data if (!fSaved) { hr2 = cuSaveAsnToFile(pbIn, cbIn, s_major, s_level, iElement, L".bin"); _PrintIfError(hr2, "cuSaveAsnToFile"); } if (NULL != pkpi) { LocalFree(pkpi); } if (NULL != pCert) { CertFreeCertificateContext(pCert); } if (NULL != hStorePFX) { myDeleteGuidKeys(hStorePFX, FALSE); CertCloseStore(hStorePFX, CERT_CLOSE_STORE_CHECK_FLAG); } if (NULL != pcsci) { LocalFree(pcsci); } if (NULL != pbDecoded) { LocalFree(pbDecoded); } if (1 < s_level) { wprintf(myLoadResourceString(IDS_FORMAT_DUMP_LEVEL_END), s_level - 1); wprintf(wszNewLine); } s_level--; return(hr); } HRESULT cuDumpAsnBinary( IN BYTE const *pbIn, IN DWORD cbIn, IN DWORD iElement) { return(DumpAsnBlob(NULL, FALSE, pbIn, cbIn, iElement)); } HRESULT cuDumpExtensionArray( IN DWORD idMessage, IN DWORD cExtension, IN CERT_EXTENSION const *rgExtension) { HRESULT hr; DWORD i; WCHAR *pwszName = NULL; WCHAR const *pwszExtensionFormat; if (!g_fQuiet) { wprintf(myLoadResourceString(idMessage)); wprintf(L" %u\n", cExtension); } pwszExtensionFormat = myLoadResourceString(IDS_FORMAT_EXTENSION); // "%ws: Flags = %x%ws, Length = %x" for (i = 0; i < cExtension; i++) { CERT_EXTENSION const *pce; if (NULL != pwszName) { LocalFree(pwszName); pwszName = NULL; } pce = &rgExtension[i]; if (g_fQuiet && 0 != strcmp(pce->pszObjId, szOID_CERTSRV_CA_VERSION) && 0 != strcmp(pce->pszObjId, szOID_ENROLL_CERTTYPE_EXTENSION) && 0 != strcmp(pce->pszObjId, szOID_CRL_NUMBER) && 0 != strcmp(pce->pszObjId, szOID_CRL_VIRTUAL_BASE) && 0 != strcmp(pce->pszObjId, szOID_DELTA_CRL_INDICATOR)) { continue; } if (!ConvertSzToWsz(&pwszName, pce->pszObjId, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertSzToWsz"); } if (!g_fQuiet) { wprintf(g_wszPad4); wprintf( pwszExtensionFormat, pwszName, pce->fCritical, cuwszFromExtFlags(pce->fCritical), pce->Value.cbData); wprintf(wszNewLine); } if (!cuDumpFormattedExtension( pwszName, pce->Value.pbData, pce->Value.cbData) || g_fVerbose) { wprintf(wszNewLine); DumpHex(DH_NOTABPREFIX | 4, pce->Value.pbData, pce->Value.cbData); } if (!g_fQuiet) { wprintf(wszNewLine); } } hr = S_OK; error: if (NULL != pwszName) { LocalFree(pwszName); } return(hr); } VOID cuDumpVersion( IN DWORD dwVersion) { wprintf( myLoadResourceString(IDS_FORMAT_VERSION), // "Version: %u" dwVersion); wprintf(wszNewLine); } HRESULT cuDumpCMSSignerInfo( IN CMSG_CMS_SIGNER_INFO const *pcsi, IN DWORD iElement, IN BOOL fQuiet, DWORD idVerify, OPTIONAL IN HCERTSTORE hStore, OPTIONAL OUT BYTE *pbHashUserCert, OPTIONAL IN OUT DWORD *pcbHashUserCert) { HRESULT hr; WCHAR const *pwszFmt = MAXDWORD == iElement? L"%ws:\n" : L"%ws[%u]:\n"; if (!fQuiet || g_fVerbose) { if (!fQuiet) { wprintf(wszNewLine); } wprintf( pwszFmt, myLoadResourceString(IDS_SIGNER_INFO), // "Signer Info" iElement); if (!fQuiet) { WCHAR const *pwszVersion = NULL; if (0 != idVerify) { wprintf(myLoadResourceString(idVerify)); wprintf(wszNewLine); } switch (pcsi->dwVersion) { case CMSG_SIGNER_INFO_PKCS_1_5_VERSION: pwszVersion = L"CMSG_SIGNER_INFO_PKCS_1_5_VERSION"; break; case CMSG_SIGNER_INFO_CMS_VERSION: pwszVersion = L"CMSG_SIGNER_INFO_CMS_VERSION"; break; } if (NULL == pwszVersion) { cuDumpVersion(pcsi->dwVersion); } else { wprintf(L"%ws(%u)\n", pwszVersion, pcsi->dwVersion); } } switch (pcsi->SignerId.dwIdChoice) { case CERT_ID_ISSUER_SERIAL_NUMBER: wprintf( L"%ws(%u)\n", L"CERT_ID_ISSUER_SERIAL_NUMBER", pcsi->SignerId.dwIdChoice); hr = cuDumpIssuerSerialAndSubject( &pcsi->SignerId.IssuerSerialNumber.Issuer, &pcsi->SignerId.IssuerSerialNumber.SerialNumber, NULL, // pSubject hStore); _JumpIfError(hr, error, "cuDumpIssuerSerialAndSubject(Signer)"); break; case CERT_ID_KEY_IDENTIFIER: wprintf( L"%ws(%u)\n", L"CERT_ID_KEY_IDENTIFIER", pcsi->SignerId.dwIdChoice); DumpHex( DH_MULTIADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 4, pcsi->SignerId.KeyId.pbData, pcsi->SignerId.KeyId.cbData); break; case CERT_ID_SHA1_HASH: wprintf( L"%ws(%u)\n", L"CERT_ID_SHA1_HASH", pcsi->SignerId.dwIdChoice); DumpHex( DH_MULTIADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 4, pcsi->SignerId.HashId.pbData, pcsi->SignerId.HashId.cbData); break; default: wprintf( L"%ws(%u)\n", myLoadResourceString(IDS_QUESTIONMARKS), // "???" pcsi->SignerId.dwIdChoice); break; } } if (!fQuiet) { cuDumpAlgorithm(IDS_HASH_ALGORITHM, &pcsi->HashAlgorithm); cuDumpAlgorithm(IDS_HASH_ENCRYPTION_ALGORITHM, &pcsi->HashEncryptionAlgorithm); wprintf(myLoadResourceString(IDS_FORMAT_ENCRYPTEDHASH_COLON)); // "Encrypted Hash:" wprintf(wszNewLine); DumpHex( DH_MULTIADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 4, pcsi->EncryptedHash.pbData, pcsi->EncryptedHash.cbData); wprintf(wszNewLine); wprintf( pwszFmt, myLoadResourceString(IDS_DUMP_PKCS7_ATTRIBUTES), iElement); } if (!fQuiet || NULL != pbHashUserCert) { hr = DumpAttributes( pcsi->AuthAttrs.rgAttr, pcsi->AuthAttrs.cAttr, fQuiet, FOT_ATTRIBUTE, hStore, pbHashUserCert, pcbHashUserCert, NULL); _JumpIfError(hr, error, "DumpAttributes"); } if (!fQuiet) { wprintf(wszNewLine); wprintf( pwszFmt, myLoadResourceString(IDS_DUMP_PKCS7_UNAUTHATTRIBUTES), iElement); hr = DumpAttributes( pcsi->UnauthAttrs.rgAttr, pcsi->UnauthAttrs.cAttr, fQuiet, FOT_ATTRIBUTE, hStore, NULL, NULL, NULL); _JumpIfError(hr, error, "DumpAttributes"); } hr = S_OK; error: return(hr); } HRESULT cuDumpSignerInfo( IN CMSG_SIGNER_INFO const *psi, IN DWORD iElement, IN BOOL fQuiet, DWORD idVerify, OPTIONAL IN HCERTSTORE hStore, OPTIONAL OUT BYTE *pbHashUserCert, OPTIONAL IN OUT DWORD *pcbHashUserCert) { HRESULT hr; CMSG_CMS_SIGNER_INFO csi; ZeroMemory(&csi, sizeof(csi)); csi.dwVersion = psi->dwVersion; csi.SignerId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; csi.SignerId.IssuerSerialNumber.Issuer = psi->Issuer; csi.SignerId.IssuerSerialNumber.SerialNumber = psi->SerialNumber; csi.HashAlgorithm = psi->HashAlgorithm; csi.HashEncryptionAlgorithm = psi->HashEncryptionAlgorithm; csi.EncryptedHash = psi->EncryptedHash; csi.AuthAttrs = psi->AuthAttrs; csi.UnauthAttrs = psi->UnauthAttrs; hr = cuDumpCMSSignerInfo( &csi, iElement, fQuiet, idVerify, hStore, pbHashUserCert, pcbHashUserCert); _JumpIfError(hr, error, "cuDumpCMSSignerInfo"); error: return(hr); } HRESULT DumpAttributes( IN CRYPT_ATTRIBUTE const *rgAttr, IN DWORD cAttr, IN BOOL fQuiet, IN DWORD Type, // FOT_* OPTIONAL IN HCERTSTORE hStore, OPTIONAL OUT BYTE *pbHashUserCert, OPTIONAL IN OUT DWORD *pcbHashUserCert, OPTIONAL IN OUT CERT_EXTENSIONS **ppExtInfo) { HRESULT hr; CRYPT_ATTRIBUTE const *pAttr; CRYPT_ATTRIBUTE const *pAttrEnd; CRYPT_ENROLLMENT_NAME_VALUE_PAIR *pNamePair = NULL; CERT_EXTENSIONS *pExtInfo = NULL; CERT_NAME_VALUE *pNameInfo = NULL; DWORD cb; DWORD iv; if (NULL != ppExtInfo) { *ppExtInfo = NULL; } if (!fQuiet && FOT_PROPERTY != Type) { wprintf( myLoadResourceString(IDS_FORMAT_PKCS7_ATTRIBUTE_COUNT), // " %d attributes:" cAttr); wprintf(wszNewLine); } pAttrEnd = &rgAttr[cAttr]; for (pAttr = rgAttr; pAttr < pAttrEnd; pAttr++) { WCHAR const *pwszOID = cuGetOIDNameA(pAttr->pszObjId); if (!fQuiet && FOT_PROPERTY != Type) { wprintf(wszNewLine); wprintf( L" %ws[%u]: %hs%ws%ws%ws\n", myLoadResourceString(IDS_ATTRIBUTE), // "Attribute" pAttr - rgAttr, pAttr->pszObjId, L'\0' != *pwszOID? L" " wszLPAREN : g_wszEmpty, pwszOID, L'\0' != *pwszOID? wszRPAREN : g_wszEmpty); } for (iv = 0; iv < pAttr->cValue; iv++) { CRYPT_ATTR_BLOB const *pval = &pAttr->rgValue[iv]; if (fQuiet) { if (0 == strcmp(pAttr->pszObjId, szOID_ARCHIVED_KEY_CERT_HASH)) { hr = DumpOctetHash( g_wszEmpty, 0, g_wszEmpty, pval->pbData, pval->cbData, pbHashUserCert, pcbHashUserCert); _JumpIfError(hr, error, "DumpOctetHash"); } } else { if (FOT_PROPERTY != Type) { wprintf( myLoadResourceString(IDS_FORMAT_PKCS7_ATTRIBUTE_VALUE), // " Value[%d][%d]:" pAttr - rgAttr, iv); wprintf(wszNewLine); } if (!DumpFormattedObject( pAttr->pszObjId, Type, // FOT_* pval->pbData, pval->cbData)) { BOOL fDumpHex = FALSE; if (0 == strcmp(pAttr->pszObjId, szOID_ENROLLMENT_NAME_VALUE_PAIR)) { if (g_fVerbose) { DumpHex(0, pval->pbData, pval->cbData); } if (NULL != pNamePair) { LocalFree(pNamePair); pNamePair = NULL; } if (!myDecodeNameValuePair( X509_ASN_ENCODING, pval->pbData, pval->cbData, CERTLIB_USE_LOCALALLOC, &pNamePair, &cb)) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "myDecodeNameValuePair"); // if attribute name & value are both non-empty ... } wprintf( L" %ws%ws = %ws\n", pNamePair->pwszName, g_wszCertUtil, pNamePair->pwszValue); } else if (0 == strcmp(pAttr->pszObjId, szOID_CERT_EXTENSIONS) || 0 == strcmp(pAttr->pszObjId, szOID_RSA_certExtensions)) { if (NULL != pNameInfo) { LocalFree(pNameInfo); pNameInfo = NULL; } while (TRUE) { if (NULL != pExtInfo) { LocalFree(pExtInfo); pExtInfo = NULL; } if (myDecodeObject( X509_ASN_ENCODING, X509_EXTENSIONS, pval->pbData, pval->cbData, CERTLIB_USE_LOCALALLOC, (VOID **) &pExtInfo, &cb)) { break; // success } hr = myHLastError(); // if we already decoded the attribute as a T61 // string, or if it's not a PKCS 9.14 attribute, // just hex dump the attribute -- we don't know // what it contains. if (NULL != pNameInfo || 0 != strcmp( pAttr->pszObjId, szOID_RSA_certExtensions)) { //_JumpError(hr, error, "myDecodeObject"); _PrintError(hr, "myDecodeObject"); fDumpHex = TRUE; break; } // decode the attribute as a T61 string. Some // implementations wrap the PKCS 9.14 extension // array in an extra level of encoding as a Teletex // string. if (!myDecodeObject( X509_ASN_ENCODING, X509_ANY_STRING, pval->pbData, pval->cbData, CERTLIB_USE_LOCALALLOC, (VOID **) &pNameInfo, &cb)) { hr = myHLastError(); //_JumpError(hr, error, "myDecodeObject"); _PrintError(hr, "myDecodeObject"); fDumpHex = TRUE; break; } // Now loop again and try to decode the raw name // blob as X509_EXTENSIONS. pval = &pNameInfo->Value; wprintf(myLoadResourceString(IDS_TELETEX_EXTENSIONS)); // "Decoded extra Extension Array encoding layer (Teletex string)" wprintf(wszNewLine); } if (!fDumpHex) { hr = cuDumpExtensionArray( IDS_CERTIFICATE_EXTENSIONS, pExtInfo->cExtension, pExtInfo->rgExtension); _JumpIfError(hr, error, "cuDumpExtensionArray"); } } else if (0 == strcmp(pAttr->pszObjId, szOID_RENEWAL_CERTIFICATE) || 0 == strcmp(pAttr->pszObjId, szOID_RSA_SMIMECapabilities)) { wprintf(myLoadResourceString( 0 == strcmp( pAttr->pszObjId, szOID_RENEWAL_CERTIFICATE)? IDS_RENEWAL_CERT : // "Renewal Certificate:" IDS_SMIME_CAPABILITIES)); // "SMIME Capabilities:" wprintf(wszNewLine); hr = cuDumpAsnBinary(pval->pbData, pval->cbData, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); } else if (0 == strcmp(pAttr->pszObjId, szOID_RSA_contentType)) { char *pszObjId; hr = cuDecodeObjId(pval->pbData, pval->cbData, &pszObjId); if (S_OK != hr) { fDumpHex = TRUE; } else { wprintf(g_wszPad4); cuDumpOIDAndDescriptionA(pszObjId); wprintf(wszNewLine); LocalFree(pszObjId); } } else if (0 == strcmp(pAttr->pszObjId, szOID_RSA_messageDigest)) { hr = DumpOctetHash( g_wszPad4, IDS_MESSAGE_DIGEST, g_wszCertUtil, pval->pbData, pval->cbData, NULL, NULL); if (S_OK != hr) { fDumpHex = TRUE; } } else if (0 == strcmp(pAttr->pszObjId, szOID_ARCHIVED_KEY_ATTR)) { hr = cuDumpAsnBinary(pval->pbData, pval->cbData, MAXDWORD); if (S_OK != hr) { fDumpHex = TRUE; } } else if (0 == strcmp(pAttr->pszObjId, szOID_ARCHIVED_KEY_CERT_HASH)) { hr = DumpOctetHash( g_wszPad4, IDS_ARCHIVED_KEY_CERT_HASH, g_wszCertUtil, pval->pbData, pval->cbData, pbHashUserCert, pcbHashUserCert); if (S_OK != hr) { fDumpHex = TRUE; } } else if (0 == strcmp(pAttr->pszObjId, szOID_ISSUED_CERT_HASH)) { hr = DumpOctetHash( g_wszPad4, IDS_ISSUED_CERT_HASH, g_wszCertUtil, pval->pbData, pval->cbData, pbHashUserCert, pcbHashUserCert); if (S_OK != hr) { fDumpHex = TRUE; } } else if (0 == strcmp(pAttr->pszObjId, szOID_ENCRYPTED_KEY_HASH)) { hr = DumpOctetHash( g_wszPad4, IDS_ENCRYPTED_KEY_HASH, g_wszCertUtil, pval->pbData, pval->cbData, NULL, NULL); if (S_OK != hr) { fDumpHex = TRUE; } } else if (0 == strcmp(pAttr->pszObjId, szOID_ENROLLMENT_CSP_PROVIDER)) { CRYPT_CSP_PROVIDER *pccp; hr = myDecodeCSPProviderAttribute( pval->pbData, pval->cbData, &pccp); if (S_OK == hr) { wprintf(g_wszPad4); wprintf( myLoadResourceString(IDS_CSP_PROVIDER_INFO)); wprintf(wszNewLine); wprintf(g_wszPad4); wprintf( myLoadResourceString(IDS_FORMAT_KEYSPEC), pccp->dwKeySpec); wprintf(wszNewLine); wprintf(g_wszPad4); wprintf( myLoadResourceString(IDS_FORMAT_PROVIDER_NAME), NULL == pccp->pwszProviderName? myLoadResourceString(IDS_PROP_EMPTY) : pccp->pwszProviderName); wprintf(wszNewLine); wprintf(g_wszPad4); wprintf( myLoadResourceString(IDS_FORMAT_SIGNATURE_UNUSEDBITS), // "Signature: UnusedBits=%u" pccp->Signature.cUnusedBits); wprintf(wszNewLine); DumpHex( DH_NOTABPREFIX | DH_NOASCIIHEX | 4, pccp->Signature.pbData, pccp->Signature.cbData); LocalFree(pccp); } else { fDumpHex = TRUE; } } else if (0 == strcmp(pAttr->pszObjId, szOID_RSA_signingTime)) { FILETIME ft; cb = sizeof(ft); if (CryptDecodeObject( X509_ASN_ENCODING, X509_CHOICE_OF_TIME, pval->pbData, pval->cbData, 0, &ft, &cb)) { wprintf( L"%ws%ws%ws: ", g_wszPad4, myLoadResourceString(IDS_SIGNING_TIME), g_wszCertUtil); hr = cuDumpFileTime(0, NULL, &ft); _JumpIfError(hr, error, "cuDumpFileTime"); } else { fDumpHex = TRUE; } } else if (0 == strcmp(pAttr->pszObjId, szOID_REQUEST_CLIENT_INFO)) { CRYPT_REQUEST_CLIENT_INFO *pcrci = NULL; hr = myDecodeRequestClientAttribute( pval->pbData, pval->cbData, &pcrci); if (S_OK == hr) { wprintf(g_wszPad2); cuRegPrintDwordValue( TRUE, wszREQUESTCLIENTID, myLoadResourceString(IDS_CLIENTID), pcrci->dwClientId); wprintf( L"%ws%ws %ws\n", g_wszPad4, myLoadResourceString(IDS_USERCOLON), pcrci->pwszUser); wprintf( L"%ws%ws %ws\n", g_wszPad4, myLoadResourceString(IDS_MACHINECOLON), pcrci->pwszMachine); wprintf( L"%ws%ws %ws\n", g_wszPad4, myLoadResourceString(IDS_PROCESSCOLON), pcrci->pwszProcess); LocalFree(pcrci); } else { fDumpHex = TRUE; } } else if (0 == strcmp(pAttr->pszObjId, szOID_RSA_counterSign)) { CMSG_SIGNER_INFO *psi = NULL; if (!myDecodeObject( X509_ASN_ENCODING, PKCS7_SIGNER_INFO, pval->pbData, pval->cbData, CERTLIB_USE_LOCALALLOC, (VOID **) &psi, &cb)) { CSASSERT(NULL == psi); hr = myHLastError(); _PrintError(hr, "myDecodeObject"); fDumpHex = TRUE; } else { wprintf( L"%ws%ws%ws: ", g_wszPad4, myLoadResourceString(IDS_COUNTER_SIGNATURE), g_wszCertUtil); hr = cuDumpSignerInfo( psi, MAXDWORD, // iElement fQuiet, 0, hStore, pbHashUserCert, pcbHashUserCert); _PrintIfError(hr, "cuDumpSignerInfo"); if (S_OK != hr) { fDumpHex = TRUE; } } if (NULL != psi) { LocalFree(psi); } } else if (0 == strcmp(pAttr->pszObjId, szOID_RSA_challengePwd)) { CRYPT_DATA_BLOB Value; WCHAR *pwsz; Value.pbData = pval->pbData; Value.cbData = pval->cbData; hr = UnicodeDecode(&Value, &pwsz); if (S_OK == hr) { wprintf(L"%ws%ws\n", g_wszPad4, pwsz); LocalFree(pwsz); } else { fDumpHex = TRUE; } } else if (0 == strcmp(pAttr->pszObjId, szOID_YESNO_TRUST_ATTR)) { DWORD Bool; cb = sizeof(Bool); Bool = 0; if (CryptDecodeObject( X509_ASN_ENCODING, X509_INTEGER, pval->pbData, pval->cbData, 0, &Bool, &cb)) { wprintf( L"%ws%x\n", g_wszPad4, Bool); } else { fDumpHex = TRUE; } } if (fDumpHex) { DumpHex( DH_NOTABPREFIX | 4, pval->pbData, pval->cbData); } } } } } if (NULL != ppExtInfo) { *ppExtInfo = pExtInfo; pExtInfo = NULL; } hr = S_OK; error: if (NULL != pNamePair) { LocalFree(pNamePair); } if (NULL != pExtInfo) { LocalFree(pExtInfo); } if (NULL != pNameInfo) { LocalFree(pNameInfo); } return(hr); } HRESULT FindCertStoreIndex( IN HCERTSTORE hStore, IN CERT_CONTEXT const *pCertSigner, OUT DWORD *piElement) { HRESULT hr; DWORD iElement; CERT_CONTEXT const *pcc = NULL; *piElement = -1; for (iElement = 0; ; iElement++) { pcc = CertEnumCertificatesInStore(hStore, pcc); if (NULL == pcc) { hr = CRYPT_E_NOT_FOUND; _JumpError(hr, error, "CertEnumCertificatesInStore"); } if (pCertSigner->cbCertEncoded == pcc->cbCertEncoded && 0 == memcmp( pCertSigner->pbCertEncoded, pcc->pbCertEncoded, pcc->cbCertEncoded)) { break; } } *piElement = iElement; hr = S_OK; error: if (NULL != pcc) { CertFreeCertificateContext(pcc); } return(hr); } HRESULT cuDumpIssuerSerialAndSubject( IN CERT_NAME_BLOB const *pIssuer, IN CRYPT_INTEGER_BLOB const *pSerialNumber, OPTIONAL IN CERT_NAME_BLOB const *pSubject, OPTIONAL IN HCERTSTORE hStore) { HRESULT hr; BOOL fVerbose = g_fVerbose; CERT_ID CertId; CERT_CONTEXT const *pcc = NULL; BOOL fMultiLine = NULL == pSerialNumber || g_fVerbose; if (g_fVerbose) { g_fVerbose--; } hr = cuDumpSerial(g_wszPad4, IDS_SERIAL, pSerialNumber); _JumpIfError(hr, error, "cuDumpSerial"); hr = cuDisplayCertName( fMultiLine, g_wszPad4, myLoadResourceString(IDS_ISSUER), // "Issuer" g_wszPad8, pIssuer, NULL); _JumpIfError(hr, error, "cuDisplayCertName(Issuer)"); ZeroMemory(&CertId, sizeof(CertId)); CertId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; CertId.IssuerSerialNumber.Issuer = *pIssuer; if (NULL != pSerialNumber) { CertId.IssuerSerialNumber.SerialNumber = *pSerialNumber; } if (NULL == pSubject && NULL != hStore) { pcc = CertFindCertificateInStore( hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, // dwFindFlags CERT_FIND_CERT_ID, &CertId, NULL); if (NULL == pcc) { hr = myHLastError(); _PrintError2(hr, "CertFindCertificateInStore", hr); } else { pSubject = &pcc->pCertInfo->Subject; } } if (NULL != pSubject) { hr = cuDisplayCertName( fMultiLine, g_wszPad4, myLoadResourceString(IDS_SUBJECT), // "Subject" g_wszPad8, pSubject, NULL); _JumpIfError(hr, error, "cuDisplayCertName(Issuer)"); } hr = S_OK; error: g_fVerbose = fVerbose; if (NULL != pcc) { CertFreeCertificateContext(pcc); } return(hr); } HRESULT cuDumpSigners( IN HCRYPTMSG hMsg, IN CHAR const *pszInnerContentObjId, IN HCERTSTORE hStore, IN DWORD cSigner, IN BOOL fContentEmpty, IN BOOL fQuiet, OPTIONAL OUT BYTE *pbHashUserCert, OPTIONAL IN OUT DWORD *pcbHashUserCert) { HRESULT hr; DWORD i; CMSG_CMS_SIGNER_INFO *pcsi = NULL; DWORD cb; CERT_CONTEXT const *pcc = NULL; BYTE abHash[CBMAX_CRYPT_HASH_LEN]; DWORD iElement; DWORD VerifyState; BOOL fVerbose = g_fVerbose; CERT_REQUEST_INFO *pRequest = NULL; if (!fQuiet) { if (0 == cSigner) { wprintf(myLoadResourceString(IDS_DUMP_PKCS7_NO_SIGNER)); wprintf(wszNewLine); } else { wprintf( L"%ws: %d\n", myLoadResourceString(IDS_DUMP_PKCS7_SIGNER_COUNT), cSigner); } } for (i = 0; i < cSigner; i++) { DWORD idVerify = 0; if (NULL != pcsi) { LocalFree(pcsi); pcsi = NULL; } hr = myCryptMsgGetParam( hMsg, CMSG_CMS_SIGNER_INFO_PARAM, i, CERTLIB_USE_LOCALALLOC, (VOID **) &pcsi, &cb); _JumpIfError(hr, error, "myCryptMsgGetParam"); if (CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice || (NULL != pcsi->HashEncryptionAlgorithm.pszObjId && 0 == strcmp( szOID_PKIX_NO_SIGNATURE, pcsi->HashEncryptionAlgorithm.pszObjId))) { CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA cvse; ZeroMemory(&cvse, sizeof(cvse)); cvse.cbSize = sizeof(cvse); cvse.dwSignerIndex = i; if (CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice) { if (NULL == pRequest) { hr = myGetInnerPKCS10( hMsg, pszInnerContentObjId, &pRequest); _JumpIfError(hr, error, "myGetInnerPKCS10"); } cvse.dwSignerType = CMSG_VERIFY_SIGNER_PUBKEY; cvse.pvSigner = &pRequest->SubjectPublicKeyInfo; } else { cvse.dwSignerType = CMSG_VERIFY_SIGNER_NULL; } if (!CryptMsgControl( hMsg, 0, // dwFlags CMSG_CTRL_VERIFY_SIGNATURE_EX, &cvse)) { hr = myHLastError(); _PrintError(hr, "CryptMsgControl"); cuPrintError(0, hr); } else { idVerify = CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice? IDS_REQUEST_SIGNATUREMATCHES : // "Signature matches request Public Key" IDS_NULL_SIGNATUREMATCHES; // "NULL signature verifies" } } else { DWORD dwFlags; dwFlags = CMSG_USE_SIGNER_INDEX_FLAG; while (TRUE) { iElement = i; if (CryptMsgGetAndVerifySigner( hMsg, 0, // cSignerStore NULL, // rghSignerStore dwFlags, &pcc, &iElement)) { hr = S_OK; break; } hr = myHLastError(); _PrintError(hr, "CryptMsgGetAndVerifySigner"); if (CMSG_SIGNER_ONLY_FLAG & dwFlags) { cuPrintError(0, hr); break; } cuPrintError( (fContentEmpty && NTE_BAD_SIGNATURE == hr)? IDS_DETACHED_SIGNATURE : // "Cannot verify detached signature" 0, hr); dwFlags |= CMSG_SIGNER_ONLY_FLAG; } if (S_OK == hr) { idVerify = IDS_SIGNATUREMATCHES; // "Signature matches Public Key" hr = FindCertStoreIndex(hStore, pcc, &iElement); _JumpIfError(hr, error, "FindCertStoreIndex"); if (!fQuiet) { wprintf( L"%ws: %u\n", myLoadResourceString(IDS_DUMP_PKCS7_SIGNCERT), // "Signing Certificate Index" iElement); } hr = cuVerifyCertContext( pcc, hStore, 0, // cApplicationPolicies NULL, // apszApplicationPolicies 0, // cIssuancePolicies NULL, // apszIssuancePolicies FALSE, // fNTAuth &VerifyState); _PrintIfError(hr, "cuVerifyCertContext"); CertFreeCertificateContext(pcc); pcc = NULL; } } hr = cuDumpCMSSignerInfo( pcsi, i, fQuiet, idVerify, hStore, pbHashUserCert, pcbHashUserCert); _PrintIfError(hr, "cuDumpCMSSignerInfo"); cb = sizeof(abHash); if (!CryptMsgGetParam( hMsg, CMSG_COMPUTED_HASH_PARAM, 0, abHash, &cb)) { hr = myHLastError(); _PrintError(hr, "CryptMsgGetParam(computed hash)"); } else { wprintf(wszNewLine); hr = DumpHash( NULL, IDS_FORMAT_COMPUTED_HASH_COLON, // "Computed Hash%ws: %ws" NULL, g_wszEmpty, abHash, cb); _JumpIfError(hr, error, "DumpHash"); } } hr = S_OK; error: if (NULL != pRequest) { LocalFree(pRequest); } if (NULL != pcsi) { LocalFree(pcsi); } if (NULL != pcc) { CertFreeCertificateContext(pcc); } return(hr); } HRESULT cuDumpRecipientCertHash( IN CERT_INFO const *pci, IN HCERTSTORE hStore) { HRESULT hr; CERT_CONTEXT const *pcc = NULL; CERT_ID CertId; CSASSERT(NULL != hStore); CertId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; CertId.IssuerSerialNumber.Issuer = pci->Issuer; CertId.IssuerSerialNumber.SerialNumber = pci->SerialNumber; pcc = CertFindCertificateInStore( hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, // dwFindFlags CERT_FIND_CERT_ID, &CertId, NULL); if (NULL == pcc) { hr = myHLastError(); _JumpError(hr, error, "CertFindCertificateInStore"); } hr = cuDisplayHash(g_wszPad4, pcc, NULL, CERT_SHA1_HASH_PROP_ID, L"sha1"); _JumpIfError(hr, error, "cuDisplayHash"); error: if (NULL != pcc) { CertFreeCertificateContext(pcc); } return(hr); } HRESULT cuDumpRecipients( IN HCRYPTMSG hMsg, OPTIONAL IN HCERTSTORE hStoreWrapper, IN DWORD cRecipient, IN BOOL fQuiet) { HRESULT hr; DWORD i; CERT_INFO *pci = NULL; DWORD cb; if (!fQuiet) { if (0 == cRecipient) { wprintf(myLoadResourceString(IDS_DUMP_PKCS7_NO_RECIPIENT)); wprintf(wszNewLine); } else { wprintf( L"%ws: %d\n", myLoadResourceString(IDS_DUMP_PKCS7_RECIPIENT_COUNT), cRecipient); } } for (i = 0; i < cRecipient; i++) { if (NULL != pci) { LocalFree(pci); pci = NULL; } hr = myCryptMsgGetParam( hMsg, CMSG_RECIPIENT_INFO_PARAM, i, CERTLIB_USE_LOCALALLOC, (VOID **) &pci, &cb); _JumpIfError(hr, error, "myCryptMsgGetParam"); wprintf(wszNewLine); wprintf( L"%ws[%u]:\n", myLoadResourceString(IDS_RECIPIENT_INFO), // "Recipient Info" i); hr = cuDumpIssuerSerialAndSubject( &pci->Issuer, &pci->SerialNumber, NULL, // pSubject hStoreWrapper); _JumpIfError(hr, error, "cuDumpIssuerSerialAndSubject(Recipient)"); if (NULL != hStoreWrapper) { hr = cuDumpRecipientCertHash(pci, hStoreWrapper); _PrintIfError(hr, "cuDumpRecipientCertHash"); } } hr = S_OK; error: if (NULL != pci) { LocalFree(pci); } return(hr); } HRESULT OpenCAXchgMemoryStore( OUT HCERTSTORE *phStore) { HRESULT hr; WCHAR const *pwszConfig = g_pwszConfig; BSTR strConfig = NULL; DISPATCHINTERFACE diRequest; BSTR strCert = NULL; HCERTSTORE hStore = NULL; if (NULL == pwszConfig) { hr = ConfigGetConfig(g_DispatchFlags, CC_LOCALACTIVECONFIG, &strConfig); _JumpIfError(hr, error, "ConfigGetConfig"); pwszConfig = strConfig; } hr = Request_Init(g_DispatchFlags, &diRequest); _JumpIfError(hr, error, "Request_Init"); hr = Request2_GetCAProperty( &diRequest, pwszConfig, CR_PROP_CAXCHGCERT, MAXDWORD, // PropIndex PROPTYPE_BINARY, CR_OUT_BINARY, &strCert); _JumpIfError(hr, error, "Request2_GetCAProperty"); hStore = CertOpenStore( CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, 0, NULL); if (NULL == hStore) { hr = myHLastError(); _JumpError(hr, error, "CertOpenStore"); } // Add as encoded blob to avoid all properties, key prov info, etc. if (!CertAddEncodedCertificateToStore( hStore, X509_ASN_ENCODING, (BYTE *) strCert, SysStringByteLen(strCert), CERT_STORE_ADD_REPLACE_EXISTING, NULL)) // ppCertContext { hr = myHLastError(); _JumpError(hr, error, "CertAddEncodedCertificateToStore"); } *phStore = hStore; hStore = NULL; hr = S_OK; error: if (NULL != hStore) { CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG); } if (NULL != strCert) { SysFreeString(strCert); } Request_Release(&diRequest); if (NULL != strConfig) { SysFreeString(strConfig); } return(hr); } HRESULT OpenNamedStore( IN BOOL fUserStore, IN WCHAR const *pwszStoreName, OUT HCERTSTORE *phStore) { HRESULT hr; *phStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING, NULL, // hProv CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG | (fUserStore? CERT_SYSTEM_STORE_CURRENT_USER : CERT_SYSTEM_STORE_LOCAL_MACHINE), pwszStoreName); if (NULL == *phStore) { hr = myHLastError(); _JumpErrorStr2( hr, error, "CertOpenStore", pwszStoreName, HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); } hr = S_OK; error: return(hr); } HRESULT cuCryptDecryptMessageFromCert( IN CERT_CONTEXT const *pcc, IN BYTE const *pbIn, IN DWORD cbIn, OUT DWORD *pdwKeySpecFound, OUT BYTE **ppbDecrypted, OUT DWORD *pcbDecrypted) { HRESULT hr; HCERTSTORE hStore = NULL; CERT_CONTEXT const *pccStore = NULL; CERT_KEY_CONTEXT ckc; HCRYPTPROV hProv = NULL; DWORD dwKeySpec; CRYPT_KEY_PROV_INFO *pkpi = NULL; DWORD dwTickCount = GetTickCount(); *pdwKeySpecFound = 0; hStore = CertOpenStore( CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, 0, NULL); if (NULL == hStore) { hr = myHLastError(); _JumpError(hr, error, "CertOpenStore"); } // Add as encoded blob to avoid all properties, key prov info, etc. if (!CertAddEncodedCertificateToStore( hStore, X509_ASN_ENCODING, pcc->pbCertEncoded, pcc->cbCertEncoded, CERT_STORE_ADD_REPLACE_EXISTING, &pccStore)) // ppCertContext { hr = myHLastError(); _JumpError(hr, error, "CertAddEncodedCertificateToStore"); } hr = myCertGetKeyProviderInfo(pcc, &pkpi); _PrintIfError2(hr, "myCertGetKeyProviderInfo", CRYPT_E_NOT_FOUND); if (S_OK == hr) { DBGPRINT(( s_DbgSsRecoveryTrace, "Original KeyProvInfo: container=%ws, type=%x, prov=%ws, KeySpec=%x, f=%x\n", pkpi->pwszContainerName, pkpi->dwProvType, pkpi->pwszProvName, pkpi->dwKeySpec, pkpi->dwFlags)); } else if (!g_fForce) { _JumpError2(hr, error, "myCertGetKeyProviderInfo", CRYPT_E_NOT_FOUND); } DBGPRINT(( s_DbgSsRecoveryTrace, "Before CryptAcquireCertificatePrivateKey: Ticks=%u\n", GetTickCount() - dwTickCount)); if (!CryptAcquireCertificatePrivateKey( pcc, 0, // dwFlags NULL, // pvReserved &hProv, &dwKeySpec, NULL)) // pfCallerFreeProv { hr = myHLastError(); _PrintError2( hr, "CryptAcquireCertificatePrivateKey", CRYPT_E_NO_KEY_PROPERTY); DBGPRINT(( s_DbgSsRecoveryTrace, "Before CryptFindCertificateKeyProvInfo: Ticks=%u\n", GetTickCount() - dwTickCount)); if (!CryptFindCertificateKeyProvInfo(pcc, 0, NULL)) { hr = myHLastError(); _JumpError2( hr, error, "CryptFindCertificateKeyProvInfo", HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); } if (NULL != pkpi) { LocalFree(pkpi); pkpi = NULL; } hr = myCertGetKeyProviderInfo(pcc, &pkpi); _JumpIfError(hr, error, "myCertGetKeyProviderInfo"); DBGPRINT(( s_DbgSsRecoveryTrace, "Constructed KeyProvInfo: container=%ws, type=%x, prov=%ws, KeySpec=%x, f=%x\n", pkpi->pwszContainerName, pkpi->dwProvType, pkpi->pwszProvName, pkpi->dwKeySpec, pkpi->dwFlags)); dwKeySpec = pkpi->dwKeySpec; DBGPRINT(( s_DbgSsRecoveryTrace, "Before CryptAcquireContext: Ticks=%u\n", GetTickCount() - dwTickCount)); if (!CryptAcquireContext( &hProv, pkpi->pwszContainerName, pkpi->pwszProvName, pkpi->dwProvType, pkpi->dwFlags)) { hr = myHLastError(); _JumpErrorStr( hr, error, "CryptAcquireContext", pkpi->pwszContainerName); } } ZeroMemory(&ckc, sizeof(ckc)); ckc.cbSize = sizeof(ckc); ckc.dwKeySpec = dwKeySpec; ckc.hCryptProv = hProv; *pdwKeySpecFound = dwKeySpec; DBGPRINT(( s_DbgSsRecoveryTrace, "Before CertSetCertificateContextProperty: Ticks=%u\n", GetTickCount() - dwTickCount)); if (!CertSetCertificateContextProperty( pccStore, CERT_KEY_CONTEXT_PROP_ID, CERT_STORE_NO_CRYPT_RELEASE_FLAG, &ckc)) { hr = myHLastError(); _JumpError(hr, error, "CertSetCertificateContextProperty"); } DBGPRINT(( s_DbgSsRecoveryTrace, "Before myCryptDecryptMessage: Ticks=%u\n", GetTickCount() - dwTickCount)); hr = myCryptDecryptMessage( hStore, pbIn, cbIn, CERTLIB_USE_LOCALALLOC, ppbDecrypted, pcbDecrypted); _JumpIfError(hr, error, "myCryptDecryptMessage"); DBGPRINT(( s_DbgSsRecoveryTrace, "After myCryptDecryptMessage: Ticks=%u\n", GetTickCount() - dwTickCount)); error: if (S_OK != hr) { DBGPRINT(( s_DbgSsRecoveryTrace, "Skipped myCryptDecryptMessage(%x): Ticks=%u\n", hr, GetTickCount() - dwTickCount)); } if (NULL != pkpi) { LocalFree(pkpi); } if (NULL != pccStore) { CertFreeCertificateContext(pccStore); } if (NULL != hStore) { CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG); } if (NULL != hProv) { CryptReleaseContext(hProv, 0); } return(hr); } // Attempt to find any one recipient cert with a usable private key in the // following locations: // - the next outer PKCS7 store (hStoreWrapper parameter) // - the PKCS7 store (hStorePKCS7 parameter) // - the local machine's current CA Exchange cert // - the HKLM KRA store // - the HKLM MY store // - the HKCU MY store HRESULT cuDumpEncryptedAsnBinary( IN HCRYPTMSG hMsg, IN DWORD cRecipient, IN DWORD RecipientIndex, OPTIONAL IN HCERTSTORE hStoreWrapper, IN HCERTSTORE hStorePKCS7, IN BYTE const *pbIn, IN DWORD cbIn, IN BOOL fQuiet, OPTIONAL OUT BYTE **ppbDecrypted, OPTIONAL OUT DWORD *pcbDecrypted) { HRESULT hr; HCERTSTORE ahStore[6]; WCHAR *apwszStore[6]; DWORD cStore = 0; DWORD iRecipient; DWORD iStore; DWORD cb; CERT_INFO *pci = NULL; CERT_CONTEXT const *pcc = NULL; BOOL fDecrypted = FALSE; BYTE *pbDecrypted = NULL; DWORD cbDecrypted; DWORD dwKeySpecFound; BOOL fSignatureKey = FALSE; BOOL fExchangeKey = FALSE; DWORD dwTickCount = GetTickCount(); if (NULL != ppbDecrypted) { *ppbDecrypted = NULL; } if (NULL != pcbDecrypted) { *pcbDecrypted = 0; } s_DbgSsRecoveryTrace = g_fVerbose? DBG_SS_CERTUTIL : DBG_SS_CERTUTILI; hr = OpenNamedStore(TRUE, wszMY_CERTSTORE, &ahStore[cStore]); if (S_OK == hr) { apwszStore[cStore] = L"HKCU MY"; cStore++; } hr = OpenNamedStore(FALSE, wszMY_CERTSTORE, &ahStore[cStore]); if (S_OK == hr) { apwszStore[cStore] = L"HKLM MY"; cStore++; } if (NULL != hStoreWrapper) { apwszStore[cStore] = L"PKCS7 Wrapper"; ahStore[cStore++] = hStoreWrapper; } if (NULL != hStorePKCS7) { apwszStore[cStore] = L"PKCS7"; ahStore[cStore++] = hStorePKCS7; } hr = OpenCAXchgMemoryStore(&ahStore[cStore]); if (S_OK == hr) { apwszStore[cStore] = L"CAXchgMemory"; cStore++; } hr = OpenNamedStore(FALSE, wszKRA_CERTSTORE, &ahStore[cStore]); if (S_OK == hr) { apwszStore[cStore] = L"HKLM KRA"; cStore++; } for (iRecipient = 0; !fDecrypted && iRecipient < cRecipient; iRecipient++) { CERT_ID CertId; if (MAXDWORD != RecipientIndex && iRecipient != RecipientIndex) { continue; } if (NULL != pci) { LocalFree(pci); pci = NULL; } hr = myCryptMsgGetParam( hMsg, CMSG_RECIPIENT_INFO_PARAM, iRecipient, CERTLIB_USE_LOCALALLOC, (VOID **) &pci, &cb); _JumpIfError(hr, error, "myCryptMsgGetParam"); CertId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER; CertId.IssuerSerialNumber.Issuer = pci->Issuer; CertId.IssuerSerialNumber.SerialNumber = pci->SerialNumber; for (iStore = 0; !fDecrypted && iStore < cStore; iStore++) { if (NULL != pcc) { CertFreeCertificateContext(pcc); pcc = NULL; } while (TRUE) { pcc = CertFindCertificateInStore( ahStore[iStore], X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, // dwFindFlags CERT_FIND_CERT_ID, &CertId, pcc); if (NULL == pcc) { hr = myHLastError(); _PrintError2(hr, "CertFindCertificateInStore", hr); break; } { WCHAR *pwsz; pwsz = NULL; hr = myCertNameToStr( X509_ASN_ENCODING, &pcc->pCertInfo->Subject, CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, &pwsz); _PrintIfError(hr, "myCertNameToStr"); DBGPRINT(( s_DbgSsRecoveryTrace, "================================================\n")); DBGPRINT(( s_DbgSsRecoveryTrace, "Found Recipient[%u] in %ws -- ahStore[%u of %u]: %ws\n", iRecipient, apwszStore[iStore], iStore, cStore, pwsz)); if (NULL != pwsz) { LocalFree(pwsz); } } if (g_fVerbose) { wprintf(wszNewLine); wprintf( L"%ws[%u]:\n", myLoadResourceString(IDS_RECIPIENT_INFO), // "Recipient Info" iRecipient); hr = cuDumpIssuerSerialAndSubject( &pci->Issuer, &pci->SerialNumber, &pcc->pCertInfo->Subject, NULL); // hStore _JumpIfError(hr, error, "cuDumpIssuerSerialAndSubject(Recipient)"); } hr = cuCryptDecryptMessageFromCert( pcc, pbIn, cbIn, &dwKeySpecFound, &pbDecrypted, &cbDecrypted); _PrintIfError2( hr, "cuCryptDecryptMessageFromCert", HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); { DBGPRINT(( s_DbgSsRecoveryTrace, "cuCryptDecryptMessageFromCert(Recipient[%u]): %x\n", iRecipient, hr)); } if (AT_SIGNATURE == dwKeySpecFound) { fSignatureKey = TRUE; } else if (AT_KEYEXCHANGE == dwKeySpecFound) { fExchangeKey = TRUE; } if (S_OK != hr) { DBGPRINT(( s_DbgSsRecoveryTrace, "cuDumpEncryptedAsnBinary failed(%x): Ticks=%u\n", hr, GetTickCount() - dwTickCount)); continue; } wprintf(myLoadResourceString(IDS_DUMP_DECRYPTED)); // "Decrypted PKCS7 Content" wprintf(wszNewLine); hr = DumpAsnBlob( NULL, fQuiet, pbDecrypted, cbDecrypted, MAXDWORD); _PrintIfError(hr, "DumpAsnBlob(decrypted content)"); if (S_OK == hr) { fDecrypted = TRUE; if (NULL != ppbDecrypted) { *ppbDecrypted = pbDecrypted; pbDecrypted = NULL; } if (NULL != pcbDecrypted) { *pcbDecrypted = cbDecrypted; } } break; } } } DBGPRINT(( s_DbgSsRecoveryTrace, "cuDumpEncryptedAsnBinary end(fDecrypted=%d): Ticks=%u\n", fDecrypted, GetTickCount() - dwTickCount)); if (!fDecrypted) { if (fSignatureKey && !fExchangeKey) { wprintf(myLoadResourceString(IDS_SIGNATURE_NOTKEYEXCHANGE)); // "Found AT_SIGNATURE key but no AT_KEYEXCHANGE key" wprintf(wszNewLine); } hr = CRYPT_E_NO_DECRYPT_CERT; _JumpError(hr, error, "No decryption key"); } hr = S_OK; error: if (NULL != pbDecrypted) { LocalFree(pbDecrypted); } if (NULL != pci) { LocalFree(pci); } if (NULL != pcc) { CertFreeCertificateContext(pcc); } for (iStore = 0; iStore < cStore; iStore++) { if (NULL != ahStore[iStore] && hStoreWrapper != ahStore[iStore] && hStorePKCS7 != ahStore[iStore]) { CertCloseStore(ahStore[iStore], CERT_CLOSE_STORE_CHECK_FLAG); } } return(hr); } HRESULT dumpPKCS7( OPTIONAL IN HCERTSTORE hStoreWrapper, IN BYTE const *pbIn, IN DWORD cbIn) { HRESULT hr; BYTE *pbContents = NULL; DWORD cbContents; HCERTSTORE hStore = NULL; CERT_CONTEXT const *pCert = NULL; CRL_CONTEXT const *pCRL = NULL; HCRYPTMSG hMsg = NULL; CRYPT_ATTRIBUTES *pAttrib = NULL; BOOL fDisplayed; DWORD iElement; DWORD cSigner; DWORD cRecipient; DWORD cb; DWORD dwMsgType; DWORD dwMsgVersion; char *pszInnerContentObjId = NULL; WCHAR const *pwsz; WCHAR const *pwszVersion; UINT idsType = IDS_DUMP_PKCS7; hr = myDecodePKCS7( pbIn, cbIn, &pbContents, &cbContents, &dwMsgType, &pszInnerContentObjId, &cSigner, &cRecipient, &hStore, &hMsg); _JumpIfError2(hr, error, "myDecodePKCS7", CRYPT_E_ASN1_BADTAG); cb = sizeof(dwMsgVersion); if (!CryptMsgGetParam( hMsg, CMSG_VERSION_PARAM, 0, &dwMsgVersion, &cb)) { hr = myHLastError(); _PrintError(hr, "CryptMsgGetParam(version)"); dwMsgVersion = MAXDWORD; } pwszVersion = NULL; switch (dwMsgType) { case CMSG_DATA: pwsz = L"CMSG_DATA"; break; case CMSG_ENVELOPED: pwsz = L"CMSG_ENVELOPED"; switch (dwMsgVersion) { case CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION: pwszVersion = L"CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION"; break; case CMSG_ENVELOPED_DATA_CMS_VERSION: pwszVersion = L"CMSG_ENVELOPED_DATA_CMS_VERSION"; idsType = IDS_DUMP_PKCS7CMS; break; } break; case CMSG_HASHED: pwsz = L"CMSG_HASHED"; switch (dwMsgVersion) { case CMSG_HASHED_DATA_PKCS_1_5_VERSION: pwszVersion = L"CMSG_HASHED_DATA_PKCS_1_5_VERSION"; break; case CMSG_HASHED_DATA_CMS_VERSION: pwszVersion = L"CMSG_HASHED_DATA_CMS_VERSION"; idsType = IDS_DUMP_PKCS7CMS; break; } break; case CMSG_SIGNED: pwsz = L"CMSG_SIGNED"; switch (dwMsgVersion) { case CMSG_SIGNED_DATA_PKCS_1_5_VERSION: pwszVersion = L"CMSG_SIGNED_DATA_PKCS_1_5_VERSION"; break; case CMSG_SIGNED_DATA_CMS_VERSION: pwszVersion = L"CMSG_SIGNED_DATA_CMS_VERSION"; idsType = IDS_DUMP_PKCS7CMS; break; } break; case CMSG_SIGNED_AND_ENVELOPED: pwsz = L"CMSG_SIGNED_AND_ENVELOPED"; break; default: pwsz = myLoadResourceString(IDS_QUESTIONMARKS); // "???" break; } wprintf(myLoadResourceString(idsType)); wprintf(wszNewLine); wprintf(L" %ws(%u)\n", pwsz, dwMsgType); if (NULL != pwszVersion) { wprintf(L" %ws(%u)\n", pwszVersion, dwMsgVersion); } if (NULL != pszInnerContentObjId) { wprintf( L" %ws: ", myLoadResourceString(IDS_DUMP_PKCS7_CONTENT_TYPE)); cuDumpOIDAndDescriptionA(pszInnerContentObjId); wprintf(wszNewLine); } wprintf(wszNewLine); if (NULL == pbContents) { wprintf(myLoadResourceString(IDS_DUMP_PKCS7_NO_CONTENT)); wprintf(wszNewLine); } else { wprintf(myLoadResourceString(IDS_DUMP_PKCS7_CONTENTS)); // "PKCS7 Message Content:" wprintf(wszNewLine); fDisplayed = FALSE; if (CMSG_ENVELOPED != dwMsgType) { hr = DumpAsnBlob(hStore, FALSE, pbContents, cbContents, MAXDWORD); _PrintIfError(hr, "DumpAsnBlob(content)"); fDisplayed = TRUE; } else if (NULL != hMsg && 0 != cRecipient) { hr = cuDumpEncryptedAsnBinary( hMsg, cRecipient, MAXDWORD, // RecipientIndex hStoreWrapper, hStore, pbIn, cbIn, FALSE, NULL, NULL); _PrintIfError(hr, "cuDumpEncryptedAsnBinary"); if (S_OK == hr) { fDisplayed = TRUE; } } if (!fDisplayed) { DumpHex(0, pbContents, cbContents); } } wprintf(wszNewLine); if (NULL != hMsg) { BYTE abHash[CBMAX_CRYPT_HASH_LEN]; hr = cuDumpSigners( hMsg, pszInnerContentObjId, hStore, cSigner, NULL == pbContents, // fContentEmpty FALSE, // fVerifyOnly NULL, // pbHashUserCert NULL); // pcbHashUserCert _JumpIfError(hr, error, "cuDumpSigners"); hr = cuDumpRecipients(hMsg, hStoreWrapper, cRecipient, FALSE); _JumpIfError(hr, error, "cuDumpRecipients"); cb = sizeof(abHash); if (!CryptMsgGetParam( hMsg, CMSG_HASH_DATA_PARAM, 0, abHash, &cb)) { hr = myHLastError(); _PrintError2(hr, "CryptMsgGetParam(stored hash)", CRYPT_E_INVALID_MSG_TYPE); } else { hr = DumpHash( NULL, IDS_FORMAT_STORED_HASH_COLON, // "Stored Hash%ws: %ws" NULL, g_wszEmpty, abHash, cb); _JumpIfError(hr, error, "DumpHash"); } wprintf(wszNewLine); } fDisplayed = FALSE; if (NULL != hStore) { CSASSERT(NULL == pCert); for (iElement = 0; ; iElement++) { pCert = CertEnumCertificatesInStore(hStore, pCert); if (NULL == pCert) { break; } if (!fDisplayed) { wprintf(myLoadResourceString(IDS_DUMP_PKCS7_CERTIFICATES)); wprintf(wszNewLine); fDisplayed = TRUE; } hr = cuDumpAsnBinary( pCert->pbCertEncoded, pCert->cbCertEncoded, iElement); _JumpIfError(hr, error, "cuDumpAsnBinary"); } } if (!fDisplayed) { wprintf(myLoadResourceString(IDS_DUMP_PKCS7_NO_CERTIFICATES)); wprintf(wszNewLine); } fDisplayed = FALSE; if (NULL != hStore) { CSASSERT(NULL == pCRL); for (iElement = 0; ; iElement++) { pCRL = CertEnumCRLsInStore(hStore, pCRL); if (NULL == pCRL) { break; } if (!fDisplayed) { wprintf(myLoadResourceString(IDS_DUMP_PKCS7_CRLS)); wprintf(wszNewLine); fDisplayed = TRUE; } hr = cuDumpAsnBinary( pCRL->pbCrlEncoded, pCRL->cbCrlEncoded, iElement); _JumpIfError(hr, error, "cuDumpAsnBinary"); } } if (!fDisplayed) { wprintf(myLoadResourceString(IDS_DUMP_PKCS7_NO_CRLS)); wprintf(wszNewLine); } hr = S_OK; error: if (NULL != pszInnerContentObjId) { LocalFree(pszInnerContentObjId); } if (NULL != pAttrib) { LocalFree(pAttrib); } if (NULL != hMsg) { CryptMsgClose(hMsg); } if (NULL != pCRL) { CertFreeCRLContext(pCRL); } if (NULL != pCert) { CertFreeCertificateContext(pCert); } if (NULL != hStore) { CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG); } if (NULL != pbContents) { LocalFree(pbContents); } return(hr); } HRESULT GetVersionStuff( IN WCHAR const *pwszFileName, OUT DWORD *pdwLangRet, OUT VS_FIXEDFILEINFO *pvsRet) { HRESULT hr; VOID *pvData = NULL; DWORD cbData; DWORD dwHandle; DWORD *pdwTranslation; UINT uLen; DWORD dwDefLang = 0x409; VS_FIXEDFILEINFO *pvs; cbData = GetFileVersionInfoSize( const_cast(pwszFileName), &dwHandle); if (0 == cbData) { hr = GetLastError(); if (S_OK == hr) { hr = ERROR_RESOURCE_DATA_NOT_FOUND; } goto error; } pvData = LocalAlloc(LMEM_FIXED, cbData); if (NULL == pvData) { hr = GetLastError(); goto error; } if (!GetFileVersionInfo( const_cast(pwszFileName), 0, cbData, pvData)) { hr = GetLastError(); goto error; } if (!VerQueryValue(pvData, L"\\VarFileInfo\\Translation", (VOID **) &pdwTranslation, &uLen)) { pdwTranslation = &dwDefLang; uLen = sizeof(DWORD); } *pdwLangRet = *pdwTranslation; if (!VerQueryValue(pvData, L"\\", (VOID **) &pvs, &uLen)) { hr = GetLastError(); goto error; } *pvsRet = *pvs; hr = S_OK; error: if (NULL != pvData) { LocalFree(pvData); } return(hr); } HRESULT FileVersionDump( IN WCHAR const *pwszFileName) { HRESULT hr; DWORD dwLang; VS_FIXEDFILEINFO vs; hr = GetVersionStuff(pwszFileName, &dwLang, &vs); if (S_OK == hr) { wprintf( myLoadResourceString(IDS_FORMAT_LANG), // "%ws: Lang %08x (%d.%d)" pwszFileName, dwLang, HIWORD(dwLang), LOWORD(dwLang)); wprintf( myLoadResourceString(IDS_FORMAT_FILE), // " File %d.%d:%d.%d" HIWORD(vs.dwFileVersionMS), LOWORD(vs.dwFileVersionMS), HIWORD(vs.dwFileVersionLS), LOWORD(vs.dwFileVersionLS)); wprintf( myLoadResourceString(IDS_FORMAT_PRODUCT), // " Product %d.%d:%d.%d\n" HIWORD(vs.dwProductVersionMS), LOWORD(vs.dwProductVersionMS), HIWORD(vs.dwProductVersionLS), LOWORD(vs.dwProductVersionLS)); } return(hr); } HRESULT cuFileDump( IN WCHAR const *pwszfn) { HRESULT hr; BYTE *pbIn = NULL; DWORD cbIn; hr = FileVersionDump(pwszfn); if (S_OK == hr) { goto error; } hr = EPFFileDump(pwszfn, g_pwszPassword, NULL); if (S_FALSE != hr) { _PrintIfError(hr, "EPFFileDump"); goto error; } hr = DecodeFileW(pwszfn, &pbIn, &cbIn, CRYPT_STRING_ANY); if (S_OK != hr) { cuPrintError(IDS_ERR_FORMAT_DECODEFILE, hr); goto error; } CSASSERT(NULL != pbIn); hr = cuDumpAsnBinary(pbIn, cbIn, MAXDWORD); if (S_OK != hr) { cuPrintError(IDS_ERR_FORMAT_CANNOT_DECODE, hr); goto error; } error: if (NULL != pbIn) { LocalFree(pbIn); } return(hr); } HRESULT cuDumpSerial( OPTIONAL IN WCHAR const *pwszPrefix, IN DWORD idMessage, IN CRYPT_INTEGER_BLOB const *pSerial) { HRESULT hr; BSTR strSerial = NULL; hr = MultiByteIntegerToBstr( FALSE, pSerial->cbData, pSerial->pbData, &strSerial); _JumpIfError(hr, error, "MultiByteIntegerToBstr"); if (NULL != pwszPrefix) { wprintf(pwszPrefix); } wprintf(myLoadResourceString(idMessage)); wprintf(L" %ws\n", strSerial); if (g_fVerbose) { DumpHex( DH_MULTIADDRESS | DH_NOTABPREFIX | DH_NOASCIIHEX | 4, pSerial->pbData, pSerial->cbData); } error: if (NULL != strSerial) { SysFreeString(strSerial); } return(hr); } HRESULT cuDumpFileTimePeriod( IN DWORD idMessage, OPTIONAL IN WCHAR const *pwszQuote, IN FILETIME const *pftGMT) { HRESULT hr; WCHAR *pwszTimePeriod; hr = myFileTimePeriodToWszTimePeriod(pftGMT, g_fSeconds, &pwszTimePeriod); _JumpIfError(hr, error, "myFileTimePeriodToWszTimePeriod"); if (NULL == pwszQuote) { pwszQuote = g_wszEmpty; } wprintf(L" %ws%ws%ws\n", pwszQuote, pwszTimePeriod, pwszQuote); hr = S_OK; error: if (NULL != pwszTimePeriod) { LocalFree(pwszTimePeriod); } return(hr); } HRESULT cuDumpFileTime( IN DWORD idMessage, OPTIONAL IN WCHAR const *pwszQuote, IN FILETIME const *pftGMT) { HRESULT hr; WCHAR *pwszDate = NULL; WCHAR const *pwszResource = NULL; if (0 != idMessage) { pwszResource = myLoadResourceString(idMessage); } if (NULL == pwszResource) { pwszResource = g_wszEmpty; } if (NULL == pwszQuote) { pwszQuote = g_wszEmpty; } if (0 == pftGMT->dwLowDateTime && 0 == pftGMT->dwHighDateTime) { wprintf( L"%ws %ws\n", pwszResource, myLoadResourceString(IDS_PROP_EMPTY)); // "EMPTY" } else { if (g_fGMT) { hr = myFileTimeToWszTime(pftGMT, g_fSeconds, &pwszDate); _JumpIfError(hr, error, "myFileTimeToWszTime"); } else { hr = myGMTFileTimeToWszLocalTime(pftGMT, g_fSeconds, &pwszDate); _JumpIfError(hr, error, "myGMTFileTimeToWszLocalTime"); } wprintf( L"%ws %ws%ws%ws%ws%ws\n", pwszResource, pwszQuote, pwszDate, g_fGMT? L" " : g_wszEmpty, g_fGMT? myLoadResourceString(IDS_GMT_SUFFIX) : g_wszEmpty, pwszQuote); } hr = S_OK; error: if (NULL != pwszDate) { LocalFree(pwszDate); } return(hr); } HRESULT cuDumpFileTimeOrPeriod( IN DWORD idMessage, OPTIONAL IN WCHAR const *pwszQuote, IN FILETIME const *pftGMT) { HRESULT hr; if (0 <= (LONG) pftGMT->dwHighDateTime) { hr = cuDumpFileTime(idMessage, pwszQuote, pftGMT); _JumpIfError(hr, error, "cuDumpFileTime"); } else { hr = cuDumpFileTimePeriod(idMessage, pwszQuote, pftGMT); _JumpIfError(hr, error, "cuDumpFileTimePeriod"); } error: return(hr); } HRESULT cuDumpDate( IN DATE const *pDate) { HRESULT hr; FILETIME ft; if (0.0 == *pDate) { ft.dwLowDateTime = 0; ft.dwHighDateTime = 0; } else { hr = myDateToFileTime(pDate, &ft); _JumpIfError(hr, error, "myDateToFileTime"); } hr = cuDumpFileTime(0, NULL, &ft); _JumpIfError(hr, error, "cuDumpFileTime"); error: return(hr); } VOID DumpBlob( IN DWORD idMessage, IN CRYPT_BIT_BLOB const *pBlob) { if (NULL != pBlob->pbData) { wprintf(myLoadResourceString(idMessage)); wprintf(wszNewLine); DumpHex(DH_NOTABPREFIX | 4, pBlob->pbData, pBlob->cbData); } } HRESULT cuDisplayKeyIdFromExtension( IN DWORD cExtension, OPTIONAL IN CERT_EXTENSION const *rgExtension, BYTE const *pbHash, DWORD cbHash) { HRESULT hr; hr = S_FALSE; if (0 != cExtension && NULL != rgExtension) { CERT_EXTENSION const *pExt; DWORD cb; CRYPT_DATA_BLOB aBlob[1 + BLOB_ROUND(CBMAX_CRYPT_HASH_LEN)]; pExt = CertFindExtension( szOID_SUBJECT_KEY_IDENTIFIER, cExtension, const_cast(rgExtension)); if (NULL != pExt) { cb = sizeof(aBlob); if (!CryptDecodeObject( X509_ASN_ENCODING, X509_OCTET_STRING, pExt->Value.pbData, pExt->Value.cbData, 0, aBlob, &cb)) { hr = myHLastError(); _JumpError(hr, error, "CryptDecodeObject"); } if (cbHash != aBlob[0].cbData || 0 != memcmp(pbHash, aBlob[0].pbData, aBlob[0].cbData)) { hr = DumpHash( NULL, IDS_FORMAT_SUBJECTKEYID_COLON, // "Subject Key Id (%ws): %ws" NULL, myLoadResourceString(IDS_PRECOMPUTED), // "precomputed" aBlob[0].pbData, aBlob[0].cbData); _JumpIfError(hr, error, "DumpHash"); } } hr = S_OK; } error: return(hr); } HRESULT cuDisplayKeyIdCanonicalized( IN CERT_PUBLIC_KEY_INFO const *pPublicKeyInfo) { HRESULT hr; CERT_PUBLIC_KEY_INFO PublicKeyInfo; BYTE *pbKey = NULL; DWORD cbKey; DWORD cbHash; BYTE abHash[CBMAX_CRYPT_HASH_LEN]; #if 0 DumpHex( DH_NOTABPREFIX | 4, pPublicKeyInfo->PublicKey.pbData, pPublicKeyInfo->PublicKey.cbData); #endif hr = myCanonicalizePublicKey( pPublicKeyInfo->PublicKey.pbData, pPublicKeyInfo->PublicKey.cbData, &pbKey, &cbKey); _JumpIfError2(hr, error, "myCanonicalizePublicKey", hr); PublicKeyInfo = *pPublicKeyInfo; PublicKeyInfo.PublicKey.pbData = pbKey; PublicKeyInfo.PublicKey.cbData = cbKey; #if 0 DumpHex( DH_NOTABPREFIX | 4, PublicKeyInfo.PublicKey.pbData, PublicKeyInfo.PublicKey.cbData); #endif cbHash = sizeof(abHash); if (!CryptHashPublicKeyInfo( NULL, // hCryptProv CALG_SHA1, 0, // dwFlags, X509_ASN_ENCODING, &PublicKeyInfo, abHash, &cbHash)) { hr = myHLastError(); _JumpError(hr, error, "CryptHashPublicKeyInfo"); } hr = DumpHash( NULL, IDS_FORMAT_KEYIDHASH_COLON, // "Public Key Hash(%ws): %ws" myLoadResourceString(IDS_CANONICALIZED), // "canonicalized" L"sha1", abHash, cbHash); _JumpIfError(hr, error, "DumpHash"); error: if (NULL != pbKey) { LocalFree(pbKey); } return(hr); } HRESULT cuDisplayKeyId( IN CERT_PUBLIC_KEY_INFO const *pPublicKeyInfo, IN DWORD cExtension, OPTIONAL IN CERT_EXTENSION const *rgExtension) { HRESULT hr; DWORD cbHash; BYTE abHash[CBMAX_CRYPT_HASH_LEN]; cbHash = sizeof(abHash); if (!CryptHashPublicKeyInfo( NULL, // hCryptProv CALG_SHA1, 0, // dwFlags, X509_ASN_ENCODING, const_cast(pPublicKeyInfo), abHash, &cbHash)) { hr = myHLastError(); _JumpError(hr, error, "CryptHashPublicKeyInfo"); } hr = DumpHash( NULL, IDS_FORMAT_KEYIDHASH_COLON, // "Public Key Hash(%ws): %ws" NULL, L"sha1", abHash, cbHash); _JumpIfError(hr, error, "DumpHash"); hr = cuDisplayKeyIdFromExtension( cExtension, rgExtension, abHash, cbHash); _PrintIfError2(hr, "cuDisplayKeyIdFromExtension", hr); hr = cuDisplayKeyIdCanonicalized(pPublicKeyInfo); _PrintIfError2(hr, "cuDisplayKeyIdCanonicalized", hr); hr = S_OK; error: return(hr); } HRESULT cuDisplayHash( OPTIONAL IN WCHAR const *pwszPrefix, OPTIONAL IN CERT_CONTEXT const *pCertContext, OPTIONAL IN CRL_CONTEXT const *pCRLContext, IN DWORD dwPropId, IN WCHAR const *pwszHashName) { HRESULT hr; BYTE abHash[CBMAX_CRYPT_HASH_LEN]; DWORD cbHash; UINT idMsg; cbHash = sizeof(abHash); if (NULL != pCertContext) { if (!CertGetCertificateContextProperty( pCertContext, dwPropId, abHash, &cbHash)) { hr = myHLastError(); _JumpError(hr, error, "CertGetCertificateContextProperty"); } idMsg = IDS_FORMAT_CERTHASH_COLON; // "Cert Hash(%ws): %ws" } else { CSASSERT(NULL != pCRLContext); if (!CertGetCRLContextProperty(pCRLContext, dwPropId, abHash, &cbHash)) { hr = myHLastError(); _JumpError(hr, error, "CertGetCRLContextProperty"); } idMsg = IDS_FORMAT_CRLHASH_COLON; // "CRL Hash(%ws): %ws" } hr = DumpHash(pwszPrefix, idMsg, NULL, pwszHashName, abHash, cbHash); _JumpIfError(hr, error, "DumpHash"); error: return(hr); } HRESULT cuGetCertType( IN CERT_INFO const *pCertInfo, OPTIONAL OUT WCHAR **ppwszCertTypeNameV1, OPTIONAL OUT WCHAR **ppwszDisplayNameV1, OPTIONAL OUT WCHAR **ppwszCertTypeObjId, OPTIONAL OUT WCHAR **ppwszCertTypeName, OPTIONAL OUT WCHAR **ppwszDisplayName) { HRESULT hr; CERT_EXTENSION *pExt; WCHAR *pwszCertTypeNameV1 = NULL; WCHAR *pwszCNV1 = NULL; WCHAR *pwszDisplayNameV1 = NULL; WCHAR *pwszCertTypeObjId = NULL; WCHAR *pwszCN = NULL; WCHAR *pwszDisplayName = NULL; CERT_TEMPLATE_EXT *pTemplate = NULL; if (NULL != ppwszCertTypeNameV1) { *ppwszCertTypeNameV1 = NULL; } if (NULL != ppwszDisplayNameV1) { *ppwszDisplayNameV1 = NULL; } if (NULL != ppwszCertTypeObjId) { *ppwszCertTypeObjId = NULL; } if (NULL != ppwszCertTypeName) { *ppwszCertTypeName = NULL; } if (NULL != ppwszDisplayName) { *ppwszDisplayName = NULL; } // Look for the V1 cert type extension first pExt = CertFindExtension( szOID_ENROLL_CERTTYPE_EXTENSION, pCertInfo->cExtension, pCertInfo->rgExtension); if (NULL != pExt) { hr = UnicodeDecode(&pExt->Value, &pwszCertTypeNameV1); _JumpIfError(hr, error, "UnicodeDecode"); hr = cuGetTemplateNames( pwszCertTypeNameV1, &pwszCNV1, &pwszDisplayNameV1); _PrintIfErrorStr2(hr, "cuGetTemplateNames", pwszCertTypeNameV1, hr); if (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) != hr) { _JumpIfErrorStr(hr, error, "cuGetTemplateNames", pwszCertTypeNameV1); } } pExt = CertFindExtension( szOID_CERTIFICATE_TEMPLATE, pCertInfo->cExtension, pCertInfo->rgExtension); if (NULL != pExt) { DWORD cb; if (!myDecodeObject( X509_ASN_ENCODING, X509_CERTIFICATE_TEMPLATE, pExt->Value.pbData, pExt->Value.cbData, CERTLIB_USE_LOCALALLOC, (VOID **) &pTemplate, &cb)) { CSASSERT(NULL == pTemplate); hr = myHLastError(); _JumpError(hr, error, "myDecodeObject"); } if (!ConvertSzToWsz(&pwszCertTypeObjId, pTemplate->pszObjId, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "ConvertSzToWsz"); } hr = cuGetTemplateNames(pwszCertTypeObjId, &pwszCN, &pwszDisplayName); _PrintIfErrorStr2(hr, "cuGetTemplateNames", pwszCertTypeObjId, hr); if (HRESULT_FROM_WIN32(ERROR_NOT_FOUND) != hr) { _JumpIfErrorStr(hr, error, "cuGetTemplateNames", pwszCertTypeObjId); } } if (NULL == pwszCertTypeNameV1 && NULL == pwszCertTypeObjId) { hr = CRYPT_E_NOT_FOUND; _JumpError2(hr, error, "CertFindExtension", CRYPT_E_NOT_FOUND); } if (NULL != ppwszCertTypeNameV1) { if (NULL != pwszCNV1) { *ppwszCertTypeNameV1 = pwszCNV1; pwszCNV1 = NULL; } else { *ppwszCertTypeNameV1 = pwszCertTypeNameV1; pwszCertTypeNameV1 = NULL; } } if (NULL != ppwszDisplayNameV1) { *ppwszDisplayNameV1 = pwszDisplayNameV1; pwszDisplayNameV1 = NULL; } if (NULL != ppwszCertTypeObjId) { *ppwszCertTypeObjId = pwszCertTypeObjId; pwszCertTypeObjId = NULL; } if (NULL != ppwszCertTypeName) { *ppwszCertTypeName = pwszCN; pwszCN = NULL; } if (NULL != ppwszDisplayName) { *ppwszDisplayName = pwszDisplayName; pwszDisplayName = NULL; } hr = S_OK; error: if (NULL != pwszCertTypeNameV1) { LocalFree(pwszCertTypeNameV1); } if (NULL != pwszCNV1) { LocalFree(pwszCNV1); } if (NULL != pwszDisplayNameV1) { LocalFree(pwszDisplayNameV1); } if (NULL != pwszCertTypeObjId) { LocalFree(pwszCertTypeObjId); } if (NULL != pwszCN) { LocalFree(pwszCN); } if (NULL != pwszDisplayName) { LocalFree(pwszDisplayName); } if (NULL != pTemplate) { LocalFree(pTemplate); } return(hr); } HRESULT cuDumpCertType( OPTIONAL IN WCHAR const *pwszPrefix, IN CERT_INFO const *pCertInfo) { HRESULT hr; WCHAR *apwsz[6]; DWORD i; DWORD j; BOOL fFirst; ZeroMemory(apwsz, sizeof(apwsz)); hr = cuGetCertType( pCertInfo, &apwsz[0], // ppwszCertTypeNameV1 &apwsz[1], // ppwszDisplayNameV1 &apwsz[2], // ppwszCertTypeObjId &apwsz[3], // ppwszCertTypeName &apwsz[4]); // ppwszDisplayName _JumpIfError2(hr, error, "cuGetCertType", CRYPT_E_NOT_FOUND); if (NULL != apwsz[2]) // pwszCertTypeObjId { WCHAR const *pwszFriendlyName; pwszFriendlyName = cuGetOIDName(apwsz[2]); if (NULL != pwszFriendlyName && L'\0' != *pwszFriendlyName) { hr = myDupString(pwszFriendlyName, &apwsz[5]); _JumpIfError(hr, error, "myDupString"); } } wprintf( L"%ws%ws: ", NULL != pwszPrefix? pwszPrefix : L"", myLoadResourceString(IDS_TEMPLATE_NAME)); // "Template" // Suppress the long, ugly ObjId, unless they really want to see it: if (!g_fVerbose && NULL != apwsz[2] && (NULL != apwsz[0] || NULL != apwsz[3])) { LocalFree(apwsz[2]); apwsz[2] = NULL; } fFirst = TRUE; for (i = 0; i < ARRAYSIZE(apwsz); i++) { if (NULL != apwsz[i]) { BOOL fDup = FALSE; for (j = 0; j < i; j++) { if (NULL != apwsz[j] && 0 == lstrcmp(apwsz[i], apwsz[j])) { fDup = TRUE; break; } } if (!fDup) { if (!fFirst) { wprintf(L", "); } wprintf(L"%ws", apwsz[i]); fFirst = FALSE; } } } wprintf(wszNewLine); error: for (i = 0; i < ARRAYSIZE(apwsz); i++) { if (NULL != apwsz[i]) { LocalFree(apwsz[i]); } } return(hr); } HRESULT dumpCert( IN DWORD idMessage, IN BYTE const *pbIn, IN DWORD cbIn, IN BYTE const *pbDecoded, IN DWORD cbDecoded, IN CERT_SIGNED_CONTENT_INFO const *pcsci) { HRESULT hr; CERT_CONTEXT const *pCertContext = NULL; CERT_INFO *pCertInfo; BOOL fIssuerMatches; DWORD id; pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING, pbIn, cbIn); if (NULL == pCertContext) { hr = myHLastError(); _JumpError(hr, error, "CertCreateCertificateContext"); } pCertInfo = pCertContext->pCertInfo; if (!g_fQuiet) { wprintf(myLoadResourceString(idMessage)); wprintf(wszNewLine); cuDumpVersion(pCertInfo->dwVersion + 1); } hr = cuDumpSerial(NULL, IDS_SERIAL, &pCertInfo->SerialNumber); _JumpIfError(hr, error, "cuDumpSerial"); if (!g_fQuiet) { cuDumpAlgorithm(IDS_SIGNATURE_ALGORITHM, &pCertInfo->SignatureAlgorithm); } hr = cuDisplayCertName( !g_fQuiet, NULL, myLoadResourceString(IDS_ISSUER), // "Issuer" g_wszPad4, &pCertInfo->Issuer, NULL); _JumpIfError(hr, error, "cuDisplayCertName(Issuer)"); if (!g_fQuiet) { wprintf(wszNewLine); hr = cuDumpFileTime(IDS_NOTBEFORE, NULL, &pCertInfo->NotBefore); _JumpIfError(hr, error, "cuDumpFileTime"); hr = cuDumpFileTime(IDS_NOTAFTER, NULL, &pCertInfo->NotAfter); _JumpIfError(hr, error, "cuDumpFileTime"); wprintf(wszNewLine); } hr = cuDisplayCertName( !g_fQuiet, NULL, myLoadResourceString(IDS_SUBJECT), // "Subject" g_wszPad4, &pCertInfo->Subject, pCertInfo); _JumpIfError(hr, error, "cuDisplayCertName(Subject)"); if (!g_fQuiet) { wprintf(wszNewLine); cuDumpPublicKey(&pCertInfo->SubjectPublicKeyInfo); DumpBlob(IDS_ISSUERUNIQUEID, &pCertInfo->IssuerUniqueId); DumpBlob(IDS_SUBJECTUNIQUEID, &pCertInfo->SubjectUniqueId); } hr = cuDumpExtensionArray( IDS_CERTIFICATE_EXTENSIONS, pCertInfo->cExtension, pCertInfo->rgExtension); _JumpIfError(hr, error, "cuDumpExtensionArray"); if (!g_fQuiet) { cuDumpSignature(pcsci); } if (!CertCompareCertificateName( X509_ASN_ENCODING, &pCertInfo->Issuer, &pCertInfo->Subject)) { fIssuerMatches = FALSE; } else { fIssuerMatches = TRUE; } hr = cuVerifySignature(pbIn, cbIn, &pCertInfo->SubjectPublicKeyInfo, FALSE, TRUE); if (S_OK != hr) { if (fIssuerMatches) { id = IDS_ERR_FORMAT_ROOT_CERT_BAD_SIG; // "Possible Root Certificate: Subject matches Issuer, but Signature check fails: %x" } else { id = IDS_NO_ROOT_CERT; // "Non-root Certificate" } } else { if (fIssuerMatches) { id = IDS_ROOT_CERT; // "Root Certificate: Subject matches Issuer" } else { id = IDS_NO_ROOT_CERT_GOOD_SIG; // "Non-root Certificate uses same Public Key as Issuer" } } wprintf(myLoadResourceString(id), hr); wprintf(wszNewLine); if (g_fQuiet) { hr = cuDumpCertType(NULL, pCertContext->pCertInfo); _PrintIfError2(hr, "cuDumpCertType", CRYPT_E_NOT_FOUND); } else { cuDisplayKeyId( &pCertContext->pCertInfo->SubjectPublicKeyInfo, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension); hr = cuDisplayHash( NULL, pCertContext, NULL, CERT_MD5_HASH_PROP_ID, L"md5"); _JumpIfError(hr, error, "cuDisplayHash"); } hr = cuDisplayHash( NULL, pCertContext, NULL, CERT_SHA1_HASH_PROP_ID, L"sha1"); _JumpIfError(hr, error, "cuDisplayHash"); error: if (NULL != pCertContext) { CertFreeCertificateContext(pCertContext); } return(hr); } HRESULT dumpCertSequence( IN DWORD idMessage, IN BYTE const *pbIn, IN DWORD cbIn, IN BYTE const *pbDecoded, IN DWORD cbDecoded, IN CERT_SIGNED_CONTENT_INFO const *pcsci) { HRESULT hr; HRESULT hr2; DWORD iCert; CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY const *pSeq; pSeq = (CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY const *) pbDecoded; if (0 != strcmp(szOID_NETSCAPE_CERT_SEQUENCE, pSeq->pszObjId)) { hr = CRYPT_E_ASN1_ERROR; _JumpError2(hr, error, "not a cert sequence", hr); } wprintf(myLoadResourceString(idMessage)); wprintf(wszNewLine); hr = S_OK; for (iCert = 0; iCert < pSeq->cValue; iCert++) { wprintf( myLoadResourceString(IDS_FORMAT_DUMP_CERT_INDEX), // "================ Certificate %d ================" iCert); wprintf(wszNewLine); hr2 = cuDumpAsnBinary( pSeq->rgValue[iCert].pbData, pSeq->rgValue[iCert].cbData, iCert); if (S_OK != hr2) { cuPrintError(IDS_ERR_FORMAT_CANNOT_DECODE, hr2); if (S_OK == hr) { hr = hr2; } } } error: return(hr); } HRESULT dumpCRL( IN DWORD idMessage, IN BYTE const *pbIn, IN DWORD cbIn, IN BYTE const *pbDecoded, IN DWORD cbDecoded, IN CERT_SIGNED_CONTENT_INFO const *pcsci) { HRESULT hr; CRL_CONTEXT const *pCRLContext = NULL; CRL_INFO const *pCRLInfo; DWORD i; CRL_ENTRY *pCRLEntry; CSASSERT(NULL != pbIn && 0 != cbIn); CSASSERT(NULL != pbDecoded && 0 != cbDecoded); pCRLContext = CertCreateCRLContext(X509_ASN_ENCODING, pbIn, cbIn); if (NULL == pCRLContext) { hr = myHLastError(); _JumpError(hr, error, "CertCreateCRLContext"); } pCRLInfo = pCRLContext->pCrlInfo; if (!g_fQuiet) { wprintf(myLoadResourceString(idMessage)); wprintf(wszNewLine); cuDumpVersion(pCRLInfo->dwVersion + 1); cuDumpAlgorithm(IDS_SIGNATURE_ALGORITHM, &pCRLInfo->SignatureAlgorithm); } hr = cuDisplayCertName( TRUE, NULL, myLoadResourceString(IDS_ISSUER), // "Issuer" g_wszPad4, &pCRLInfo->Issuer, NULL); _JumpIfError(hr, error, "cuDisplayCertName(Issuer)"); if (!g_fQuiet) { wprintf(wszNewLine); hr = cuDumpFileTime(IDS_THISUPDATE, NULL, &pCRLInfo->ThisUpdate); _JumpIfError(hr, error, "cuDumpFileTime"); hr = cuDumpFileTime(IDS_NEXTUPDATE, NULL, &pCRLInfo->NextUpdate); _JumpIfError(hr, error, "cuDumpFileTime"); wprintf(myLoadResourceString(IDS_CRLENTRIES)); // "CRL Entries:" wprintf(L" %u\n", pCRLInfo->cCRLEntry); for (i = 0; i < pCRLInfo->cCRLEntry; i++) { pCRLEntry = &pCRLInfo->rgCRLEntry[i]; wprintf(g_wszPad2); hr = cuDumpSerial(NULL, IDS_SERIAL, &pCRLEntry->SerialNumber); _JumpIfError(hr, error, "cuDumpSerial"); wprintf(g_wszPad2); hr = cuDumpFileTime( IDS_REVOCATIONDATE, NULL, &pCRLEntry->RevocationDate); _JumpIfError(hr, error, "cuDumpFileTime"); if (0 != pCRLEntry->cExtension) { wprintf(g_wszPad2); hr = cuDumpExtensionArray( IDS_EXTENSIONS, pCRLEntry->cExtension, pCRLEntry->rgExtension); _JumpIfError(hr, error, "cuDumpExtensionArray"); } wprintf(wszNewLine); } } if (0 != pCRLInfo->cExtension) { hr = cuDumpExtensionArray( IDS_CRLEXTENSIONS, pCRLInfo->cExtension, pCRLInfo->rgExtension); _JumpIfError(hr, error, "cuDumpExtensionArray"); } if (!g_fQuiet) { cuDumpSignature(pcsci); hr = cuDisplayHash( NULL, NULL, pCRLContext, CERT_MD5_HASH_PROP_ID, L"md5"); _JumpIfError(hr, error, "cuDisplayHash"); } hr = cuDisplayHash( NULL, NULL, pCRLContext, CERT_SHA1_HASH_PROP_ID, L"sha1"); _JumpIfError(hr, error, "cuDisplayHash"); error: return(hr); } HRESULT dumpRequest( IN DWORD idMessage, IN BYTE const *pbIn, IN DWORD cbIn, IN BYTE const *pbDecoded, IN DWORD cbDecoded, IN CERT_SIGNED_CONTENT_INFO const *pcsci) { HRESULT hr; CERT_REQUEST_INFO const *pRequest; CERT_EXTENSIONS *pExtInfo = NULL; CSASSERT(NULL != pbIn && 0 != cbIn); CSASSERT(NULL != pbDecoded && 0 != cbDecoded); wprintf(myLoadResourceString(idMessage)); wprintf(wszNewLine); pRequest = (CERT_REQUEST_INFO const *) pbDecoded; cuDumpVersion(pRequest->dwVersion + 1); hr = cuDisplayCertName( TRUE, NULL, myLoadResourceString(IDS_SUBJECT), // "Subject" g_wszPad4, &pRequest->Subject, NULL); _JumpIfError(hr, error, "cuDisplayCertName(Subject)"); wprintf(wszNewLine); cuDumpPublicKey(&pRequest->SubjectPublicKeyInfo); wprintf(myLoadResourceString(IDS_REQUEST_ATTRIBUTES)); // "Request Attributes:" wprintf(L" %u\n", pRequest->cAttribute); // Dump attributes and certificate extensions hr = DumpAttributes( pRequest->rgAttribute, pRequest->cAttribute, FALSE, FOT_ATTRIBUTE, NULL, // hStore NULL, NULL, &pExtInfo); _JumpIfError(hr, error, "DumpAttributes"); cuDumpSignature(pcsci); if (NULL != pcsci) { hr = cuVerifySignature( pbIn, cbIn, &pRequest->SubjectPublicKeyInfo, FALSE, FALSE); _JumpIfError(hr, error, "cuVerifySignature"); } hr = cuDisplayKeyId( &pRequest->SubjectPublicKeyInfo, NULL == pExtInfo? 0 : pExtInfo->cExtension, NULL == pExtInfo? NULL : pExtInfo->rgExtension); _JumpIfError(hr, error, "cuDisplayKeyId"); hr = S_OK; error: if (NULL != pExtInfo) { LocalFree(pExtInfo); } return(hr); } VOID DumpCMCDataReference( IN DWORD dwCmcDataReference, IN DWORD cCertReference, IN DWORD const *rgdwCertReference) { DWORD i; wprintf( L" %ws: %u\n", myLoadResourceString(IDS_DATA_REFERENCE), dwCmcDataReference); for (i = 0; i < cCertReference; i++) { wprintf( L" %ws[%u]: %u\n", myLoadResourceString(IDS_CERT_REFERENCE), i, rgdwCertReference[i]); } } HRESULT DumpCMCStatus( IN CMC_STATUS_INFO const *pcmcStatus) { HRESULT hr; WCHAR const *pwsz; DWORD i; switch (pcmcStatus->dwStatus) { case CMC_STATUS_SUCCESS: pwsz = L"CMC_STATUS_SUCCESS"; break; case CMC_STATUS_FAILED: pwsz = L"CMC_STATUS_FAILED"; break; case CMC_STATUS_PENDING: pwsz = L"CMC_STATUS_PENDING"; break; case CMC_STATUS_NO_SUPPORT: pwsz = L"CMC_STATUS_NO_SUPPORT"; break; case CMC_STATUS_CONFIRM_REQUIRED: pwsz = L"CMC_STATUS_CONFIRM_REQUIRED"; break; default: pwsz = g_wszEmpty; break; } wprintf( L" %ws: %ws(%u)\n", myLoadResourceString(IDS_CMC_STATUS), pwsz, pcmcStatus->dwStatus); for (i = 0; i < pcmcStatus->cBodyList; i++) { wprintf( L" %ws[%u]: %u\n", myLoadResourceString(IDS_BODY_REFERENCE), i, pcmcStatus->rgdwBodyList[i]); } if (NULL != pcmcStatus->pwszStatusString) { wprintf( L" %ws: %ws\n", myLoadResourceString(IDS_CMC_STATUSSTRING), pcmcStatus->pwszStatusString); } switch (pcmcStatus->dwOtherInfoChoice) { case CMC_OTHER_INFO_NO_CHOICE: pwsz = L"CMC_OTHER_INFO_NO_CHOICE"; break; case CMC_OTHER_INFO_FAIL_CHOICE: pwsz = L"CMC_OTHER_INFO_FAIL_CHOICE"; break; case CMC_OTHER_INFO_PEND_CHOICE: pwsz = L"CMC_OTHER_INFO_PEND_CHOICE"; break; default: pwsz = g_wszEmpty; break; } wprintf( L" %ws: %ws(%u)\n", myLoadResourceString(IDS_CMC_OTHERCHOICE), pwsz, pcmcStatus->dwOtherInfoChoice); switch (pcmcStatus->dwOtherInfoChoice) { case CMC_OTHER_INFO_FAIL_CHOICE: switch (pcmcStatus->dwFailInfo) { case CMC_FAIL_BAD_ALG: pwsz = L"CMC_FAIL_BAD_ALG"; break; case CMC_FAIL_BAD_MESSAGE_CHECK: pwsz = L"CMC_FAIL_BAD_MESSAGE_CHECK"; break; case CMC_FAIL_BAD_REQUEST: pwsz = L"CMC_FAIL_BAD_REQUEST"; break; case CMC_FAIL_BAD_TIME: pwsz = L"CMC_FAIL_BAD_TIME"; break; case CMC_FAIL_BAD_CERT_ID: pwsz = L"CMC_FAIL_BAD_CERT_ID"; break; case CMC_FAIL_UNSUPORTED_EXT: pwsz = L"CMC_FAIL_UNSUPORTED_EXT"; break; case CMC_FAIL_MUST_ARCHIVE_KEYS: pwsz = L"CMC_FAIL_MUST_ARCHIVE_KEYS"; break; case CMC_FAIL_BAD_IDENTITY: pwsz = L"CMC_FAIL_BAD_IDENTITY"; break; case CMC_FAIL_POP_REQUIRED: pwsz = L"CMC_FAIL_POP_REQUIRED"; break; case CMC_FAIL_POP_FAILED: pwsz = L"CMC_FAIL_POP_FAILED"; break; case CMC_FAIL_NO_KEY_REUSE: pwsz = L"CMC_FAIL_NO_KEY_REUSE"; break; case CMC_FAIL_INTERNAL_CA_ERROR: pwsz = L"CMC_FAIL_INTERNAL_CA_ERROR"; break; case CMC_FAIL_TRY_LATER: pwsz = L"CMC_FAIL_TRY_LATER"; break; default: pwsz = g_wszEmpty; break; } wprintf( L" %ws: %ws(%u)\n", myLoadResourceString(IDS_CMC_FAILINFO), pwsz, pcmcStatus->dwFailInfo); break; case CMC_OTHER_INFO_PEND_CHOICE: wprintf(myLoadResourceString(IDS_PENDTOKEN)); //"Pend Token:" DumpHex( DH_NOTABPREFIX | 4, pcmcStatus->pPendInfo->PendToken.pbData, pcmcStatus->pPendInfo->PendToken.cbData); wprintf(g_wszPad4); hr = cuDumpFileTime( IDS_PENDTIME, NULL, &pcmcStatus->pPendInfo->PendTime); _JumpIfError(hr, error, "cuDumpFileTime"); break; } hr = S_OK; error: return(hr); } HRESULT DumpCMCRegInfo( IN BYTE const *pbData, IN DWORD cbData) { HRESULT hr; WCHAR *pwszDup = NULL; WCHAR *pwszBuf; WCHAR const *pwszName; WCHAR const *pwszValue; WCHAR *pwszNameAlloc = NULL; WCHAR *pwszValueAlloc = NULL; if (NULL == pbData || 0 == cbData) { hr = S_OK; goto error; // silently ignore empty string } hr = myDecodeCMCRegInfo(pbData, cbData, &pwszDup); _JumpIfError(hr, error, "myDecodeCMCRegInfo"); if (NULL != pwszDup) { pwszBuf = pwszDup; while (TRUE) { hr = myParseNextAttribute(&pwszBuf, TRUE, &pwszName, &pwszValue); if (S_FALSE == hr) { break; } _JumpIfError(hr, error, "myParseNextAttribute"); if (NULL != pwszNameAlloc) { LocalFree(pwszNameAlloc); pwszNameAlloc = NULL; } if (NULL != pwszValueAlloc) { LocalFree(pwszValueAlloc); pwszValueAlloc = NULL; } hr = myUncanonicalizeURLParm(pwszName, &pwszNameAlloc); _JumpIfError(hr, error, "myUncanonicalizeURLParm"); hr = myUncanonicalizeURLParm(pwszValue, &pwszValueAlloc); _JumpIfError(hr, error, "myUncanonicalizeURLParm"); wprintf(L"%ws%ws: %ws\n", g_wszPad4, pwszNameAlloc, pwszValueAlloc); } } hr = S_OK; error: if (NULL != pwszNameAlloc) { LocalFree(pwszNameAlloc); } if (NULL != pwszValueAlloc) { LocalFree(pwszValueAlloc); } if (NULL != pwszDup) { LocalFree(pwszDup); } return(hr); } HRESULT DumpTaggedAttributes( IN DWORD cTaggedAttribute, IN CMC_TAGGED_ATTRIBUTE const *rgTaggedAttribute) { HRESULT hr; DWORD i; DWORD cb; CMC_ADD_EXTENSIONS_INFO *pcmcExt = NULL; CMC_ADD_ATTRIBUTES_INFO *pcmcAttrib = NULL; CMC_STATUS_INFO *pcmcStatus = NULL; wprintf(myLoadResourceString(IDS_TAGGED_ATTRIBUTES)); //"Tagged Attributes:" wprintf(L" %u\n", cTaggedAttribute); wprintf(wszNewLine); for (i = 0; i < cTaggedAttribute; i++) { CMC_TAGGED_ATTRIBUTE const *pTaggedAttribute = &rgTaggedAttribute[i]; CRYPT_ATTRIBUTE const *pAttribute = &pTaggedAttribute->Attribute; DWORD j; wprintf(g_wszPad2); wprintf(myLoadResourceString(IDS_BODY_PART_ID)); // "Body Part Id:" wprintf(L" %u\n", pTaggedAttribute->dwBodyPartID); wprintf(g_wszPad2); cuDumpOIDAndDescriptionA(pAttribute->pszObjId); wprintf(wszNewLine); for (j = 0; j < pAttribute->cValue; j++) { BOOL fUnknown = FALSE; wprintf(L" %ws[%u]:\n", myLoadResourceString(IDS_VALUE), j); if (0 == strcmp(szOID_CMC_ADD_EXTENSIONS, pAttribute->pszObjId)) { // Decode CMC_ADD_EXTENSIONS_INFO from Attribute Blob CSASSERT(NULL == pcmcExt); if (!myDecodeObject( X509_ASN_ENCODING, CMC_ADD_EXTENSIONS, pAttribute->rgValue[j].pbData, pAttribute->rgValue[j].cbData, CERTLIB_USE_LOCALALLOC, (VOID **) &pcmcExt, &cb)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeObject"); } DumpCMCDataReference( pcmcExt->dwCmcDataReference, pcmcExt->cCertReference, pcmcExt->rgdwCertReference); wprintf(g_wszPad2); hr = cuDumpExtensionArray( IDS_EXTENSIONS, pcmcExt->cExtension, pcmcExt->rgExtension); _JumpIfError(hr, error, "cuDumpExtensionArray"); LocalFree(pcmcExt); pcmcExt = NULL; } else if (0 == strcmp(szOID_CMC_ADD_ATTRIBUTES, pAttribute->pszObjId)) { // Decode CMC_ADD_ATTRIBUTES_INFO from Attribute Blob CSASSERT(NULL == pcmcAttrib); if (!myDecodeObject( X509_ASN_ENCODING, CMC_ADD_ATTRIBUTES, pAttribute->rgValue[j].pbData, pAttribute->rgValue[j].cbData, CERTLIB_USE_LOCALALLOC, (VOID **) &pcmcAttrib, &cb)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeObject"); } DumpCMCDataReference( pcmcAttrib->dwCmcDataReference, pcmcAttrib->cCertReference, pcmcAttrib->rgdwCertReference); hr = DumpAttributes( pcmcAttrib->rgAttribute, pcmcAttrib->cAttribute, FALSE, FOT_ATTRIBUTE, NULL, // hStore NULL, NULL, NULL); _JumpIfError(hr, error, "DumpAttributes"); wprintf(wszNewLine); LocalFree(pcmcAttrib); pcmcAttrib = NULL; } else if (0 == strcmp(szOID_CMC_STATUS_INFO, pAttribute->pszObjId)) { // Decode CMC_STATUS_INFO from Attribute Blob CSASSERT(NULL == pcmcStatus); if (!myDecodeObject( X509_ASN_ENCODING, CMC_STATUS, pAttribute->rgValue[j].pbData, pAttribute->rgValue[j].cbData, CERTLIB_USE_LOCALALLOC, (VOID **) &pcmcStatus, &cb)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeObject"); } hr = DumpCMCStatus(pcmcStatus); _JumpIfError(hr, error, "DumpStatus"); wprintf(wszNewLine); LocalFree(pcmcStatus); pcmcStatus = NULL; } else if (0 == strcmp(szOID_CMC_TRANSACTION_ID, pAttribute->pszObjId)) { DWORD XactId; cb = sizeof(XactId); XactId = 0; if (CryptDecodeObject( X509_ASN_ENCODING, X509_INTEGER, pAttribute->rgValue[j].pbData, pAttribute->rgValue[j].cbData, 0, &XactId, &cb)) { wprintf( L"%ws%x(%u)\n\n", g_wszPad4, XactId, XactId); } else { fUnknown = TRUE; } } else if (0 == strcmp(szOID_CMC_REG_INFO, pAttribute->pszObjId)) { hr = DumpCMCRegInfo( pAttribute->rgValue[j].pbData, pAttribute->rgValue[j].cbData); if (S_OK != hr) { fUnknown = TRUE; } } else if (0 == strcmp(szOID_CMC_QUERY_PENDING, pAttribute->pszObjId) || 0 == strcmp(szOID_CMC_SENDER_NONCE, pAttribute->pszObjId) || 0 == strcmp(szOID_CMC_RECIPIENT_NONCE, pAttribute->pszObjId)) { CRYPT_DATA_BLOB *pBlob; DWORD cbBlob; if (myDecodeObject( X509_ASN_ENCODING, X509_OCTET_STRING, pAttribute->rgValue[j].pbData, pAttribute->rgValue[j].cbData, CERTLIB_USE_LOCALALLOC, (VOID **) &pBlob, &cbBlob)) { DumpHex( DH_NOTABPREFIX | 4, pBlob->pbData, pBlob->cbData); wprintf(wszNewLine); LocalFree(pBlob); } else { fUnknown = TRUE; } } else { fUnknown = TRUE; } if (fUnknown) { wprintf(myLoadResourceString(IDS_UNKNOWN_TAGGED_ATTRIBUTE)); // "UNKNOWN Tagged Attribute" wprintf(wszNewLine); DumpHex( DH_NOTABPREFIX | 4, pAttribute->rgValue[j].pbData, pAttribute->rgValue[j].cbData); wprintf(wszNewLine); } } } if (0 < i) { wprintf(wszNewLine); } hr = S_OK; error: if (NULL != pcmcExt) { LocalFree(pcmcExt); } if (NULL != pcmcAttrib) { LocalFree(pcmcAttrib); } if (NULL != pcmcStatus) { LocalFree(pcmcStatus); } return(hr); } HRESULT DumpTaggedRequests( IN DWORD cTaggedRequest, IN CMC_TAGGED_REQUEST const *rgTaggedRequest) { HRESULT hr; DWORD i; wprintf(myLoadResourceString(IDS_TAGGED_REQUESTS)); // "Tagged Requests:" wprintf(L" %u\n", cTaggedRequest); for (i = 0; i < cTaggedRequest; i++) { CMC_TAGGED_REQUEST const *pTaggedRequest = &rgTaggedRequest[i]; CMC_TAGGED_CERT_REQUEST const *pTaggedCertRequest; switch (pTaggedRequest->dwTaggedRequestChoice) { case CMC_TAGGED_CERT_REQUEST_CHOICE: pTaggedCertRequest = pTaggedRequest->pTaggedCertRequest; wprintf(L" CMC_TAGGED_CERT_REQUEST_CHOICE:\n"); wprintf(g_wszPad2); wprintf(myLoadResourceString(IDS_BODY_PART_ID)); // "Body Part Id:" wprintf(L" %u\n", pTaggedCertRequest->dwBodyPartID); hr = cuDumpAsnBinary( pTaggedCertRequest->SignedCertRequest.pbData, pTaggedCertRequest->SignedCertRequest.cbData, i); _JumpIfError(hr, error, "cuDumpAsnBinary"); break; default: wprintf(myLoadResourceString(IDS_UNKNOWN_REQUEST_CHOICE)); // "UNKNOWN Request Choice" wprintf(wszNewLine); break; } } if (0 < i) { wprintf(wszNewLine); } hr = S_OK; error: return(hr); } HRESULT DumpTaggedContent( IN DWORD cTaggedContentInfo, IN CMC_TAGGED_CONTENT_INFO const *rgTaggedContentInfo) { HRESULT hr; DWORD i; wprintf(myLoadResourceString(IDS_TAGGED_CONTENTINFO)); // "Tagged Content Info:" wprintf(L" %u\n", cTaggedContentInfo); for (i = 0; i < cTaggedContentInfo; i++) { CMC_TAGGED_CONTENT_INFO const *pTaggedContentInfo = &rgTaggedContentInfo[i]; wprintf(g_wszPad2); wprintf(myLoadResourceString(IDS_BODY_PART_ID)); // "Body Part Id:" wprintf(L" %u\n", pTaggedContentInfo->dwBodyPartID); hr = cuDumpAsnBinary( pTaggedContentInfo->EncodedContentInfo.pbData, pTaggedContentInfo->EncodedContentInfo.cbData, i); _JumpIfError(hr, error, "cuDumpAsnBinary"); } if (0 < i) { wprintf(wszNewLine); } hr = S_OK; error: return(hr); } HRESULT DumpTaggedOther( IN DWORD cTaggedOtherMsg, IN CMC_TAGGED_OTHER_MSG const *rgTaggedOtherMsg) { HRESULT hr; DWORD i; wprintf(myLoadResourceString(IDS_TAGGED_OTHERMESSAGES)); // "Tagged Other Messages:" wprintf(L" %u\n", cTaggedOtherMsg); for (i = 0; i < cTaggedOtherMsg; i++) { CMC_TAGGED_OTHER_MSG const *pTaggedOtherMsg = &rgTaggedOtherMsg[i]; wprintf(L" TaggedOtherMessage[%u]\n", i); wprintf(g_wszPad2); cuDumpOIDAndDescriptionA(pTaggedOtherMsg->pszObjId); wprintf(L" %ws[%u]:\n", myLoadResourceString(IDS_VALUE), i); DumpHex( DH_NOADDRESS | DH_NOTABPREFIX | 4, pTaggedOtherMsg->Value.pbData, pTaggedOtherMsg->Value.cbData); } if (0 < i) { wprintf(wszNewLine); } hr = S_OK; //error: return(hr); } HRESULT dumpCMCRequest( IN DWORD idMessage, IN BYTE const *pbIn, IN DWORD cbIn, IN BYTE const *pbDecoded, IN DWORD cbDecoded, IN CERT_SIGNED_CONTENT_INFO const *pcsci) { HRESULT hr; CMC_DATA_INFO const *pcmcData; CSASSERT(NULL != pbIn && 0 != cbIn); CSASSERT(NULL != pbDecoded && 0 != cbDecoded); wprintf(myLoadResourceString(idMessage)); wprintf(wszNewLine); pcmcData = (CMC_DATA_INFO const *) pbDecoded; hr = DumpTaggedAttributes( pcmcData->cTaggedAttribute, pcmcData->rgTaggedAttribute); _JumpIfError(hr, error, "DumpTaggedAttributes"); hr = DumpTaggedRequests( pcmcData->cTaggedRequest, pcmcData->rgTaggedRequest); _JumpIfError(hr, error, "DumpTaggedRequests"); hr = DumpTaggedContent( pcmcData->cTaggedContentInfo, pcmcData->rgTaggedContentInfo); _JumpIfError(hr, error, "DumpTaggedContent"); hr = DumpTaggedOther( pcmcData->cTaggedOtherMsg, pcmcData->rgTaggedOtherMsg); _JumpIfError(hr, error, "DumpTaggedOther"); error: return(hr); } HRESULT dumpCMCResponse( IN DWORD idMessage, IN BYTE const *pbIn, IN DWORD cbIn, IN BYTE const *pbDecoded, IN DWORD cbDecoded, IN CERT_SIGNED_CONTENT_INFO const *pcsci) { HRESULT hr; CMC_RESPONSE_INFO const *pcmcResponse; CSASSERT(NULL != pbIn && 0 != cbIn); CSASSERT(NULL != pbDecoded && 0 != cbDecoded); wprintf(myLoadResourceString(idMessage)); wprintf(wszNewLine); pcmcResponse = (CMC_RESPONSE_INFO const *) pbDecoded; hr = DumpTaggedAttributes( pcmcResponse->cTaggedAttribute, pcmcResponse->rgTaggedAttribute); _JumpIfError(hr, error, "DumpTaggedAttributes"); hr = DumpTaggedContent( pcmcResponse->cTaggedContentInfo, pcmcResponse->rgTaggedContentInfo); _JumpIfError(hr, error, "DumpTaggedContent"); hr = DumpTaggedOther( pcmcResponse->cTaggedOtherMsg, pcmcResponse->rgTaggedOtherMsg); _JumpIfError(hr, error, "DumpTaggedOther"); error: return(hr); } HRESULT dumpKeyGenRequest( IN DWORD idMessage, IN BYTE const *pbIn, IN DWORD cbIn, IN BYTE const *pbDecoded, IN DWORD cbDecoded, IN CERT_SIGNED_CONTENT_INFO const *pcsci) { HRESULT hr; CERT_KEYGEN_REQUEST_INFO const *pKeyGenRequest; CSASSERT(NULL != pbIn && 0 != cbIn); CSASSERT(NULL != pbDecoded && 0 != cbDecoded); wprintf(myLoadResourceString(idMessage)); wprintf(wszNewLine); pKeyGenRequest = (CERT_KEYGEN_REQUEST_INFO const *) pbDecoded; cuDumpPublicKey(&pKeyGenRequest->SubjectPublicKeyInfo); wprintf( myLoadResourceString(IDS_FORMAT_CHALLENGE_STRING), // "ChallengeString: ""%ws""" pKeyGenRequest->pwszChallengeString); wprintf(wszNewLine); cuDumpSignature(pcsci); hr = cuVerifySignature( pbIn, cbIn, &pKeyGenRequest->SubjectPublicKeyInfo, FALSE, FALSE); _JumpIfError(hr, error, "cuVerifySignature"); hr = S_OK; error: return(hr); } HRESULT dumpCTL( IN DWORD idMessage, IN BYTE const *pbIn, IN DWORD cbIn, IN BYTE const *pbDecoded, IN DWORD cbDecoded, IN CERT_SIGNED_CONTENT_INFO const *pcsci) { HRESULT hr; CTL_INFO const *pCTLInfo; CTL_CONTEXT const *pCTLContext = NULL; BOOL fIssuerMatches; DWORD id; DWORD i; pCTLInfo = (CTL_INFO const *) pbDecoded; //if (!g_fQuiet) { wprintf(myLoadResourceString(idMessage)); wprintf(wszNewLine); cuDumpVersion(pCTLInfo->dwVersion + 1); } hr = cuDumpUsage(NULL, IDS_USAGEENTRIES, &pCTLInfo->SubjectUsage); _JumpIfError(hr, error, "cuDumpUsage"); if (0 != pCTLInfo->ListIdentifier.cbData) { hr = cuDumpSerial(NULL, IDS_LISTID, &pCTLInfo->ListIdentifier); _JumpIfError(hr, error, "cuDumpSerial"); } if (0 != pCTLInfo->SequenceNumber.cbData) { hr = cuDumpSerial(NULL, IDS_SEQUENCENO, &pCTLInfo->SequenceNumber); _JumpIfError(hr, error, "cuDumpSerial"); } hr = cuDumpFileTime(IDS_THISUPDATE, NULL, &pCTLInfo->ThisUpdate); _JumpIfError(hr, error, "cuDumpFileTime"); hr = cuDumpFileTime(IDS_NEXTUPDATE, NULL, &pCTLInfo->NextUpdate); _JumpIfError(hr, error, "cuDumpFileTime"); cuDumpAlgorithm(IDS_SUBJECT_ALGORITHM, &pCTLInfo->SubjectAlgorithm); wprintf(myLoadResourceString(IDS_CTLENTRIES)); // "CTL Entries:" wprintf(L" %u\n", pCTLInfo->cCTLEntry); for (i = 0; i < pCTLInfo->cCTLEntry; i++) { CTL_ENTRY const *pCTLEntry = &pCTLInfo->rgCTLEntry[i]; wprintf(wszNewLine); hr = DumpHash( g_wszEmpty, IDS_FORMAT_SUBJECTID_COLON, NULL, g_wszEmpty, pCTLEntry->SubjectIdentifier.pbData, pCTLEntry->SubjectIdentifier.cbData); _JumpIfError(hr, error, "DumpHash"); hr = DumpAttributes( pCTLEntry->rgAttribute, pCTLEntry->cAttribute, g_fQuiet, FOT_ATTRIBUTE, NULL, // hStore NULL, // pbHashUserCert NULL, // pcbHashUserCert NULL); // ppExtInfo _JumpIfError(hr, error, "DumpAttributes"); } hr = cuDumpExtensionArray( IDS_EXTENSIONS, pCTLInfo->cExtension, pCTLInfo->rgExtension); _JumpIfError(hr, error, "cuDumpExtensionArray"); hr = S_OK; error: if (NULL != pCTLContext) { CertFreeCTLContext(pCTLContext); } return(hr); } HRESULT verbDump( IN WCHAR const *pwszOption, IN WCHAR const *pwszfn, IN WCHAR const *pwszArg2, IN WCHAR const *pwszArg3, IN WCHAR const *pwszArg4) { HRESULT hr; if (NULL == pwszfn) { hr = cuConfigDump(); _JumpIfError(hr, error, "cuConfigDump"); } else { hr = cuFileDump(pwszfn); _JumpIfErrorStr(hr, error, "cuFileDump", pwszfn); } error: return(hr); }