//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1996 - 2000 // // File: epf.cpp // //-------------------------------------------------------------------------- #include #pragma hdrstop #include #define EXPORT_CONTROL DOMESTIC #include "csber.h" #include "csldap.h" #include "cainfop.h" #include "crcutil.h" #include "cast3.h" #define __dwFILE__ __dwFILE_CERTUTIL_EPF_CPP__ #define CBTOKEN 8 CRC16 g_CrcTable[256]; typedef struct { DWORD dwAlgId; #define EPFALG_CAST_MD5 0x10 #define EPFALG_RC2_SHA 0x20 #define EPFALG_3DES 0x40 // if EPFALG_RC2_SHA, this will be the key HCRYPTKEY hKey; // if EPFALG_CAST_MD5, we'll have a CAST context ready CAST3_CTX sCastContext; } EPF_SYM_KEY_STRUCT; #define wszSIGNING L"Signing" #define wszEXCHANGE L"Exchange" #if 0 Entrust - CAST3 return codes #define C3E_OK 0 // No error #define C3E_DEPAD_FAILURE -1 // The de-padding operation failed #define C3E_BAD_KEYLEN -2 // Key length not supported #define C3E_SELFTEST_FAILED -3 // Self-test failed #define C3E_NOT_SUPPORTED -4 // Function not supported #endif #define EPFALG_EXPORT 0 #define EPFALG_DOMESTIC 0x01000000 static const WCHAR s_wszHeader[] = L"================================================================\n"; VOID InitCrcTable() { static BOOL s_fInit = FALSE; if (!s_fInit) { USHORT ccitt_crc_poly = 0x8404; // CCITT crc16 polynominal I_CRC16(g_CrcTable, &ccitt_crc_poly); // initialize CRC generator s_fInit = TRUE; } } HRESULT IterateHash( IN DWORD dwSymAlgId, IN HCRYPTPROV hProv, IN int iIterations, IN BYTE const *rgbHash, IN DWORD cbBufferSize, IN DWORD cbInternalHashBuffer) { HRESULT hr; HCRYPTHASH hIterativeHash = NULL; BYTE *pbBufferExtension = NULL; DWORD cbBufferExtension; DWORD cbHash = cbBufferSize; int i; // use later to extend internal buffer during hash iteration if (cbInternalHashBuffer > cbHash) { pbBufferExtension = (BYTE *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, cbInternalHashBuffer - cbHash); if (NULL == pbBufferExtension) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } } // iterate to get output // 99 more times -- we've already done one hash for (i = 1; i < iIterations; i++) { if (!CryptCreateHash( hProv, EPFALG_CAST_MD5 == dwSymAlgId? CALG_MD5 : CALG_SHA1, 0, 0, &hIterativeHash)) { hr = myHLastError(); _JumpError(hr, error, "CryptCreateHash"); } // hash the intermediate result if (!CryptHashData(hIterativeHash, rgbHash, cbHash, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptHashData"); } if (cbInternalHashBuffer > cbHash) { // If hash buffer param is larger than hash length, do something // about it. Fill a buffer with the iteration count & tack it on // the end of the hash. memset(pbBufferExtension, i, cbInternalHashBuffer-cbHash); if (!CryptHashData( hIterativeHash, pbBufferExtension, cbInternalHashBuffer - cbHash, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptHashData"); } } // done with this round, continue to the next cbHash = cbBufferSize; if (!CryptGetHashParam( hIterativeHash, HP_HASHVAL, const_cast(rgbHash), &cbHash, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptGetHashParam"); } CryptDestroyHash(hIterativeHash); hIterativeHash = NULL; } hr = S_OK; error: if (NULL != pbBufferExtension) { LocalFree(pbBufferExtension); } if (NULL != hIterativeHash) { CryptDestroyHash(hIterativeHash); } #if 0 wprintf(L"FinalHash output\n"); DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 4, rgbHash, cbBufferSize); wprintf(wszNewLine); #endif return(hr); } // derive sym encr key HRESULT EPFDeriveKey( IN DWORD dwAlgId, IN DWORD dwKeyLen, IN HCRYPTPROV hProv, IN WCHAR const *pwszPassword, IN WCHAR const *pwszSaltValue, IN BYTE const *pbSaltValue, IN DWORD cbSaltValue, IN DWORD cbHashSize, IN OUT EPF_SYM_KEY_STRUCT *psKey) { HRESULT hr; char *pszPassword = NULL; char *pszSaltValue = NULL; HCRYPTHASH hHash = NULL; HCRYPTHASH hIVHash = NULL; BYTE rgbHash[20]; // hash output DWORD cbHash; BYTE rgbIV[8]; // IV BYTE rgbKeyBlob[sizeof(BLOBHEADER) + sizeof(DWORD) + 16]; // 128 bit key BYTE *pbWritePtr; DWORD cbPwdBuf; BYTE *pbPwdBuf = NULL; switch (dwAlgId) { case EPFALG_CAST_MD5: case EPFALG_RC2_SHA: case EPFALG_3DES: break; default: hr = E_UNEXPECTED; _JumpError(hr, error, "dwAlgId"); } if (NULL == pwszPassword || NULL == pwszSaltValue) { hr = E_POINTER; _JumpError(hr, error, "SaltValue"); } if (!myConvertWszToSz(&pszPassword, pwszPassword, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertWszToSz"); } if (!myConvertWszToSz(&pszSaltValue, pwszSaltValue, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertWszToSz"); } //wprintf(L"password=\"%hs\", salt=\"%hs\"\n", pszPassword, pszSaltValue); cbPwdBuf = strlen(pszPassword) + strlen(pszSaltValue) + 1; pbPwdBuf = (BYTE *) LocalAlloc(LMEM_FIXED, cbPwdBuf); if (pbPwdBuf == NULL) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "pbPwdBuf"); } strcpy((char *) pbPwdBuf, pszPassword); strcat((char *) pbPwdBuf, pszSaltValue); // pszPassword + pszSaltValue if (!CryptCreateHash( hProv, EPFALG_CAST_MD5 == dwAlgId? CALG_MD5 : CALG_SHA1, 0, 0, &hHash)) { hr = myHLastError(); _JumpError(hr, error, "CryptCreateHash"); } // hash pwd | salt if (!CryptHashData(hHash, pbPwdBuf, cbPwdBuf - 1, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptHashData"); } // wprintf(L"\npbPwdBuf: %hs, len: %d\n", (char const *) pbPwdBuf, cbPwdBuf - 1); cbHash = sizeof(rgbHash); if (!CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptGetHashParam"); } #if 0 wprintf(L"=====KEY======\n"); wprintf(L"FirstHash output\n"); DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 4, rgbHash, cbHash); wprintf(wszNewLine); #endif hr = IterateHash(dwAlgId, hProv, 100, rgbHash, cbHash, cbHashSize); _JumpIfError(hr, error, "IterateHash"); // now rgbHash[0..15] is raw key psKey->dwAlgId = dwAlgId; if (EPFALG_RC2_SHA == dwAlgId) { // set up rgbKeyBlob as a contiguous, plaintext blob pbWritePtr = rgbKeyBlob + sizeof(BLOBHEADER); ((BLOBHEADER *) rgbKeyBlob)->bType = PLAINTEXTKEYBLOB; ((BLOBHEADER *) rgbKeyBlob)->bVersion = 2; ((BLOBHEADER *) rgbKeyBlob)->reserved = 0; ((BLOBHEADER *) rgbKeyBlob)->aiKeyAlg = CALG_RC2; // size *(DWORD *) pbWritePtr = 16; pbWritePtr += sizeof(DWORD); // data CopyMemory(pbWritePtr, rgbHash, 16); // 128 bit key // save last 4 bytes for the first half of the IV CopyMemory(rgbIV, &rgbHash[16], 4); // PLAINTEXTKEYBLOB if (!CryptImportKey( hProv, rgbKeyBlob, sizeof(rgbKeyBlob), 0, // no wrapper key 0, &psKey->hKey)) { hr = myHLastError(); _JumpError(hr, error, "CryptImportKey"); } { DWORD cbEffectiveLen = 128; if (!CryptSetKeyParam( psKey->hKey, KP_EFFECTIVE_KEYLEN, (BYTE *) &cbEffectiveLen, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptSetKeyParam(eff keylen)"); } } { DWORD cbMode = CRYPT_MODE_CBC; if (!CryptSetKeyParam(psKey->hKey, KP_MODE, (BYTE *) &cbMode, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptSetKeyParam(mode)"); } } } else // gen CAST context { if (g_fVerbose) { wprintf( L"CAST KeyMatl: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", rgbHash[0], rgbHash[1], rgbHash[2], rgbHash[3], rgbHash[4], rgbHash[5], rgbHash[6], rgbHash[7]); } // Set up key schedule. No errors since SetNumBits already checked length hr = CAST3SetKeySchedule(&psKey->sCastContext, rgbHash, 64); // 64 bit for now _JumpIfError(hr, error, "CAST3SetKeySchedule"); } // compute IV if (EPFALG_RC2_SHA == dwAlgId) { // now, generate IV. Start with new hash, hash in (pwd buf | 0x1) if (!CryptCreateHash( hProv, EPFALG_CAST_MD5 == dwAlgId? CALG_MD5 : CALG_SHA1, 0, 0, &hIVHash)) { hr = myHLastError(); _JumpError(hr, error, "CryptCreateHash"); } // hash pwd | salt if (!CryptHashData(hIVHash, pbPwdBuf, cbPwdBuf - 1, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptHashData"); } // hash 0x1 this time (internally, this is 2nd iteration for // ExtendedHash) BYTE bAppendage = 0x1; if (!CryptHashData(hIVHash, &bAppendage, sizeof(bAppendage), 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptHashData"); } if (!CryptGetHashParam(hIVHash, HP_HASHVAL, rgbHash, &cbHash, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptGetHashParam"); } hr = IterateHash(dwAlgId, hProv, 100, rgbHash, cbHash, cbHashSize); _JumpIfError(hr, error, "IterateHash"); // DONE! previous rgbHash[16..20] and rgbHash[0..4] is IV CopyMemory(&rgbIV[4], rgbHash, 4); if (!CryptSetKeyParam(psKey->hKey, KP_IV, rgbIV, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptSetKeyParam(iv)"); } } else { // DONE! rgbHash[0..8] is IV if (g_fVerbose) { wprintf( L"IV: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", rgbHash[8], rgbHash[9], rgbHash[10], rgbHash[11], rgbHash[12], rgbHash[13], rgbHash[14], rgbHash[15]); } // Start CAST in CBC mode w/ IV hr = CAST3StartEncryptCBC(&psKey->sCastContext, &rgbHash[8]); _JumpIfError(hr, error, "CAST3SetKeySchedule"); } hr = S_OK; error: SecureZeroMemory(rgbHash, cbHash); // Key material SecureZeroMemory(rgbKeyBlob, sizeof(rgbKeyBlob)); // Key material if (NULL != pszPassword) { myZeroDataStringA(pszPassword); // password data LocalFree(pszPassword); } if (NULL != pszSaltValue) { LocalFree(pszSaltValue); } if (NULL != pbPwdBuf) { SecureZeroMemory(pbPwdBuf, cbPwdBuf); // password data LocalFree(pbPwdBuf); } if (NULL != hHash) { CryptDestroyHash(hHash); } if (NULL != hIVHash) { CryptDestroyHash(hIVHash); } return(hr); } // generate token from password-dependent key HRESULT EPFGenerateKeyToken( IN EPF_SYM_KEY_STRUCT const *psKey, OUT BYTE *pbToken, IN DWORD cbToken) { HRESULT hr; HCRYPTKEY hLocalKey = NULL; if (CBTOKEN != cbToken) { hr = E_INVALIDARG; _JumpError(hr, error, "cbToken"); } if (EPFALG_RC2_SHA == psKey->dwAlgId) { if (!CryptDuplicateKey(psKey->hKey, NULL, 0, &hLocalKey)) { hr = myHLastError(); _JumpError(hr, error, "CryptDuplicateKey"); } // We have the key already set up. // Just CBC encrypt one block of zeros as the token. ZeroMemory(pbToken, CBTOKEN); if (!CryptEncrypt(hLocalKey, 0, FALSE, 0, pbToken, &cbToken, CBTOKEN)) { hr = myHLastError(); _JumpError(hr, error, "CryptEncrypt"); } // and one block of 8s as padding... memset(pbToken, 8, CBTOKEN); cbToken = CBTOKEN; if (!CryptEncrypt(hLocalKey, 0, FALSE, 0, pbToken, &cbToken, CBTOKEN)) { hr = myHLastError(); _JumpError(hr, error, "CryptEncrypt"); } } else // generate CAST token { // duplicate key state CAST3_CTX sLocalKey; CopyMemory(&sLocalKey, (BYTE *) &psKey->sCastContext, sizeof(sLocalKey)); // We have the key already set up. // Just CBC encrypt one block of zeros as the token. ZeroMemory(pbToken, CBTOKEN); // MAC 0 hr = CAST3UpdateMAC(&sLocalKey, (BYTE *) pbToken, CBTOKEN); _JumpIfError(hr, error, "CAST3UpdateEncryptCBC"); hr = CAST3EndMAC(&sLocalKey); _JumpIfError(hr, error, "CAST3UpdateEncryptCBC"); // and copy intermediate out CopyMemory(pbToken, sLocalKey.cbcBuffer.asBYTE, CBTOKEN); CAST3Cleanup(&sLocalKey); } hr = S_OK; error: if (NULL != hLocalKey) { CryptDestroyKey(hLocalKey); } return(hr); } // check pwd via token HRESULT EPFVerifyKeyToken( IN EPF_SYM_KEY_STRUCT const *psKey, IN BYTE const *pbToken, IN DWORD cbToken) { HRESULT hr; BYTE rgbComputedToken[CBTOKEN]; hr = EPFGenerateKeyToken(psKey, rgbComputedToken, sizeof(rgbComputedToken)); _JumpIfError(hr, error, "EPFGenerateKeyToken"); if (sizeof(rgbComputedToken) != cbToken || 0 != memcmp(pbToken, rgbComputedToken, sizeof(rgbComputedToken))) { wprintf(L"pbToken\n"); DumpHex(DH_NOTABPREFIX | 4, pbToken, cbToken); wprintf(wszNewLine); wprintf(L"rgbComputedToken\n"); DumpHex(DH_NOTABPREFIX | 4, rgbComputedToken, sizeof(rgbComputedToken)); wprintf(wszNewLine); hr = HRESULT_FROM_WIN32(ERROR_INVALID_PASSWORD); _JumpError(hr, error, "bad password"); } if (g_fVerbose) { wprintf(myLoadResourceString(IDS_TOKENMATCH)); // "Token match" wprintf(wszNewLine); DumpHex(DH_NOTABPREFIX | 4, pbToken, cbToken); wprintf(wszNewLine); } hr = S_OK; error: return(hr); } // decrypt a section HRESULT EPFDecryptSection( IN EPF_SYM_KEY_STRUCT const *psKey, IN BYTE const *pbSection, IN DWORD cbSection, OUT BYTE **ppbDecrypted, OUT DWORD *pcbDecrypted) { HRESULT hr; HCRYPTKEY hLocalKey = NULL; switch (psKey->dwAlgId) { case EPFALG_CAST_MD5: case EPFALG_RC2_SHA: break; case EPFALG_3DES: DumpHex(DH_NOTABPREFIX | 4, pbSection, cbSection); wprintf(wszNewLine); // FALLTHROUGH default: hr = E_UNEXPECTED; _JumpError(hr, error, "dwAlgId"); } // add extra block just in case *ppbDecrypted = (BYTE *) LocalAlloc(LMEM_FIXED, cbSection + 8); if (NULL == *ppbDecrypted) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "*ppbDecrypted"); } *pcbDecrypted = cbSection; // input len // copy into working area CopyMemory(*ppbDecrypted, pbSection, cbSection); if (EPFALG_RC2_SHA == psKey->dwAlgId) { if (!CryptDuplicateKey(psKey->hKey, NULL, 0, &hLocalKey)) { hr = myHLastError(); _JumpError(hr, error, "CryptDuplicateKey"); } // We have the key already set up if (!CryptDecrypt( hLocalKey, 0, TRUE, 0, // flags *ppbDecrypted, pcbDecrypted)) { hr = myHLastError(); _JumpError(hr, error, "CryptDecrypt"); } } else // CAST MD5 { // duplicate key state CAST3_CTX sLocalKey; CopyMemory( &sLocalKey, (BYTE *) &psKey->sCastContext, sizeof(sLocalKey)); // We have the key already set up. CAST3UpdateDecryptCBC( &sLocalKey, pbSection, *ppbDecrypted, (UINT *) pcbDecrypted); // decrypt call is a void return // _JumpIfError(hr, error, "CAST3UpdateDecryptCBC"); // handle anything still left in the cipher state BYTE *pbTmp = *ppbDecrypted + *pcbDecrypted; // point to known end DWORD cbTmp = 0; hr = CAST3EndDecryptCBC( &sLocalKey, pbTmp, (UINT *) &cbTmp); // tack any extra on the end _JumpIfError(hr, error, "CAST3EndDecryptCBC"); *pcbDecrypted += cbTmp; CAST3Cleanup(&sLocalKey); } #if 0 wprintf(L"pbDecrypted Data\n"); DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 4, *ppbDecrypted, *pcbDecrypted); wprintf(wszNewLine); #endif hr = S_OK; error: if (NULL != hLocalKey) { CryptDestroyKey(hLocalKey); } if (S_OK != hr && NULL != *ppbDecrypted) { LocalFree(*ppbDecrypted); *ppbDecrypted = NULL; } return(hr); } // Encrypt a section HRESULT EPFEncryptSection( IN EPF_SYM_KEY_STRUCT const *psKey, IN BYTE const *pbToBeEncrypted, IN DWORD cbToBeEncrypted, OUT BYTE **ppbEncrypted, OUT DWORD *pcbEncrypted) { HRESULT hr; HCRYPTKEY hLocalKey = NULL; *ppbEncrypted = NULL; *pcbEncrypted = cbToBeEncrypted; if (EPFALG_CAST_MD5 != psKey->dwAlgId && EPFALG_RC2_SHA != psKey->dwAlgId) { hr = E_UNEXPECTED; _JumpError(hr, error, "dwAlgId"); } if (EPFALG_RC2_SHA == psKey->dwAlgId) { if (!CryptDuplicateKey(psKey->hKey, NULL, 0, &hLocalKey)) { hr = myHLastError(); _JumpError(hr, error, "CryptDuplicateKey"); } // We have the key already set up. Just CBC encrypt one block of zeros // as the token. if (!CryptEncrypt( hLocalKey, 0, TRUE, 0, // flags NULL, pcbEncrypted, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptDecrypt"); } *ppbEncrypted = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbEncrypted); if (NULL == *ppbEncrypted) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "*ppbEncrypted"); } // copy data into slightly larger buffer CopyMemory(*ppbEncrypted, pbToBeEncrypted, cbToBeEncrypted); if (!CryptEncrypt( hLocalKey, 0, TRUE, 0, // flags *ppbEncrypted, &cbToBeEncrypted, *pcbEncrypted)) { hr = myHLastError(); _JumpError(hr, error, "CryptDecrypt"); } } else // CAST & SHA { // duplicate key state CAST3_CTX sLocalKey; CopyMemory( &sLocalKey, (BYTE *) &psKey->sCastContext, sizeof(sLocalKey)); // allow for final block to run over *ppbEncrypted = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbEncrypted + 8); if (NULL == *ppbEncrypted) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "*ppbEncrypted"); } // We have the key already set up. hr = CAST3UpdateEncryptCBC( &sLocalKey, pbToBeEncrypted, *ppbEncrypted, (UINT *) pcbEncrypted); _JumpIfError(hr, error, "CAST3UpdateEncryptCBC"); // handle anything still left in the cipher state BYTE *pbTmp = *ppbEncrypted + *pcbEncrypted; // point to known end DWORD cbTmp = 0; hr = CAST3EndEncryptCBC( &sLocalKey, pbTmp, (UINT *) &cbTmp); // tack any extra on the end _JumpIfError(hr, error, "CAST3EndEncryptCBC"); *pcbEncrypted += cbTmp; CAST3Cleanup(&sLocalKey); } hr = S_OK; error: if (NULL != hLocalKey) { CryptDestroyKey(hLocalKey); } if (S_OK != hr && NULL != *ppbEncrypted) { LocalFree(*ppbEncrypted); *ppbEncrypted = NULL; } return(hr); } // char section and key name strings: #define szINFSECTION_PASSWORDTOKEN "Password Token" #define szINFKEY_PROTECTION "Protection" #define szINFKEY_PROFILEVERSION "Profile Version" #define szINFKEY_CAST "CAST" #define szINFKEY_TOKEN "Token" #define szINFKEY_SALTVALUE "SaltValue" #define szINFKEY_HASHSIZE "HashSize" // 3DES keys: #define szINFKEY_MACALGORITHM "MAC Algorithm" #define szINFKEY_HASHCOUNT "HashCount" #define szINFKEY_CRC "CRC" #define szINFKEY_OPTIONSMAC "Options MAC" #define szINFKEY_USERX500NAMEMAC "User X.500 Name MAC" // 3DES section: #define szINFSECTION_PROTECTED "Protected" #define szINFKEY_RANDOMSEED "randomSeed" #define szINFKEY_PWHISTORY "pwHistory" // 3DES section: #define szINFSECTION_OPTIONS "Options" #define szINFKEY_PROFILETYPE "ProfileType" #define szINFKEY_CERTPUBLICATIONPENDING "CertificatePublicationPending" #define szINFKEY_USESMIME "UseSMIME" #define szINFKEY_ENCRYPTWITH "EncryptWith" #define szINFKEY_SMIMEENCRYPTWITH "SMIMEEncryptWith" #define szINFKEY_DELETEAFTERDECRYPT "DeleteAfterDecrypt" #define szINFKEY_DELETEAFTERENCRYPT "DeleteAfterEncrypt" // 3DES section: #define szINFSECTION_CACERTIFICATES "CA Certificates" //#define szINFKEY_CERTIFICATE "Certificate" #define szINFSECTION_USERX500NAME "User X.500 Name" #define szINFKEY_X500NAME "X500Name" #define szINFSECTION_DIGITALSIGNATURE "Digital Signature" #define szINFKEY_CERTIFICATE "Certificate" #define szINFKEY_KEY "Key" #define szINFSECTION_PRIVATEKEYS "Private Keys" #define szINFKEY_KEY_FORMAT "Key%u" //#define szINFKEY_KEYCOUNT "KeyCount" #define szINFSECTION_CERTIFICATEHISTORY "Certificate History" #define szINFKEY_NAME_FORMAT "Name%u" #define szINFSECTION_USERCERTIFICATE "User Certificate" #define szINFKEY_CERTIFICATE "Certificate" #define szINFSECTION_CA "CA" //#define szINFKEY_CERTIFICATE "Certificate" // 40 bit only: #define szINFSECTION_MANAGER "Manager" //#define szINFKEY_CERTIFICATE "Certificate" #define szINFSECTION_MICROSOFTEXCHANGE "Microsoft Exchange" #define szINFKEY_FRIENDLYNAME "FriendlyName" #define szINFKEY_KEYALGID "KeyAlgId" // 40 bit only: #define szINFSECTION_REVOKATIONINFORMATION "Revokation Information" #define szINFKEY_CRL "CRL" #define szINFKEY_CRL1 "CRL1" #define szINFSECTION_SMIME "S/MIME" #define szINFKEY_SIGNINGCERTIFICATE "Signing Certificate" #define szINFKEY_SIGNINGKEY "Signing Key" #define szINFKEY_PRIVATEKEYS "Private Keys" #define szINFKEY_KEYCOUNT "KeyCount" #define szINFKEY_ISSUINGCERTIFICATES "Issuing Certificates" #define szINFKEY_TRUSTLISTCERTIFICATE "Trust List Certificate" #define szINFSECTION_FULLCERTIFICATEHISTORY "Full Certificate History" //#define szINFKEY_NAME_FORMAT "Name%u" #define szINFKEY_SMIME_FORMAT "SMIME_%u" // WCHAR section and key name strings: #define wszINFSECTION_PASSWORDTOKEN TEXT(szINFSECTION_PASSWORDTOKEN) #define wszINFKEY_PROTECTION TEXT(szINFKEY_PROTECTION) #define wszINFKEY_PROFILEVERSION TEXT(szINFKEY_PROFILEVERSION) #define wszINFKEY_CAST TEXT(szINFKEY_CAST) #define wszINFKEY_TOKEN TEXT(szINFKEY_TOKEN) #define wszINFKEY_SALTVALUE TEXT(szINFKEY_SALTVALUE) #define wszINFKEY_HASHSIZE TEXT(szINFKEY_HASHSIZE) // 3DES keys: #define wszINFKEY_MACALGORITHM TEXT(szINFKEY_MACALGORITHM) #define wszINFKEY_HASHCOUNT TEXT(szINFKEY_HASHCOUNT) #define wszINFKEY_CRC TEXT(szINFKEY_CRC) #define wszINFKEY_OPTIONSMAC TEXT(szINFKEY_OPTIONSMAC) #define wszINFKEY_USERX500NAMEMAC TEXT(szINFKEY_USERX500NAMEMAC) // 3DES section: #define wszINFSECTION_PROTECTED TEXT(szINFSECTION_PROTECTED) #define wszINFKEY_RANDOMSEED TEXT(szINFKEY_RANDOMSEED) #define wszINFKEY_PWHISTORY TEXT(szINFKEY_PWHISTORY) // 3DES section: #define wszINFSECTION_OPTIONS TEXT(szINFSECTION_OPTIONS) #define wszINFKEY_PROFILETYPE TEXT(szINFKEY_PROFILETYPE) #define wszINFKEY_CERTPUBLICATIONPENDING TEXT(szINFKEY_CERTPUBLICATIONPENDING) #define wszINFKEY_USESMIME TEXT(szINFKEY_USESMIME) #define wszINFKEY_ENCRYPTWITH TEXT(szINFKEY_ENCRYPTWITH) #define wszINFKEY_SMIMEENCRYPTWITH TEXT(szINFKEY_SMIMEENCRYPTWITH) #define wszINFKEY_DELETEAFTERDECRYPT TEXT(szINFKEY_DELETEAFTERDECRYPT) #define wszINFKEY_DELETEAFTERENCRYPT TEXT(szINFKEY_DELETEAFTERENCRYPT) // 3DES section: #define wszINFSECTION_CACERTIFICATES TEXT(szINFSECTION_CACERTIFICATES) //#define wszINFKEY_CERTIFICATE TEXT(szINFKEY_CERTIFICATE) #define wszINFSECTION_USERX500NAME TEXT(szINFSECTION_USERX500NAME) #define wszINFKEY_X500NAME TEXT(szINFKEY_X500NAME) #define wszINFSECTION_DIGITALSIGNATURE TEXT(szINFSECTION_DIGITALSIGNATURE) #define wszINFKEY_CERTIFICATE TEXT(szINFKEY_CERTIFICATE) #define wszINFKEY_KEY TEXT(szINFKEY_KEY) #define wszINFSECTION_PRIVATEKEYS TEXT(szINFSECTION_PRIVATEKEYS) #define wszINFKEY_KEY_FORMAT TEXT(szINFKEY_KEY_FORMAT) //#define wszINFKEY_KEYCOUNT TEXT(szINFKEY_KEYCOUNT) #define wszINFSECTION_CERTIFICATEHISTORY TEXT(szINFSECTION_CERTIFICATEHISTORY) #define wszINFKEY_NAME_FORMAT TEXT(szINFKEY_NAME_FORMAT) #define wszINFSECTION_USERCERTIFICATE TEXT(szINFSECTION_USERCERTIFICATE) #define wszINFKEY_CERTIFICATE TEXT(szINFKEY_CERTIFICATE) #define wszINFSECTION_CA TEXT(szINFSECTION_CA) //#define wszINFKEY_CERTIFICATE TEXT(szINFKEY_CERTIFICATE) // 40 bit only: #define wszINFSECTION_MANAGER TEXT(szINFSECTION_MANAGER) //#define szINFKEY_CERTIFICATE TEXT(szINFKEY_CERTIFICATE) #define wszINFSECTION_MICROSOFTEXCHANGE TEXT(szINFSECTION_MICROSOFTEXCHANGE) #define wszINFKEY_FRIENDLYNAME TEXT(szINFKEY_FRIENDLYNAME) #define wszINFKEY_KEYALGID TEXT(szINFKEY_KEYALGID) // 40 bit only: #define wszINFSECTION_REVOKATIONINFORMATION TEXT(szINFSECTION_REVOKATIONINFORMATION) #define wszINFKEY_CRL TEXT(szINFKEY_CRL) #define wszINFKEY_CRL1 TEXT(szINFKEY_CRL1) #define wszINFSECTION_SMIME TEXT(szINFSECTION_SMIME) #define wszINFKEY_SIGNINGCERTIFICATE TEXT(szINFKEY_SIGNINGCERTIFICATE) #define wszINFKEY_SIGNINGKEY TEXT(szINFKEY_SIGNINGKEY) #define wszINFKEY_PRIVATEKEYS TEXT(szINFKEY_PRIVATEKEYS) #define wszINFKEY_KEYCOUNT TEXT(szINFKEY_KEYCOUNT) #define wszINFKEY_ISSUINGCERTIFICATES TEXT(szINFKEY_ISSUINGCERTIFICATES) #define wszINFKEY_TRUSTLISTCERTIFICATE TEXT(szINFKEY_TRUSTLISTCERTIFICATE) #define wszINFSECTION_FULLCERTIFICATEHISTORY TEXT(szINFSECTION_FULLCERTIFICATEHISTORY) //#define wszINFKEY_NAME_FORMAT TEXT(szINFKEY_NAME_FORMAT) #define wszINFKEY_SMIME_FORMAT TEXT(szINFKEY_SMIME_FORMAT) // fixed maximum buffer lengths #define cwcINFKEY_KEY_FORMATTED \ (ARRAYSIZE(wszINFKEY_KEY_FORMAT) + cwcDWORDSPRINTF) #define cwcINFKEY_NAME_FORMATTED \ (ARRAYSIZE(wszINFKEY_NAME_FORMAT) + cwcDWORDSPRINTF) #define cwcINFKEY_SMIME_FORMATTED \ (ARRAYSIZE(wszINFKEY_SMIME_FORMAT) + cwcDWORDSPRINTF) #define wszSECTION_KEY(Alg, wszSECTION, wszKEY) \ (EPFALG_3DES == (Alg)? \ wszLBRACKET wszSECTION wszRBRACKET L" &" wszKEY : \ wszLBRACKET wszSECTION wszRBRACKET L" @" wszKEY) const WCHAR g_wszCACertCN[] = L"Certificate Authority"; HRESULT cuPatchEPFFile( IN WCHAR const *pwszfnIn, OUT WCHAR **ppwszfnOut) { HRESULT hr; char *pszfnIn = NULL; char *pszfnOut = NULL; FILE *pfIn = NULL; FILE *pfOut = NULL; char *psz; char achLine[1024]; WCHAR awcTempDir[MAX_PATH]; WCHAR awcfnOut[MAX_PATH]; BOOL fDeleteTempFile = FALSE; DWORD cwc; *ppwszfnOut = NULL; if (!myConvertWszToSz(&pszfnIn, pwszfnIn, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertWszToSz"); } pfIn = fopen(pszfnIn, "r"); if (NULL == pfIn) { DWORD dwFileAttr; // Ansi conversion lost characters & the ansi file cannot be found? hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); dwFileAttr = GetFileAttributes(pwszfnIn); if (MAXDWORD != dwFileAttr) { hr = S_FALSE; } _JumpError2(hr, error, "fopen", S_FALSE); } hr = S_FALSE; if (NULL == fgets(achLine, ARRAYSIZE(achLine), pfIn)) { _JumpError2(hr, error, "fgets", hr); } psz = strchr(achLine, chLBRACKET); if (NULL == psz || NULL == strstr(psz, szINFSECTION_PASSWORDTOKEN) || NULL == strchr(psz, chRBRACKET)) { _JumpError2(hr, error, "[]", hr); } cwc = GetEnvironmentVariable(L"temp", awcTempDir, ARRAYSIZE(awcTempDir)); if (0 == cwc) { cwc = GetEnvironmentVariable(L"tmp", awcTempDir, ARRAYSIZE(awcTempDir)); } if (0 == cwc || ARRAYSIZE(awcTempDir) <= cwc) { hr = myHLastError(); _PrintError(hr, "GetEnvironmentVariable"); wcscpy(awcTempDir, L"."); } if (!GetTempFileName( awcTempDir, // directory name L"epf", // lpPrefixString 0, // uUnique awcfnOut)) { hr = myHLastError(); _JumpError(hr, error, "GetTempFileName"); } fDeleteTempFile = TRUE; if (!myConvertWszToSz(&pszfnOut, awcfnOut, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertWszToSz"); } pfOut = fopen(pszfnOut, "w"); if (NULL == pfOut) { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); _JumpError(hr, error, "fopen"); } fputs("[Version]\nSignature=\"$Windows NT$\"\n\n", pfOut); if (fseek(pfIn, 0L, SEEK_SET)) { hr = HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); _JumpError(hr, error, "fseek"); } while (NULL != fgets(achLine, ARRAYSIZE(achLine), pfIn)) { char *pszPrint; char *pszToken; BOOL fQuote; psz = strchr(achLine, '\n'); if (NULL == psz) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "Line overflow"); } *psz = '\0'; fQuote = FALSE; pszPrint = achLine; pszToken = achLine; while (' ' == *pszToken) { pszToken++; } psz = strchr(achLine, '='); if (';' != *pszToken && NULL != psz) { pszPrint = psz + 1; *psz = '\0'; while (achLine < psz && ' ' == *--psz) { *psz = '\0'; } fQuote = NULL != strchr(pszToken, ' '); if (fQuote) { fputs("\"", pfOut); } fputs(pszToken, pfOut); if (fQuote) { fputs("\"", pfOut); } fputs(" = ", pfOut); while (' ' == *pszPrint) { pszPrint++; } psz = &pszPrint[strlen(pszPrint)]; while (pszPrint < psz && ' ' == *--psz) { *psz = '\0'; } fQuote = '\0' != pszPrint[strcspn(pszPrint, " =")]; } if (fQuote) { fputs("\"", pfOut); // if there's no equal sign after a comma, then we need to quote // only the first value, and leave the rest of the line alone. psz = strchr(pszPrint, ','); if (NULL != psz && NULL == strchr(psz, '=')) { pszToken = psz + 1; while (' ' == *pszToken) { pszToken++; } *psz = '\0'; while (pszPrint < psz && ' ' == *--psz) { *psz = '\0'; } fputs(pszPrint, pfOut); fputs("\"", pfOut); fputs(",", pfOut); pszPrint = pszToken; fQuote = FALSE; } } fputs(pszPrint, pfOut); if (fQuote) { fputs("\"", pfOut); } fputs("\n", pfOut); } fflush(pfOut); if (ferror(pfOut)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "I/O error"); } hr = myDupString(awcfnOut, ppwszfnOut); _JumpIfError(hr, error, "myDupString"); fDeleteTempFile = FALSE; error: if (NULL != pfIn) { fclose(pfIn); } if (NULL != pfOut) { fclose(pfOut); } if (fDeleteTempFile) { DeleteFile(awcfnOut); } if (NULL != pszfnIn) { LocalFree(pszfnIn); } if (NULL != pszfnOut) { LocalFree(pszfnOut); } return(hr); } HRESULT BuildProtectedKey( IN WCHAR const *pwszKey, IN DWORD dwAlgId, OUT WCHAR **ppwszProtectedKey) { HRESULT hr; WCHAR *pwsz; *ppwszProtectedKey = NULL; pwsz = (WCHAR *) LocalAlloc( LMEM_FIXED, (1 + wcslen(pwszKey) + 1) * sizeof(WCHAR)); if (NULL == pwsz) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } pwsz[0] = EPFALG_3DES == dwAlgId? L'&' : L'@'; wcscpy(&pwsz[1], pwszKey); *ppwszProtectedKey = pwsz; hr = S_OK; error: return(hr); } HRESULT BuildProtectedHeader( IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, OUT BYTE **ppbHeader, OUT DWORD *pcbHeader) { HRESULT hr; WCHAR *pwszHeader = NULL; char *pszHeader = NULL; *ppbHeader = NULL; pwszHeader = (WCHAR *) LocalAlloc( LMEM_FIXED, (wcslen(pwszSection) + wcslen(pwszKey) + 1) * sizeof(WCHAR)); if (NULL == pwszHeader) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } wcscpy(pwszHeader, pwszSection); wcscat(pwszHeader, pwszKey); if (!myConvertWszToSz(&pszHeader, pwszHeader, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertWszToSz"); } *ppbHeader = (BYTE *) pszHeader; *pcbHeader = strlen(pszHeader); hr = S_OK; error: if (NULL != pwszHeader) { LocalFree(pwszHeader); } return(hr); } VOID cuInfDisplayError() { WCHAR *pwszError = myInfGetError(); if (NULL != pwszError) { wprintf(L"%ws\n", pwszError); LocalFree(pwszError); } } HRESULT cuInfDumpValue( IN HINF hInf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN DWORD Index, IN BOOL fLastValue, IN HRESULT hrQuiet, OPTIONAL OUT BYTE **ppbOut, // if non NULL, caller must call LocalFree OPTIONAL OUT DWORD *pcbOut) { HRESULT hr; WCHAR *pwszValue = NULL; BYTE *pbValue = NULL; DWORD cbValue; hr = myInfGetKeyValue( hInf, TRUE, // fLog pwszSection, pwszKey, Index, fLastValue, &pwszValue); if (S_OK != hr) { cuInfDisplayError(); _PrintErrorStr2(hr, "myInfGetKeyValue", pwszSection, hrQuiet); _JumpErrorStr2(hr, error, "myInfGetKeyValue", pwszKey, hrQuiet); } if (g_fVerbose) { wprintf(L"[%ws] %ws = %ws\n", pwszSection, pwszKey, pwszValue); } hr = myCryptStringToBinary( pwszValue, 0, CRYPT_STRING_BASE64, &pbValue, &cbValue, NULL, NULL); _JumpIfError(hr, error, "myCryptStringToBinary"); if (g_fVerbose) { DumpHex(DH_PRIVATEDATA, pbValue, cbValue); } if (NULL != ppbOut && NULL != pcbOut) { *pcbOut = cbValue; *ppbOut = pbValue; pbValue = NULL; } hr = S_OK; error: if (NULL != pwszValue) { LocalFree(pwszValue); } if (NULL != pbValue) { LocalFree(pbValue); } return(hr); } HRESULT cuInfDumpProtectedValue( IN HINF hInf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN EPF_SYM_KEY_STRUCT const *psKey, IN HRESULT hrQuiet, OPTIONAL OUT BYTE **ppbOut, // if non NULL, caller must call LocalFree OPTIONAL OUT DWORD *pcbOut) { HRESULT hr; WCHAR *pwszProtectedKey = NULL; BYTE *pbHeader = NULL; DWORD cbHeader; BYTE *pbEncrypted = NULL; DWORD cbEncrypted; BYTE *pbDecrypted = NULL; DWORD cbDecrypted; DWORD cbData; CRC16 CrcRead; CRC16 CrcComputed; if (NULL != ppbOut) { *ppbOut = NULL; } hr = BuildProtectedKey(pwszKey, psKey->dwAlgId, &pwszProtectedKey); _JumpIfError(hr, error, "BuildProtectedKey"); hr = BuildProtectedHeader(pwszSection, pwszKey, &pbHeader, &cbHeader); _JumpIfError(hr, error, "BuildProtectedHeader"); hr = cuInfDumpValue( hInf, pwszSection, pwszProtectedKey, 1, // Index TRUE, // fLastValue hrQuiet, &pbEncrypted, &cbEncrypted); _JumpIfError2(hr, error, "cuInfDumpValue", hrQuiet); hr = EPFDecryptSection( psKey, pbEncrypted, cbEncrypted, &pbDecrypted, &cbDecrypted); _JumpIfError(hr, error, "EPFDecryptSection"); if (g_fVerbose) { wprintf(wszNewLine); DumpHex(DH_MULTIADDRESS | DH_NOTABPREFIX | DH_PRIVATEDATA | 4, pbDecrypted, cbDecrypted); } if (sizeof(CrcRead) + cbHeader > cbDecrypted || 0 != memcmp(&pbDecrypted[sizeof(CrcRead)], pbHeader, cbHeader)) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "bad header"); } // Calculate the CRC CrcComputed = 0xffff; F_CRC16( g_CrcTable, &CrcComputed, &pbDecrypted[sizeof(CrcRead)], cbDecrypted - sizeof(CrcRead)); _swab((char *) pbDecrypted, (char *) &CrcRead, sizeof(CrcRead)); DBGPRINT(( CrcRead == CrcComputed? DBG_SS_CERTUTILI : DBG_SS_ERROR, "[%ws] %ws: crc: Read=%x, Computed=%x\n", pwszSection, pwszProtectedKey, CrcRead, CrcComputed)); if (CrcRead != CrcComputed) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "bad crc"); } if (NULL != ppbOut && NULL != pcbOut) { cbData = cbDecrypted - (sizeof(CrcRead) + cbHeader); if (0 != cbData) { *ppbOut = (BYTE *) LocalAlloc(LMEM_FIXED, cbData); if (NULL == *ppbOut) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory( *ppbOut, &pbDecrypted[sizeof(CrcRead) + cbHeader], cbData); } *pcbOut = cbData; } error: if (NULL != pwszProtectedKey) { LocalFree(pwszProtectedKey); } if (NULL != pbHeader) { LocalFree(pbHeader); } if (NULL != pbEncrypted) { LocalFree(pbEncrypted); } if (NULL != pbDecrypted) { LocalFree(pbDecrypted); } return(hr); } HRESULT cuInfDumpNumericKeyValue( IN HINF hInf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN DWORD Index, IN BOOL fLastValue, IN BOOL fDump, IN HRESULT hrQuiet, OUT DWORD *pdw) { HRESULT hr; DWORD dw; hr = myInfGetNumericKeyValue( hInf, TRUE, // fLog pwszSection, pwszKey, Index, fLastValue, &dw); if (S_OK != hr) { if (hrQuiet != hr) { cuInfDisplayError(); } _JumpErrorStr2(hr, error, "myInfGetNumericKeyValue", pwszKey, hrQuiet); } if (fDump) { wprintf(L"[%ws] %ws = %u", pwszSection, pwszKey, dw); if (9 < dw) { wprintf(L" (0x%x)", dw); } wprintf(wszNewLine); } *pdw = dw; error: return(hr); } HRESULT cuInfDumpStringKeyValue( IN HINF hInf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN BOOL fDump, IN HRESULT hrQuiet, OPTIONAL OUT WCHAR **ppwszValue) { HRESULT hr; WCHAR *pwszValue = NULL; hr = myInfGetKeyValue( hInf, TRUE, // fLog pwszSection, pwszKey, 1, // Index TRUE, // fLastValue &pwszValue); if (S_OK != hr) { if (hrQuiet != hr) { cuInfDisplayError(); } _JumpErrorStr2(hr, error, "myInfGetKeyValue", pwszKey, hrQuiet); } if (fDump) { wprintf(L"[%ws] %ws = %ws\n", pwszSection, pwszKey, pwszValue); } if (NULL != ppwszValue) { *ppwszValue = pwszValue; pwszValue = NULL; } error: if (NULL != pwszValue) { LocalFree(pwszValue); } return(hr); } HRESULT cuInfDumpDNKeyValue( IN HINF hInf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN BOOL fDump) { HRESULT hr; WCHAR *pwszValue = NULL; WCHAR *pwszName = NULL; CERT_NAME_BLOB Name; Name.pbData = NULL; hr = myInfGetKeyValue( hInf, TRUE, // fLog pwszSection, pwszKey, 1, // Index TRUE, // fLastValue &pwszValue); if (S_OK != hr) { cuInfDisplayError(); _JumpErrorStr(hr, error, "myInfGetKeyValue", pwszKey); } //wprintf(L"[%ws] %ws = %ws\n", pwszSection, pwszKey, pwszValue); hr = myCertStrToName( X509_ASN_ENCODING, pwszValue, // pszX500 0, // CERT_NAME_STR_REVERSE_FLAG NULL, // pvReserved &Name.pbData, &Name.cbData, NULL); // ppszError _JumpIfErrorStr(hr, error, "myCertStrToName", pwszValue); hr = myCertNameToStr( X509_ASN_ENCODING, &Name, CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, &pwszName); _JumpIfError(hr, error, "myCertNameToStr"); if (fDump) { wprintf(L"[%ws] %ws = ", pwszSection, pwszKey); } wprintf(L"%ws\n", pwszName); error: if (NULL != pwszName) { LocalFree(pwszName); } if (NULL != Name.pbData) { LocalFree(Name.pbData); } if (NULL != pwszValue) { LocalFree(pwszValue); } return(hr); } HRESULT cuInfDumpBinaryNameKeyValue( IN HINF hInf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN DWORD Index, IN BOOL fLastValue, IN BOOL fDump, IN HRESULT hrQuiet) { HRESULT hr; WCHAR *pwszName = NULL; CERT_NAME_BLOB Name; Name.pbData = NULL; hr = cuInfDumpValue( hInf, pwszSection, pwszKey, Index, fLastValue, hrQuiet, &Name.pbData, &Name.cbData); _JumpIfErrorStr(hr, error, "cuInfDumpValue", pwszKey); hr = myCertNameToStr( X509_ASN_ENCODING, &Name, CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, &pwszName); _JumpIfError(hr, error, "myCertNameToStr"); if (fDump) { wprintf(L"[%ws] %ws = ", pwszSection, pwszKey); } wprintf(L"%ws\n", pwszName); error: if (NULL != pwszName) { LocalFree(pwszName); } if (NULL != Name.pbData) { LocalFree(Name.pbData); } return(hr); } HRESULT cuInfDumpProtectedStringValue( IN HINF hInf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN EPF_SYM_KEY_STRUCT const *psKey, IN BOOL fDump, IN HRESULT hrQuiet, OUT WCHAR **ppwszValue) { HRESULT hr; BYTE *pbValue = NULL; DWORD cbValue; *ppwszValue = NULL; hr = cuInfDumpProtectedValue( hInf, pwszSection, pwszKey, psKey, hrQuiet, &pbValue, &cbValue); _JumpIfError(hr, error, "cuInfDumpProtectedValue"); if (!myConvertSzToWsz(ppwszValue, (char const *) pbValue, cbValue)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertSzToWsz"); } hr = S_OK; error: if (NULL != pbValue) { LocalFree(pbValue); } return(hr); } HRESULT cuInfDumpProtectedDwordValue( IN HINF hInf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN EPF_SYM_KEY_STRUCT const *psKey, IN BOOL fDump, IN HRESULT hrQuiet, OUT DWORD *pdwValue) { HRESULT hr; BYTE *pbValue = NULL; DWORD cbValue; *pdwValue = 0; hr = cuInfDumpProtectedValue( hInf, pwszSection, pwszKey, psKey, hrQuiet, &pbValue, &cbValue); _JumpIfError(hr, error, "cuInfDumpProtectedValue"); if (sizeof(*pdwValue) != cbValue) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "cbValue"); } CopyMemory(pdwValue, pbValue, sizeof(*pdwValue)); hr = S_OK; error: if (NULL != pbValue) { LocalFree(pbValue); } return(hr); } HRESULT cuInfDumpHexKeyValue( IN HINF hInf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN BOOL fDump, OPTIONAL OUT BYTE **ppbOut, OPTIONAL OUT DWORD *pcbOut) { HRESULT hr; WCHAR *pwszValue = NULL; BYTE *pbOut = NULL; DWORD cbOut; hr = myInfGetKeyValue( hInf, TRUE, // fLog pwszSection, pwszKey, 1, // Index TRUE, // fLastValue &pwszValue); if (S_OK != hr) { cuInfDisplayError(); _JumpErrorStr(hr, error, "myInfGetKeyValue", pwszKey); } if (fDump) { wprintf(L"[%ws] %ws = %ws\n", pwszSection, pwszKey, pwszValue); } hr = WszToMultiByteInteger(TRUE, pwszValue, &cbOut, &pbOut); _JumpIfErrorStr(hr, error, "WszToMultiByteInteger", pwszValue); if (g_fVerbose) { DumpHex(DH_PRIVATEDATA, pbOut, cbOut); } if (NULL != ppbOut && NULL != pcbOut) { *ppbOut = pbOut; *pcbOut = cbOut; pbOut = NULL; } error: if (NULL != pbOut) { LocalFree(pbOut); } if (NULL != pwszValue) { LocalFree(pwszValue); } return(hr); } VOID ExtraAsnBytes( IN BYTE const *pbCert, IN DWORD cbCert) { DWORD cbAsn = MAXDWORD; if (6 < cbCert && BER_SEQUENCE == pbCert[0]) { if (0x80 & pbCert[1]) { switch (0x7f & pbCert[1]) { case 1: cbAsn = pbCert[2]; cbAsn += 3; break; case 2: cbAsn = (pbCert[2] << 8) | pbCert[3]; cbAsn += 4; break; case 3: cbAsn = (pbCert[2] << 16) | (pbCert[3] << 8) | pbCert[4]; cbAsn += 5; break; case 4: cbAsn = (pbCert[2] << 24) | (pbCert[3] << 16) | (pbCert[4] << 8) | pbCert[5]; cbAsn += 6; break; } } else { cbAsn = pbCert[1]; cbAsn += 2; } } if (MAXDWORD == cbAsn) { DumpHex(0, pbCert, min(6, cbCert)); wprintf(myLoadResourceString(IDS_BAD_ASN_LENGTH)); // "Bad Asn length encoding" wprintf(wszNewLine); } else { if (cbCert != cbAsn) { wprintf(L"cbCert=%x cbAsn=%x\n", cbCert, cbAsn); wprintf( myLoadResourceString(IDS_FORMAT_ASN_EXTRA), // "Asn encoding: %x extra bytes" cbCert - cbAsn); wprintf(wszNewLine); } } } HRESULT AddCertAndKeyToStore( IN OUT HCERTSTORE hStore, IN BYTE const *pbCert, IN DWORD cbCert, IN BYTE const *pbKey, IN DWORD cbKey, IN DWORD dwKeySpec) { HRESULT hr; CERT_CONTEXT const *pcc = NULL; GUID guid; WCHAR *pwszKeyContainerName = NULL; HCRYPTPROV hProv = NULL; HCRYPTKEY hKey = NULL; CRYPT_KEY_PROV_INFO kpi; if (!CertAddEncodedCertificateToStore( hStore, X509_ASN_ENCODING, pbCert, cbCert, CERT_STORE_ADD_REPLACE_EXISTING, &pcc)) { hr = myHLastError(); _JumpError(hr, error, "CertAddEncodedCertificateToStore"); } // Use standard GUID key container names so they get cleaned up properly myUuidCreate(&guid); hr = StringFromCLSID(guid, &pwszKeyContainerName); _JumpIfError(hr, error, "StringFromCLSID"); ZeroMemory(&kpi, sizeof(kpi)); kpi.pwszContainerName = pwszKeyContainerName; kpi.pwszProvName = MS_STRONG_PROV; kpi.dwProvType = PROV_RSA_FULL; kpi.dwFlags = g_fUserRegistry? 0 : CRYPT_MACHINE_KEYSET; kpi.dwKeySpec = dwKeySpec; if (!CryptAcquireContext( &hProv, kpi.pwszContainerName, kpi.pwszProvName, kpi.dwProvType, CRYPT_NEWKEYSET | kpi.dwFlags)) { hr = myHLastError(); _JumpError(hr, error, "CryptAcquireContext"); } if (!CryptImportKey(hProv, pbKey, cbKey, NULL, CRYPT_EXPORTABLE, &hKey)) { hr = myHLastError(); _JumpError(hr, error, "CryptImportKey"); } if (!CertSetCertificateContextProperty( pcc, CERT_KEY_PROV_INFO_PROP_ID, 0, &kpi)) { hr = myHLastError(); _JumpError(hr, error, "CertSetCertificateContextProperty"); } hr = S_OK; error: if (NULL != hKey) { CryptDestroyKey(hKey); } if (NULL != hProv) { CryptReleaseContext(hProv, 0); } if (NULL != pwszKeyContainerName) { CoTaskMemFree(pwszKeyContainerName); } if (NULL != pcc) { CertFreeCertificateContext(pcc); } return(hr); } // Define a structure to hold all of the private Key Exchange key material // Commented out the pointer elements to match the binary data image. typedef struct { DWORD dwKeySpec; DWORD cbPrivKey; union { //LPBYTE pbPrivKey; DWORD obPrivKey; }; DWORD cbPubKey; union { //LPBYTE pbPubKey; DWORD obPubKey; }; } OneKeyBlob; #if 0 typedef struct { DWORD dwSize; DWORD cKeys; OneKeyBlob rgKeyBlobs[0]; } ExchangeKeyBlob_Old; #endif typedef struct { DWORD dwSize; DWORD cKeys; DWORD dwKeyAlg; //OneKeyBlob rgKeyBlobs[0]; } ExchangeKeyBlobEx; #define CBEKB CCSIZEOF_STRUCT(ExchangeKeyBlobEx, dwKeyAlg) #define dwKEYSPEC_V1ENCRYPTION_BASE 1000 #define dwKEYSPEC_V1SIGNATURE 1500 #define dwKEYSPEC_V3ENCRYPTION_BASE 2000 #define dwKEYSPEC_V3SIGNATURE 2500 HRESULT VerifyAndSaveCertAndKey( OPTIONAL IN OUT HCERTSTORE hStore, IN BOOL fDump, IN WCHAR const *pwszKeyType, IN BYTE const *pbCert, IN DWORD cbCert, IN BYTE const *pbEPFKey, IN DWORD cbEPFKey, IN DWORD cKey, IN ALG_ID aiKeyAlg, IN DWORD dwKeySpec) { HRESULT hr; BYTE *pbKey = NULL; DWORD cbKey; ExchangeKeyBlobEx ekb; BYTE const *pb; DWORD cb; OneKeyBlob okb; DWORD i; pb = pbEPFKey; hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); if (CBEKB > cbEPFKey) { _JumpError(hr, error, "ExchangeKeyBlobEx size"); } //DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 4, pbEPFKey, CBEKB); CopyMemory(&ekb, pbEPFKey, CBEKB); if (aiKeyAlg != ekb.dwKeyAlg) { _JumpError(hr, error, "unexpected AlgId"); } pb += CBEKB; if (CBEKB != ekb.dwSize) { _JumpError(hr, error, "ExchangeKeyBlobEx.dwSize"); } cb = CBEKB + sizeof(OneKeyBlob) * ekb.cKeys; if (cb > cbEPFKey) { _JumpError(hr, error, "ExchangeKeyBlobEx size"); } if (cKey != ekb.cKeys) { _JumpError(hr, error, "ExchangeKeyBlobEx.cKeys"); } for (i = 0; i < ekb.cKeys; i++) { CopyMemory(&okb, &pb[sizeof(OneKeyBlob) * i], sizeof(okb)); if (cb != okb.obPrivKey) { _JumpError(hr, error, "OneKeyBlob.obPrivKey"); } cb += okb.cbPrivKey; if (cb > cbEPFKey) { _JumpError(hr, error, "OneKeyBlob.cbPrivKey"); } if (0 != okb.obPubKey || 0 != okb.cbPubKey) { if (cb != okb.obPubKey) { _JumpError(hr, error, "OneKeyBlob.obPubKey"); } cb += okb.cbPubKey; if (cb > cbEPFKey) { _JumpError(hr, error, "OneKeyBlob.cbPubKey"); } } } if (cb != cbEPFKey) { _JumpError(hr, error, "cbEPFKey"); } for (i = 0; i < ekb.cKeys; i++) { CopyMemory(&okb, &pb[sizeof(OneKeyBlob) * i], sizeof(okb)); //DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 4, &pbEPFKey[okb.obPrivKey], okb.cbPrivKey); if (NULL != pbKey) { SecureZeroMemory(pbKey, cbKey); // Key material LocalFree(pbKey); pbKey = NULL; } hr = myDecodeKMSRSAKey( &pbEPFKey[okb.obPrivKey], okb.cbPrivKey, aiKeyAlg, &pbKey, &cbKey); _JumpIfError(hr, error, "myDecodeKMSRSAKey"); hr = myVerifyKMSKey(pbCert, cbCert, pbKey, cbKey, dwKeySpec, TRUE); _PrintIfError2(hr, "myVerifyKMSKey", HRESULT_FROM_WIN32(ERROR_INVALID_DATA)); if (S_OK == hr) { if (fDump) { wprintf(L" dwKeySpec = %u\n", okb.dwKeySpec); hr = cuDumpPrivateKeyBlob(pbKey, cbKey, FALSE); _PrintIfError(hr, "cuDumpPrivateKeyBlob"); } wprintf( myLoadResourceString(IDS_FORMAT_VERIFIES_AGAINST_CERT), // "%ws key verifies against certificate" pwszKeyType); wprintf(wszNewLine); if (fDump && 0 != okb.obPubKey && 0 != okb.cbPubKey) { wprintf(myLoadResourceString(IDS_PUBLIC_KEY_COLON)); // "Public key:" wprintf(wszNewLine); DumpHex( DH_NOTABPREFIX | 4, &pbEPFKey[okb.obPubKey], okb.cbPubKey); } if (NULL != hStore) { hr = AddCertAndKeyToStore( hStore, pbCert, cbCert, pbKey, cbKey, dwKeySpec); _JumpIfError(hr, error, "AddCertAndKeyToStore"); } break; // success! } } error: if (S_OK != hr) { wprintf( myLoadResourceString(IDS_FORMAT_NO_MATCH_CERT), // "%ws key does not match certifcate" pwszKeyType); wprintf(L": %x\n", hr); wprintf(wszNewLine); } if (NULL != pbKey) { SecureZeroMemory(pbKey, cbKey); // Key material LocalFree(pbKey); } return(hr); } HRESULT VerifyAndSaveOneCertAndKey( OPTIONAL IN OUT HCERTSTORE hStore, IN BOOL fDump, IN WCHAR const *pwszKeyType, IN BYTE const *pbCert, IN DWORD cbCert, IN BYTE const *pbKMSKey, IN DWORD cbKMSKey, IN ALG_ID aiKeyAlg, IN DWORD dwKeySpec) { HRESULT hr; BYTE *pbKey = NULL; DWORD cbKey; BOOL fMatch; hr = myDecodeKMSRSAKey(pbKMSKey, cbKMSKey, aiKeyAlg, &pbKey, &cbKey); _JumpIfError(hr, error, "myDecodeKMSRSAKey"); hr = myVerifyKMSKey(pbCert, cbCert, pbKey, cbKey, dwKeySpec, TRUE); if (S_OK != hr) { _PrintError(hr, "myVerifyKMSKey"); if (!g_fForce) { goto error; // -f ignores this error } } fMatch = S_OK == hr; if (fDump) { wprintf(L" dwKeySpec = %u\n", dwKeySpec); hr = cuDumpPrivateKeyBlob(pbKey, cbKey, FALSE); _PrintIfError(hr, "cuDumpPrivateKeyBlob"); } wprintf( myLoadResourceString( fMatch? IDS_FORMAT_VERIFIES_AGAINST_CERT : // "%ws key verifies against certificate" IDS_FORMAT_NO_MATCH_CERT), // "%ws key does not match certificate" pwszKeyType); wprintf(wszNewLine); if (NULL != hStore) { hr = AddCertAndKeyToStore( hStore, pbCert, cbCert, pbKey, cbKey, dwKeySpec); _JumpIfError(hr, error, "AddCertAndKeyToStore"); } error: if (NULL != pbKey) { SecureZeroMemory(pbKey, cbKey); // Key material LocalFree(pbKey); } return(hr); } HRESULT AddCACertToStore( IN BYTE const *pbCertCA, IN DWORD cbCertCA) { HRESULT hr; CERT_CONTEXT const *pccCA = NULL; HCERTSTORE hStore = NULL; pccCA = CertCreateCertificateContext(X509_ASN_ENCODING, pbCertCA, cbCertCA); if (NULL == pccCA) { hr = myHLastError(); _JumpError(hr, error, "CertCreateCertificateContext"); } hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_REGISTRY_W, X509_ASN_ENCODING, NULL, // hProv CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG | CERT_SYSTEM_STORE_LOCAL_MACHINE, wszCA_CERTSTORE); if (NULL == hStore) { hr = myHLastError(); _JumpError(hr, error, "CertOpenStore"); } if (!CertAddCertificateContextToStore( hStore, pccCA, CERT_STORE_ADD_USE_EXISTING, NULL)) { hr = myHLastError(); _JumpError(hr, error, "CertAddCertificateContextToStore"); } hr = S_OK; error: if (NULL != pccCA) { CertFreeCertificateContext(pccCA); } if (NULL != hStore) { CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG); } return(hr); } HRESULT DumpSerializedCertStore( IN BYTE const *pbStore, IN DWORD cbStore) { HRESULT hr; HCERTSTORE hStore = NULL; CRYPT_DATA_BLOB Blob; Blob.pbData = const_cast(pbStore); Blob.cbData = cbStore; hStore = CertOpenStore( CERT_STORE_PROV_SERIALIZED, X509_ASN_ENCODING, NULL, // hCryptProv CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG, &Blob); if (NULL == hStore) { hr = myHLastError(); _JumpError(hr, error, "CertOpenStore"); } hr = cuDumpAndVerifyStore( hStore, DVNS_DUMP | DVNS_DUMPKEYS | DVNS_DUMPPROPERTIES, NULL, // pwszCertName MAXDWORD, // iCertSave MAXDWORD, // iCRLSave MAXDWORD, // iCTLSave NULL, // pwszfnOut NULL); // pwszPassword _JumpIfError(hr, error, "cuDumpAndVerifyStore"); error: if (NULL != hStore) { CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG); } return(hr); } HRESULT GenerateV1Keys( IN BOOL fRoot, OUT HCRYPTPROV *phProv) { HRESULT hr; HCRYPTKEY hKey = NULL; *phProv = NULL; // create verify container if (!CryptAcquireContext( phProv, NULL, // pwszContainer NULL, // pwszProvName PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { hr = myHLastError(); _JumpError(hr, error, "CryptAcquireContext"); } // create signature keys if (!CryptGenKey( *phProv, AT_SIGNATURE, (512 << 16) | CRYPT_EXPORTABLE, &hKey)) { hr = myHLastError(); _JumpError(hr, error, "CryptGenKey"); } hr = S_OK; error: if (NULL != hKey) { CryptDestroyKey(hKey); } return(hr); } // valid decrypted non-PKCS1 signature (512 bits/64 bytes): // 1) Byte reversed hash // 2) length of hash (0x10 bytes) // 3) Octet string tag (BER_OCTET_STRING) // 4) 0x00 byte // 5) 0xff pad (as many bytes as necessary) // 6) 0x01 pad byte // 7) 0x00 pad byte // // 6e e3 f9 e8 83 e6 b1 a0-ff 63 96 df 2e 30 bb fe // 10 04 00 ff ff ff ff ff-ff ff ff ff ff ff ff ff // ff ff ff ff ff ff ff ff-ff ff ff ff ff ff ff ff // ff ff ff ff ff ff ff ff-ff ff ff ff ff ff 01 00 HRESULT mySignMD5HashOnly( IN HCRYPTPROV hProv, IN char const *pszAlgId, IN BYTE const *pbEncoded, IN DWORD cbEncoded, OUT BYTE **ppbSigned, OUT DWORD *pcbSigned) { HRESULT hr; HCRYPTHASH hHash = NULL; BYTE abHash[CBMAX_CRYPT_HASH_LEN]; DWORD cbHash; BYTE abSig[64]; DWORD cbSig; DWORD i; HCRYPTKEY hKey = NULL; #if 0 #else BYTE *pbKey = NULL; DWORD cbKey; HCRYPTKEY hKeySig = NULL; #endif static BYTE abSigPrefix[] = { BER_SEQUENCE, 9, BER_OBJECT_ID, 5, 0x2b, 0x0e, 0x03, 0x02, 0x03, BER_NULL, 0, BER_BIT_STRING, sizeof(abSig) + 1, 0, // Unused bits // encryted signature (sizeof(abSig)) }; BYTE abSigSequence[sizeof(abSigPrefix) + sizeof(abSig)]; CRYPT_SEQUENCE_OF_ANY Seq; CRYPT_DER_BLOB rgBlob[2]; *ppbSigned = NULL; if (!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash)) { hHash = NULL; hr = myHLastError(); _JumpError(hr, error, "CryptCreateHash"); } if (!CryptHashData(hHash, pbEncoded, cbEncoded, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptHashData"); } cbHash = sizeof(abHash); if (!CryptGetHashParam(hHash, HP_HASHVAL, abHash, &cbHash, 0)) { hr = myHLastError(); _JumpError(hr, error, "CryptGetHashParam"); } #if 0 wprintf(L"\nV1 Cert to-be-signed:\n"); DumpHex(DH_NOTABPREFIX | DH_NOASCIIHEX | 4, pbEncoded, cbEncoded); wprintf(L"\nV1 Cert to-be-signed Hash:\n"); DumpHex(DH_NOTABPREFIX | DH_NOASCIIHEX | 4, abHash, cbHash); #endif memset(abSig, (BYTE) 0xff, sizeof(abSig)); for (i = 0; i < cbHash; i++) { abSig[i] = abHash[cbHash - i - 1]; } abSig[cbHash] = (BYTE) cbHash; abSig[cbHash + 1] = (BYTE) BER_OCTET_STRING; abSig[cbHash + 2] = (BYTE) 0x00; abSig[sizeof(abSig) - 2] = (BYTE) 0x01; abSig[sizeof(abSig) - 1] = (BYTE) 0x00; #if 0 wprintf(L"\nV1 clear text signature (padded hash):\n"); DumpHex(DH_NOTABPREFIX | DH_NOASCIIHEX | 4, abSig, sizeof(abSig)); #endif #if 0 if (!CryptGetUserKey(hProv, AT_SIGNATURE, &hKey)) { hr = myHLastError(); _JumpError(hr, error, "CryptGetUserKey"); } #else if (!CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hKey)) { hr = myHLastError(); if (hr != NTE_NO_KEY) { _JumpError(hr, error, "CryptGetUserKey"); } if (!CryptGetUserKey(hProv, AT_SIGNATURE, &hKeySig)) { hr = myHLastError(); _JumpError(hr, error, "CryptGetUserKey - sig"); } // UGH! migrate from AT_SIGNATURE container! cbKey = 0; hr = myCryptExportKey( hKeySig, // hKey NULL, // hKeyExp PRIVATEKEYBLOB, // dwBlobType 0, // dwFlags &pbKey, &cbKey); _JumpIfError(hr, error, "myCryptExportKey"); // UGH! fix up the algid to signature... ((PUBLICKEYSTRUC *) pbKey)->aiKeyAlg = CALG_RSA_KEYX; // and re-import it if (!CryptImportKey( hProv, pbKey, cbKey, NULL, CRYPT_EXPORTABLE, &hKey)) { hr = myHLastError(); _JumpError(hr, error, "CryptImportKey"); } } #endif //#define RSAENH_NOT_FIXED // should no longer be necessary... #ifdef RSAENH_NOT_FIXED BYTE abSig2[64 + 8]; ZeroMemory(abSig2, sizeof(abSig2)); CopyMemory(abSig2, abSig, sizeof(abSig)); #endif cbSig = sizeof(abSig); if (!CryptDecrypt( hKey, NULL, // hHash TRUE, // Final CRYPT_DECRYPT_RSA_NO_PADDING_CHECK, // dwFlags #ifdef RSAENH_NOT_FIXED abSig2, #else abSig, #endif &cbSig)) { hr = myHLastError(); _JumpError(hr, error, "CryptDecrypt"); } #ifdef RSAENH_NOT_FIXED CopyMemory(abSig, abSig2, sizeof(abSig)); #endif #if 0 wprintf(L"\nV1 encrypted signature:\n"); DumpHex(DH_NOTABPREFIX | DH_NOASCIIHEX | 4, abSig, cbSig); #endif // Append signature goop to cert. CopyMemory(abSigSequence, abSigPrefix, sizeof(abSigPrefix)); //CopyMemory(&abSigSequence[sizeof(abSigPrefix)], abSig, sizeof(abSig)); for (i = 0; i < cbSig; i++) { abSigSequence[sizeof(abSigPrefix) + i] = abSig[cbSig - i - 1]; } rgBlob[0].pbData = const_cast(pbEncoded); rgBlob[0].cbData = cbEncoded; rgBlob[1].pbData = abSigSequence; rgBlob[1].cbData = sizeof(abSigSequence); Seq.cValue = ARRAYSIZE(rgBlob); Seq.rgValue = rgBlob; if (!myEncodeObject( X509_ASN_ENCODING, X509_SEQUENCE_OF_ANY, &Seq, 0, CERTLIB_USE_LOCALALLOC, ppbSigned, pcbSigned)) { hr = myHLastError(); _JumpError(hr, error, "myEncodeObject"); } #if 0 wprintf(L"\nV1 Cert:\n"); DumpHex(DH_NOTABPREFIX | DH_NOASCIIHEX | 4, *ppbSigned, *pcbSigned); #endif hr = S_OK; error: if (NULL != hKey) { CryptDestroyKey(hKey); } if (NULL != hHash) { CryptDestroyHash(hHash); } #if 0 #else if (NULL != pbKey) { LocalFree(pbKey); } if (NULL != hKeySig) { CryptDestroyKey(hKeySig); } #endif return(hr); } HRESULT epfEncodeCertAndSign( IN HCRYPTPROV hProvSigner, IN CERT_PUBLIC_KEY_INFO *pSubjectPublicKeyInfoSigner, IN CERT_INFO *pCert, IN char const *pszAlgId, OUT BYTE **ppbSigned, OUT DWORD *pcbSigned) { HRESULT hr; BYTE *pbEncoded = NULL; DWORD cbEncoded; *ppbSigned = NULL; if (!myEncodeToBeSigned( X509_ASN_ENCODING, pCert, CERTLIB_USE_LOCALALLOC, &pbEncoded, &cbEncoded)) { hr = myHLastError(); _JumpError(hr, error, "myEncodeToBeSigned"); } // Try to use the new rsaenc.dll to generate a Nortel-compliant signature. // The enrypted signature will not contain the algorithm OID or parameters. hr = mySignMD5HashOnly( hProvSigner, pszAlgId, pbEncoded, cbEncoded, ppbSigned, pcbSigned); _PrintIfError(hr, "mySignMD5HashOnly"); if (S_OK == hr) { if (CryptVerifyCertificateSignature( NULL, X509_ASN_ENCODING, *ppbSigned, *pcbSigned, pSubjectPublicKeyInfoSigner)) { wprintf(myLoadResourceString(IDS_CERT_SIG_OK)); // "Cert signature is valid" wprintf(wszNewLine); } else { hr = myHLastError(); _PrintError(hr, "CryptVerifyCertificateSignature"); LocalFree(*ppbSigned); *ppbSigned = NULL; } } if (S_OK != hr && 1 < g_fForce) { // Must be running on an old rsaenh.dll that only supports PKCS1 // signatures. Just generate a standard PKCS1 signature. hr = myEncodeSignedContent( hProvSigner, X509_ASN_ENCODING, pszAlgId, pbEncoded, cbEncoded, CERTLIB_USE_LOCALALLOC, ppbSigned, pcbSigned); _JumpIfError(hr, error, "myEncodeSignedContent"); } _JumpIfError(hr, error, "mySignMD5HashOnly"); error: if (NULL != pbEncoded) { LocalFree(pbEncoded); } return(hr); } HRESULT GenerateV1SerialNumber( IN HCRYPTPROV hProv, IN CRYPT_INTEGER_BLOB const *pSerialNumberOld, OUT DWORD *pdwV1SerialNumber) { HRESULT hr; BYTE *pb; DWORD cb; pb = (BYTE *) pdwV1SerialNumber; cb = sizeof(*pdwV1SerialNumber); if (!CryptGenRandom(hProv, cb, pb)) { hr = myHLastError(); _JumpError(hr, error, "CryptGenRandom"); } pb += sizeof(*pdwV1SerialNumber) - 1; if (sizeof(*pdwV1SerialNumber) == pSerialNumberOld->cbData && NULL != pSerialNumberOld->pbData) { *pb = pSerialNumberOld->pbData[pSerialNumberOld->cbData - 1]; } // make sure the last byte is never zero if (0 == *pb) { *pb = 0x3a; } // Some clients can't handle negative serial numbers: *pb &= 0x7f; hr = S_OK; error: return(hr); } HRESULT AddExtraByteToKey( IN OUT BYTE **ppbKey, IN OUT DWORD *pcbKey) { HRESULT hr; BYTE *pbKey; pbKey = (BYTE *) LocalAlloc(LMEM_FIXED, *pcbKey + 1); if (NULL == pbKey) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(pbKey, *ppbKey, *pcbKey); pbKey[*pcbKey] = 0x01; (*pcbKey)++; LocalFree(*ppbKey); *ppbKey = pbKey; hr = S_OK; error: return(hr); } HRESULT epfEncodeV1Cert( OPTIONAL IN HCRYPTPROV hProvSigner, OPTIONAL CERT_CONTEXT const *pccSigner, IN CRYPT_INTEGER_BLOB const *pSerialNumberOld, IN CERT_NAME_BLOB const *pIssuer, IN CERT_NAME_BLOB const *pSubject, OUT HCRYPTPROV *phProv, OUT CERT_CONTEXT const **ppCert) { HRESULT hr; HCRYPTPROV hProv = NULL; CERT_PUBLIC_KEY_INFO *pPubKey = NULL; DWORD cbPubKey; BYTE *pbPubKeyNew = NULL; CERT_INFO Cert; //char *pszAlgId = szOID_RSA_MD5RSA; char *pszAlgId = szOID_OIWSEC_md5RSA; DWORD dwV1SerialNumber; BYTE *pbEncoded = NULL; DWORD cbEncoded; SYSTEMTIME st; SYSTEMTIME st2; *phProv = NULL; *ppCert = NULL; hr = GenerateV1Keys(NULL == hProvSigner, &hProv); _JumpIfError(hr, error, "GenerateV1Keys"); if (!myCryptExportPublicKeyInfo( hProv, AT_SIGNATURE, CERTLIB_USE_LOCALALLOC, &pPubKey, &cbPubKey)) { hr = myHLastError(); _JumpError(hr, error, "myCryptExportPublicKeyInfo"); } #if 0 wprintf(L"\nCERT_PUBLIC_KEY_INFO:\n"); DumpHex( DH_NOTABPREFIX | DH_NOASCIIHEX | 4, (BYTE const *) pPubKey, cbPubKey); wprintf(L"\nBefore mySqueezePublicKey:\n"); wprintf(L"cUnusedBits=%u\n", pPubKey->PublicKey.cUnusedBits); DumpHex( DH_NOTABPREFIX | DH_NOASCIIHEX | 4, pPubKey->PublicKey.pbData, pPubKey->PublicKey.cbData); #endif hr = mySqueezePublicKey( pPubKey->PublicKey.pbData, pPubKey->PublicKey.cbData, &pbPubKeyNew, &pPubKey->PublicKey.cbData); _JumpIfError(hr, error, "mySqueezePublicKey"); hr = AddExtraByteToKey(&pbPubKeyNew, &pPubKey->PublicKey.cbData); _JumpIfError(hr, error, "AddExtraByteToKey"); pPubKey->PublicKey.pbData = pbPubKeyNew; #if 0 //wprintf(L"cUnusedBits=%u\n", pPubKey->PublicKey.cUnusedBits); wprintf(L"\nAfter mySqueezePublicKey:\n"); DumpHex( DH_NOTABPREFIX | DH_NOASCIIHEX | 4, pPubKey->PublicKey.pbData, pPubKey->PublicKey.cbData); #endif // CERT: ZeroMemory(&Cert, sizeof(Cert)); Cert.dwVersion = CERT_V1; // Use a DWORD for the V1 serial number GenerateV1SerialNumber(hProv, pSerialNumberOld, &dwV1SerialNumber); Cert.SerialNumber.pbData = (BYTE *) &dwV1SerialNumber; Cert.SerialNumber.cbData = sizeof(dwV1SerialNumber); Cert.SignatureAlgorithm.pszObjId = pszAlgId; // ISSUER: Cert.Issuer = *pIssuer; // Structure assignment // Start with an arbitrary constant date in the past 12 months. // Choose January 1st or June 1st: whichever will result in at least // several months remaining until we hit the date again. // From Feb 1st to June 30th, pick Jan 1st. // From July 1st to Jan 31st, pick Jun 1st. GetSystemTime(&st); ZeroMemory(&st2, sizeof(st2)); st2.wYear = st.wYear; st2.wDay = 1; // Jan or Jun 1st st2.wHour = 12; // at Noon if (2 <= st.wMonth && 6 >= st.wMonth) { st2.wMonth = 1; // January } else { st2.wMonth = 6; // June } CSASSERT(st2.wMonth != st.wMonth); if (st2.wMonth > st.wMonth) { st2.wYear--; } if (!SystemTimeToFileTime(&st2, &Cert.NotBefore)) { hr = myHLastError(); _JumpError(hr, error, "SystemTimeToFileTime"); } Cert.NotAfter = Cert.NotBefore; if (NULL == hProvSigner) { // Generate 20 year V1 root CA cert, centered over an arbitrary date // in the past 12 months. myMakeExprDateTime(&Cert.NotBefore, -10, ENUM_PERIOD_YEARS); myMakeExprDateTime(&Cert.NotAfter, +10, ENUM_PERIOD_YEARS); } else { // Generate 1 year V1 user cert, that expired at least a year ago myMakeExprDateTime(&Cert.NotBefore, -2, ENUM_PERIOD_YEARS); myMakeExprDateTime(&Cert.NotAfter, -1, ENUM_PERIOD_YEARS); } // SUBJECT: Cert.Subject = *pSubject; // Structure assignment Cert.SubjectPublicKeyInfo = *pPubKey; // Structure assignment hr = epfEncodeCertAndSign( NULL != hProvSigner? hProvSigner : hProv, NULL != pccSigner? &pccSigner->pCertInfo->SubjectPublicKeyInfo : &Cert.SubjectPublicKeyInfo, &Cert, pszAlgId, &pbEncoded, &cbEncoded); _JumpIfError(hr, error, "EncodeCertAndSign"); CSASSERT(NULL != pbEncoded); *ppCert = CertCreateCertificateContext( X509_ASN_ENCODING, pbEncoded, cbEncoded); if (NULL == *ppCert) { hr = myHLastError(); _JumpError(hr, error, "CertCreateCertificateContext"); } *phProv = hProv; hProv = NULL; error: if (NULL != hProv) { CryptReleaseContext(hProv, 0); } if (NULL != pbEncoded) { LocalFree(pbEncoded); } if (NULL != pPubKey) { LocalFree(pPubKey); } if (NULL != pbPubKeyNew) { LocalFree(pbPubKeyNew); } return(hr); } HRESULT epfBuildV1Certs( IN CERT_CONTEXT const *pccUserV1, OUT CERT_CONTEXT const **ppccSigV1, OUT HCRYPTPROV *phProvSigV1, OUT CERT_CONTEXT const **ppccCAV1) { HRESULT hr; CERT_CONTEXT const *pccCAV1 = NULL; CERT_CONTEXT const *pccSigV1 = NULL; HCRYPTPROV hProvCA = NULL; HCRYPTPROV hProvSig = NULL; *ppccSigV1 = NULL; *phProvSigV1 = NULL; *ppccCAV1 = NULL; hr = epfEncodeV1Cert( NULL, // hProvSigner NULL, // pccSigner &pccUserV1->pCertInfo->SerialNumber, &pccUserV1->pCertInfo->Issuer, &pccUserV1->pCertInfo->Issuer, &hProvCA, &pccCAV1); _JumpIfError(hr, error, "epfEncodeV1Cert"); hr = epfEncodeV1Cert( hProvCA, pccCAV1, // pccSigner &pccUserV1->pCertInfo->SerialNumber, &pccUserV1->pCertInfo->Issuer, &pccUserV1->pCertInfo->Subject, &hProvSig, &pccSigV1); _JumpIfError(hr, error, "epfEncodeV1Cert"); CSASSERT(NULL != hProvSig); CSASSERT(NULL != pccSigV1); CSASSERT(NULL != pccCAV1); *phProvSigV1 = hProvSig; hProvSig = NULL; *ppccSigV1 = pccSigV1; pccSigV1 = NULL; *ppccCAV1 = pccCAV1; pccCAV1 = NULL; error: if (NULL != hProvCA) { CryptReleaseContext(hProvCA, 0); } if (NULL != hProvSig) { CryptReleaseContext(hProvSig, 0); } if (NULL != pccCAV1) { CertFreeCertificateContext(pccCAV1); } if (NULL != pccSigV1) { CertFreeCertificateContext(pccSigV1); } return(hr); } WCHAR const * epfLoadResource( IN UINT ids, IN WCHAR const *pwszStatic) { WCHAR const *pwsz = myLoadResourceString(ids); if (NULL == pwsz) { pwsz = pwszStatic; } return(pwsz); } HRESULT cuInfDumpProtectedStoreValue( IN HINF hInf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN WCHAR const *pwszSectionAndKey, IN BOOL fDump, OPTIONAL IN EPF_SYM_KEY_STRUCT const *psKey, IN HRESULT hrQuiet) { HRESULT hr; BYTE *pbStore = NULL; DWORD cbStore; if (NULL == psKey) { hr = cuInfDumpValue( hInf, pwszSection, pwszKey, 1, // Index TRUE, // fLastValue hrQuiet, &pbStore, &cbStore); _PrintIfErrorStr(hr, "cuInfDumpValue", pwszSectionAndKey); } else { hr = cuInfDumpProtectedValue( hInf, pwszSection, pwszKey, psKey, hrQuiet, &pbStore, &cbStore); _PrintIfErrorStr(hr, "cuInfDumpProtectedValue", pwszSectionAndKey); } wprintf(wszNewLine); if (fDump) { wprintf(s_wszHeader); wprintf(L"[%ws] ", pwszSection); } wprintf(L"%ws:\n", pwszKey); if (NULL != pbStore) { if (1 < g_fVerbose) { DumpHex(DH_NOTABPREFIX | 4, pbStore, cbStore); } DumpHex( DH_NOTABPREFIX | 4, pbStore, cbStore); hr = DumpSerializedCertStore(pbStore, cbStore); _JumpIfError(hr, error, "DumpSerializedCertStore"); } hr = S_OK; error: if (NULL != pbStore) { LocalFree(pbStore); } return(hr); } HRESULT cuDumpAsnAlgorithm( IN BYTE const *pbIn, IN DWORD cbIn) { HRESULT hr; CRYPT_SEQUENCE_OF_ANY *pSeqAlg = NULL; char *pszObjId = NULL; DWORD cb; CRYPT_ALGORITHM_IDENTIFIER Alg; hr = cuDecodeSequence(pbIn, cbIn, 2, &pSeqAlg); _JumpIfError(hr, error, "cuDecodeSequence"); hr = cuDecodeObjId( pSeqAlg->rgValue[0].pbData, pSeqAlg->rgValue[0].cbData, &pszObjId); _JumpIfError(hr, error, "cuDecodeObjId"); Alg.pszObjId = pszObjId; Alg.Parameters = pSeqAlg->rgValue[1]; cuDumpAlgorithm(IDS_SIGNATURE_ALGORITHM, &Alg); error: if (NULL != pszObjId) { LocalFree(pszObjId); } if (NULL != pSeqAlg) { LocalFree(pSeqAlg); } return(hr); } HRESULT cuDumpAsnTime( IN BYTE const *pbIn, IN DWORD cbIn) { HRESULT hr; FILETIME ft; DWORD cb; cb = sizeof(FILETIME); if (!CryptDecodeObject( X509_ASN_ENCODING, X509_CHOICE_OF_TIME, pbIn, cbIn, 0, &ft, &cb)) { hr = myHLastError(); _JumpError(hr, error, "CryptDecodeObject"); } hr = cuDumpFileTime(0, NULL, &ft); _JumpIfError(hr, error, "cuDumpFileTime"); error: return(hr); } HRESULT epfDumpCRLValue( IN BYTE const *pbIn, IN DWORD cbIn) { HRESULT hr; CRYPT_SEQUENCE_OF_ANY *pSeqOuter = NULL; CRYPT_SEQUENCE_OF_ANY *pSeqInner = NULL; CRYPT_SEQUENCE_OF_ANY *pSeq04 = NULL; CRYPT_SEQUENCE_OF_ANY *pSeq040 = NULL; CERT_SIGNED_CONTENT_INFO *pcsci = NULL; DWORD cb; DWORD dwVersion; if (SZARRAYSIZE(szPROPASNTAG) < cbIn && 0 == _strnicmp( (char const *) pbIn, szPROPASNTAG, SZARRAYSIZE(szPROPASNTAG))) { pbIn += SZARRAYSIZE(szPROPASNTAG); cbIn -= SZARRAYSIZE(szPROPASNTAG); } if (1 < g_fVerbose) { DumpHex(DH_MULTIADDRESS | DH_NOTABPREFIX | 4, pbIn, cbIn); } // 3 SEQUENCES hr = cuDecodeSequence(pbIn, cbIn, 3, &pSeqOuter); _JumpIfError(hr, error, "cuDecodeSequence"); // Sequence 0: // SEQUENCE { 5 SEQUENCES } hr = cuDecodeSequence( pSeqOuter->rgValue[0].pbData, pSeqOuter->rgValue[0].cbData, 5, &pSeqInner); _JumpIfError(hr, error, "cuDecodeSequence"); // Sequence 0.0: // NAME hr = cuDisplayCertName( TRUE, g_wszEmpty, myLoadResourceString(IDS_ISSUER), // "Issuer" g_wszPad4, &pSeqInner->rgValue[0], NULL); _JumpIfError(hr, error, "cuDisplayCertName(Subject)"); // Sequence 0.1: // DATE cuDumpAsnTime( pSeqInner->rgValue[1].pbData, pSeqInner->rgValue[1].cbData); // Sequence 0.2: // DATE cuDumpAsnTime( pSeqInner->rgValue[2].pbData, pSeqInner->rgValue[2].cbData); // Sequence 0.3: // SEQUENCE { OID, NULL } cuDumpAsnAlgorithm( pSeqInner->rgValue[3].pbData, pSeqInner->rgValue[3].cbData); // Sequence 0.4: // SEQUENCE { SEQUENCE { INTEGER, DATE } } hr = cuDecodeSequence( pSeqInner->rgValue[4].pbData, pSeqInner->rgValue[4].cbData, 1, &pSeq04); _JumpIfError(hr, error, "cuDecodeSequence"); // Sequence 0.4.0: // SEQUENCE { INTEGER, DATE } hr = cuDecodeSequence( pSeq04->rgValue[0].pbData, pSeq04->rgValue[0].cbData, 2, &pSeq040); _JumpIfError(hr, error, "cuDecodeSequence"); // Sequence 0.4.0.0.0: // INTEGER cb = sizeof(dwVersion); if (!CryptDecodeObject( X509_ASN_ENCODING, X509_INTEGER, pSeq040->rgValue[0].pbData, pSeq040->rgValue[0].cbData, 0, &dwVersion, &cb)) { hr = myHLastError(); _JumpError(hr, error, "CryptDecodeObject"); } cuDumpVersion(dwVersion + 1); // Sequence 0.4.0.0.1: // DATE cuDumpAsnTime( pSeqInner->rgValue[2].pbData, pSeqInner->rgValue[2].cbData); // Sequence 1: // SEQUENCE { OID, NULL } (part of signature) // cuDumpAsnAlgorithm( // pSeqOuter->rgValue[1].pbData, // pSeqOuter->rgValue[1].cbData); // Sequence 2: // BITSTRING (part of signature) // pSeqOuter->rgValue[2].pbData // pSeqOuter->rgValue[2].cbData if (!myDecodeObject( X509_ASN_ENCODING, X509_CERT, pbIn, cbIn, CERTLIB_USE_LOCALALLOC, (VOID **) &pcsci, &cb)) { hr = myHLastError(); _JumpError(hr, error, "myDecodeObject"); } cuDumpSignature(pcsci); hr = S_OK; error: if (NULL != pcsci) { LocalFree(pcsci); } if (NULL != pSeq04) { LocalFree(pSeq04); } if (NULL != pSeq040) { LocalFree(pSeq040); } if (NULL != pSeqInner) { LocalFree(pSeqInner); } if (NULL != pSeqOuter) { LocalFree(pSeqOuter); } return(hr); } HRESULT cuInfDumpCRLValue( IN HINF hInf) { HRESULT hr; BYTE *pbCRL0 = NULL; DWORD cbCRL0; BYTE *pbCRL1 = NULL; DWORD cbCRL1; BYTE *pbCRL = NULL; wprintf(wszNewLine); wprintf( L"[%ws] %ws\n", wszINFSECTION_REVOKATIONINFORMATION, wszINFKEY_CRL); hr = cuInfDumpValue( hInf, wszINFSECTION_REVOKATIONINFORMATION, wszINFKEY_CRL, 1, TRUE, S_OK, &pbCRL0, &cbCRL0); _JumpIfErrorStr(hr, error, "cuInfDumpValue", wszINFKEY_CRL); wprintf( L"[%ws] %ws\n", wszINFSECTION_REVOKATIONINFORMATION, wszINFKEY_CRL1); hr = cuInfDumpValue( hInf, wszINFSECTION_REVOKATIONINFORMATION, wszINFKEY_CRL1, 1, TRUE, S_OK, &pbCRL1, &cbCRL1); _JumpIfErrorStr(hr, error, "cuInfDumpValue", wszINFKEY_CRL1); pbCRL = (BYTE *) LocalAlloc(LMEM_FIXED, cbCRL0 + cbCRL1); if (NULL == pbCRL) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(pbCRL, pbCRL0, cbCRL0); CopyMemory(&pbCRL[cbCRL0], pbCRL1, cbCRL1); hr = epfDumpCRLValue(pbCRL, cbCRL0 + cbCRL1); _JumpIfError(hr, error, "epfDumpCRLValue"); error: if (NULL != pbCRL0) { LocalFree(pbCRL0); } if (NULL != pbCRL1) { LocalFree(pbCRL1); } if (NULL != pbCRL) { LocalFree(pbCRL); } return(hr); } HRESULT EPFFileDump( IN WCHAR const *pwszFileName, OPTIONAL IN WCHAR const *pwszPassword, OPTIONAL IN OUT HCERTSTORE hStore) { HRESULT hr; HRESULT hrQuiet; WCHAR *pwszTempFile = NULL; HINF hInf = INVALID_HANDLE_VALUE; DWORD ErrorLine; WCHAR wszPassword[MAX_PATH]; WCHAR *pwszSaltValue = NULL; BYTE *pbToken = NULL; DWORD cbToken; DWORD dw; DWORD dwVersion; DWORD dwKeyCountV2; DWORD dwKeyCount; DWORD dwHashCount; DWORD iKey; BOOL fDump = g_fVerbose || NULL == hStore; HCRYPTPROV hProv = NULL; EPF_SYM_KEY_STRUCT sKey; BYTE *pbCertV1Signing = NULL; DWORD cbCertV1Signing; BYTE *pbKeyV1Signing = NULL; DWORD cbKeyV1Signing; BYTE *pbKeyV1Exchange = NULL; DWORD cbKeyV1Exchange; BYTE *pbCertUser = NULL; DWORD cbCertUser; BYTE *pbCertCA = NULL; DWORD cbCertCA; BYTE *pbCertManager = NULL; DWORD cbCertManager; BYTE *pbCertV1Exchange = NULL; DWORD cbCertV1Exchange; BYTE *pbCertSigning = NULL; DWORD cbCertSigning; BYTE *pbKeySigning = NULL; DWORD cbKeySigning; BYTE *pbCertHistory = NULL; DWORD cbCertHistory; BYTE *pbrgKeyPrivate = NULL; DWORD cbrgKeyPrivate; BYTE *pbCertTrustList = NULL; DWORD cbCertTrustList; BYTE *pbSaltValue = NULL; DWORD cbSaltValue; DWORD dwEPFAlg; DWORD dwSymKeyLen; BOOL f40bit; WCHAR *pwszFriendlyName = NULL; BOOL fQuietOld = g_fQuiet; ZeroMemory(&sKey, sizeof(sKey)); hrQuiet = S_OK; hr = cuPatchEPFFile(pwszFileName, &pwszTempFile); _JumpIfError2(hr, error, "cuPatchEPFFile", S_FALSE); hr = cuGetPassword( 0, // idsPrompt NULL, // pwszfn pwszPassword, FALSE, // fVerify wszPassword, ARRAYSIZE(wszPassword), &pwszPassword); _JumpIfError(hr, error, "cuGetPassword"); hr = myInfOpenFile(pwszTempFile, &hInf, &ErrorLine); _JumpIfError(hr, error, "myInfOpenFile"); if (!CryptAcquireContext( &hProv, NULL, // container name MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { hr = myHLastError(); _JumpError(hr, error, "CryptAcquireContext"); } //================================================================ // wszINFSECTION_USERX500NAME: hr = cuInfDumpDNKeyValue( hInf, wszINFSECTION_USERX500NAME, wszINFKEY_X500NAME, fDump); _JumpIfError(hr, error, "cuInfDumpDNKeyValue"); //================================================================ // wszINFSECTION_PASSWORDTOKEN: hr = cuInfDumpNumericKeyValue( hInf, wszINFSECTION_PASSWORDTOKEN, wszINFKEY_PROTECTION, 1, // Index TRUE, // fLastValue fDump, hrQuiet, &dwSymKeyLen); _JumpIfError(hr, error, "cuInfDumpNumericKeyValue"); hr = cuInfDumpNumericKeyValue( hInf, wszINFSECTION_PASSWORDTOKEN, wszINFKEY_PROFILEVERSION, 1, // Index TRUE, // fLastValue fDump, hrQuiet, &dwVersion); _JumpIfError(hr, error, "cuInfDumpNumericKeyValue"); f40bit = FALSE; switch (dwVersion) { case 2: dwEPFAlg = EPFALG_CAST_MD5; if (40 == dwSymKeyLen) { f40bit = TRUE; } else if (64 == dwSymKeyLen) { } else { wprintf( L"%ws %ws=40 | %ws=64!\n", myLoadResourceString(IDS_EXPECTED), // "Expected" wszINFKEY_PROTECTION, wszINFKEY_PROTECTION); hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "cuInfDumpNumericKeyValue"); } break; case 3: dwEPFAlg = EPFALG_RC2_SHA; if (128 != dwSymKeyLen) { wprintf( L"%ws %ws=128!\n", myLoadResourceString(IDS_EXPECTED), // "Expected" wszINFKEY_PROTECTION); hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "cuInfDumpNumericKeyValue"); } hr = cuInfDumpNumericKeyValue( hInf, wszINFSECTION_PASSWORDTOKEN, wszINFKEY_HASHCOUNT, 1, // Index TRUE, // fLastValue fDump, ERROR_LINE_NOT_FOUND, // hrQuiet &dwHashCount); _PrintIfError2(hr, "cuInfDumpNumericKeyValue", hr); if (S_OK == hr) { dwEPFAlg = EPFALG_3DES; } break; default: wprintf( L"%ws %ws=2 | %ws=3!\n", myLoadResourceString(IDS_EXPECTED), // "Expected" wszINFKEY_PROFILEVERSION, wszINFKEY_PROFILEVERSION); hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "cuInfDumpNumericKeyValue"); } if (EPFALG_CAST_MD5 == dwEPFAlg) { hr = cuInfDumpNumericKeyValue( hInf, wszINFSECTION_PASSWORDTOKEN, wszINFKEY_CAST, 1, // Index TRUE, // fLastValue fDump, hrQuiet, &dw); _JumpIfError(hr, error, "cuInfDumpNumericKeyValue"); if (3 != dw) { wprintf( L"%ws CAST=3!\n", myLoadResourceString(IDS_EXPECTED)); // "Expected" hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "cuInfDumpNumericKeyValue"); } } hr = cuInfDumpHexKeyValue( hInf, wszINFSECTION_PASSWORDTOKEN, wszINFKEY_TOKEN, fDump, &pbToken, &cbToken); _JumpIfError(hr, error, "cuInfDumpHexKeyValue"); hr = cuInfDumpStringKeyValue( hInf, wszINFSECTION_PASSWORDTOKEN, wszINFKEY_SALTVALUE, fDump, hrQuiet, &pwszSaltValue); _JumpIfError(hr, error, "cuInfDumpStringKeyValue"); hr = cuInfDumpNumericKeyValue( hInf, wszINFSECTION_PASSWORDTOKEN, wszINFKEY_HASHSIZE, 1, // Index TRUE, // fLastValue fDump, hrQuiet, &dw); _PrintIfError(hr, "cuInfDumpNumericKeyValue"); //================================================================ // Now we have password, SALT & token -- derive & verify proper type key. // In most cases, cbHashSize is ZERO. Should pull from inf above, though. pbSaltValue = NULL; cbSaltValue = 0; hr = EPFDeriveKey( dwEPFAlg, dwSymKeyLen, hProv, pwszPassword, pwszSaltValue, pbSaltValue, cbSaltValue, 0, // cbHashSize &sKey); _JumpIfError(hr, error, "EPFDeriveKey"); // check pwd via token hr = EPFVerifyKeyToken(&sKey, pbToken, cbToken); if (S_OK != hr) { _PrintError(hr, "EPFVerifyKeyToken"); if (2 > g_fForce || EPFALG_3DES != dwEPFAlg) { goto error; } } //================================================================ // password looks good. Decrypt the EPF file data. if (!g_fVerbose && !fDump) { g_fQuiet = TRUE; } InitCrcTable(); if (2 == dwVersion || EPFALG_3DES == dwEPFAlg) { DWORD dwKeyAlgId; WCHAR const *pwszCertSection; //================================================================ // wszINFSECTION_DIGITALSIGNATURE: hr = cuInfDumpProtectedValue( hInf, wszINFSECTION_DIGITALSIGNATURE, wszINFKEY_CERTIFICATE, &sKey, ERROR_LINE_NOT_FOUND, // hrQuiet &pbCertV1Signing, &cbCertV1Signing); _PrintIfErrorStr( hr, "cuInfDumpProtectedValue", wszSECTION_KEY( dwEPFAlg, wszINFSECTION_DIGITALSIGNATURE, wszINFKEY_CERTIFICATE)); wprintf(wszNewLine); if (fDump) { wprintf(s_wszHeader); wprintf(L"[%ws] ", wszINFSECTION_DIGITALSIGNATURE); } wprintf(L"%ws:\n", wszINFKEY_CERTIFICATE); if (NULL != pbCertV1Signing) { ExtraAsnBytes(pbCertV1Signing, cbCertV1Signing); hr = cuDumpAsnBinary(pbCertV1Signing, cbCertV1Signing, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); wprintf(wszNewLine); } hr = cuInfDumpProtectedValue( hInf, wszINFSECTION_DIGITALSIGNATURE, wszINFKEY_KEY, &sKey, NULL == pbCertV1Signing? ERROR_LINE_NOT_FOUND : S_OK, &pbKeyV1Signing, &cbKeyV1Signing); _PrintIfErrorStr( hr, "cuInfDumpProtectedValue", wszSECTION_KEY( dwEPFAlg, wszINFSECTION_DIGITALSIGNATURE, wszINFKEY_KEY)); if (fDump) { wprintf( L"[%ws] %ws:\n", wszINFSECTION_DIGITALSIGNATURE, wszINFKEY_KEY); } // DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 4, pbKeyV1Signing, cbKeyV1Signing); if (NULL != pbCertV1Signing && NULL != pbKeyV1Signing) { hr = VerifyAndSaveOneCertAndKey( hStore, fDump, epfLoadResource(IDS_SIGNING, wszSIGNING), pbCertV1Signing, cbCertV1Signing, pbKeyV1Signing, cbKeyV1Signing, CALG_RSA_SIGN, AT_SIGNATURE); _JumpIfError(hr, error, "VerifyAndSaveOneCertAndKey"); } //================================================================ // wszINFSECTION_PRIVATEKEYS: hr = cuInfDumpNumericKeyValue( hInf, wszINFSECTION_PRIVATEKEYS, wszINFKEY_KEYCOUNT, 1, // Index TRUE, // fLastValue fDump, hrQuiet, &dwKeyCountV2); _JumpIfError(hr, error, "cuInfDumpNumericKeyValue"); pwszCertSection = f40bit? wszINFSECTION_USERCERTIFICATE : (2 == dwVersion? wszINFSECTION_FULLCERTIFICATEHISTORY : wszINFSECTION_CERTIFICATEHISTORY); for (iKey = 0; iKey < dwKeyCountV2; iKey++) { WCHAR wszKey[cwcINFKEY_KEY_FORMATTED]; WCHAR wszName[cwcINFKEY_NAME_FORMATTED]; DWORD dwSerial; WCHAR const *pwszCertKey; pwszCertKey = f40bit? wszINFKEY_CERTIFICATE : wszName; if (NULL != pbCertV1Exchange) { LocalFree(pbCertV1Exchange); pbCertV1Exchange = NULL; } if (NULL != pbKeyV1Exchange) { LocalFree(pbKeyV1Exchange); pbKeyV1Exchange = NULL; } // wszINFSECTION_FULLCERTIFICATEHISTORY (cast) or // wszINFSECTION_CERTIFICATEHISTORY (3des) wsprintf(wszName, wszINFKEY_NAME_FORMAT, iKey + 1); hr = cuInfDumpProtectedValue( hInf, pwszCertSection, pwszCertKey, &sKey, hrQuiet, &pbCertV1Exchange, &cbCertV1Exchange); _JumpIfError(hr, error, "cuInfDumpProtectedValue"); wprintf(wszNewLine); if (fDump) { wprintf(s_wszHeader); } wprintf( L"[%ws] %ws:\n", pwszCertSection, pwszCertKey); ExtraAsnBytes(pbCertV1Exchange, cbCertV1Exchange); hr = cuDumpAsnBinary( pbCertV1Exchange, cbCertV1Exchange, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); wsprintf(wszKey, wszINFKEY_KEY_FORMAT, iKey + 1); hr = cuInfDumpProtectedValue( hInf, wszINFSECTION_PRIVATEKEYS, wszKey, &sKey, hrQuiet, &pbKeyV1Exchange, &cbKeyV1Exchange); _JumpIfError(hr, error, "cuInfDumpProtectedValue"); wprintf(wszNewLine); if (fDump) { wprintf(L"[%ws] %ws:\n", wszINFSECTION_PRIVATEKEYS, wszKey); } if (g_fVerbose) { DumpHex(DH_NOTABPREFIX | DH_PRIVATEDATA | 4, pbKeyV1Exchange, cbKeyV1Exchange); } hr = VerifyAndSaveOneCertAndKey( hStore, fDump, epfLoadResource(IDS_EXCHANGE, wszEXCHANGE), pbCertV1Exchange, cbCertV1Exchange, pbKeyV1Exchange, cbKeyV1Exchange, CALG_RSA_KEYX, AT_KEYEXCHANGE); _JumpIfError(hr, error, "VerifyAndSaveOneCertAndKey"); //================================================================ // wszINFSECTION_CERTIFICATEHISTORY: wsprintf(wszName, wszINFKEY_NAME_FORMAT, iKey + 1); hr = cuInfDumpBinaryNameKeyValue( hInf, wszINFSECTION_CERTIFICATEHISTORY, wszName, 1, // Index FALSE, // fLastValue fDump, hrQuiet); _JumpIfError(hr, error, "cuInfDumpBinaryNameKeyValue"); hr = cuInfDumpNumericKeyValue( hInf, wszINFSECTION_CERTIFICATEHISTORY, wszName, 2, // Index TRUE, // fLastValue fDump, hrQuiet, &dwSerial); _JumpIfError(hr, error, "cuInfDumpNumericKeyValue"); } //================================================================ // wszINFSECTION_USERCERTIFICATE: if (!f40bit) { hr = cuInfDumpProtectedValue( hInf, wszINFSECTION_USERCERTIFICATE, wszINFKEY_CERTIFICATE, &sKey, hrQuiet, &pbCertUser, &cbCertUser); _JumpIfError(hr, error, "cuInfDumpProtectedValue"); wprintf(wszNewLine); if (fDump) { wprintf(s_wszHeader); } wprintf( L"[%ws] %ws:\n", wszINFSECTION_USERCERTIFICATE, wszINFKEY_CERTIFICATE); ExtraAsnBytes(pbCertUser, cbCertUser); hr = cuDumpAsnBinary(pbCertUser, cbCertUser, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); } //================================================================ // wszINFSECTION_CA: hr = cuInfDumpProtectedValue( hInf, wszINFSECTION_CA, wszINFKEY_CERTIFICATE, &sKey, hrQuiet, &pbCertCA, &cbCertCA); _JumpIfError(hr, error, "cuInfDumpProtectedValue"); wprintf(wszNewLine); if (fDump) { wprintf(s_wszHeader); } wprintf( L"[%ws] %ws:\n", wszINFSECTION_CA, wszINFKEY_CERTIFICATE); ExtraAsnBytes(pbCertCA, cbCertCA); hr = cuDumpAsnBinary(pbCertCA, cbCertCA, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); hr = AddCACertToStore(pbCertCA, cbCertCA); _PrintIfError(hr, "AddCACertToStore"); //================================================================ // wszINFSECTION_MANAGER: if (f40bit) { hr = cuInfDumpProtectedValue( hInf, wszINFSECTION_MANAGER, wszINFKEY_CERTIFICATE, &sKey, hrQuiet, &pbCertManager, &cbCertManager); _JumpIfError(hr, error, "cuInfDumpProtectedValue"); wprintf(wszNewLine); if (fDump) { wprintf(s_wszHeader); } wprintf( L"[%ws] %ws:\n", wszINFSECTION_MANAGER, wszINFKEY_CERTIFICATE); ExtraAsnBytes(pbCertManager, cbCertManager); hr = cuDumpAsnBinary(pbCertManager, cbCertManager, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); hr = AddCACertToStore(pbCertManager, cbCertManager); _PrintIfError(hr, "AddCACertToStore"); } //================================================================ // wszINFSECTION_MICROSOFTEXCHANGE: hr = cuInfDumpProtectedStringValue( hInf, wszINFSECTION_MICROSOFTEXCHANGE, wszINFKEY_FRIENDLYNAME, &sKey, fDump, hrQuiet, &pwszFriendlyName); _JumpIfError(hr, error, "cuInfDumpProtectedStringValue"); wprintf( L"[%ws] %ws = %ws\n", wszINFSECTION_MICROSOFTEXCHANGE, wszINFKEY_FRIENDLYNAME, pwszFriendlyName); hr = cuInfDumpProtectedDwordValue( hInf, wszINFSECTION_MICROSOFTEXCHANGE, wszINFKEY_KEYALGID, &sKey, fDump, hrQuiet, &dwKeyAlgId); _JumpIfError(hr, error, "cuInfDumpProtectedDwordValue"); wprintf( L"[%ws] %ws = 0x%x\n", wszINFSECTION_MICROSOFTEXCHANGE, wszINFKEY_KEYALGID, dwKeyAlgId); } if (f40bit) { if (fDump) { hr = cuInfDumpCRLValue(hInf); _PrintIfError(hr, "cuInfDumpCRLValue"); } } else { //================================================================ // wszINFSECTION_SMIME: hr = cuInfDumpNumericKeyValue( hInf, wszINFSECTION_SMIME, wszINFKEY_KEYCOUNT, 1, // Index TRUE, // fLastValue fDump, ERROR_LINE_NOT_FOUND, // hrQuiet &dwKeyCount); if (S_OK != hr) { dwKeyCount = 0; hrQuiet = ERROR_LINE_NOT_FOUND; _PrintErrorStr( hr, "cuInfDumpProtectedValue", wszSECTION_KEY( dwEPFAlg, wszINFSECTION_SMIME, wszINFKEY_KEYCOUNT)); } hr = cuInfDumpProtectedValue( hInf, wszINFSECTION_SMIME, wszINFKEY_SIGNINGCERTIFICATE, &sKey, ERROR_LINE_NOT_FOUND, // hrQuiet &pbCertSigning, &cbCertSigning); _PrintIfErrorStr( hr, "cuInfDumpProtectedValue", wszSECTION_KEY( dwEPFAlg, wszINFSECTION_SMIME, wszINFKEY_SIGNINGCERTIFICATE)); wprintf(wszNewLine); if (fDump) { wprintf(s_wszHeader); wprintf(L"[%ws] ", wszINFSECTION_SMIME); } wprintf(L"%ws:\n", wszINFKEY_SIGNINGCERTIFICATE); if (NULL != pbCertSigning) { ExtraAsnBytes(pbCertSigning, cbCertSigning); hr = cuDumpAsnBinary(pbCertSigning, cbCertSigning, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); hr = cuInfDumpProtectedValue( hInf, wszINFSECTION_SMIME, wszINFKEY_SIGNINGKEY, &sKey, hrQuiet, &pbKeySigning, &cbKeySigning); _JumpIfError(hr, error, "cuInfDumpProtectedValue"); if (fDump) { wprintf(L"[%ws] %ws:\n", wszINFSECTION_SMIME, wszINFKEY_SIGNINGKEY); } hr = VerifyAndSaveCertAndKey( hStore, fDump, epfLoadResource(IDS_SIGNING, wszSIGNING), pbCertSigning, cbCertSigning, pbKeySigning, cbKeySigning, 1, // cKey CALG_RSA_SIGN, AT_SIGNATURE); if (S_OK != hr) { _PrintErrorStr( hr, "VerifyAndSaveCertAndKey", wszSECTION_KEY( dwEPFAlg, wszINFSECTION_SMIME, wszINFKEY_SIGNINGKEY)); if (NULL != hStore) { goto error; } } } if (fDump) { wprintf(L"[%ws] %ws:\n", wszINFSECTION_SMIME, wszINFKEY_PRIVATEKEYS); } hr = cuInfDumpProtectedValue( hInf, wszINFSECTION_SMIME, wszINFKEY_PRIVATEKEYS, &sKey, hrQuiet, &pbrgKeyPrivate, &cbrgKeyPrivate); if (0 != dwKeyCount) { _JumpIfError(hr, error, "cuInfDumpProtectedValue"); } //================================================================ // wszINFSECTION_FULLCERTIFICATEHISTORY: for (iKey = 0; iKey < dwKeyCount; iKey++) { WCHAR wszSMIME[cwcINFKEY_SMIME_FORMATTED]; wsprintf(wszSMIME, wszINFKEY_SMIME_FORMAT, iKey + 1); hr = cuInfDumpProtectedValue( hInf, wszINFSECTION_FULLCERTIFICATEHISTORY, wszSMIME, &sKey, hrQuiet, &pbCertHistory, &cbCertHistory); _JumpIfError(hr, error, "cuInfDumpProtectedValue"); wprintf(wszNewLine); if (fDump) { wprintf(s_wszHeader); } wprintf( L"[%ws] %ws:\n", wszINFSECTION_FULLCERTIFICATEHISTORY, wszSMIME); ExtraAsnBytes(pbCertHistory, cbCertHistory); hr = cuDumpAsnBinary(pbCertHistory, cbCertHistory, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); hr = VerifyAndSaveCertAndKey( hStore, fDump, epfLoadResource(IDS_EXCHANGE, wszEXCHANGE), pbCertHistory, cbCertHistory, pbrgKeyPrivate, cbrgKeyPrivate, dwKeyCount, CALG_RSA_KEYX, AT_KEYEXCHANGE); if (S_OK != hr) { _PrintErrorStr( hr, "VerifyAndSaveCertAndKey", wszSECTION_KEY( dwEPFAlg, wszINFSECTION_SMIME, wszINFKEY_PRIVATEKEYS)); if (NULL != hStore) { goto error; } } LocalFree(pbCertHistory); pbCertHistory = NULL; } hr = cuInfDumpProtectedStoreValue( hInf, wszINFSECTION_SMIME, wszINFKEY_ISSUINGCERTIFICATES, wszSECTION_KEY( dwEPFAlg, wszINFSECTION_SMIME, wszINFKEY_ISSUINGCERTIFICATES), fDump, &sKey, hrQuiet); _PrintIfErrorStr( hr, "cuInfDumpProtectedStoreValue", wszSECTION_KEY( dwEPFAlg, wszINFSECTION_SMIME, wszINFKEY_ISSUINGCERTIFICATES)); hr = cuInfDumpProtectedValue( hInf, wszINFSECTION_SMIME, wszINFKEY_TRUSTLISTCERTIFICATE, &sKey, hrQuiet, &pbCertTrustList, &cbCertTrustList); _PrintIfErrorStr( hr, "cuInfDumpProtectedValue", wszSECTION_KEY( dwEPFAlg, wszINFSECTION_SMIME, wszINFKEY_TRUSTLISTCERTIFICATE)); wprintf(wszNewLine); if (fDump) { wprintf(s_wszHeader); wprintf(L"[%ws] ", wszINFSECTION_SMIME); } wprintf(L"%ws:\n", wszINFKEY_TRUSTLISTCERTIFICATE); if (NULL != pbCertTrustList) { ExtraAsnBytes(pbCertTrustList, cbCertTrustList); hr = cuDumpAsnBinary(pbCertTrustList, cbCertTrustList, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); hr = AddCACertToStore(pbCertTrustList, cbCertTrustList); _PrintIfError(hr, "AddCACertToStore"); } } wprintf(wszNewLine); hr = S_OK; error: SecureZeroMemory(wszPassword, sizeof(wszPassword)); // password data if (NULL != pwszSaltValue) { LocalFree(pwszSaltValue); } if (NULL != pbCertV1Signing) { LocalFree(pbCertV1Signing); } if (NULL != pbKeyV1Exchange) { SecureZeroMemory(pbKeyV1Exchange, cbKeyV1Exchange); // Key material LocalFree(pbKeyV1Exchange); } if (NULL != pbKeyV1Signing) { SecureZeroMemory(pbKeyV1Signing, cbKeyV1Signing); // Key material LocalFree(pbKeyV1Signing); } if (NULL != pbCertUser) { LocalFree(pbCertUser); } if (NULL != pbCertCA) { LocalFree(pbCertCA); } if (NULL != pbCertManager) { LocalFree(pbCertManager); } if (NULL != pbCertV1Exchange) { LocalFree(pbCertV1Exchange); } if (NULL != pbCertSigning) { LocalFree(pbCertSigning); } if (NULL != pbKeySigning) { SecureZeroMemory(pbKeySigning, cbKeySigning); // Key material LocalFree(pbKeySigning); } if (NULL != pbCertHistory) { LocalFree(pbCertHistory); } if (NULL != pbrgKeyPrivate) { SecureZeroMemory(pbrgKeyPrivate, cbrgKeyPrivate); // Key material LocalFree(pbrgKeyPrivate); } if (NULL != pbCertTrustList) { LocalFree(pbCertTrustList); } if (NULL != pwszFriendlyName) { LocalFree(pwszFriendlyName); } if (NULL != pbToken) { LocalFree(pbToken); } if (NULL != pbSaltValue) { LocalFree(pbSaltValue); } if (NULL != sKey.hKey) { CryptDestroyKey(sKey.hKey); } CAST3Cleanup(&sKey.sCastContext); if (NULL != hProv) { CryptReleaseContext(hProv, 0); } if (INVALID_HANDLE_VALUE != hInf) { myInfCloseFile(hInf); } if (NULL != pwszTempFile) { if (!g_fSplitASN) { DeleteFile(pwszTempFile); } LocalFree(pwszTempFile); } g_fQuiet = fQuietOld; return(hr); } VOID FreeCertList( IN CERT_CONTEXT const **ppcc, IN DWORD ccc) { DWORD i; if (NULL != ppcc) { for (i = 0; i < ccc; i++) { if (NULL != ppcc[i]) { CertFreeCertificateContext(ppcc[i]); } } LocalFree(ppcc); } } int _cdecl fnEPFCertSort( IN VOID const *pvpcc1, IN VOID const *pvpcc2) { CERT_CONTEXT const *pcc1 = *(CERT_CONTEXT const **) pvpcc1; CERT_CONTEXT const *pcc2 = *(CERT_CONTEXT const **) pvpcc2; BYTE abHash1[CBMAX_CRYPT_HASH_LEN]; DWORD cbHash1; BYTE abHash2[CBMAX_CRYPT_HASH_LEN]; DWORD cbHash2; int r = 0; #define IHASH 5 cbHash1 = sizeof(abHash1); if (CertGetCertificateContextProperty( pcc1, CERT_SHA1_HASH_PROP_ID, abHash1, &cbHash1) && CertGetCertificateContextProperty( pcc2, CERT_SHA1_HASH_PROP_ID, abHash2, &cbHash2)) { r = abHash1[5] - abHash2[5]; } if (0 == r) { r = CompareFileTime( &pcc1->pCertInfo->NotBefore, &pcc2->pCertInfo->NotBefore); } return(r); } #define ICC_V1SIGNING 0 #define ICC_V1ENCRYPTION 1 #define ICC_V3SIGNING 2 #define ICC_V3ENCRYPTION 3 #define ICC_MAX 4 HRESULT GetCertListFromStore( IN HCERTSTORE hStore, IN DWORD icc, OUT CERT_CONTEXT const ***pppcc, OUT DWORD *pccc) { HRESULT hr; CERT_CONTEXT const *pcc = NULL; CRYPT_KEY_PROV_INFO *pkpi = NULL; DWORD ccc; DWORD i; CERT_CONTEXT const **ppcc = NULL; DWORD dwKeySpec = (ICC_V1SIGNING == icc || ICC_V3SIGNING == icc)? AT_SIGNATURE : AT_KEYEXCHANGE; BOOL fV1 = ICC_V1SIGNING == icc || ICC_V1ENCRYPTION == icc; *pppcc = NULL; ccc = 0; while (TRUE) { if (NULL != pkpi) { LocalFree(pkpi); pkpi = NULL; } pcc = CertEnumCertificatesInStore(hStore, pcc); if (NULL == pcc) { break; } if ((CERT_V1 == pcc->pCertInfo->dwVersion) ^ !fV1) { hr = myCertGetKeyProviderInfo(pcc, &pkpi); _PrintIfError2(hr, "myCertGetKeyProviderInfo", CRYPT_E_NOT_FOUND); if (S_OK == hr && pkpi->dwKeySpec == dwKeySpec) { ccc++; } } } if (0 == ccc) { hr = CRYPT_E_NOT_FOUND; _JumpError2(hr, error, "no certs", hr); } ppcc = (CERT_CONTEXT const **) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, ccc * sizeof(*ppcc)); if (NULL == ppcc) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } i = 0; while (TRUE) { if (NULL != pkpi) { LocalFree(pkpi); pkpi = NULL; } pcc = CertEnumCertificatesInStore(hStore, pcc); if (NULL == pcc) { break; } if ((CERT_V1 == pcc->pCertInfo->dwVersion) ^ !fV1) { hr = myCertGetKeyProviderInfo(pcc, &pkpi); _PrintIfError2(hr, "myCertGetKeyProviderInfo", CRYPT_E_NOT_FOUND); if (S_OK == hr && pkpi->dwKeySpec == dwKeySpec) { ppcc[i] = CertDuplicateCertificateContext(pcc); if (NULL == ppcc[i]) { hr = myHLastError(); _JumpError(hr, error, "CertDuplicateCertificateContext"); } i++; } } } CSASSERT(i == ccc); qsort(ppcc, ccc, sizeof(ppcc[0]), fnEPFCertSort); *pppcc = ppcc; ppcc = NULL; *pccc = ccc; error: FreeCertList(ppcc, ccc); if (NULL != pkpi) { LocalFree(pkpi); } return(hr); } HRESULT GetLowerCaseDNAndCN( IN CERT_CONTEXT const *pcc, OUT CHAR **ppszDN, OUT WCHAR **ppwszCN) { HRESULT hr; WCHAR *pwszDN = NULL; char *pszDN = NULL; DWORD Flags = CERT_X500_NAME_STR; *ppszDN = NULL; *ppwszCN = NULL; if (CERT_V1 == pcc->pCertInfo->dwVersion) { Flags |= CERT_NAME_STR_REVERSE_FLAG; } hr = myCertNameToStr( X509_ASN_ENCODING, &pcc->pCertInfo->Subject, Flags, &pwszDN); _JumpIfError(hr, error, "myCertNameToStr"); if (!myConvertWszToSz(&pszDN, pwszDN, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertWszToSz"); } _strlwr(pszDN); hr = myCertGetNameString(pcc, CERT_NAME_SIMPLE_DISPLAY_TYPE, ppwszCN); _JumpIfError(hr, error, "myCertGetNameString"); *ppszDN = pszDN; pszDN = NULL; error: if (NULL != pwszDN) { LocalFree(pwszDN); } if (NULL != pszDN) { LocalFree(pszDN); } return(hr); } HRESULT EPFCryptBinaryToBase64( IN BYTE const *pbData, IN DWORD cbData, OUT WCHAR **ppwszBase64) { HRESULT hr; WCHAR *pwszSrc; WCHAR *pwszDst; *ppwszBase64 = NULL; hr = myCryptBinaryToString( pbData, cbData, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR, ppwszBase64); _JumpIfError(hr, error, "myCryptBinaryToString"); for (pwszSrc = pwszDst = *ppwszBase64; L'\0' != *pwszSrc; pwszSrc++) { switch (*pwszSrc) { case L'\r': case L'\n': case L'\t': case L' ': break; // skip all whitespace default: *pwszDst++ = *pwszSrc; // copy the rest break; } } *pwszDst = L'\0'; hr = S_OK; error: return(hr); } HRESULT WriteBase64Value( IN FILE *pf, IN WCHAR const *pwszKey, IN WCHAR const *pwszBase64Value, OPTIONAL IN WCHAR const *pwsz2ndValue) { HRESULT hr; WCHAR const *pwszRemain = pwszBase64Value; DWORD cwcRemain = wcslen(pwszBase64Value); CSASSERT(0 != cwcRemain); while (0 != cwcRemain) { DWORD cwcLine; DWORD cwc; WCHAR const *pwsz1 = g_wszEmpty; WCHAR const *pwsz2 = g_wszEmpty; fprintf(pf, "%ws=", pwszKey); cwcLine = 256 - (wcslen(pwszKey) + 1); cwc = min(cwcLine, cwcRemain); if (cwc == cwcRemain && NULL != pwsz2ndValue) { pwsz1 = L","; pwsz2 = pwsz2ndValue; } fprintf( pf, "%.*ws%ws%ws\n", cwc, pwszRemain, pwsz1, pwsz2); cwcRemain -= cwc; pwszRemain += cwc; pwszKey = L"_continue_"; } hr = S_OK; return(hr); } HRESULT WriteIssuerNameAndSerialValue( IN FILE *pf, IN WCHAR const *pwszKey, OPTIONAL IN CERT_CONTEXT const *pccCA, IN CERT_CONTEXT const *pccUser) { HRESULT hr; CERT_NAME_BLOB const *pName; WCHAR *pwszBase64 = NULL; DWORD dwSerial; WCHAR wszSerial[cwcDWORDSPRINTF]; DWORD cb; DWORD cwc; if (NULL != pccCA) { pName = &pccCA->pCertInfo->Subject; } else { pName = &pccUser->pCertInfo->Issuer; } hr = EPFCryptBinaryToBase64(pName->pbData, pName->cbData, &pwszBase64); _JumpIfError(hr, error, "EPFCryptBinaryToBase64"); dwSerial = 0; cb = pccUser->pCertInfo->SerialNumber.cbData; if (cb > sizeof(dwSerial)) { cb = sizeof(dwSerial); } CopyMemory(&dwSerial, pccUser->pCertInfo->SerialNumber.pbData, cb); wsprintf(wszSerial, L"%u", dwSerial); hr = WriteBase64Value(pf, pwszKey, pwszBase64, wszSerial); _JumpIfError(hr, error, "WriteBase64Value"); error: if (NULL != pwszBase64) { LocalFree(pwszBase64); } return(hr); } HRESULT WriteProtectedValue( IN FILE *pf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN EPF_SYM_KEY_STRUCT const *psKey, IN BYTE const *pbData, IN DWORD cbData) { HRESULT hr; DWORD i; CRC16 Crc; WCHAR *pwszProtectedKey = NULL; BYTE *pbHeader = NULL; DWORD cbHeader; BYTE *pbValue = NULL; DWORD cbValue; BYTE *pbEncrypted = NULL; DWORD cbEncrypted; WCHAR *pwszBase64 = NULL; hr = BuildProtectedKey(pwszKey, psKey->dwAlgId, &pwszProtectedKey); _JumpIfError(hr, error, "BuildProtectedKey"); hr = BuildProtectedHeader(pwszSection, pwszKey, &pbHeader, &cbHeader); _JumpIfError(hr, error, "BuildProtectedHeader"); cbValue = sizeof(Crc) + cbHeader + cbData; pbValue = (BYTE *) LocalAlloc(LMEM_FIXED, cbValue); if (NULL == pbValue) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertWszToSz"); } CopyMemory(&pbValue[sizeof(Crc)], pbHeader, cbHeader); CopyMemory(&pbValue[sizeof(Crc) + cbHeader], pbData, cbData); // Calculate the CRC Crc = 0xffff; F_CRC16(g_CrcTable, &Crc, &pbValue[sizeof(Crc)], cbHeader + cbData); _swab((char *) &Crc, (char *) pbValue, sizeof(Crc)); hr = EPFEncryptSection( psKey, pbValue, cbValue, &pbEncrypted, &cbEncrypted); _JumpIfError(hr, error, "EPFEncryptSection"); hr = EPFCryptBinaryToBase64(pbEncrypted, cbEncrypted, &pwszBase64); _JumpIfError(hr, error, "EPFCryptBinaryToBase64"); hr = WriteBase64Value(pf, pwszProtectedKey, pwszBase64, NULL); _JumpIfError(hr, error, "WriteBase64Value"); error: if (NULL != pwszProtectedKey) { LocalFree(pwszProtectedKey); } if (NULL != pbHeader) { SecureZeroMemory(pbValue, cbValue); // possible private key material LocalFree(pbHeader); } if (NULL != pbValue) { LocalFree(pbValue); } if (NULL != pbEncrypted) { LocalFree(pbEncrypted); } if (NULL != pwszBase64) { LocalFree(pwszBase64); } return(hr); } HRESULT WriteProtectedStringValue( IN FILE *pf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN EPF_SYM_KEY_STRUCT const *psKey, IN WCHAR const *pwszValue) { HRESULT hr; char *pszValue = NULL; if (!myConvertWszToSz(&pszValue, pwszValue, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertWszToSz"); } hr = WriteProtectedValue( pf, pwszSection, pwszKey, psKey, (BYTE const *) pszValue, strlen(pszValue)); _JumpIfError(hr, error, "WriteProtectedValue"); error: if (NULL != pszValue) { LocalFree(pszValue); } return(hr); } HRESULT WriteProtectedDwordValue( IN FILE *pf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN EPF_SYM_KEY_STRUCT const *psKey, IN DWORD dwValue) { HRESULT hr; hr = WriteProtectedValue( pf, pwszSection, pwszKey, psKey, (BYTE const *) &dwValue, sizeof(dwValue)); _JumpIfError(hr, error, "WriteProtectedValue"); error: return(hr); } HRESULT LoadKMSRSAKeyFromCert( IN CERT_CONTEXT const *pcc, OPTIONAL IN HCRYPTPROV hProv, IN DWORD dwKeySpec, OUT BYTE **ppbKey, OUT DWORD *pcbKey, OPTIONAL OUT CERT_PUBLIC_KEY_INFO **ppPublicKeyInfo) { HRESULT hr; HCRYPTPROV hProvT = NULL; HCRYPTKEY hKeyPrivate = NULL; CRYPT_BIT_BLOB PrivateKey; CERT_PUBLIC_KEY_INFO *pPublicKeyInfo = NULL; DWORD cb; ZeroMemory(&PrivateKey, sizeof(PrivateKey)); *ppbKey = NULL; if (NULL != ppPublicKeyInfo) { *ppPublicKeyInfo = NULL; } if (NULL == hProv) { DWORD dwKeySpecT; if (!CryptAcquireCertificatePrivateKey( pcc, 0, // dwFlags NULL, // pvReserved &hProvT, &dwKeySpecT, NULL)) // pfCallerFreeProv { hr = myHLastError(); _JumpError(hr, error, "CryptAcquireCertificatePrivateKey"); } if (dwKeySpec != dwKeySpecT) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "dwKeySpec mismatch"); } hProv = hProvT; } if (!CryptGetUserKey(hProv, dwKeySpec, &hKeyPrivate)) { hr = myHLastError(); _JumpError(hr, error, "CryptGetUserKey"); } hr = myCryptExportPrivateKey( hKeyPrivate, &PrivateKey.pbData, &PrivateKey.cbData); _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 == pcc->pCertInfo->dwVersion, pPublicKeyInfo, &pcc->pCertInfo->SubjectPublicKeyInfo)) { // by design, (my)CertComparePublicKeyInfo doesn't set last error! hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "public key mismatch"); } hr = myEncodeKMSRSAKey( PrivateKey.pbData, PrivateKey.cbData, ppbKey, pcbKey); _JumpIfError(hr, error, "myEncodeKMSRSAKey"); if (NULL != ppPublicKeyInfo) { *ppPublicKeyInfo = pPublicKeyInfo; pPublicKeyInfo = NULL; } error: if (NULL != PrivateKey.pbData) { SecureZeroMemory(PrivateKey.pbData, PrivateKey.cbData); // Key material LocalFree(PrivateKey.pbData); } if (NULL != pPublicKeyInfo) { LocalFree(pPublicKeyInfo); } if (NULL != hKeyPrivate) { CryptDestroyKey(hKeyPrivate); } if (NULL != hProvT) { CryptReleaseContext(hProvT, 0); } return(hr); } HRESULT WriteSingleEPFKeyValue( IN FILE *pf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN EPF_SYM_KEY_STRUCT const *psKey, IN CERT_CONTEXT const *pcc, IN ALG_ID aiKeyAlg, IN DWORD dwKeySpec, IN DWORD dwKMSKeySpec) { HRESULT hr; CERT_PUBLIC_KEY_INFO *pPublicKeyInfo = NULL; BYTE *pbKMSRSAKey = NULL; DWORD cbKMSRSAKey; BYTE *pbPubKey = NULL; DWORD cbPubKey; BYTE *pbEPFKey = NULL; DWORD cbEPFKey; ExchangeKeyBlobEx ekb; OneKeyBlob okb; hr = LoadKMSRSAKeyFromCert( pcc, NULL, // hProv dwKeySpec, &pbKMSRSAKey, &cbKMSRSAKey, &pPublicKeyInfo); _JumpIfError(hr, error, "LoadKMSRSAKeyFromCert"); ekb.dwSize = CBEKB; ekb.cKeys = 1; ekb.dwKeyAlg = aiKeyAlg; ZeroMemory(&okb, sizeof(okb)); okb.dwKeySpec = dwKMSKeySpec; okb.cbPrivKey = cbKMSRSAKey; okb.obPrivKey = CBEKB + sizeof(okb); if (AT_SIGNATURE == dwKeySpec) { // If this is a valid public key with a proper leading zero byte before // the sign bit set in the next public key byte, remove the zero byte // and decrement the lengths. This conforms with the old incorrect V1 // public key encoding used in EPF files. hr = mySqueezePublicKey( pPublicKeyInfo->PublicKey.pbData, pPublicKeyInfo->PublicKey.cbData, &pbPubKey, &cbPubKey); _JumpIfError(hr, error, "mySqueezePublicKey"); okb.cbPubKey = cbPubKey; okb.obPubKey = okb.obPrivKey + cbKMSRSAKey; } cbEPFKey = okb.obPrivKey + okb.cbPrivKey + okb.cbPubKey; pbEPFKey = (BYTE *) LocalAlloc(LMEM_FIXED, cbEPFKey); if (NULL == pbEPFKey) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } CopyMemory(pbEPFKey, &ekb, CBEKB); CopyMemory(&pbEPFKey[CBEKB], &okb, sizeof(okb)); CopyMemory(&pbEPFKey[okb.obPrivKey], pbKMSRSAKey, cbKMSRSAKey); if (0 != okb.cbPubKey) { CopyMemory(&pbEPFKey[okb.obPubKey], pbPubKey, okb.cbPubKey); if (g_fVerbose) { wprintf(myLoadResourceString(IDS_CERT_PUBLIC_KEY_COLON)); // "Cert Public key:" wprintf(wszNewLine); DumpHex( DH_NOTABPREFIX | 4, pcc->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData, pcc->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData); wprintf(myLoadResourceString(IDS_PUBLIC_KEY_COLON)); // "Public key:" wprintf(wszNewLine); DumpHex( DH_NOTABPREFIX | 4, &pbEPFKey[okb.obPubKey], okb.cbPubKey); } } hr = WriteProtectedValue( pf, pwszSection, pwszKey, psKey, pbEPFKey, cbEPFKey); _JumpIfError(hr, error, "WriteProtectedValue"); error: if (NULL != pbEPFKey) { SecureZeroMemory(pbEPFKey, cbEPFKey); // Key material LocalFree(pbEPFKey); } if (NULL != pbPubKey) { LocalFree(pbPubKey); } if (NULL != pbKMSRSAKey) { SecureZeroMemory(pbKMSRSAKey, cbKMSRSAKey); // Key material LocalFree(pbKMSRSAKey); } if (NULL != pPublicKeyInfo) { LocalFree(pPublicKeyInfo); } return(hr); } HRESULT WriteSingleKMSRSAKeyValue( IN FILE *pf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN EPF_SYM_KEY_STRUCT const *psKey, IN CERT_CONTEXT const *pcc, OPTIONAL IN HCRYPTPROV hProv, IN ALG_ID aiKeyAlg, IN DWORD dwKeySpec, IN DWORD dwKMSKeySpec) { HRESULT hr; CERT_PUBLIC_KEY_INFO *pPublicKeyInfo = NULL; BYTE *pbKMSRSAKey = NULL; DWORD cbKMSRSAKey; hr = LoadKMSRSAKeyFromCert( pcc, hProv, dwKeySpec, &pbKMSRSAKey, &cbKMSRSAKey, &pPublicKeyInfo); _JumpIfError(hr, error, "LoadKMSRSAKeyFromCert"); hr = WriteProtectedValue( pf, pwszSection, pwszKey, psKey, pbKMSRSAKey, cbKMSRSAKey); _JumpIfError(hr, error, "WriteProtectedValue"); error: if (NULL != pbKMSRSAKey) { SecureZeroMemory(pbKMSRSAKey, cbKMSRSAKey); // Key material LocalFree(pbKMSRSAKey); } if (NULL != pPublicKeyInfo) { LocalFree(pPublicKeyInfo); } return(hr); } HRESULT WriteEncryptionKeysValue( IN FILE *pf, IN WCHAR const *pwszSection, IN WCHAR const *pwszKey, IN EPF_SYM_KEY_STRUCT const *psKey, IN DWORD cccV1, IN CERT_CONTEXT const **rgpccV1, IN DWORD cccV3, IN CERT_CONTEXT const **rgpccV3) { HRESULT hr; DWORD i; DWORD iKey; ExchangeKeyBlobEx ekb; BYTE *pbKeyData = NULL; DWORD cbKeyData; BYTE *pb; OneKeyBlob okb; CRYPT_DATA_BLOB *prgBlob = NULL; ekb.dwSize = CBEKB; ekb.cKeys = cccV1 + cccV3; ekb.dwKeyAlg = CALG_RSA_KEYX; if (0 != ekb.cKeys) { prgBlob = (CRYPT_DATA_BLOB *) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, ekb.cKeys * sizeof(*prgBlob)); if (NULL == prgBlob) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } iKey = 0; for (i = 0; i < cccV1; i++) { hr = LoadKMSRSAKeyFromCert( rgpccV1[i], NULL, // hProv AT_KEYEXCHANGE, &prgBlob[iKey].pbData, &prgBlob[iKey].cbData, NULL); _JumpIfError(hr, error, "LoadKMSRSAKeyFromCert"); iKey++; } for (i = 0; i < cccV3; i++) { hr = LoadKMSRSAKeyFromCert( rgpccV3[i], NULL, // hProv AT_KEYEXCHANGE, &prgBlob[iKey].pbData, &prgBlob[iKey].cbData, NULL); _JumpIfError(hr, error, "LoadKMSRSAKeyFromCert"); iKey++; } cbKeyData = CBEKB + ekb.cKeys * sizeof(okb); for (iKey = 0; iKey < ekb.cKeys; iKey++) { cbKeyData += prgBlob[iKey].cbData; } pbKeyData = (BYTE *) LocalAlloc(LMEM_FIXED, cbKeyData); if (NULL == pbKeyData) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } pb = pbKeyData; CopyMemory(pb, &ekb, CBEKB); pb += CBEKB; ZeroMemory(&okb, sizeof(okb)); okb.dwKeySpec = dwKEYSPEC_V1ENCRYPTION_BASE; okb.obPrivKey = CBEKB + ekb.cKeys * sizeof(okb); for (iKey = 0; iKey < ekb.cKeys; iKey++) { if (iKey == cccV1) { okb.dwKeySpec = dwKEYSPEC_V3ENCRYPTION_BASE; } okb.cbPrivKey = prgBlob[iKey].cbData; CopyMemory(pb, &okb, sizeof(okb)); CopyMemory( &pbKeyData[okb.obPrivKey], prgBlob[iKey].pbData, okb.cbPrivKey); pb += sizeof(okb); okb.dwKeySpec++; okb.obPrivKey += okb.cbPrivKey; } CSASSERT(pb == &pbKeyData[CBEKB + ekb.cKeys * sizeof(okb)]); CSASSERT(okb.obPrivKey == cbKeyData); hr = WriteProtectedValue( pf, pwszSection, pwszKey, psKey, pbKeyData, cbKeyData); _JumpIfError(hr, error, "WriteProtectedValue"); } hr = S_OK; error: if (NULL != prgBlob) { for (iKey = 0; iKey < ekb.cKeys; iKey++) { if (NULL != prgBlob[iKey].pbData) { SecureZeroMemory(prgBlob[iKey].pbData, prgBlob[iKey].cbData); // Key material LocalFree(prgBlob[iKey].pbData); } } LocalFree(prgBlob); } if (NULL != pbKeyData) { SecureZeroMemory(pbKeyData, cbKeyData); // Key material LocalFree(pbKeyData); } return(hr); } #define wszDSKCCSTATUSATTRIBUTE L"kCCStatus" WCHAR *s_apwszAttrs[] = { wszDSDNATTRIBUTE, // full DS DN wszDSOBJECTCLASSATTRIBUTE, // object Class CERTTYPE_PROP_CN, // DS CN wszDSBASECRLATTRIBUTE, // rearranged CRL wszDSCROSSCERTPAIRATTRIBUTE, // CTL certs? L"teletexTerminalIdentifier", // proper CRL wszDSKCCSTATUSATTRIBUTE, // CTL? NULL }; BOOL s_afString[] = { TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, }; #define ISEMPTYATTR(pberval) \ (0 == (pberval)->bv_len || \ (1 == (pberval)->bv_len && 0 == *(BYTE const *) (pberval)->bv_val)) HRESULT epfParseCTL( IN BYTE const *pbCTL, IN DWORD cbCTL, IN BYTE const *pbHash, IN DWORD cbHash, OUT CTL_CONTEXT const **ppCTL) { HRESULT hr; CTL_CONTEXT const *pCTL = NULL; DWORD i; *ppCTL = NULL; if (g_fSplitASN) { hr = cuDumpAsnBinary(pbCTL, cbCTL, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); } pCTL = CertCreateCTLContext(X509_ASN_ENCODING, pbCTL, cbCTL); if (NULL == pCTL) { hr = myHLastError(); _JumpError(hr, error, "CertCreateCTLContext"); } hr = CRYPT_E_NOT_FOUND; for (i = 0; i < pCTL->pCtlInfo->cCTLEntry; i++) { CTL_ENTRY const *pCTLEntry = &pCTL->pCtlInfo->rgCTLEntry[i]; if (cbHash == pCTLEntry->SubjectIdentifier.cbData && 0 == memcmp( pbHash, pCTLEntry->SubjectIdentifier.pbData, cbHash)) { hr = S_OK; *ppCTL = pCTL; pCTL = NULL; break; } } _JumpIfError(hr, error, "memcmp"); error: if (NULL != pCTL) { CertFreeCTLContext(pCTL); } return(hr); } HRESULT epfGetOneKMSDSCTL( IN WCHAR const *pwszDN, IN BYTE const *pbHash, IN DWORD cbHash, OUT CTL_CONTEXT const **ppCTL); HRESULT epfGetCTLFromSearchResult( IN LDAP *pld, IN LDAPMessage *pSearchResult, IN BOOL fGC, IN BYTE const *pbHash, IN DWORD cbHash, OUT CTL_CONTEXT const **ppCTL) { HRESULT hr; DWORD cres; LDAPMessage *pres; WCHAR **ppwszValues = NULL; DWORD ires; BOOL fIssuerFound = FALSE; *ppCTL = NULL; cres = ldap_count_entries(pld, pSearchResult); if (0 == cres) { hr = HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT); _JumpError(hr, error, "ldap_count_entries"); } for (ires = 0, pres = ldap_first_entry(pld, pSearchResult); NULL != pres; ires++, pres = ldap_next_entry(pld, pres)) { DWORD iAttr; wprintf(s_wszHeader); //wprintf(L"Result[%u]:\n", ires); for (iAttr = 0; NULL != s_apwszAttrs[iAttr]; iAttr++) { DWORD iVal; if (s_afString[iAttr]) { WCHAR **rgpwszval = NULL; rgpwszval = ldap_get_values(pld, pres, s_apwszAttrs[iAttr]); if (NULL != rgpwszval) { //wprintf(L"%ws:\n", s_apwszAttrs[iAttr]); for (iVal = 0; NULL != rgpwszval[iVal]; iVal++) { if (0 == LSTRCMPIS( s_apwszAttrs[iAttr], wszDSDNATTRIBUTE)) { wprintf(L" %ws\n", rgpwszval[iVal]); if (fGC) { hr = epfGetOneKMSDSCTL( rgpwszval[iVal], pbHash, cbHash, ppCTL); _PrintIfError(hr, "epfGetOneKMSDSCTL"); } } } if (NULL != rgpwszval) { ldap_value_free(rgpwszval); } //wprintf(wszNewLine); } else { //wprintf(L"%ws: EMPTY string value\n", s_apwszAttrs[iAttr]); } } else { berval **rgpberval; rgpberval = ldap_get_values_len(pld, pres, s_apwszAttrs[iAttr]); if (NULL != rgpberval) { if (g_fVerbose) { wprintf(L"%ws:\n", s_apwszAttrs[iAttr]); } for (iVal = 0; NULL != rgpberval[iVal]; iVal++) { BOOL fEmpty = ISEMPTYATTR(rgpberval[iVal]); BYTE const *pb = (BYTE const *) rgpberval[iVal]->bv_val; DWORD cb = rgpberval[iVal]->bv_len; #if 0 wprintf( L" %ws[%u]: pb=%x cb=%x\n", s_apwszAttrs[iAttr], iVal, pb, cb); #endif if (g_fVerbose) { hr = cuDumpAsnBinary(pb, cb, iVal); _PrintIfError(hr, "cuDumpAsnBinary"); } //DumpHex(DH_NOTABPREFIX | 4, pb, cb); if (!fIssuerFound && 0 == LSTRCMPIS( s_apwszAttrs[iAttr], wszDSKCCSTATUSATTRIBUTE)) { //wprintf(L"epfParseCTL(%ws)\n", s_apwszAttrs[iAttr]); //DumpHex(DH_NOTABPREFIX | 4, pb, cb); hr = epfParseCTL( pb, cb, pbHash, cbHash, ppCTL); _PrintIfError(hr, "epfAddAsnBlobToStore"); fIssuerFound = S_OK == hr; } } if (NULL != rgpberval) { ldap_value_free_len(rgpberval); } //wprintf(wszNewLine); } else { //wprintf(L"%ws: EMPTY binary value\n", s_apwszAttrs[iAttr]); } } } } hr = fIssuerFound? S_OK : S_FALSE; error: return(hr); } HRESULT epfGetOneKMSDSCTL( IN WCHAR const *pwszDN, IN BYTE const *pbHash, IN DWORD cbHash, OUT CTL_CONTEXT const **ppCTL) { HRESULT hr; ULONG ldaperr; LDAP *pld = NULL; struct l_timeval timeout; BSTR strConfigDN = NULL; LDAPMessage *pSearchResult = NULL; *ppCTL = NULL; timeout.tv_sec = csecLDAPTIMEOUT; timeout.tv_usec = 0; hr = myLdapOpen( g_pwszDC, // pwszDomainName 0, // dwFlags &pld, NULL, // pstrDomainDN &strConfigDN); _JumpIfError(hr, error, "myLdapOpen"); wprintf(L"==> %ws\n", strConfigDN); ldaperr = ldap_search_ext_s( pld, const_cast(pwszDN), LDAP_SCOPE_BASE, L"(objectCategory=msExchKeyManagementServer)", s_apwszAttrs, 0, NULL, NULL, &timeout, 10000, // size limit (number of entries) &pSearchResult); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pld, ldaperr, NULL); _JumpError(hr, error, "ldap_search_ext_s"); } hr = epfGetCTLFromSearchResult( pld, pSearchResult, FALSE, pbHash, cbHash, ppCTL); _JumpIfError(hr, error, "epfGetCTLFromSearchResult"); error: if (NULL != pSearchResult) { ldap_msgfree(pSearchResult); } myLdapClose(pld, NULL, strConfigDN); return(hr); } HRESULT epfGetV3CACTLFromHash( IN BYTE const *pbHash, IN DWORD cbHash, OUT CTL_CONTEXT const **ppCTL) { HRESULT hr; ULONG ldaperr; struct l_timeval timeout; LDAP *pldGC = NULL; LDAPMessage *pSearchResult = NULL; BSTR strConfigDN = NULL; BOOL fGCFirst = FALSE; *ppCTL = NULL; timeout.tv_sec = csecLDAPTIMEOUT; timeout.tv_usec = 0; hr = myLdapOpen( g_pwszDC, // pwszDomainName fGCFirst? RLBF_REQUIRE_GC : 0, // dwFlags &pldGC, NULL, // pstrDomainDN &strConfigDN); _JumpIfError(hr, error, "myLdapOpen"); wprintf(L"%ws\n", strConfigDN); ldaperr = ldap_search_ext_s( pldGC, strConfigDN, LDAP_SCOPE_SUBTREE, L"(objectCategory=msExchKeyManagementServer)", s_apwszAttrs, 0, NULL, NULL, &timeout, 10000, // size limit (number of entries) &pSearchResult); if (LDAP_SUCCESS != ldaperr) { hr = myHLdapError(pldGC, ldaperr, NULL); _JumpError(hr, error, "ldap_search_ext_s"); } hr = epfGetCTLFromSearchResult( pldGC, pSearchResult, fGCFirst, pbHash, cbHash, ppCTL); _JumpIfError(hr, error, "epfGetCTLFromSearchResult"); error: if (NULL != pSearchResult) { ldap_msgfree(pSearchResult); } myLdapClose(pldGC, NULL, strConfigDN); return(hr); } HRESULT epfGetMSCARootHash( IN CERT_CONTEXT const *pccUser, OUT BYTE *pbHash, IN OUT DWORD *pcbHash) { HRESULT hr; CERT_CHAIN_PARA ChainParams; CERT_CHAIN_CONTEXT const *pChainContext = NULL; CERT_CHAIN_ELEMENT const *pElement; ZeroMemory(&ChainParams, sizeof(ChainParams)); ChainParams.cbSize = sizeof(ChainParams); DBGPRINT((DBG_SS_CERTUTIL, "Calling CertGetCertificateChain...\n")); // Get the chain and verify the cert: if (!CertGetCertificateChain( g_fUserRegistry? HCCE_CURRENT_USER : HCCE_LOCAL_MACHINE, pccUser, // pCertContext NULL, // pTime NULL, // hAdditionalStore &ChainParams, // pChainPara 0, // dwFlags NULL, // pvReserved &pChainContext)) // ppChainContext { hr = myHLastError(); _JumpError(hr, error, "CertGetCertificateChain"); } DBGPRINT((DBG_SS_CERTUTIL, "CertGetCertificateChain done\n")); myDumpChain( S_OK, CA_VERIFY_FLAGS_DUMP_CHAIN | (g_fSplitASN? CA_VERIFY_FLAGS_SAVE_CHAIN : 0), pccUser, NULL, // pfnCallback NULL, // pwszMissingIssuer pChainContext); hr = CRYPT_E_NOT_FOUND; if (1 > pChainContext->cChain || 2 > pChainContext->rgpChain[0]->cElement) { _JumpError(hr, error, "no chain"); } pElement = pChainContext->rgpChain[0]->rgpElement[ pChainContext->rgpChain[0]->cElement - 1]; if (0 == (CERT_TRUST_IS_SELF_SIGNED & pElement->TrustStatus.dwInfoStatus)) { _JumpError(hr, error, "incomplete chain"); } if (!CertGetCertificateContextProperty( pElement->pCertContext, CERT_SHA1_HASH_PROP_ID, pbHash, pcbHash)) { hr = myHLastError(); _JumpError(hr, error, "CertGetCertificateContextProperty"); } hr = S_OK; error: if (NULL != pChainContext) { CertFreeCertificateChain(pChainContext); } return(hr); } HRESULT epfGetV3CACTLFromChain( IN CERT_CONTEXT const *pccUserV3, OUT CTL_CONTEXT const **ppCTL) { HRESULT hr; BYTE abHash[CBMAX_CRYPT_HASH_LEN]; DWORD cbHash; *ppCTL = NULL; cbHash = sizeof(abHash); hr = epfGetMSCARootHash(pccUserV3, abHash, &cbHash); if (S_OK != hr) { _PrintError(hr, "epfGetMSCARootHash"); if (1 >= g_fForce) { goto error; } cbHash = sizeof(abHash); ZeroMemory(abHash, sizeof(abHash)); } hr = epfGetV3CACTLFromHash(abHash, cbHash, ppCTL); _JumpIfError(hr, error, "epfGetV3CACTLFromHash"); error: return(hr); } HRESULT GetCACertFromStore( IN CERT_NAME_BLOB const *pIssuer, OPTIONAL IN CRYPT_INTEGER_BLOB const *pSerialNumber, OPTIONAL IN CERT_CONTEXT const *pccUserV1, IN BOOL fV1CA, IN WCHAR const *pwszStore, IN BOOL fUserStore, OUT CERT_CONTEXT const **ppccCA) { HRESULT hr; HCERTSTORE hStore = NULL; CERT_CONTEXT const *pcc = NULL; WCHAR *pwszIssuer = NULL; *ppccCA = NULL; hr = myCertNameToStr( X509_ASN_ENCODING, pIssuer, CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, &pwszIssuer); _JumpIfError(hr, error, "myCertNameToStr"); DBGPRINT(( DBG_SS_CERTUTILI, "fV1=%x, fUser=%u, %ws '%ws'\n", fV1CA, fUserStore, pwszStore, pwszIssuer)); hStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING, NULL, // hProv CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG | CERT_STORE_READONLY_FLAG | (fUserStore? 0 : CERT_SYSTEM_STORE_LOCAL_MACHINE), pwszStore); if (NULL == hStore) { hr = myHLastError(); _JumpErrorStr(hr, error, "CertOpenStore", pwszStore); } while (TRUE) { pcc = CertFindCertificateInStore( hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, // dwFindFlags CERT_FIND_SUBJECT_NAME, pIssuer, pcc); if (NULL == pcc) { hr = myHLastError(); DBGPRINT(( DBG_SS_ERROR, "fV1=%x, fUser=%u, %ws\n", fV1CA, fUserStore, pwszStore)); _JumpErrorStr(hr, error, "CertFindCertificateInStore", pwszIssuer); } if (fV1CA ^ (CERT_V1 != pcc->pCertInfo->dwVersion)) { // The V1 CA should have been used to sign the V1 user cert. if (fV1CA && NULL != pccUserV1 && !CryptVerifyCertificateSignature( NULL, X509_ASN_ENCODING, pccUserV1->pbCertEncoded, pccUserV1->cbCertEncoded, &pcc->pCertInfo->SubjectPublicKeyInfo)) { hr = myHLastError(); _PrintError(hr, "CryptVerifyCertificateSignature"); } // The V1 signature check fails, so ignore the error and use the // cert anyway. The binary Issuer name match will have to suffice. //else { *ppccCA = pcc; pcc = NULL; break; } } } hr = S_OK; error: if (NULL != pwszIssuer) { LocalFree(pwszIssuer); } if (NULL != pcc) { CertFreeCertificateContext(pcc); } if (NULL != hStore) { CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG); } return(hr); } typedef struct _STORELIST { WCHAR const *pwszStoreName; BOOL fUserStore; } STORELIST; STORELIST g_aCAStoreList[] = { { wszCA_CERTSTORE, FALSE }, { wszCA_CERTSTORE, TRUE }, { wszROOT_CERTSTORE, FALSE }, { wszROOT_CERTSTORE, TRUE }, { wszMY_CERTSTORE, FALSE }, { wszMY_CERTSTORE, TRUE }, }; HRESULT GetCACert( OPTIONAL IN CERT_CONTEXT const *pccUserV1, OPTIONAL IN CERT_CONTEXT const *pccUserV3, IN BOOL fV1CA, OPTIONAL IN WCHAR const *pwszCACertId, OUT CERT_CONTEXT const **ppccCA) { HRESULT hr; WCHAR *pwszSimpleName = NULL; CTL_CONTEXT const *pCTL = NULL; CMSG_CMS_SIGNER_INFO *pcsi = NULL; BSTR strSerialNumber = NULL; CERT_NAME_BLOB const *pIssuer = NULL; CRYPT_INTEGER_BLOB const *pSerialNumber = NULL; *ppccCA = NULL; hr = CRYPT_E_NOT_FOUND; if (NULL == pwszCACertId && NULL != pccUserV3) { hr = epfGetV3CACTLFromChain(pccUserV3, &pCTL); _PrintIfError(hr, "epfGetV3CACTLFromChain"); if (S_OK == hr && NULL != pCTL) { DWORD cb; hr = myCryptMsgGetParam( pCTL->hCryptMsg, CMSG_CMS_SIGNER_INFO_PARAM, 0, CERTLIB_USE_LOCALALLOC, (VOID **) &pcsi, &cb); _JumpIfError(hr, error, "myCryptMsgGetParam"); if (CERT_ID_ISSUER_SERIAL_NUMBER == pcsi->SignerId.dwIdChoice) { hr = MultiByteIntegerToBstr( FALSE, pcsi->SignerId.IssuerSerialNumber.SerialNumber.cbData, pcsi->SignerId.IssuerSerialNumber.SerialNumber.pbData, &strSerialNumber); _JumpIfError(hr, error, "MultiByteIntegerToBstr"); pwszCACertId = strSerialNumber; pSerialNumber = &pcsi->SignerId.IssuerSerialNumber.SerialNumber; pIssuer = &pcsi->SignerId.IssuerSerialNumber.Issuer; } } } if (NULL != pccUserV1 || NULL != pIssuer) { DWORD i; if (NULL == pIssuer) { pIssuer = &pccUserV1->pCertInfo->Issuer; } for (i = 0; i < ARRAYSIZE(g_aCAStoreList); i++) { hr = GetCACertFromStore( pIssuer, pSerialNumber, pccUserV1, fV1CA, g_aCAStoreList[i].pwszStoreName, g_aCAStoreList[i].fUserStore, ppccCA); if (S_OK == hr) { break; } _PrintErrorStr( hr, fV1CA? "GetCACertFromStore:V1" : "GetCACertFromStore:V3", g_aCAStoreList[i].pwszStoreName); } } if (NULL == *ppccCA) { hr = myGetCertificateFromPicker( g_hInstance, NULL, // hwndParent fV1CA? IDS_GETKMSV1CACERT_TITLE : IDS_GETKMSCACERT_TITLE, fV1CA? IDS_GETKMSV1CACERT_SUBTITLE : IDS_GETKMSCACERT_SUBTITLE, // dwFlags: HKLM+HKCU My store CUCS_MYSTORE | CUCS_CASTORE | CUCS_ROOTSTORE | CUCS_MACHINESTORE | CUCS_USERSTORE | (g_fCryptSilent? CUCS_SILENT : 0) | (fV1CA? CUCS_V1ONLY : CUCS_V3ONLY), NULL != pwszCACertId? pwszCACertId : g_wszCACertCN, 0, // cStore NULL, // rghStore 0, // cpszObjId NULL, // apszObjId ppccCA); _JumpIfError(hr, error, "myGetCertificateFromPicker"); } if (NULL != *ppccCA) { hr = myCertGetNameString( *ppccCA, CERT_NAME_SIMPLE_DISPLAY_TYPE, &pwszSimpleName); if (S_OK != hr || 0 != lstrcmp(g_wszCACertCN, pwszSimpleName)) { _PrintIfError(hr, "myCertGetNameString"); CertFreeCertificateContext(*ppccCA); *ppccCA = NULL; hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpErrorStr( hr, error, "bad CA CommonName", pwszSimpleName); } if (NULL != pCTL) { CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA cvse; ZeroMemory(&cvse, sizeof(cvse)); cvse.cbSize = sizeof(cvse); cvse.dwSignerType = CMSG_VERIFY_SIGNER_PUBKEY; cvse.pvSigner = &(*ppccCA)->pCertInfo->SubjectPublicKeyInfo; if (!CryptMsgControl( pCTL->hCryptMsg, 0, // dwFlags CMSG_CTRL_VERIFY_SIGNATURE_EX, &cvse)) { hr = myHLastError(); _JumpError(hr, error, "CryptMsgControl(VerifySig)"); } } hr = S_OK; } error: // myGetCertificateFromPicker cancel returns S_OK & NULL if (S_OK != hr || NULL == *ppccCA) { wprintf( L"%ws\n", myLoadResourceString(IDS_CANNOT_FIND_EPF_CA_CERT)); } if (NULL != pCTL) { CertFreeCTLContext(pCTL); } if (NULL != pcsi) { LocalFree(pcsi); } if (NULL != strSerialNumber) { SysFreeString(strSerialNumber); } if (NULL != pwszSimpleName) { LocalFree(pwszSimpleName); } return(hr); } // [Password Token] // Protection=128 // Profile Version=3 // Token=4BA715FC963A9B50 // SaltValue=J0+bHju332R+5Ia4dP52HvLav04= // HashSize=0 // // [User X.500 Name] // X500Name=o=pki-kms-test, ou=dcross, cn=recipients, cn=user1 // // [S/MIME] // @Signing Certificate=FQLn5nUsYfhZZnmb5Zid8NIzJeXpKatACMsiXHsLzx... // _continue_=... // ... // @Signing Key=ot7snTvKNUM2BSFwKXxyrLnDK5qmAcnpreL9MD84wXY4pW2... // _continue_=... // ... // @Private Keys=E6oly3MbeMk6VCJuZ6UgUhX3npQCUFBmbEvw9L+... // _continue_=... // ... // KeyCount=1 // @Issuing Certificates=bWQQmVuPjFkWSL... // @Trust List Certificate=25irS5M5LL... // _continue_=... // ... // // [Full Certificate History] // @SMIME_1=y3OPoks2yR6EAag5IiBsx+MzWeF3a3xy9Zj... // _continue_=... // @SMIME_2=NB5HNJNXp4IVu5cvNyZFS+MzWeF3a3xy9Zj... // _continue_=... // ... // // EPF file cert and key contents: // [S/MIME] @Signing Certificate: Single signing cert. // [S/MIME] @Signing Key: Single signing key. // // [S/MIME] KeyCount: count of encryption certs and keys // [S/MIME] @Private Keys: encryption keys // [Full Certificate History] SMIME_1: encryption cert // [Full Certificate History] SMIME_2: encryption cert // // [S/MIME] @Trust List Certificate: Single root cert; not issuing CA cert! // // [S/MIME] @Issuing Certificates: serialized CAPI cert store // 0000 00 00 00 00 43 45 52 54 00 00 00 00 00 00 00 00 ....CERT........ // 0010 00 00 00 00 .... // HRESULT EPFSaveCertStoreToFile( IN HCERTSTORE hStore, IN WCHAR const *pwszPassword, IN WCHAR const *pwszfnOut, OPTIONAL IN WCHAR const *pwszV3CACertId, IN DWORD dwEPFAlg, OPTIONAL IN WCHAR const *pwszSalt) { HRESULT hr; FILE *pf = NULL; char *pszfnOut = NULL; WCHAR *pwszSaltValue = NULL; char *pszDN = NULL; char *pszDNT = NULL; WCHAR *pwszCN = NULL; WCHAR *pwszCNT = NULL; DWORD i; DWORD iCertHistory; CERT_CONTEXT const **appcc[ICC_MAX]; DWORD accc[ICC_MAX]; HCRYPTPROV hProvV1Signing = NULL; DWORD ccert; HCERTSTORE hStoreMem = NULL; CRYPT_DATA_BLOB BlobStore; HCRYPTPROV hProv = NULL; EPF_SYM_KEY_STRUCT sKey; BYTE abSaltValue[CBMAX_CRYPT_HASH_LEN]; BYTE abToken[CBTOKEN]; BYTE *pbSalt = NULL; DWORD cbSalt; CERT_CONTEXT const *pccCAV1 = NULL; CERT_CONTEXT const *pccCAV3 = NULL; WCHAR wszSMIME[cwcINFKEY_SMIME_FORMATTED]; CERT_CONTEXT const *pccUserV1; CERT_CONTEXT const *pccUserV3; CERT_CONTEXT const *pccT; BOOL fQuietOld = g_fQuiet; ZeroMemory(&sKey, sizeof(sKey)); ZeroMemory(appcc, sizeof(appcc)); ZeroMemory(accc, sizeof(accc)); BlobStore.pbData = NULL; ccert = 0; for (i = 0; i < ARRAYSIZE(appcc); i++) { hr = GetCertListFromStore(hStore, i, &appcc[i], &accc[i]); _PrintIfError2(hr, "GetCertListFromStore", CRYPT_E_NOT_FOUND); ccert += accc[i]; if (0 != accc[i]) { wprintf( L"V%u %ws %ws: %u\n", (ICC_V1SIGNING == i || ICC_V1ENCRYPTION == i)? 1 : 3, (ICC_V1SIGNING == i || ICC_V3SIGNING == i)? epfLoadResource(IDS_SIGNING, wszSIGNING) : epfLoadResource(IDS_EXCHANGE, wszEXCHANGE), myLoadResourceString(IDS_CERTS), // "certs" accc[i]); } } if (0 == ccert) { hr = CRYPT_E_NOT_FOUND; _JumpError(hr, error, "no certs"); } for (i = 0; i < ARRAYSIZE(appcc); i++) { if (0 != accc[i]) { DWORD j; for (j = 0; j < accc[i]; j++) { int r; if (NULL != pszDNT) { LocalFree(pszDNT); pszDNT = NULL; } if (NULL != pwszCNT) { LocalFree(pwszCNT); pwszCNT = NULL; } hr = GetLowerCaseDNAndCN(appcc[i][j], &pszDNT, &pwszCNT); _JumpIfError(hr, error, "GetLowerCaseDNAndCN"); if (g_fVerbose) { wprintf(L"DN[%u][%u] = %hs\n", i, j, pszDNT); wprintf(L"CN[%u][%u] = %ws\n", i, j, pwszCNT); } if (NULL == pszDN) { pszDN = pszDNT; pszDNT = NULL; } if (NULL == pwszCN) { pwszCN = pwszCNT; pwszCNT = NULL; continue; } r = lstrcmp(pwszCN, pwszCNT); if (0 != r) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _PrintErrorStr(hr, "bad subject CN", pwszCNT); _JumpErrorStr(hr, error, "expected subject CN", pwszCN); } } } } if (!myConvertWszToSz(&pszfnOut, pwszfnOut, -1)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "myConvertWszToSz"); } if (!CryptAcquireContext( &hProv, NULL, // container name MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { hr = myHLastError(); _JumpError(hr, error, "CryptAcquireContext"); } if (NULL != pwszSalt) { hr = myCryptStringToBinary( pwszSalt, 0, CRYPT_STRING_BASE64, &pbSalt, &cbSalt, NULL, NULL); _JumpIfError(hr, error, "myCryptStringToBinary"); if (sizeof(abSaltValue) != cbSalt) { hr = E_INVALIDARG; _JumpError(hr, error, "cbSalt"); } } else { if (!CryptGenRandom(hProv, sizeof(abSaltValue), abSaltValue)) { hr = myHLastError(); _JumpError(hr, error, "CryptGenRandom"); } hr = EPFCryptBinaryToBase64( abSaltValue, sizeof(abSaltValue), &pwszSaltValue); _JumpIfError(hr, error, "EPFCryptBinaryToBase64"); pwszSalt = pwszSaltValue; } pccUserV1 = NULL; if (0 != accc[ICC_V1SIGNING]) { pccUserV1 = appcc[ICC_V1SIGNING][accc[ICC_V1SIGNING] - 1]; } else if (0 != accc[ICC_V1ENCRYPTION]) { pccUserV1 = appcc[ICC_V1ENCRYPTION][accc[ICC_V1ENCRYPTION] - 1]; } if (NULL != pccUserV1 && EPFALG_DEFAULT == dwEPFAlg) { dwEPFAlg = EPFALG_CAST; } hr = EPFDeriveKey( EPFALG_DEFAULT == dwEPFAlg? EPFALG_RC2_SHA : EPFALG_CAST_MD5, EPFALG_DEFAULT == dwEPFAlg? 128 : 64, hProv, pwszPassword, pwszSalt, pbSalt, cbSalt, 0, // cbHashSize &sKey); _JumpIfError(hr, error, "EPFDeriveKey"); hr = EPFGenerateKeyToken(&sKey, abToken, sizeof(abToken)); _JumpIfError(hr, error, "EPFGenerateKeyToken"); if (!g_fForce) { pf = fopen(pszfnOut, "r"); if (NULL != pf) { hr = HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); _JumpError(hr, error, "fopen"); } } pf = fopen(pszfnOut, "w"); if (NULL == pf) { hr = CO_E_FAILEDTOCREATEFILE; _JumpError(hr, error, "fopen"); } fprintf(pf, "[" szINFSECTION_PASSWORDTOKEN "]\n"); fprintf(pf, szINFKEY_PROTECTION "=%u\n", EPFALG_DEFAULT == dwEPFAlg? 128 : 64); fprintf(pf, szINFKEY_PROFILEVERSION "=%u\n", EPFALG_DEFAULT == dwEPFAlg? 3 : 2); if (EPFALG_DEFAULT != dwEPFAlg) { fprintf(pf, szINFKEY_CAST "=3\n"); } fprintf(pf, szINFKEY_TOKEN "="); for (i = 0; i < sizeof(abToken); i++) { fprintf(pf, "%02X", abToken[i]); } fprintf(pf, "\n"); fprintf(pf, szINFKEY_SALTVALUE "=%ws\n", pwszSalt); fprintf(pf, szINFKEY_HASHSIZE "=0\n"); fprintf(pf, "\n[" szINFSECTION_USERX500NAME "]\n"); fprintf(pf, szINFKEY_X500NAME "=%hs\n", pszDN); InitCrcTable(); if (!g_fVerbose) { g_fQuiet = TRUE; } if (EPFALG_DEFAULT != dwEPFAlg) { if (0 == accc[ICC_V1SIGNING] && NULL != pccUserV1) { appcc[ICC_V1SIGNING] = (CERT_CONTEXT const **) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, sizeof(appcc[ICC_V1SIGNING][0])); if (NULL == appcc[ICC_V1SIGNING]) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } hr = epfBuildV1Certs( pccUserV1, &appcc[ICC_V1SIGNING][0], &hProvV1Signing, &pccCAV1); _JumpIfError(hr, error, "epfBuildV1Certs"); accc[ICC_V1SIGNING] = 1; } if (0 != accc[ICC_V1SIGNING]) { pccT = appcc[ICC_V1SIGNING][accc[ICC_V1SIGNING] - 1]; fprintf(pf, "\n[" szINFSECTION_DIGITALSIGNATURE "]\n"); hr = WriteProtectedValue( pf, wszINFSECTION_DIGITALSIGNATURE, wszINFKEY_CERTIFICATE, &sKey, pccT->pbCertEncoded, pccT->cbCertEncoded); _JumpIfError(hr, error, "WriteProtectedValue"); hr = cuDumpAsnBinary(pccT->pbCertEncoded, pccT->cbCertEncoded, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); // szINFKEY_KEY hr = WriteSingleKMSRSAKeyValue( pf, wszINFSECTION_DIGITALSIGNATURE, wszINFKEY_KEY, &sKey, pccT, hProvV1Signing, CALG_RSA_SIGN, AT_SIGNATURE, dwKEYSPEC_V1SIGNATURE); _JumpIfError(hr, error, "WriteSingleKMSRSAKeyValue"); } if (NULL == pccCAV1) { hr = GetCACert(pccUserV1, NULL, TRUE, NULL, &pccCAV1); _JumpIfError(hr, error, "GetCACert"); } if (0 != accc[ICC_V1ENCRYPTION]) { WCHAR wszName[cwcINFKEY_NAME_FORMATTED]; fprintf(pf, "\n[" szINFSECTION_PRIVATEKEYS "]\n"); for (i = 0; i < accc[ICC_V1ENCRYPTION]; i++) { WCHAR wszKey[cwcINFKEY_KEY_FORMATTED]; pccT = appcc[ICC_V1ENCRYPTION][i]; wsprintf(wszKey, wszINFKEY_KEY_FORMAT, i + 1); hr = WriteSingleKMSRSAKeyValue( pf, wszINFSECTION_PRIVATEKEYS, wszKey, &sKey, pccT, NULL, // hProv CALG_RSA_KEYX, AT_KEYEXCHANGE, dwKEYSPEC_V1ENCRYPTION_BASE + i); _JumpIfError(hr, error, "WriteSingleKMSRSAKeyValue"); } fprintf(pf, szINFKEY_KEYCOUNT "=%u\n", accc[ICC_V1ENCRYPTION]); fprintf(pf, "\n[" szINFSECTION_CERTIFICATEHISTORY "]\n"); for (i = 0; i < accc[ICC_V1ENCRYPTION]; i++) { pccT = appcc[ICC_V1ENCRYPTION][i]; wsprintf(wszName, wszINFKEY_NAME_FORMAT, i + 1); hr = WriteIssuerNameAndSerialValue(pf, wszName, pccCAV1, pccT); _JumpIfError(hr, error, "WriteIssuerNameAndSerialValue"); } fprintf(pf, "\n[" szINFSECTION_FULLCERTIFICATEHISTORY "]\n"); // szINFKEY_NAME_FORMAT: Name%u -- V1 Encryption certs for (i = 0; i < accc[ICC_V1ENCRYPTION]; i++) { pccT = appcc[ICC_V1ENCRYPTION][i]; wsprintf(wszName, wszINFKEY_NAME_FORMAT, i + 1); hr = WriteProtectedValue( pf, wszINFSECTION_FULLCERTIFICATEHISTORY, wszName, &sKey, pccT->pbCertEncoded, pccT->cbCertEncoded); _JumpIfError(hr, error, "WriteProtectedValue"); hr = cuDumpAsnBinary(pccT->pbCertEncoded, pccT->cbCertEncoded, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); } // szINFKEY_SMIME_FORMAT: SMIME_%u -- V3 Encryption certs for (i = 0; i < accc[ICC_V3ENCRYPTION]; i++) { pccT = appcc[ICC_V3ENCRYPTION][i]; wsprintf(wszSMIME, wszINFKEY_SMIME_FORMAT, i + 1); hr = WriteProtectedValue( pf, wszINFSECTION_FULLCERTIFICATEHISTORY, wszSMIME, &sKey, pccT->pbCertEncoded, pccT->cbCertEncoded); _JumpIfError(hr, error, "WriteProtectedValue"); hr = cuDumpAsnBinary(pccT->pbCertEncoded, pccT->cbCertEncoded, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); } fprintf(pf, "\n[" szINFSECTION_USERCERTIFICATE "]\n"); pccT = appcc[ICC_V1ENCRYPTION][accc[ICC_V1ENCRYPTION] - 1]; hr = WriteProtectedValue( pf, wszINFSECTION_USERCERTIFICATE, wszINFKEY_CERTIFICATE, &sKey, pccT->pbCertEncoded, pccT->cbCertEncoded); _JumpIfError(hr, error, "WriteProtectedValue"); hr = cuDumpAsnBinary(pccT->pbCertEncoded, pccT->cbCertEncoded, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); } fprintf(pf, "\n[" szINFSECTION_CA "]\n"); hr = WriteProtectedValue( pf, wszINFSECTION_CA, wszINFKEY_CERTIFICATE, &sKey, NULL != pccCAV1? pccCAV1->pbCertEncoded : NULL, NULL != pccCAV1? pccCAV1->cbCertEncoded : 0); _JumpIfError(hr, error, "WriteProtectedValue"); hr = cuDumpAsnBinary(pccT->pbCertEncoded, pccT->cbCertEncoded, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); fprintf(pf, "\n[" szINFSECTION_MICROSOFTEXCHANGE "]\n"); hr = WriteProtectedStringValue( pf, wszINFSECTION_MICROSOFTEXCHANGE, wszINFKEY_FRIENDLYNAME, &sKey, L"SzNull"); _JumpIfError(hr, error, "WriteProtectedStringValue"); hr = WriteProtectedDwordValue( pf, wszINFSECTION_MICROSOFTEXCHANGE, wszINFKEY_KEYALGID, &sKey, EPFALG_CASTEXPORT == dwEPFAlg? EPFALG_EXPORT : EPFALG_DOMESTIC); _JumpIfError(hr, error, "WriteProtectedDwordValue"); } if (0 != accc[ICC_V3SIGNING] || 0 != accc[ICC_V3ENCRYPTION]) { fprintf(pf, "\n[" szINFSECTION_SMIME "]\n"); // szINFKEY_SIGNINGCERTIFICATE if (0 != accc[ICC_V3SIGNING]) { pccT = appcc[ICC_V3SIGNING][accc[ICC_V3SIGNING] - 1]; hr = WriteProtectedValue( pf, wszINFSECTION_SMIME, wszINFKEY_SIGNINGCERTIFICATE, &sKey, pccT->pbCertEncoded, pccT->cbCertEncoded); _JumpIfError(hr, error, "WriteProtectedValue"); hr = cuDumpAsnBinary(pccT->pbCertEncoded, pccT->cbCertEncoded, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); // szINFKEY_SIGNINGKEY hr = WriteSingleEPFKeyValue( pf, wszINFSECTION_SMIME, wszINFKEY_SIGNINGKEY, &sKey, pccT, CALG_RSA_SIGN, AT_SIGNATURE, dwKEYSPEC_V3SIGNATURE); _JumpIfError(hr, error, "WriteSingleEPFKeyValue"); } // szINFKEY_PRIVATEKEYS if (0 != accc[ICC_V3ENCRYPTION]) { hr = WriteEncryptionKeysValue( pf, wszINFSECTION_SMIME, wszINFKEY_PRIVATEKEYS, &sKey, 0, // V3 keys only? accc[ICC_V1ENCRYPTION], appcc[ICC_V1ENCRYPTION], accc[ICC_V3ENCRYPTION], appcc[ICC_V3ENCRYPTION]); _JumpIfError(hr, error, "WriteEncryptionKeys"); } fprintf(pf, szINFKEY_KEYCOUNT "=%u\n", accc[ICC_V3ENCRYPTION]); // szINFKEY_ISSUINGCERTIFICATES -- empty serialized cert store hStoreMem = CertOpenStore( CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, CERT_STORE_NO_CRYPT_RELEASE_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG, NULL); if (NULL == hStoreMem) { hr = myHLastError(); _JumpError(hr, error, "CertOpenStore"); } while (TRUE) { if (!CertSaveStore( hStoreMem, X509_ASN_ENCODING, CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_MEMORY, &BlobStore, 0)) { hr = myHLastError(); _JumpError(hr, error, "CertSaveStore"); } if (NULL != BlobStore.pbData) { break; } BlobStore.pbData = (BYTE *) LocalAlloc(LMEM_FIXED, BlobStore.cbData); if (NULL == BlobStore.pbData) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "LocalAlloc"); } } hr = WriteProtectedValue( pf, wszINFSECTION_SMIME, wszINFKEY_ISSUINGCERTIFICATES, &sKey, BlobStore.pbData, BlobStore.cbData); _JumpIfError(hr, error, "WriteProtectedValue"); // szINFKEY_TRUSTLISTCERTIFICATE -- root cert pccUserV3 = NULL; if (0 != accc[ICC_V3SIGNING]) { pccUserV3 = appcc[ICC_V3SIGNING][accc[ICC_V3SIGNING] - 1]; } else if (0 != accc[ICC_V3ENCRYPTION]) { pccUserV3 = appcc[ICC_V3ENCRYPTION][accc[ICC_V3ENCRYPTION] - 1]; } hr = GetCACert(pccUserV1, pccUserV3, FALSE, pwszV3CACertId, &pccCAV3); _JumpIfError(hr, error, "GetCACert"); hr = WriteProtectedValue( pf, wszINFSECTION_SMIME, wszINFKEY_TRUSTLISTCERTIFICATE, &sKey, NULL != pccCAV3? pccCAV3->pbCertEncoded : NULL, NULL != pccCAV3? pccCAV3->cbCertEncoded : 0); _JumpIfError(hr, error, "WriteProtectedValue"); } if (EPFALG_DEFAULT == dwEPFAlg) { fprintf(pf, "\n[" szINFSECTION_FULLCERTIFICATEHISTORY "]\n"); // szINFKEY_SMIME_FORMAT: SMIME_%u -- V3 Encryption certs for (i = 0; i < accc[ICC_V3ENCRYPTION]; i++) { pccT = appcc[ICC_V3ENCRYPTION][i]; wsprintf(wszSMIME, wszINFKEY_SMIME_FORMAT, i + 1); hr = WriteProtectedValue( pf, wszINFSECTION_FULLCERTIFICATEHISTORY, wszSMIME, &sKey, pccT->pbCertEncoded, pccT->cbCertEncoded); _JumpIfError(hr, error, "WriteProtectedValue"); hr = cuDumpAsnBinary( pccT->pbCertEncoded, pccT->cbCertEncoded, MAXDWORD); _JumpIfError(hr, error, "cuDumpAsnBinary"); } } fprintf(pf, "\n"); fflush(pf); if (ferror(pf)) { hr = HRESULT_FROM_WIN32(ERROR_DISK_FULL); _JumpError(hr, error, "write error"); } hr = S_OK; error: if (NULL != hStoreMem) { CertCloseStore(hStoreMem, CERT_CLOSE_STORE_CHECK_FLAG); } for (i = 0; i < ARRAYSIZE(appcc); i++) { FreeCertList(appcc[i], accc[i]); } if (NULL != pccCAV1) { CertFreeCertificateContext(pccCAV1); } if (NULL != pccCAV3) { CertFreeCertificateContext(pccCAV3); } if (NULL != pf) { fclose(pf); } if (NULL != pszDNT) { LocalFree(pszDNT); } if (NULL != pszDN) { LocalFree(pszDN); } if (NULL != pwszCNT) { LocalFree(pwszCNT); } if (NULL != pwszCN) { LocalFree(pwszCN); } if (NULL != pbSalt) { LocalFree(pbSalt); } if (NULL != pwszSaltValue) { LocalFree(pwszSaltValue); } if (NULL != pszfnOut) { LocalFree(pszfnOut); } if (NULL != BlobStore.pbData) { LocalFree(BlobStore.pbData); } if (NULL != sKey.hKey) { CryptDestroyKey(sKey.hKey); } if (NULL != hProvV1Signing) { CryptReleaseContext(hProvV1Signing, 0); } if (NULL != hProv) { CryptReleaseContext(hProv, 0); } g_fQuiet = fQuietOld; return(hr); }