Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

6833 lines
156 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 2000
//
// File: epf.cpp
//
//--------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <winldap.h>
#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<BYTE *>(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<BYTE *>(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<BYTE *>(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<WCHAR *>(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);
}