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.
 
 
 
 
 
 

19425 lines
617 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: wincrmsg.cpp
//
// Contents: Cryptographic Message APIs
//
// APIs:
//
// History: 14-Feb-96 kevinr created
//
//--------------------------------------------------------------------------
#include "global.hxx"
HCRYPTASN1MODULE ICM_hAsn1Module;
COssDecodeInfoNode::~COssDecodeInfoNode()
{
PkiAsn1FreeInfo( ICM_GetDecoder(), m_data.iPDU, m_data.pvPDU);
}
CBlobNode::~CBlobNode()
{
ICM_Free( m_data.pbData);
}
CSignerNode::~CSignerNode()
{
ICM_Free( m_data.blob.pbData);
delete m_data.pUnauthAttrList;
}
CHashNode::~CHashNode()
{
ICM_Free( m_data.HashBlob.pbData);
if (m_data.hHash)
CryptDestroyHash( m_data.hHash);
}
inline
BOOL
ICM_IsAddInnerContentOctetWrapper(
IN PCRYPT_MSG_INFO pcmi
)
{
#ifdef CMS_PKCS7
return NULL == pcmi->pszInnerContentObjID ||
(pcmi->dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG);
#else
return NULL == pcmi->pszInnerContentObjID;
#endif // CMS_PKCS7
}
DWORD
ICM_GetTaggedBlobCount(
IN CBlobList *pBlobList,
IN BYTE bTag
)
{
DWORD dwCount = 0;
CBlobNode *pBlobNode;
for (pBlobNode=pBlobList->Head(); pBlobNode; pBlobNode=pBlobNode->Next()) {
if (bTag == *(pBlobNode->Data()->pbData))
dwCount++;
}
return dwCount;
}
// Advances index past other Tags
CBlobNode *
ICM_GetTaggedBlobAndAdvanceIndex(
IN CBlobList *pBlobList,
IN BYTE bTag, // 0 => any
IN OUT DWORD *pdwIndex
)
{
DWORD dwIndex = *pdwIndex;
CBlobNode *pBlobNode;
DWORD i;
for (i=dwIndex, pBlobNode=pBlobList->Head();
pBlobNode;
pBlobNode=pBlobNode->Next()) {
if (bTag && bTag != *(pBlobNode->Data()->pbData)) {
// Advance index past other tags
dwIndex++;
} else {
if (0 == i)
break;
else
i--;
}
}
*pdwIndex = dwIndex;
return pBlobNode;
}
ObjectID aoidMessages[] = {
{ 7, {1,2,840,113549,1,7,1}}, // data
{ 7, {1,2,840,113549,1,7,2}}, // signed
{ 7, {1,2,840,113549,1,7,3}}, // enveloped
{ 7, {1,2,840,113549,1,7,4}}, // signed and enveloped
{ 7, {1,2,840,113549,1,7,5}}, // digested
{ 7, {1,2,840,113549,1,7,6}}, // encrypted
{ 7, {1,2,840,113549,1,7,7}} // dual-signed
};
#define COUNTOF_aoidMessages (sizeof(aoidMessages)/sizeof(aoidMessages[0]))
ObjectID oidMessageDigest = { 7, {1,2,840,113549,1,9,4}};
const LPSTR apszObjIdPKCS7[] = {
szOID_RSA_data ,
szOID_RSA_signedData ,
szOID_RSA_envelopedData ,
szOID_RSA_signEnvData ,
szOID_RSA_digestedData ,
szOID_RSA_encryptedData
};
const DWORD COUNTOF_apszObjIdPKCS7 = (sizeof(apszObjIdPKCS7)/sizeof(apszObjIdPKCS7[0]));
//#if COUNTOF_apszObjIdPKCS7 - (sizeof(apszObjIdPKCS7)/sizeof(apszObjIdPKCS7[0]))
//#error COUNTOF_apszObjIdPKCS7 wrong
//#endif
const LPSTR pszObjIdDataType = szOID_RSA_data;
const LPSTR pszObjIdContentType = szOID_RSA_contentType;
const LPSTR pszObjIdMessageDigest = szOID_RSA_messageDigest;
int aiPduNum[] = {
OctetStringType_PDU,
SignedData_PDU,
#ifdef CMS_PKCS7
CmsEnvelopedData_PDU,
#else
EnvelopedData_PDU,
#endif // CMS_PKCS7
SignedAndEnvelopedData_PDU,
DigestedData_PDU,
EncryptedData_PDU
};
/*
// Should be able to use aiPduNum, but first entry of aiPduNum
// seems to need to be 0. ????
int aiPduNum2[] = {
OctetStringType_PDU,
SignedData_PDU,
#ifdef CMS_PKCS7
CmsEnvelopedData_PDU,
#else
EnvelopedData_PDU,
#endif // CMS_PKCS7
SignedAndEnvelopedData_PDU,
DigestedData_PDU,
EncryptedData_PDU
};
*/
typedef struct _CRYPT_ABLOB {
DWORD cBlob;
PCRYPT_DATA_BLOB pBlob;
} CRYPT_ABLOB, *PCRYPT_ABLOB;
// Here is a table for keeping straight which phases are legal in which
// situations:
//
// detached !detached
// encode FO,FF FF
// decode FF,SO,SF FF
//
enum Phases {
PHASE_FIRST_ONGOING = 1,
PHASE_FIRST_FINAL = 2,
PHASE_SECOND_ONGOING = 3,
PHASE_SECOND_FINAL = 4
};
BOOL
WINAPI
ICM_GetAnyData(
IN Any *pAny,
OUT void *pvData,
IN OUT DWORD *pcbData);
WINAPI
ICM_GetOssContentInfoData(
IN ContentInfo *poci,
OUT void *pvData,
IN OUT DWORD *pcbData);
BOOL
WINAPI
ICM_GetSignerParamEncoding(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwIndex,
IN DWORD dwParamType,
OUT PVOID pvData,
IN OUT PDWORD pcbData);
BOOL
WINAPI
ICM_GetALGORITHM_IDENTIFIER(
IN AlgorithmIdentifier *paiOss,
OUT void *pvData,
IN OUT DWORD *pcbData);
//+-------------------------------------------------------------------------
// Lock and unlock HCRYPTMSG functions
//--------------------------------------------------------------------------
inline
void
ICM_Lock(
IN PCRYPT_MSG_INFO pcmi
)
{
EnterCriticalSection( &pcmi->CriticalSection);
}
inline
void
ICM_Unlock(
IN PCRYPT_MSG_INFO pcmi
)
{
LeaveCriticalSection( &pcmi->CriticalSection);
}
//+-------------------------------------------------------------------------
// allocation and free routines
//--------------------------------------------------------------------------
void *
WINAPI
ICM_Alloc(
IN size_t cb)
{
void *pv;
if (NULL == (pv = malloc(cb)))
goto mallocError;
ErrorReturn:
return pv;
SET_ERROR(mallocError,E_OUTOFMEMORY)
}
void *
WINAPI
ICM_AllocZero(
IN size_t cb)
{
void *pv;
// Should map to LocalAlloc( ZERO_INIT).
if (NULL != (pv = ICM_Alloc(cb)))
memset( pv, 0, cb);
return pv;
}
void *
WINAPI
ICM_ReAlloc(
IN void *pvOrg,
IN size_t cb)
{
void *pv;
if (NULL == (pv = pvOrg ? realloc( pvOrg, cb) : malloc( cb)))
goto allocError;
ErrorReturn:
return pv;
SET_ERROR(allocError,E_OUTOFMEMORY)
}
void
WINAPI
ICM_Free(
IN void *pv)
{
if (pv)
free(pv);
}
// Stack allocations
// NB: Use heap allocs on DBG so we can more easily catch buffer over-runs, etc.
#if DBG
#define ICM_AllocA ICM_Alloc
#define ICM_FreeA ICM_Free
#else
#define ICM_AllocA ICM_Alloc
#define ICM_FreeA ICM_Free
// The following defines work fine on NT, but seem to have problems on Win95
// REASON: unknown
//#define ICM_AllocA(s) alloca(((s)+7))
//#define ICM_FreeA(p)
#endif
void *
WINAPI
ICM_AllocZeroA(
IN size_t cbBytes)
{
void *pv;
if (NULL != (pv = ICM_AllocA(cbBytes)))
memset( pv, 0, cbBytes);
return pv;
}
void *ICM_DupMem(
IN void *pvIn,
IN size_t cb)
{
void *pv = NULL;
if (pvIn) {
if (NULL != (pv = ICM_Alloc(cb)))
memcpy( pv, pvIn, cb);
} else {
SetLastError((DWORD) E_INVALIDARG);
}
return pv;
}
size_t ICM_StrLen(const char *pszIn)
{
return pszIn ? strlen(pszIn) : 0;
}
BOOL
WINAPI
ICM_AppendBlob(
PCRYPT_DATA_BLOB pblob,
const BYTE *pbIn,
DWORD cbIn)
{
BOOL fRet;
PBYTE pb = NULL;
if (NULL == (pb = (PBYTE)ICM_ReAlloc(
pblob->pbData,
pblob->cbData + cbIn)))
goto AllocError;
memcpy( pb + pblob->cbData, pbIn, cbIn);
pblob->pbData = pb;
pblob->cbData += cbIn;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(AllocError)
}
#ifdef CMS_PKCS7
STATIC
BOOL
WINAPI
ICM_InsertMsgAlloc(
IN PCRYPT_MSG_INFO pcmi,
IN void *pv
)
{
BOOL fRet;
CBlobNode *pnBlob = NULL;
CRYPT_DATA_BLOB blob;
if (NULL == pcmi->pFreeList) {
if (NULL == (pcmi->pFreeList = new CBlobList))
goto OutOfMemory;
}
if (NULL == (pnBlob = new CBlobNode))
goto OutOfMemory;
blob.cbData = 0;
blob.pbData = (BYTE *) pv;
pnBlob->SetData(&blob);
pcmi->pFreeList->InsertTail(pnBlob);
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(OutOfMemory,E_OUTOFMEMORY)
}
#endif // CMS_PKCS7
// Allocates algorithm parameters and inserts into the message's free
// list before doing the ICM_Asn1ToAlgorithmIdentifier
STATIC
BOOL
WINAPI
ICM_MsgAsn1ToAlgorithmIdentifier(
IN PCRYPT_MSG_INFO pcmi,
IN PCRYPT_ALGORITHM_IDENTIFIER pai,
IN OUT AlgorithmIdentifier *pOssAlgId
)
{
#ifdef CMS_PKCS7
CRYPT_ALGORITHM_IDENTIFIER ai;
if (pcmi && 0 < pai->Parameters.cbData) {
ai = *pai;
if (NULL == (ai.Parameters.pbData = (BYTE *) ICM_DupMem(
ai.Parameters.pbData, ai.Parameters.cbData)))
return FALSE;
if (!ICM_InsertMsgAlloc(pcmi, ai.Parameters.pbData)) {
ICM_Free(ai.Parameters.pbData);
return FALSE;
}
pai = &ai;
}
#endif // CMS_PKCS7
return ICM_Asn1ToAlgorithmIdentifier(pai, pOssAlgId);
}
//+-------------------------------------------------------------------------
//
//--------------------------------------------------------------------------
STATIC BOOL WINAPI
ICM_PkcsSignerInfoEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN PCMSG_SIGNER_INFO pInfo,
OUT PBYTE pbEncoded,
IN OUT PDWORD pcbEncoded);
STATIC BOOL WINAPI
ICM_PkcsSignerInfoDecode(
IN DWORD dwEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PCMSG_SIGNER_INFO pInfo,
IN OUT DWORD *pcbInfo);
STATIC BOOL WINAPI
ICM_CmsSignerInfoEncode(
IN DWORD dwCertEncodingType,
IN LPCSTR lpszStructType,
IN PCMSG_CMS_SIGNER_INFO pInfo,
OUT PBYTE pbEncoded,
IN OUT PDWORD pcbEncoded);
STATIC BOOL WINAPI
ICM_CmsSignerInfoDecode(
IN DWORD dwEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PCMSG_CMS_SIGNER_INFO pInfo,
IN OUT DWORD *pcbInfo);
#ifdef OSS_CRYPT_ASN1
#define ASN1_OID_OFFSET 10000 +
#define ASN1_OID_PREFIX "OssCryptAsn1."
#else
#define ASN1_OID_OFFSET
#define ASN1_OID_PREFIX
#endif // OSS_CRYPT_ASN1
STATIC
const
CRYPT_OID_FUNC_ENTRY
ICM_EncodeFuncTable[] = {
ASN1_OID_OFFSET PKCS7_SIGNER_INFO, ICM_PkcsSignerInfoEncode,
ASN1_OID_OFFSET CMS_SIGNER_INFO, ICM_CmsSignerInfoEncode,
};
#define ICM_ENCODE_FUNC_COUNT \
(sizeof(ICM_EncodeFuncTable) / sizeof(ICM_EncodeFuncTable[0]))
STATIC
const
CRYPT_OID_FUNC_ENTRY
ICM_DecodeFuncTable[] = {
ASN1_OID_OFFSET PKCS7_SIGNER_INFO, ICM_PkcsSignerInfoDecode,
ASN1_OID_OFFSET CMS_SIGNER_INFO, ICM_CmsSignerInfoDecode,
};
#define ICM_DECODE_FUNC_COUNT \
(sizeof(ICM_DecodeFuncTable) / sizeof(ICM_DecodeFuncTable[0]))
#ifdef CMS_PKCS7
static HCRYPTOIDFUNCSET hOldStyleGenEncryptKeyFuncSet;
static HCRYPTOIDFUNCSET hOldStyleExportEncryptKeyFuncSet;
static HCRYPTOIDFUNCSET hOldStyleImportEncryptKeyFuncSet;
static HCRYPTOIDFUNCSET hGenContentEncryptKeyFuncSet;
static HCRYPTOIDFUNCSET hExportKeyTransFuncSet;
static HCRYPTOIDFUNCSET hExportKeyAgreeFuncSet;
static HCRYPTOIDFUNCSET hExportMailListFuncSet;
static HCRYPTOIDFUNCSET hImportKeyTransFuncSet;
static HCRYPTOIDFUNCSET hImportKeyAgreeFuncSet;
static HCRYPTOIDFUNCSET hImportMailListFuncSet;
//+-------------------------------------------------------------------------
// GenContentEncryptKey OID Installable Functions
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultGenContentEncryptKey(
IN OUT PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
);
static const CRYPT_OID_FUNC_ENTRY GenContentEncryptKeyFuncTable[] = {
CMSG_DEFAULT_INSTALLABLE_FUNC_OID, ICM_DefaultGenContentEncryptKey
};
//+-------------------------------------------------------------------------
// ExportKeyTrans OID Installable Functions
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultExportKeyTrans(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTransEncodeInfo,
IN OUT PCMSG_KEY_TRANS_ENCRYPT_INFO pKeyTransEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
);
static const CRYPT_OID_FUNC_ENTRY ExportKeyTransFuncTable[] = {
CMSG_DEFAULT_INSTALLABLE_FUNC_OID, ICM_DefaultExportKeyTrans
};
//+-------------------------------------------------------------------------
// ExportKeyAgree OID Installable Functions
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultExportKeyAgree(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO pKeyAgreeEncodeInfo,
IN OUT PCMSG_KEY_AGREE_ENCRYPT_INFO pKeyAgreeEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
);
static const CRYPT_OID_FUNC_ENTRY ExportKeyAgreeFuncTable[] = {
CMSG_DEFAULT_INSTALLABLE_FUNC_OID, ICM_DefaultExportKeyAgree
};
//+-------------------------------------------------------------------------
// ExportMailList OID Installable Functions
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultExportMailList(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO pMailListEncodeInfo,
IN OUT PCMSG_MAIL_LIST_ENCRYPT_INFO pMailListEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
);
static const CRYPT_OID_FUNC_ENTRY ExportMailListFuncTable[] = {
CMSG_DEFAULT_INSTALLABLE_FUNC_OID, ICM_DefaultExportMailList
};
//+-------------------------------------------------------------------------
// ImportKeyTrans OID Installable Functions
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultImportKeyTrans(
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA pKeyTransDecryptPara,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved,
OUT HCRYPTKEY *phContentEncryptKey
);
static const CRYPT_OID_FUNC_ENTRY ImportKeyTransFuncTable[] = {
CMSG_DEFAULT_INSTALLABLE_FUNC_OID, ICM_DefaultImportKeyTrans
};
//+-------------------------------------------------------------------------
// ImportKeyAgree OID Installable Functions
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultImportKeyAgree(
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN PCMSG_CTRL_KEY_AGREE_DECRYPT_PARA pKeyAgreeDecryptPara,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved,
OUT HCRYPTKEY *phContentEncryptKey
);
static const CRYPT_OID_FUNC_ENTRY ImportKeyAgreeFuncTable[] = {
CMSG_DEFAULT_INSTALLABLE_FUNC_OID, ICM_DefaultImportKeyAgree
};
//+-------------------------------------------------------------------------
// ImportMailList OID Installable Functions
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultImportMailList(
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN PCMSG_CTRL_MAIL_LIST_DECRYPT_PARA pMailListDecryptPara,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved,
OUT HCRYPTKEY *phContentEncryptKey
);
static const CRYPT_OID_FUNC_ENTRY ImportMailListFuncTable[] = {
CMSG_DEFAULT_INSTALLABLE_FUNC_OID, ICM_DefaultImportMailList
};
#else
static HCRYPTOIDFUNCSET hGenEncryptKeyFuncSet;
static HCRYPTOIDFUNCSET hExportEncryptKeyFuncSet;
static HCRYPTOIDFUNCSET hImportEncryptKeyFuncSet;
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// GenEncryptKey OID Installable Functions (OldStyle)
//--------------------------------------------------------------------------
// rgcbEncryptParameters[1] contains the dwEncryptFlags passed to
// ICM_DefaultExportEncryptKey
BOOL
WINAPI
ICM_DefaultGenEncryptKey(
IN OUT HCRYPTPROV *phCryptProv,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PVOID pvEncryptAuxInfo,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
IN PFN_CMSG_ALLOC pfnAlloc,
OUT HCRYPTKEY *phEncryptKey,
OUT PBYTE *ppbEncryptParameters,
OUT DWORD rgcbEncryptParameters[2]);
static const CRYPT_OID_FUNC_ENTRY GenEncryptKeyFuncTable[] = {
szOID_OIWSEC_desCBC, ICM_DefaultGenEncryptKey,
szOID_RSA_DES_EDE3_CBC, ICM_DefaultGenEncryptKey,
szOID_RSA_RC2CBC, ICM_DefaultGenEncryptKey,
szOID_RSA_RC4, ICM_DefaultGenEncryptKey
};
#define GEN_ENCRYPT_KEY_FUNC_COUNT (sizeof(GenEncryptKeyFuncTable) / \
sizeof(GenEncryptKeyFuncTable[0]))
//+-------------------------------------------------------------------------
// ExportEncryptKey OID Installable Functions (OldStyle)
//--------------------------------------------------------------------------
// rgcbData[1] is the dwEncryptFlags passed from ICM_DefaultGenEncryptKey
BOOL
WINAPI
ICM_DefaultExportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN HCRYPTKEY hEncryptKey,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
OUT PBYTE pbData,
IN OUT DWORD rgcbData[2]);
static const CRYPT_OID_FUNC_ENTRY ExportEncryptKeyFuncTable[] = {
szOID_RSA_RSA, ICM_DefaultExportEncryptKey
};
#define EXPORT_ENCRYPT_KEY_FUNC_COUNT (sizeof(ExportEncryptKeyFuncTable) / \
sizeof(ExportEncryptKeyFuncTable[0]))
//+-------------------------------------------------------------------------
// ImportEncryptKey OID Installable Functions (OldStyle)
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultImportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN DWORD dwKeySpec,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PCRYPT_ALGORITHM_IDENTIFIER paiPubKey,
IN PBYTE pbEncodedKey,
IN DWORD cbEncodedKey,
OUT HCRYPTKEY *phEncryptKey);
static const CRYPT_OID_FUNC_ENTRY ImportEncryptKeyFuncTable[] = {
szOID_OIWSEC_desCBC, ICM_DefaultImportEncryptKey,
szOID_RSA_DES_EDE3_CBC, ICM_DefaultImportEncryptKey,
szOID_RSA_RC2CBC, ICM_DefaultImportEncryptKey,
szOID_RSA_RC4, ICM_DefaultImportEncryptKey
};
#define IMPORT_ENCRYPT_KEY_FUNC_COUNT (sizeof(ImportEncryptKeyFuncTable) / \
sizeof(ImportEncryptKeyFuncTable[0]))
#ifdef DEBUG_CRYPT_ASN1_MASTER
static HMODULE hOssCryptDll = NULL;
#endif // DEBUG_CRYPT_ASN1_MASTER
#ifdef DEBUG_CRYPT_ASN1
#define DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG 0x010
#define DEBUG_OSS_CRYPT_ASN1_CMSG_COMPARE_FLAG 0x020
#define DEBUG_OSS_CRYPT_ASN1_SAME_ENCRYPT_FLAG 0x100
static BOOL fGotDebugCryptAsn1Flags = FALSE;
static int iDebugCryptAsn1Flags = 0;
int
WINAPI
ICMTest_GetDebugCryptAsn1Flags();
#endif // DEBUG_CRYPT_ASN1
//+-------------------------------------------------------------------------
// Function: CryptMsgDllMain
//
// Synopsis: Initialize the CryptMsg module
//
// Returns: FALSE iff failed
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptMsgDllMain(
HMODULE hInst,
ULONG ulReason,
LPVOID lpReserved)
{
BOOL fRet;
switch (ulReason) {
case DLL_PROCESS_ATTACH:
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CRYPT_OID_ENCODE_OBJECT_FUNC,
ICM_ENCODE_FUNC_COUNT,
ICM_EncodeFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CRYPT_OID_DECODE_OBJECT_FUNC,
ICM_DECODE_FUNC_COUNT,
ICM_DecodeFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
#ifdef CMS_PKCS7
if (NULL == (hOldStyleGenEncryptKeyFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_GEN_ENCRYPT_KEY_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (NULL == (hOldStyleExportEncryptKeyFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_EXPORT_ENCRYPT_KEY_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (NULL == (hOldStyleImportEncryptKeyFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_IMPORT_ENCRYPT_KEY_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (NULL == (hGenContentEncryptKeyFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (NULL == (hExportKeyTransFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_EXPORT_KEY_TRANS_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (NULL == (hExportKeyAgreeFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_EXPORT_KEY_AGREE_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (NULL == (hExportMailListFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_EXPORT_MAIL_LIST_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (NULL == (hImportKeyTransFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_IMPORT_KEY_TRANS_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (NULL == (hImportKeyAgreeFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_IMPORT_KEY_AGREE_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (NULL == (hImportMailListFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_IMPORT_MAIL_LIST_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CMSG_OID_GEN_CONTENT_ENCRYPT_KEY_FUNC,
1,
GenContentEncryptKeyFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CMSG_OID_EXPORT_KEY_TRANS_FUNC,
1,
ExportKeyTransFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CMSG_OID_EXPORT_KEY_AGREE_FUNC,
1,
ExportKeyAgreeFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CMSG_OID_EXPORT_MAIL_LIST_FUNC,
1,
ExportMailListFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CMSG_OID_IMPORT_KEY_TRANS_FUNC,
1,
ImportKeyTransFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CMSG_OID_IMPORT_KEY_AGREE_FUNC,
1,
ImportKeyAgreeFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CMSG_OID_IMPORT_MAIL_LIST_FUNC,
1,
ImportMailListFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
#else
if (NULL == (hGenEncryptKeyFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_GEN_ENCRYPT_KEY_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (NULL == (hExportEncryptKeyFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_EXPORT_ENCRYPT_KEY_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
if (NULL == (hImportEncryptKeyFuncSet = CryptInitOIDFunctionSet(
CMSG_OID_IMPORT_ENCRYPT_KEY_FUNC,
0)))
goto CryptInitOIDFunctionSetError;
#endif // CMS_PKCS7
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CMSG_OID_GEN_ENCRYPT_KEY_FUNC,
GEN_ENCRYPT_KEY_FUNC_COUNT,
GenEncryptKeyFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CMSG_OID_EXPORT_ENCRYPT_KEY_FUNC,
EXPORT_ENCRYPT_KEY_FUNC_COUNT,
ExportEncryptKeyFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
if (!CryptInstallOIDFunctionAddress(
NULL, // hModule
X509_ASN_ENCODING,
CMSG_OID_IMPORT_ENCRYPT_KEY_FUNC,
IMPORT_ENCRYPT_KEY_FUNC_COUNT,
ImportEncryptKeyFuncTable,
0)) // dwFlags
goto CryptInstallOIDFunctionAddressError;
#ifdef OSS_CRYPT_ASN1
if (0 == (ICM_hAsn1Module = I_CryptInstallAsn1Module(pkcs, 0, NULL)))
goto CryptInstallAsn1ModuleError;
#else
PKCS_Module_Startup();
if (0 == (ICM_hAsn1Module = I_CryptInstallAsn1Module(
PKCS_Module, 0, NULL))) {
PKCS_Module_Cleanup();
goto CryptInstallAsn1ModuleError;
}
#endif // OSS_CRYPT_ASN1
break;
case DLL_PROCESS_DETACH:
#ifdef DEBUG_CRYPT_ASN1_MASTER
if (hOssCryptDll) {
FreeLibrary(hOssCryptDll);
hOssCryptDll = NULL;
}
#endif // DEBUG_CRYPT_ASN1_MASTER
I_CryptUninstallAsn1Module(ICM_hAsn1Module);
#ifndef OSS_CRYPT_ASN1
PKCS_Module_Cleanup();
#endif // OSS_CRYPT_ASN1
case DLL_THREAD_DETACH:
default:
break;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(CryptInstallAsn1ModuleError)
TRACE_ERROR(CryptInstallOIDFunctionAddressError)
TRACE_ERROR(CryptInitOIDFunctionSetError)
lpReserved;
hInst;
}
//+-------------------------------------------------------------------------
// Utility routines
//--------------------------------------------------------------------------
LONG
WINAPI
ICM_PszOidToIndex(
IN LPSTR pszOID)
{
LONG i;
for (i=COUNTOF_apszObjIdPKCS7; i>0; i--)
if (0 == strcmp( apszObjIdPKCS7[i-1], pszOID))
break;
return i;
}
LONG
WINAPI
ICM_ObjIdToIndex(
IN ObjectID *poi)
{
LONG i;
LONG j;
for (i=COUNTOF_aoidMessages; i>0; i--) {
if (aoidMessages[i-1].count == poi->count) {
for (j=poi->count; j>0; j--)
if (poi->value[j-1] != aoidMessages[i-1].value[j-1])
goto next;
break;
}
next:
;
}
return i;
}
BOOL
WINAPI
ICM_CopyOssObjectIdentifier(
OUT ObjectID *poiDst,
IN ObjectID *poiSrc)
{
USHORT i;
ULONG *pulDst;
ULONG *pulSrc;
poiDst->count = poiSrc->count;
for (i=poiSrc->count, pulDst=poiDst->value, pulSrc=poiSrc->value;
i>0;
i--, pulDst++, pulSrc++)
*pulDst = *pulSrc;
return TRUE;
}
BOOL
WINAPI
ICM_IsData(
IN LPSTR pszContentType)
{
return !pszContentType || (0 == strcmp( pszContentType, pszObjIdDataType));
}
BOOL
WINAPI
ICM_ReverseInPlace(
IN OUT PBYTE pbIn,
IN const ULONG cbIn)
{
PBYTE pbLo;
PBYTE pbHi;
BYTE bTmp;
for (pbLo = pbIn, pbHi = pbIn + cbIn - 1; pbLo < pbHi; pbHi--, pbLo++) {
bTmp = *pbHi;
*pbHi = *pbLo;
*pbLo = bTmp;
}
return TRUE;
}
BOOL
WINAPI
ICM_ReverseCopy(
OUT PBYTE pbOut,
IN PBYTE pbInOrg,
IN ULONG cbIn)
{
PBYTE pbIn = pbInOrg + cbIn - 1;
while (cbIn-- > 0)
*pbOut++ = *pbIn--;
return TRUE;
}
//
// return FALSE iff equal
//
BOOL
WINAPI
ICM_ReverseCompare(
IN PBYTE pbInOrg1,
IN PBYTE pbInOrg2,
IN ULONG cb)
{
PBYTE pbIn1 = pbInOrg1;
PBYTE pbIn2 = pbInOrg2 + cb - 1;
while (cb-- > 0)
if (*pbIn1++ != *pbIn2--)
return TRUE;
return FALSE;
}
BOOL
WINAPI
ICM_CopyOut(
IN PBYTE pbData,
IN DWORD cbData,
OUT PBYTE pbOut,
IN OUT PDWORD pcbOut)
{
BOOL fRet = TRUE;
if (pbOut) {
if (*pcbOut < cbData) {
SetLastError((DWORD) ERROR_MORE_DATA);
fRet = FALSE;
} else {
memcpy(pbOut, pbData, cbData);
}
}
*pcbOut = cbData;
return fRet;
}
//+-------------------------------------------------------------------------
// Copy out the encoding of the length octets for a specified content length.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetLengthOctets(
IN DWORD cbContent,
OUT OPTIONAL PBYTE pbOut,
IN OUT PDWORD pcbOut)
{
BOOL fRet;
BYTE rgbLength[5];
DWORD cbLength;
if (cbContent < 0x80) {
rgbLength[0] = (BYTE)cbContent;
cbLength = 0;
} else {
if (cbContent > 0xffffff)
cbLength = 4;
else if (cbContent > 0xffff)
cbLength = 3;
else if (cbContent > 0xff)
cbLength = 2;
else
cbLength = 1;
if (pbOut) {
rgbLength[0] = (BYTE)cbLength | 0x80;
ICM_ReverseCopy( (PBYTE)(rgbLength+1), (PBYTE)&cbContent, cbLength);
}
}
if (pbOut) {
fRet = ICM_CopyOut( (PBYTE)rgbLength, cbLength+1, pbOut, pcbOut);
} else {
fRet = TRUE;
}
*pcbOut = cbLength + 1;
assert(fRet);
return fRet;
}
//+-------------------------------------------------------------------------
// Copy out a buffer, prepending the identifier and length octets for a
// DER encoding.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_CopyOutAddDERPrefix(
IN PBYTE pbContent,
IN DWORD cbContent,
IN OPTIONAL BYTE bTag,
OUT PBYTE pbOut,
IN OUT PDWORD pcbOut)
{
BOOL fRet;
BYTE rgbLength[5];
DWORD cbLength;
DWORD cbData;
cbLength = sizeof(rgbLength);
if (!ICM_GetLengthOctets( cbContent, (PBYTE)rgbLength, &cbLength))
goto GetLengthOctetsError;
fRet = TRUE;
cbData = 1 + cbLength + cbContent;
if (pbOut) {
if (*pcbOut < cbData) {
SetLastError((DWORD) ERROR_MORE_DATA);
fRet = FALSE;
} else {
*pbOut++ = bTag;
memcpy(pbOut, rgbLength, cbLength);
pbOut += cbLength;
memcpy(pbOut, pbContent, cbContent);
}
}
CommonReturn:
*pcbOut = cbData;
return fRet;
ErrorReturn:
cbData = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetLengthOctetsError) // error already set
}
BOOL
WINAPI
ICM_GetSizeFromExtra(
IN LONG lRemainExtra,
OUT PVOID pOut,
IN OUT DWORD *pcbOut)
{
BOOL fRet = TRUE;
if ((lRemainExtra < 0) && pOut) {
SetLastError((DWORD) ERROR_MORE_DATA);
fRet = FALSE;
}
*pcbOut = (DWORD)((LONG)*pcbOut - lRemainExtra);
return fRet;
}
VOID
WINAPI
ICM_SetLastError(
IN DWORD dwError)
{
if (dwError != ERROR_SUCCESS)
SetLastError( dwError);
}
//+-------------------------------------------------------------------------
// Encode an OSS struct to a blob, internally allocated
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_Asn1Encode(
ASN1uint32_t pdunum,
IN PVOID pOssInfo,
OUT PCRYPT_DATA_BLOB pBlob)
{
BOOL fRet;
PBYTE pbEncoded = NULL;
DWORD cbEncoded;
ASN1encoding_t pEnc = ICM_GetEncoder();
DWORD dwError = ERROR_SUCCESS;
if (!PkiAsn1EncodeInfo(
pEnc,
pdunum,
pOssInfo,
NULL, // pbEncoded
&cbEncoded))
goto EncodeSizeError;
if (NULL == (pbEncoded = (PBYTE)ICM_Alloc( cbEncoded)))
goto AllocError;
if (!PkiAsn1EncodeInfo(
pEnc,
pdunum,
pOssInfo,
pbEncoded,
&cbEncoded))
goto EncodeError;
fRet = TRUE;
CommonReturn:
pBlob->pbData = pbEncoded;
pBlob->cbData = cbEncoded;
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
ICM_Free(pbEncoded);
pbEncoded = NULL;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(EncodeSizeError) // error already set
TRACE_ERROR(AllocError) // error already set
TRACE_ERROR(EncodeError) // error already set
}
//+-------------------------------------------------------------------------
// Given an OID, return the CAPI algorithm
//
// Caller sets error.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetCAPIFromOID(
IN DWORD dwGroupId,
IN LPSTR pszObjId,
OUT PDWORD pdwAlgId)
{
BOOL fRet;
PCCRYPT_OID_INFO pOIDInfo;
if (NULL == (pOIDInfo = CryptFindOIDInfo(
CRYPT_OID_INFO_OID_KEY,
pszObjId,
dwGroupId))) goto NotFoundError;
*pdwAlgId = pOIDInfo->Algid;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
*pdwAlgId = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(NotFoundError)
}
//+-------------------------------------------------------------------------
// Given an CRYPT_ALGORITHM_IDENTIFIER, return the CAPI algorithm
//
// Caller sets error.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetCAPI(
IN DWORD dwGroupId,
IN PCRYPT_ALGORITHM_IDENTIFIER pai,
OUT PDWORD pdwAlgId)
{
return ICM_GetCAPIFromOID(dwGroupId, pai->pszObjId, pdwAlgId);
}
//+-------------------------------------------------------------------------
// Given an OSS AlgorithmIdentifier, return the OID Info
//
// Caller sets error.
//--------------------------------------------------------------------------
PCCRYPT_OID_INFO
WINAPI
ICM_GetOssOIDInfo(
IN DWORD dwGroupId,
IN AlgorithmIdentifier *poai)
{
PCCRYPT_OID_INFO pInfo;
CRYPT_ALGORITHM_IDENTIFIER ai; ZEROSTRUCT( ai);
if (!ICM_Asn1FromAlgorithmIdentifier( poai, &ai))
goto Asn1FromAlgorithmIdentifierError;
pInfo = CryptFindOIDInfo(
CRYPT_OID_INFO_OID_KEY,
ai.pszObjId,
dwGroupId);
CommonReturn:
ICM_Free( ai.pszObjId);
return pInfo;
ErrorReturn:
pInfo = NULL;
goto CommonReturn;
TRACE_ERROR(Asn1FromAlgorithmIdentifierError)
}
//+-------------------------------------------------------------------------
// Given an OSS AlgorithmIdentifier, return the CAPI algorithm
//
// Caller sets error.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssCAPI(
IN DWORD dwGroupId,
IN AlgorithmIdentifier *poai,
OUT PDWORD pdwAlgId)
{
BOOL fRet;
CRYPT_ALGORITHM_IDENTIFIER ai; ZEROSTRUCT( ai);
if (!ICM_Asn1FromAlgorithmIdentifier( poai, &ai))
goto Asn1FromAlgorithmIdentifierError;
fRet = ICM_GetCAPI( dwGroupId, &ai, pdwAlgId);
CommonReturn:
ICM_Free( ai.pszObjId);
return fRet;
ErrorReturn:
*pdwAlgId = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(Asn1FromAlgorithmIdentifierError)
}
//+-------------------------------------------------------------------------
// Allocate and NOCOPY decode
//--------------------------------------------------------------------------
PVOID
WINAPI
ICM_AllocAndDecodeObject(
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded
)
{
void *pvStructInfo = NULL;
DWORD cbStructInfo;
if (!CryptDecodeObject(
X509_ASN_ENCODING,
lpszStructType,
pbEncoded,
cbEncoded,
CRYPT_DECODE_NOCOPY_FLAG,
NULL, // pvStructInfo
&cbStructInfo
) || 0 == cbStructInfo)
goto DecodeError;
if (NULL == (pvStructInfo = ICM_Alloc(cbStructInfo)))
goto OutOfMemory;
if (!CryptDecodeObject(
X509_ASN_ENCODING,
lpszStructType,
pbEncoded,
cbEncoded,
CRYPT_DECODE_NOCOPY_FLAG,
pvStructInfo,
&cbStructInfo
))
goto DecodeError;
CommonReturn:
return pvStructInfo;
ErrorReturn:
ICM_Free(pvStructInfo);
pvStructInfo = NULL;
goto CommonReturn;
TRACE_ERROR(DecodeError)
TRACE_ERROR(OutOfMemory)
}
PCRYPT_ALGORITHM_IDENTIFIER
WINAPI
ICM_AllocAndGetALGORITHM_IDENTIFIER(
IN AlgorithmIdentifier *paiOss)
{
PCRYPT_ALGORITHM_IDENTIFIER pai = NULL;
DWORD cbData;
if (!ICM_GetALGORITHM_IDENTIFIER(
paiOss,
NULL, // pvData
&cbData) || 0 == cbData)
goto GetAlgorithmError;
if (NULL == (pai = (PCRYPT_ALGORITHM_IDENTIFIER)ICM_Alloc(cbData)))
goto OutOfMemory;;
if (!ICM_GetALGORITHM_IDENTIFIER(
paiOss,
pai,
&cbData))
goto GetAlgorithmError;
CommonReturn:
return pai;
ErrorReturn:
ICM_Free(pai);
pai = NULL;
goto CommonReturn;
TRACE_ERROR(GetAlgorithmError);
TRACE_ERROR(OutOfMemory)
}
#ifdef CMS_PKCS7
void *
WINAPI
ICM_AllocAndGetParam(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwParamType,
IN DWORD dwIndex,
OUT OPTIONAL DWORD *pcbData = NULL
)
{
void *pvData = NULL;
DWORD cbData;
if (!CryptMsgGetParam(
(HCRYPTMSG) pcmi,
dwParamType,
dwIndex,
NULL, // pvData
&cbData))
goto CryptMsgGetParamError;
if (0 == cbData)
goto NoParamData;
if (NULL == (pvData = ICM_Alloc(cbData)))
goto OutOfMemory;
if (!CryptMsgGetParam(
(HCRYPTMSG) pcmi,
dwParamType,
dwIndex,
pvData,
&cbData))
goto CryptMsgGetParamError;
CommonReturn:
if (pcbData)
*pcbData = cbData;
return pvData;
ErrorReturn:
if (pvData) {
ICM_Free(pvData);
pvData = NULL;
}
cbData = 0;
goto CommonReturn;
TRACE_ERROR(CryptMsgGetParamError)
TRACE_ERROR(OutOfMemory)
SET_ERROR(NoParamData, CRYPT_E_INVALID_MSG_TYPE)
}
#endif // CMS_PKCS7
BOOL
WINAPI
ICM_RC2VersionToBitLength(
IN DWORD dwVersion,
OUT PDWORD pdwBitLen
)
{
BOOL fRet;
DWORD dwBitLen;
switch (dwVersion) {
case CRYPT_RC2_40BIT_VERSION:
dwBitLen = 40;
break;
case CRYPT_RC2_56BIT_VERSION:
dwBitLen = 56;
break;
case CRYPT_RC2_64BIT_VERSION:
dwBitLen = 64;
break;
case CRYPT_RC2_128BIT_VERSION:
dwBitLen = 128;
break;
default:
goto InvalidRC2VersionError;
}
fRet = TRUE;
CommonReturn:
*pdwBitLen = dwBitLen;
return fRet;
ErrorReturn:
dwBitLen = 0;
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidRC2VersionError, CRYPT_E_BAD_ENCODE)
}
BOOL
WINAPI
ICM_BitLengthToRC2Version(
IN DWORD dwBitLen,
OUT PDWORD pdwVersion
)
{
BOOL fRet;
DWORD dwVersion;
switch (dwBitLen) {
case 40:
dwVersion = CRYPT_RC2_40BIT_VERSION;
break;
case 56:
dwVersion = CRYPT_RC2_56BIT_VERSION;
break;
case 64:
dwVersion = CRYPT_RC2_64BIT_VERSION;
break;
case 128:
dwVersion = CRYPT_RC2_128BIT_VERSION;
break;
default:
goto InvalidArg;
}
fRet = TRUE;
CommonReturn:
*pdwVersion = dwVersion;
return fRet;
ErrorReturn:
dwVersion = 0xFFFFFFFF;
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
}
#define IV_LENGTH 8
// For RC4, the maximum salt length, (128 - 40)/8 = 11.
#define IV_MAX_LENGTH 11
#define AUX_INFO_BIT_LENGTH_MASK 0xFFFF
//+-------------------------------------------------------------------------
// Get the CAPI ALG_ID corresponding to the encryption OID. If the
// ASN.1 encryption algorithm has any parameters, decode to get IV and
// key bit length.
//
// Note, for RC4, the IV is its salt.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetEncryptParameters(
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
OUT PDWORD pdwAlgIdEncrypt,
OUT PDWORD pdwBitLen, // 0 => default length
OUT BYTE rgbIV[IV_MAX_LENGTH],
OUT PDWORD pcbIV
)
{
BOOL fRet;
PCRYPT_DATA_BLOB pIVBlob = NULL;
PCRYPT_RC2_CBC_PARAMETERS pRC2Para = NULL;
*pdwBitLen = 0;
*pcbIV = 0;
if (!ICM_GetCAPI(
CRYPT_ENCRYPT_ALG_OID_GROUP_ID,
paiEncrypt,
pdwAlgIdEncrypt))
goto GetCAPIError;
// Check if more than just the NULL parameters
if (2 < paiEncrypt->Parameters.cbData) {
PBYTE pbIV = NULL;
DWORD cbIV = 0;
PBYTE pbEncoded = paiEncrypt->Parameters.pbData;
DWORD cbEncoded = paiEncrypt->Parameters.cbData;
if (CALG_RC2 == *pdwAlgIdEncrypt) {
// Try to decode as RC2_CBC parameters
if (pRC2Para =
(PCRYPT_RC2_CBC_PARAMETERS) ICM_AllocAndDecodeObject(
PKCS_RC2_CBC_PARAMETERS,
pbEncoded,
cbEncoded)) {
if (!ICM_RC2VersionToBitLength(pRC2Para->dwVersion, pdwBitLen))
goto RC2VersionToBitLengthError;
if (pRC2Para->fIV) {
pbIV = pRC2Para->rgbIV;
cbIV = sizeof(pRC2Para->rgbIV);
}
}
}
if (NULL == pRC2Para) {
// Try to decode as an OctetString containing the IV or the
// salt for RC4
if (pIVBlob = (PCRYPT_DATA_BLOB) ICM_AllocAndDecodeObject(
X509_OCTET_STRING,
pbEncoded,
cbEncoded)) {
pbIV = pIVBlob->pbData;
cbIV = pIVBlob->cbData;
} else
goto DecodeError;
}
if (0 != cbIV) {
if (IV_LENGTH != cbIV &&
(CALG_RC4 != *pdwAlgIdEncrypt ||
IV_MAX_LENGTH < cbIV))
goto InvalidIVLengthError;
memcpy(rgbIV, pbIV, cbIV);
*pcbIV = cbIV;
}
}
fRet = TRUE;
CommonReturn:
ICM_Free(pIVBlob);
ICM_Free(pRC2Para);
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(GetCAPIError, CRYPT_E_UNKNOWN_ALGO)
TRACE_ERROR(DecodeError)
TRACE_ERROR(RC2VersionToBitLengthError)
SET_ERROR(InvalidIVLengthError, CRYPT_E_BAD_ENCODE)
}
#ifdef CMS_PKCS7
//+-------------------------------------------------------------------------
// Get the CAPI ALG_ID corresponding to the encryption OID. Generate
// default parameters for and encode. For RC2, encode as RC2_CBC parameters.
// For all others encode as an IV octet string. The IV is initialized by
// calling CryptGenRandom. For RC4, the IV is really its salt.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_CreateDefaultEncryptParameters(
IN OUT PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
OUT PDWORD pdwAlgIdEncrypt,
OUT PDWORD pdwBitLen, // 0 => default length
OUT BYTE rgbIV[IV_MAX_LENGTH],
OUT PDWORD pcbIV
)
{
BOOL fRet;
HCRYPTPROV hCryptProv; // doesn't need to be released
CRYPT_RC2_CBC_PARAMETERS RC2Para;
CRYPT_DATA_BLOB IVPara;
void *pvPara;
LPCSTR pszStructType;
PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt =
&pContentEncryptInfo->ContentEncryptionAlgorithm;
DWORD dwBitLen = 0;
DWORD cbIV = IV_LENGTH;
CRYPT_ENCODE_PARA EncodePara;
// Get provider to use for generating the random IV or RC4 salt
hCryptProv = I_CryptGetDefaultCryptProv(0);
if (0 == hCryptProv)
goto GetDefaultCryptProvError;
if (!ICM_GetCAPI(
CRYPT_ENCRYPT_ALG_OID_GROUP_ID,
paiEncrypt,
pdwAlgIdEncrypt))
goto GetCAPIError;
if (CALG_RC2 == *pdwAlgIdEncrypt) {
PCMSG_RC2_AUX_INFO pAuxInfo =
(PCMSG_RC2_AUX_INFO) pContentEncryptInfo->pvEncryptionAuxInfo;
if (pAuxInfo && pAuxInfo->cbSize >= sizeof(CMSG_RC2_AUX_INFO)) {
dwBitLen = pAuxInfo->dwBitLen & AUX_INFO_BIT_LENGTH_MASK;
if (!ICM_BitLengthToRC2Version(dwBitLen, &RC2Para.dwVersion))
goto BitLengthToRC2VersionError;
} else {
// Default to 40 bits;
dwBitLen = 40;
RC2Para.dwVersion = CRYPT_RC2_40BIT_VERSION;
}
// Generate the random IV.
if (!CryptGenRandom(hCryptProv, IV_LENGTH, rgbIV))
goto GenRandomError;
// Encode as RC2_CBC parameters
RC2Para.fIV = TRUE;
assert(sizeof(RC2Para.rgbIV) == IV_LENGTH);
memcpy(RC2Para.rgbIV, rgbIV, sizeof(RC2Para.rgbIV));
pvPara = &RC2Para;
pszStructType = PKCS_RC2_CBC_PARAMETERS;
} else {
if (CALG_RC4 == *pdwAlgIdEncrypt) {
// For RC4, the IV is really the RC4 salt. There are
// (128 - dwBitLen)/8 bytes of RC4 salt.
PCMSG_RC4_AUX_INFO pAuxInfo =
(PCMSG_RC4_AUX_INFO) pContentEncryptInfo->pvEncryptionAuxInfo;
// Default to no salt
cbIV = 0;
if (pAuxInfo && pAuxInfo->cbSize >= sizeof(CMSG_RC4_AUX_INFO)) {
dwBitLen = pAuxInfo->dwBitLen & AUX_INFO_BIT_LENGTH_MASK;
if (0 == (pAuxInfo->dwBitLen & CMSG_RC4_NO_SALT_FLAG) &&
128 > dwBitLen) {
cbIV = (128 - dwBitLen)/ 8;
if (IV_MAX_LENGTH < cbIV)
cbIV = IV_MAX_LENGTH;
}
}
if (0 == cbIV)
// No salt
goto SuccessReturn;
}
// Generate the random IV or RC4 salt
assert(0 < cbIV && IV_MAX_LENGTH >= cbIV);
if (!CryptGenRandom(hCryptProv, cbIV, rgbIV))
goto GenRandomError;
IVPara.pbData = rgbIV;
IVPara.cbData = cbIV;
pvPara = &IVPara;
pszStructType = X509_OCTET_STRING;
}
ZEROSTRUCT(EncodePara);
EncodePara.cbSize = sizeof(EncodePara);
EncodePara.pfnAlloc = pContentEncryptInfo->pfnAlloc;
EncodePara.pfnFree = pContentEncryptInfo->pfnFree;
if (!CryptEncodeObjectEx(
X509_ASN_ENCODING,
pszStructType,
pvPara,
CRYPT_ENCODE_ALLOC_FLAG,
&EncodePara,
(void *) &paiEncrypt->Parameters.pbData,
&paiEncrypt->Parameters.cbData
)) goto EncodeError;
pContentEncryptInfo->dwFlags |= CMSG_CONTENT_ENCRYPT_FREE_PARA_FLAG;
SuccessReturn:
fRet = TRUE;
CommonReturn:
*pdwBitLen = dwBitLen;
*pcbIV = cbIV;
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetDefaultCryptProvError)
SET_ERROR(GetCAPIError, CRYPT_E_UNKNOWN_ALGO)
TRACE_ERROR(BitLengthToRC2VersionError)
TRACE_ERROR(GenRandomError)
TRACE_ERROR(EncodeError)
}
BOOL
WINAPI
ICM_IsSP3CompatibleEncrypt(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo
)
{
void *pvEncryptAuxInfo = pContentEncryptInfo->pvEncryptionAuxInfo;
BOOL fSP3CompatibleEncrypt = FALSE;
if (pvEncryptAuxInfo) {
PCMSG_SP3_COMPATIBLE_AUX_INFO pSP3AuxInfo =
(PCMSG_SP3_COMPATIBLE_AUX_INFO) pvEncryptAuxInfo;
if (sizeof(CMSG_SP3_COMPATIBLE_AUX_INFO) <= pSP3AuxInfo->cbSize &&
(pSP3AuxInfo->dwFlags & CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG)) {
fSP3CompatibleEncrypt = TRUE;
}
}
return fSP3CompatibleEncrypt;
}
//+-------------------------------------------------------------------------
// Default generation of the encryption key using the ASN.1 Encryption
// algorithm OID and optional parameters.
//--------------------------------------------------------------------------
BOOL
WINAPI
#ifdef DEBUG_CRYPT_ASN1
ICMTest_DefaultGenContentEncryptKey(
#else
ICM_DefaultGenContentEncryptKey(
#endif
IN OUT PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
)
{
BOOL fRet;
PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt =
&pContentEncryptInfo->ContentEncryptionAlgorithm;
DWORD dwAlgIdEncrypt;
BYTE rgbIV[IV_MAX_LENGTH];
DWORD cbIV;
DWORD dwBitLen;
HCRYPTPROV hCryptProv;
DWORD dwGenFlags;
BOOL fSP3CompatibleEncrypt;
fSP3CompatibleEncrypt = ICM_IsSP3CompatibleEncrypt(pContentEncryptInfo);
if (fSP3CompatibleEncrypt) {
cbIV = 0;
dwBitLen = 0;
if (!ICM_GetCAPI(
CRYPT_ENCRYPT_ALG_OID_GROUP_ID,
paiEncrypt,
&dwAlgIdEncrypt))
goto GetCAPIError;
} else if (0 == paiEncrypt->Parameters.cbData) {
if (!ICM_CreateDefaultEncryptParameters(
pContentEncryptInfo,
&dwAlgIdEncrypt,
&dwBitLen,
rgbIV,
&cbIV))
goto CreateDefaultEncryptParametersError;
} else {
if (!ICM_GetEncryptParameters(
paiEncrypt,
&dwAlgIdEncrypt,
&dwBitLen,
rgbIV,
&cbIV))
goto GetEncryptParametersError;
}
hCryptProv = pContentEncryptInfo->hCryptProv;
if (0 == hCryptProv) {
DWORD dwAlgIdPubKey = 0;
if (0 < pContentEncryptInfo->cRecipients) {
PCMSG_RECIPIENT_ENCODE_INFO prei;
PCRYPT_ALGORITHM_IDENTIFIER paiPubKey;
// Get pointer to public key algorithm associated with the first
// recipient
prei = &pContentEncryptInfo->rgCmsRecipients[0];
switch (prei->dwRecipientChoice) {
case CMSG_KEY_TRANS_RECIPIENT:
paiPubKey = &prei->pKeyTrans->KeyEncryptionAlgorithm;
break;
case CMSG_KEY_AGREE_RECIPIENT:
paiPubKey = &prei->pKeyAgree->KeyEncryptionAlgorithm;
break;
case CMSG_MAIL_LIST_RECIPIENT:
default:
paiPubKey = NULL;
}
if (paiPubKey)
ICM_GetCAPI(
CRYPT_PUBKEY_ALG_OID_GROUP_ID,
paiPubKey,
&dwAlgIdPubKey);
}
hCryptProv = I_CryptGetDefaultCryptProvForEncrypt(
dwAlgIdPubKey, dwAlgIdEncrypt, dwBitLen);
if (0 == hCryptProv)
goto GetDefaultCryptProvError;
else
pContentEncryptInfo->hCryptProv = hCryptProv;
}
if (fSP3CompatibleEncrypt)
dwGenFlags = CRYPT_EXPORTABLE;
else
dwGenFlags = CRYPT_EXPORTABLE | CRYPT_NO_SALT;
dwGenFlags |= dwBitLen << 16;
fRet = CryptGenKey(
hCryptProv,
dwAlgIdEncrypt,
dwGenFlags,
&pContentEncryptInfo->hContentEncryptKey);
if (!fRet) {
// Only need to provide backwards compatibility for
// key transport recipients
if (0 < pContentEncryptInfo->cRecipients) {
PCMSG_RECIPIENT_ENCODE_INFO prei;
prei = &pContentEncryptInfo->rgCmsRecipients[0];
if (CMSG_KEY_TRANS_RECIPIENT != prei->dwRecipientChoice)
goto GenKeyError;
}
if (dwBitLen) {
// Try without setting key length
dwGenFlags &= 0xFFFF;
fRet = CryptGenKey(
hCryptProv,
dwAlgIdEncrypt,
dwGenFlags,
&pContentEncryptInfo->hContentEncryptKey);
}
if (!fRet && NTE_BAD_FLAGS == GetLastError())
// Previous versions didn't support CRYPT_NO_SALT flag
fRet = CryptGenKey(
hCryptProv,
dwAlgIdEncrypt,
CRYPT_EXPORTABLE, // dwFlags
&pContentEncryptInfo->hContentEncryptKey);
if (!fRet) {
pContentEncryptInfo->hContentEncryptKey = 0;
goto GenKeyError;
}
}
if (CALG_RC2 == dwAlgIdEncrypt && 0 != dwBitLen)
// Silently ignore any errors. Not supported in earlier versions
CryptSetKeyParam(
pContentEncryptInfo->hContentEncryptKey,
KP_EFFECTIVE_KEYLEN,
(PBYTE) &dwBitLen,
0); // dwFlags
if (0 != cbIV) {
if (CALG_RC4 == dwAlgIdEncrypt) {
// For RC4, set the SALT, not the IV
CRYPT_DATA_BLOB SaltBlob;
SaltBlob.pbData = rgbIV;
SaltBlob.cbData = cbIV;
if (!CryptSetKeyParam(
pContentEncryptInfo->hContentEncryptKey,
KP_SALT_EX,
(PBYTE) &SaltBlob,
0)) // dwFlags
goto SetSaltExError;
} else {
if (!CryptSetKeyParam(
pContentEncryptInfo->hContentEncryptKey,
KP_IV,
rgbIV,
0)) // dwFlags
goto SetIVError;
}
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(GetCAPIError, CRYPT_E_UNKNOWN_ALGO)
TRACE_ERROR(CreateDefaultEncryptParametersError)
TRACE_ERROR(GetEncryptParametersError)
TRACE_ERROR(GetDefaultCryptProvError)
TRACE_ERROR(GenKeyError)
TRACE_ERROR(SetSaltExError)
TRACE_ERROR(SetIVError)
}
BOOL
WINAPI
ICM_GenContentEncryptKey(
IN OUT PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo
)
{
BOOL fRet;
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr = NULL;
LPCSTR pszContentEncryptOID =
pContentEncryptInfo->ContentEncryptionAlgorithm.pszObjId;
if (CryptGetOIDFunctionAddress(
hGenContentEncryptKeyFuncSet,
X509_ASN_ENCODING,
pszContentEncryptOID,
0, // dwFlags
&pvFuncAddr,
&hFuncAddr)) {
fRet = ((PFN_CMSG_GEN_CONTENT_ENCRYPT_KEY) pvFuncAddr)(
pContentEncryptInfo,
0, // dwFlags
NULL // pvReserved
);
} else {
if (pContentEncryptInfo->cRecipients
&&
CMSG_KEY_TRANS_RECIPIENT ==
pContentEncryptInfo->rgCmsRecipients[0].dwRecipientChoice
&&
CryptGetOIDFunctionAddress(
hOldStyleGenEncryptKeyFuncSet,
X509_ASN_ENCODING,
pszContentEncryptOID,
0, // dwFlags
&pvFuncAddr,
&hFuncAddr)
&&
#ifdef DEBUG_CRYPT_ASN1
0 == (ICMTest_GetDebugCryptAsn1Flags() &
DEBUG_OSS_CRYPT_ASN1_SAME_ENCRYPT_FLAG)
&&
#endif // DEBUG_CRYPT_ASN1
(void *) ICM_DefaultGenEncryptKey != pvFuncAddr) {
PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTrans =
pContentEncryptInfo->rgCmsRecipients[0].pKeyTrans;
CERT_PUBLIC_KEY_INFO PublicKeyInfo;
PBYTE pbEncryptParameters = NULL;
DWORD rgcbEncryptParameters[2] = {0, 0};
PublicKeyInfo.Algorithm = pKeyTrans->KeyEncryptionAlgorithm;
PublicKeyInfo.PublicKey = pKeyTrans->RecipientPublicKey;
fRet = ((PFN_CMSG_GEN_ENCRYPT_KEY) pvFuncAddr)(
&pContentEncryptInfo->hCryptProv,
&pContentEncryptInfo->ContentEncryptionAlgorithm,
pContentEncryptInfo->pvEncryptionAuxInfo,
&PublicKeyInfo,
pContentEncryptInfo->pfnAlloc,
&pContentEncryptInfo->hContentEncryptKey,
&pbEncryptParameters,
rgcbEncryptParameters);
if (pbEncryptParameters) {
pContentEncryptInfo->ContentEncryptionAlgorithm.Parameters.pbData =
pbEncryptParameters;
pContentEncryptInfo->ContentEncryptionAlgorithm.Parameters.cbData =
rgcbEncryptParameters[0];
pContentEncryptInfo->dwFlags |=
CMSG_CONTENT_ENCRYPT_FREE_PARA_FLAG;
}
} else {
fRet = ICM_DefaultGenContentEncryptKey(
pContentEncryptInfo,
0, // dwFlags
NULL // pvReserved
);
}
}
if (hFuncAddr)
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return fRet;
}
//+-------------------------------------------------------------------------
// Default generation of the encryption key using the ASN.1 Encryption
// algorithm OID and optional parameters.
//
// rgcbEncryptParameters[1] is the dwEncryptFlags passed to
// ICM_DefaultExportEncryptKey
//
// OldStyle.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultGenEncryptKey(
IN OUT HCRYPTPROV *phCryptProv,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PVOID pvEncryptAuxInfo,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
IN PFN_CMSG_ALLOC pfnAlloc,
OUT HCRYPTKEY *phEncryptKey,
OUT PBYTE *ppbEncryptParameters,
OUT DWORD rgcbEncryptParameters[2])
{
BOOL fRet;
CMSG_CONTENT_ENCRYPT_INFO ContentEncryptInfo;
ZEROSTRUCT(ContentEncryptInfo);
CMSG_RECIPIENT_ENCODE_INFO CmsRecipientEncodeInfo;
ZEROSTRUCT(CmsRecipientEncodeInfo);
CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO KeyTransEncodeInfo;
ZEROSTRUCT(KeyTransEncodeInfo);
ContentEncryptInfo.cbSize = sizeof(ContentEncryptInfo);
ContentEncryptInfo.hCryptProv = *phCryptProv;
ContentEncryptInfo.ContentEncryptionAlgorithm = *paiEncrypt;
ContentEncryptInfo.pvEncryptionAuxInfo = pvEncryptAuxInfo;
ContentEncryptInfo.cRecipients = 1;
ContentEncryptInfo.rgCmsRecipients = &CmsRecipientEncodeInfo;
ContentEncryptInfo.pfnAlloc = pfnAlloc;
ContentEncryptInfo.pfnFree = ICM_Free;
// ContentEncryptInfo.hContentEncryptKey =
// ContentEncryptInfo.dwFlags =
CmsRecipientEncodeInfo.dwRecipientChoice = CMSG_KEY_TRANS_RECIPIENT;
CmsRecipientEncodeInfo.pKeyTrans = &KeyTransEncodeInfo;
KeyTransEncodeInfo.cbSize = sizeof(KeyTransEncodeInfo);
KeyTransEncodeInfo.KeyEncryptionAlgorithm = pPublicKeyInfo->Algorithm;
// KeyTransEncodeInfo.pvKeyEncryptionAuxInfo =
// KeyTransEncodeInfo.hCryptProv =
KeyTransEncodeInfo.RecipientPublicKey = pPublicKeyInfo->PublicKey;
// KeyTransEncodeInfo.RecipientId =
// dwEncryptFlags
if (ICM_IsSP3CompatibleEncrypt(&ContentEncryptInfo))
rgcbEncryptParameters[1] = CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG;
else
rgcbEncryptParameters[1] = 0;
fRet = ICM_DefaultGenContentEncryptKey(
&ContentEncryptInfo,
0, // dwFlags
NULL // pvReserved
);
assert(0 == (ContentEncryptInfo.dwFlags &
CMSG_CONTENT_ENCRYPT_RELEASE_CONTEXT_FLAG));
if (fRet) {
if (ContentEncryptInfo.dwFlags & CMSG_CONTENT_ENCRYPT_FREE_PARA_FLAG) {
*ppbEncryptParameters =
ContentEncryptInfo.ContentEncryptionAlgorithm.Parameters.pbData;
rgcbEncryptParameters[0] =
ContentEncryptInfo.ContentEncryptionAlgorithm.Parameters.cbData;
}
*phCryptProv = ContentEncryptInfo.hCryptProv;
*phEncryptKey = ContentEncryptInfo.hContentEncryptKey;
} else {
if (ContentEncryptInfo.dwFlags & CMSG_CONTENT_ENCRYPT_FREE_PARA_FLAG)
ICM_Free(ContentEncryptInfo.ContentEncryptionAlgorithm.Parameters.pbData);
if (ContentEncryptInfo.hContentEncryptKey) {
DWORD dwErr = GetLastError();
CryptDestroyKey(ContentEncryptInfo.hContentEncryptKey);
SetLastError(dwErr);
}
*phEncryptKey = 0;
}
return fRet;
}
#else
//+-------------------------------------------------------------------------
// Get the CAPI ALG_ID corresponding to the encryption OID. Generate
// default parameters for and encode. For RC2, encode as RC2_CBC parameters.
// For all others encode as an IV octet string. The IV is initialized by
// calling CryptGenRandom.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_CreateDefaultEncryptParameters(
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PVOID pvEncryptAuxInfo,
IN PFN_CMSG_ALLOC pfnAlloc,
OUT PBYTE *ppbEncryptParameters,
OUT PDWORD pcbEncryptParameters,
OUT PDWORD pdwAlgIdEncrypt,
OUT PDWORD pdwBitLen, // 0 => default length
OUT BYTE rgbIV[IV_LENGTH],
OUT PDWORD pcbIV
)
{
BOOL fRet;
HCRYPTPROV hCryptProv; // doesn't need to be released
CRYPT_RC2_CBC_PARAMETERS RC2Para;
CRYPT_DATA_BLOB IVPara;
void *pvPara;
LPCSTR pszStructType;
*ppbEncryptParameters = NULL;
*pcbEncryptParameters = 0;
*pdwBitLen = 0;
*pcbIV = IV_LENGTH;
if (!ICM_GetCAPI(
CRYPT_ENCRYPT_ALG_OID_GROUP_ID,
paiEncrypt,
pdwAlgIdEncrypt))
goto GetCAPIError;
// Generate the random IV.
hCryptProv = I_CryptGetDefaultCryptProv(0);
if (0 == hCryptProv)
goto GetDefaultCryptProvError;
if (!CryptGenRandom(hCryptProv, IV_LENGTH, rgbIV))
goto GenRandomError;
if (CALG_RC2 == *pdwAlgIdEncrypt) {
PCMSG_RC2_AUX_INFO pAuxInfo = (PCMSG_RC2_AUX_INFO) pvEncryptAuxInfo;
if (pAuxInfo && pAuxInfo->cbSize >= sizeof(CMSG_RC2_AUX_INFO)) {
*pdwBitLen = pAuxInfo->dwBitLen & ~CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG;
if (!ICM_BitLengthToRC2Version(*pdwBitLen, &RC2Para.dwVersion))
goto BitLengthToRC2VersionError;
} else {
// Default to 40 bits;
*pdwBitLen = 40;
RC2Para.dwVersion = CRYPT_RC2_40BIT_VERSION;
}
// Encode as RC2_CBC parameters
RC2Para.fIV = TRUE;
assert(sizeof(RC2Para.rgbIV) == IV_LENGTH);
memcpy(RC2Para.rgbIV, rgbIV, sizeof(RC2Para.rgbIV));
pvPara = &RC2Para;
pszStructType = PKCS_RC2_CBC_PARAMETERS;
} else {
IVPara.pbData = rgbIV;
IVPara.cbData = IV_LENGTH;
pvPara = &IVPara;
pszStructType = X509_OCTET_STRING;
}
if (!CryptEncodeObject(
X509_ASN_ENCODING,
pszStructType,
pvPara,
NULL, // pbEncoded
pcbEncryptParameters
)) goto EncodeError;
if (NULL == (*ppbEncryptParameters = (PBYTE) pfnAlloc(
*pcbEncryptParameters)))
goto OutOfMemory;
if (!CryptEncodeObject(
X509_ASN_ENCODING,
pszStructType,
pvPara,
*ppbEncryptParameters,
pcbEncryptParameters
)) goto EncodeError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(GetCAPIError, CRYPT_E_UNKNOWN_ALGO)
TRACE_ERROR(BitLengthToRC2VersionError)
TRACE_ERROR(GetDefaultCryptProvError)
TRACE_ERROR(GenRandomError)
TRACE_ERROR(EncodeError)
TRACE_ERROR(OutOfMemory)
}
//+-------------------------------------------------------------------------
// Default generation of the encryption key using the ASN.1 Encryption
// algorithm OID and optional parameters.
//
// rgcbEncryptParameters[1] is the dwEncryptFlags passed to
// ICM_DefaultExportEncryptKey
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultGenEncryptKey(
IN OUT HCRYPTPROV *phCryptProv,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PVOID pvEncryptAuxInfo,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
IN PFN_CMSG_ALLOC pfnAlloc,
OUT HCRYPTKEY *phEncryptKey,
OUT PBYTE *ppbEncryptParameters,
OUT DWORD rgcbEncryptParameters[2])
{
BOOL fRet;
DWORD dwAlgIdEncrypt;
HCRYPTPROV hCryptProv;
BYTE rgbIV[IV_LENGTH];
DWORD cbIV;
DWORD dwBitLen;
DWORD dwEncryptFlags;
*phEncryptKey = 0;
dwEncryptFlags = 0;
rgcbEncryptParameters[1] = 0; // dwEncryptFlags
if (pvEncryptAuxInfo) {
PCMSG_SP3_COMPATIBLE_AUX_INFO pSP3AuxInfo =
(PCMSG_SP3_COMPATIBLE_AUX_INFO) pvEncryptAuxInfo;
if (sizeof(CMSG_SP3_COMPATIBLE_AUX_INFO) <= pSP3AuxInfo->cbSize &&
(pSP3AuxInfo->dwFlags & CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG)) {
dwEncryptFlags = CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG;
rgcbEncryptParameters[1] = CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG;
}
}
if (dwEncryptFlags & CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG) {
cbIV = 0;
dwBitLen = 0;
if (!ICM_GetCAPI(
CRYPT_ENCRYPT_ALG_OID_GROUP_ID,
paiEncrypt,
&dwAlgIdEncrypt))
goto GetCAPIError;
} else if (0 == paiEncrypt->Parameters.cbData) {
if (!ICM_CreateDefaultEncryptParameters(
paiEncrypt,
pvEncryptAuxInfo,
pfnAlloc,
ppbEncryptParameters,
rgcbEncryptParameters,
&dwAlgIdEncrypt,
&dwBitLen,
rgbIV,
&cbIV))
goto CreateDefaultEncryptParametersError;
} else {
if (!ICM_GetEncryptParameters(
paiEncrypt,
&dwAlgIdEncrypt,
&dwBitLen,
rgbIV,
&cbIV))
goto GetEncryptParametersError;
}
hCryptProv = *phCryptProv;
if (0 == hCryptProv) {
DWORD dwAlgIdPubKey = 0;
ICM_GetCAPI(
CRYPT_PUBKEY_ALG_OID_GROUP_ID,
&pPublicKeyInfo->Algorithm,
&dwAlgIdPubKey);
hCryptProv = I_CryptGetDefaultCryptProvForEncrypt(
dwAlgIdPubKey, dwAlgIdEncrypt, dwBitLen);
if (0 == hCryptProv)
goto GetDefaultCryptProvError;
else
*phCryptProv = hCryptProv;
}
fRet = CryptGenKey(
hCryptProv,
dwAlgIdEncrypt,
(dwEncryptFlags & CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG) ?
CRYPT_EXPORTABLE :
CRYPT_EXPORTABLE | CRYPT_NO_SALT, // dwFlags
phEncryptKey);
if (!fRet) {
if (NTE_BAD_FLAGS == GetLastError())
// Previous versions didn't support CRYPT_NO_SALT flag
fRet = CryptGenKey(
hCryptProv,
dwAlgIdEncrypt,
CRYPT_EXPORTABLE, // dwFlags
phEncryptKey);
if (!fRet) {
*phEncryptKey = 0;
goto GenKeyError;
}
}
if (CALG_RC2 == dwAlgIdEncrypt && 0 != dwBitLen)
// Silently ignore any errors. Not supported in earlier versions
CryptSetKeyParam(
*phEncryptKey,
KP_EFFECTIVE_KEYLEN,
(PBYTE) &dwBitLen,
0); // dwFlags
if (0 != cbIV) {
if (!CryptSetKeyParam(
*phEncryptKey,
KP_IV,
rgbIV,
0)) // dwFlags
goto SetKeyParamError;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
if (*phEncryptKey) {
DWORD dwErr = GetLastError();
CryptDestroyKey(*phEncryptKey);
*phEncryptKey = 0;
SetLastError(dwErr);
}
fRet = FALSE;
goto CommonReturn;
SET_ERROR(GetCAPIError, CRYPT_E_UNKNOWN_ALGO)
TRACE_ERROR(CreateDefaultEncryptParametersError)
TRACE_ERROR(GetEncryptParametersError)
TRACE_ERROR(GetDefaultCryptProvError)
TRACE_ERROR(GenKeyError)
TRACE_ERROR(SetKeyParamError)
}
//+-------------------------------------------------------------------------
// Get an hkey for content encryption for a particular algorithm
//
// rgcbEncryptParameters[1] is the dwEncryptFlags passed to
// ICM_ExportEncryptKey
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GenEncryptKey(
IN OUT HCRYPTPROV *phCryptProv,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PVOID pvEncryptAuxInfo,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
IN PFN_CMSG_ALLOC pfnAlloc,
OUT HCRYPTKEY *phEncryptKey,
OUT PBYTE *ppbEncryptParameters,
OUT DWORD rgcbEncryptParameters[2])
{
BOOL fResult;
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (CryptGetOIDFunctionAddress(
hGenEncryptKeyFuncSet,
X509_ASN_ENCODING,
paiEncrypt->pszObjId,
0, // dwFlags
&pvFuncAddr,
&hFuncAddr)) {
fResult = ((PFN_CMSG_GEN_ENCRYPT_KEY) pvFuncAddr)(
phCryptProv,
paiEncrypt,
pvEncryptAuxInfo,
pPublicKeyInfo,
pfnAlloc,
phEncryptKey,
ppbEncryptParameters,
rgcbEncryptParameters);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
} else
fResult = ICM_DefaultGenEncryptKey(
phCryptProv,
paiEncrypt,
pvEncryptAuxInfo,
pPublicKeyInfo,
pfnAlloc,
phEncryptKey,
ppbEncryptParameters,
rgcbEncryptParameters);
return fResult;
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Advance the phase of a message
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_AdvanceMsgPhase(
IN OUT PDWORD pdwPhase,
IN BOOL fFinal)
{
BOOL fRet;
DWORD dwPhase = *pdwPhase;
switch (dwPhase) {
case PHASE_FIRST_ONGOING:
dwPhase = fFinal ? PHASE_FIRST_FINAL : PHASE_FIRST_ONGOING;
break;
case PHASE_FIRST_FINAL:
dwPhase = fFinal ? PHASE_SECOND_FINAL : PHASE_SECOND_ONGOING;
break;
case PHASE_SECOND_ONGOING:
dwPhase = fFinal ? PHASE_SECOND_FINAL : PHASE_SECOND_ONGOING;
break;
case PHASE_SECOND_FINAL:
goto TransitionFromSecondFinalError;
default:
goto InvalidPhaseError;
}
*pdwPhase = dwPhase;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(TransitionFromSecondFinalError,CRYPT_E_MSG_ERROR)
SET_ERROR(InvalidPhaseError,CRYPT_E_MSG_ERROR)
}
//+-------------------------------------------------------------------------
// Return the (cached) value of the hash
//
// Returns FALSE iff conversion failed.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetListHashValue(
IN CHashNode *pnHash,
OUT DWORD *pcbHash,
OUT PBYTE *ppbHash)
{
BOOL fRet;
PICM_HASH_INFO pHashInfo;
pHashInfo = pnHash->Data();
if (0 == pHashInfo->HashBlob.cbData) {
pHashInfo->HashBlob.pbData = NULL;
if (!CryptGetHashParam(
pHashInfo->hHash,
HP_HASHVAL,
NULL, // pbHash
&pHashInfo->HashBlob.cbData,
0)) // dwFlags
goto GetHashParamSizeError;
pHashInfo->HashBlob.pbData = (PBYTE)ICM_Alloc(
pHashInfo->HashBlob.cbData);
if (NULL == pHashInfo->HashBlob.pbData)
goto HashAllocError;
if (!CryptGetHashParam(
pHashInfo->hHash,
HP_HASHVAL,
pHashInfo->HashBlob.pbData,
&pHashInfo->HashBlob.cbData,
0)) // dwFlags
goto GetHashParamError;
}
*pcbHash = pHashInfo->HashBlob.cbData;
*ppbHash = pHashInfo->HashBlob.pbData;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
if(pHashInfo->HashBlob.pbData != NULL) {
ICM_Free(pHashInfo->HashBlob.pbData);
pHashInfo->HashBlob.pbData = NULL;
}
*pcbHash = 0;
#if DBG
*ppbHash = NULL;
#endif
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetHashParamSizeError) // error already set
TRACE_ERROR(HashAllocError) // error already set
TRACE_ERROR(GetHashParamError) // error already set
}
//+-------------------------------------------------------------------------
// Return a new hash handle equivalent to the original
//
// Returns FALSE iff creation failed.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DupListHash(
IN CHashNode *pnHash,
IN HCRYPTPROV hCryptProv,
OUT HCRYPTHASH *phHash)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PICM_HASH_INFO pHashInfo = pnHash->Data();
HCRYPTHASH hHash = NULL;
DWORD cbHash;
PBYTE pbHash;
if (!ICM_GetListHashValue(
pnHash,
&cbHash,
&pbHash))
goto GetListHashValueError;
if (!CryptCreateHash(
hCryptProv,
pHashInfo->dwAlgoCAPI,
NULL, // hKey - optional for MAC
0, // dwFlags
&hHash))
goto CreateHashError;
if (!CryptSetHashParam(
hHash,
HP_HASHVAL,
pbHash,
0)) // dwFlags
goto SetHashParamError;
fRet = TRUE;
CommonReturn:
*phHash = hHash;
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
if (hHash)
CryptDestroyHash( hHash);
hHash = NULL;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetListHashValueError) // error already set
TRACE_ERROR(CreateHashError) // error already set
TRACE_ERROR(SetHashParamError) // error already set
}
#ifndef CMS_PKCS7
//+-------------------------------------------------------------------------
// Set a DigestAlgorithmIdentifiers
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_SetAsnDigestAlgorithmIdentifiers(
OUT DigestAlgorithmIdentifiers *podais,
OUT PCRYPT_ALGORITHM_IDENTIFIER pai,
IN DWORD cSigners,
IN PCMSG_SIGNER_ENCODE_INFO rgSigners,
OUT HCRYPTPROV *phCryptProv,
OUT DWORD *pdwKeySpec)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
DWORD i;
PCMSG_SIGNER_ENCODE_INFO psei;
DigestAlgorithmIdentifier *podai;
*phCryptProv = NULL;
// This code does not remove duplicates from the list of
// algorithms. It is not wrong, but the output message is
// unnecessarily bulky.
if (cSigners) {
podai = (DigestAlgorithmIdentifier *)ICM_AllocZero(
cSigners * sizeof( DigestAlgorithmIdentifier));
if (NULL == podai)
goto DigestAlgorithmIdentifierAllocError;
} else {
podai = NULL;
}
podais->count = cSigners;
podais->value = podai;
for (i=cSigners, psei=rgSigners; i>0; i--, psei++, podai++) {
assert( psei->cbSize >= STRUCT_CBSIZE(CMSG_SIGNER_ENCODE_INFO,
rgUnauthAttr));
assert( psei->pvHashAuxInfo == NULL);
if (psei->cbSize <
STRUCT_CBSIZE(CMSG_SIGNER_ENCODE_INFO, rgUnauthAttr) ||
psei->pvHashAuxInfo != NULL)
goto InvalidArg;
*phCryptProv = psei->hCryptProv; // s/b array, one for each algo
*pdwKeySpec = psei->dwKeySpec; // s/b array, one for each algo
*pai = psei->HashAlgorithm; // s/b array, one for each algo
if (!ICM_Asn1ToAlgorithmIdentifier( &psei->HashAlgorithm, podai))
goto Asn1ToAlgorithmIdentifierError;
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
ICM_Free( podai);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(DigestAlgorithmIdentifierAllocError) // error already set
TRACE_ERROR(Asn1ToAlgorithmIdentifierError) // error already set
SET_ERROR(InvalidArg,E_INVALIDARG)
}
#endif // not defined CMS_PKCS7
//+-------------------------------------------------------------------------
// Fill digestEncryptionAlgorithm
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
ICM_FillAsnDigestEncryptionAlgorithm(
IN PCRYPT_MSG_INFO pcmi,
IN PCRYPT_ALGORITHM_IDENTIFIER pDigestEncryptAlg,
IN OUT DigestEncryptionAlgId *pdea
)
{
BOOL fRet;
CRYPT_ALGORITHM_IDENTIFIER DigestEncryptAlg;
DWORD dwFlags;
PCCRYPT_OID_INFO pOIDInfo;
dwFlags = 0;
if (pOIDInfo = CryptFindOIDInfo(
CRYPT_OID_INFO_OID_KEY,
pDigestEncryptAlg->pszObjId,
CRYPT_PUBKEY_ALG_OID_GROUP_ID)) {
if (1 <= pOIDInfo->ExtraInfo.cbData / sizeof(DWORD)) {
DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
dwFlags = pdwExtra[0];
}
// Check if more than just the NULL parameters
if (2 < pDigestEncryptAlg->Parameters.cbData) {
// Check if we should use the public key parameters
if (0 == (dwFlags & CRYPT_OID_USE_PUBKEY_PARA_FOR_PKCS7_FLAG)) {
memset(&DigestEncryptAlg, 0, sizeof(DigestEncryptAlg));
DigestEncryptAlg.pszObjId = pDigestEncryptAlg->pszObjId;
pDigestEncryptAlg = &DigestEncryptAlg;
}
}
} else if (pOIDInfo = CryptFindOIDInfo(
CRYPT_OID_INFO_OID_KEY,
pDigestEncryptAlg->pszObjId,
CRYPT_SIGN_ALG_OID_GROUP_ID)) {
if (2 <= pOIDInfo->ExtraInfo.cbData / sizeof(DWORD)) {
DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
dwFlags = pdwExtra[1];
}
}
if (!ICM_MsgAsn1ToAlgorithmIdentifier(
pcmi,
pDigestEncryptAlg,
pdea))
goto DigestEncryptionAsn1ToAlgorithmIdentifierError;
if (0 == pDigestEncryptAlg->Parameters.cbData &&
0 != (dwFlags & CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG)) {
// NO NULL parameters
pdea->bit_mask &= ~parameters_present;
pdea->parameters.length = 0;
pdea->parameters.value = NULL;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(DigestEncryptionAsn1ToAlgorithmIdentifierError) // error already set
}
void
WINAPI
ICM_GetCertIdFromCertInfo(
IN PCERT_INFO pCertInfo,
OUT PCERT_ID pCertId)
{
if (Asn1UtilExtractKeyIdFromCertInfo(pCertInfo, &pCertId->KeyId)) {
pCertId->dwIdChoice = CERT_ID_KEY_IDENTIFIER;
} else {
pCertId->dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
pCertId->IssuerSerialNumber.Issuer = pCertInfo->Issuer;
pCertId->IssuerSerialNumber.SerialNumber = pCertInfo->SerialNumber;
}
}
BOOL
WINAPI
ICM_GetSignerIdFromSignerEncodeInfo(
IN PCMSG_SIGNER_ENCODE_INFO psei,
OUT PCERT_ID pSignerId)
{
BOOL fRet;
if (STRUCT_CBSIZE(CMSG_SIGNER_ENCODE_INFO, SignerId) <= psei->cbSize &&
psei->SignerId.dwIdChoice) {
*pSignerId = psei->SignerId;
if (!(CERT_ID_ISSUER_SERIAL_NUMBER == pSignerId->dwIdChoice ||
CERT_ID_KEY_IDENTIFIER == pSignerId->dwIdChoice))
goto InvalidSignerIdChoice;
} else
ICM_GetCertIdFromCertInfo(psei->pCertInfo, pSignerId);
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidSignerIdChoice, E_INVALIDARG)
}
BOOL
WINAPI
ICM_SetOssCertIdentifier(
IN PCERT_ID pCertId,
IN OUT CertIdentifier *pOssCertId
);
void
WINAPI
ICM_FreeOssCertIdentifier(
IN OUT CertIdentifier *pOssCertId
);
//+-------------------------------------------------------------------------
// Fill a single SignerInfo
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FillAsnSignerInfo(
IN PCMSG_SIGNER_ENCODE_INFO psei,
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN OUT SignerInfo *psi,
IN OUT Attribute **ppAuthAttr,
IN OUT Attribute **ppUnauthAttr)
{
BOOL fRet;
Attribute *pAuthAttr;
Attribute *pUnauthAttr;
int i;
PCRYPT_ATTRIBUTE patr;
PCRYPT_ALGORITHM_IDENTIFIER pDigestEncryptAlg;
CERT_ID SignerId;
// psi->bit_mask = 0;
if (!ICM_GetSignerIdFromSignerEncodeInfo(psei, &SignerId))
goto GetSignerIdError;
// version
if (CERT_ID_ISSUER_SERIAL_NUMBER == SignerId.dwIdChoice)
psi->version = CMSG_SIGNER_INFO_PKCS_1_5_VERSION;
else
psi->version = CMSG_SIGNER_INFO_CMS_VERSION;
// sid
if (!ICM_SetOssCertIdentifier(
&SignerId,
&psi->sid
))
goto SetOssCertIdentifierError;
// digestAlgorithm
if (!ICM_MsgAsn1ToAlgorithmIdentifier(
pcmi,
&psei->HashAlgorithm,
&psi->digestAlgorithm))
goto DigestAsn1ToAlgorithmIdentifierError;
// authenticatedAttributes
if (!ICM_IsData( pszInnerContentObjID) ||
psei->cAuthAttr ||
(dwFlags & CMSG_AUTHENTICATED_ATTRIBUTES_FLAG)) {
psi->bit_mask |= authenticatedAttributes_present;
// NB - The actual number of authenticated attributes will be
// 2 larger than requested, because of the 2 required
// attributes (if authenticated attributes are present).
// Leave room at the beginning of the attribute array.
pAuthAttr = *ppAuthAttr;
psi->authenticatedAttributes.count = psei->cAuthAttr + 2;
psi->authenticatedAttributes.value = pAuthAttr;
for (i=psei->cAuthAttr, patr=psei->rgAuthAttr, pAuthAttr+=2;
i>0;
i--, patr++, pAuthAttr++) {
if (!ICM_Asn1ToAttribute( patr, pAuthAttr))
goto Asn1AuthenticatedAttributeError;
}
*ppAuthAttr = pAuthAttr;
}
// digestEncryptionAlgorithm
#ifdef CMS_PKCS7
if (STRUCT_CBSIZE(CMSG_SIGNER_ENCODE_INFO, HashEncryptionAlgorithm) <=
psei->cbSize && psei->HashEncryptionAlgorithm.pszObjId)
pDigestEncryptAlg = &psei->HashEncryptionAlgorithm;
else
#endif // CMS_PKCS7
pDigestEncryptAlg = &psei->pCertInfo->SubjectPublicKeyInfo.Algorithm;
if (!ICM_FillAsnDigestEncryptionAlgorithm(
pcmi, pDigestEncryptAlg, &psi->digestEncryptionAlgorithm))
goto FillAsnDigestEncryptionAlgorithmError;
// encryptedDigest is filled in later, when we see the content
// unauthenticatedAttributes
if (0 != psei->cUnauthAttr) {
psi->bit_mask |= unauthAttributes_present;
pUnauthAttr = *ppUnauthAttr;
psi->unauthAttributes.count = psei->cUnauthAttr;
psi->unauthAttributes.value = pUnauthAttr;
for (i=psei->cUnauthAttr, patr=psei->rgUnauthAttr;
i>0;
i--, patr++, pUnauthAttr++) {
if (!ICM_Asn1ToAttribute( patr, pUnauthAttr))
goto Asn1UnauthenticatedAttributeError;
}
*ppUnauthAttr = pUnauthAttr;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetSignerIdError)
TRACE_ERROR(SetOssCertIdentifierError)
TRACE_ERROR(DigestAsn1ToAlgorithmIdentifierError)
TRACE_ERROR(Asn1AuthenticatedAttributeError)
TRACE_ERROR(FillAsnDigestEncryptionAlgorithmError)
TRACE_ERROR(Asn1UnauthenticatedAttributeError)
}
//+-------------------------------------------------------------------------
// Free SignerInfo allocated memory
//--------------------------------------------------------------------------
void
WINAPI
ICM_FreeAsnSignerInfo(
IN OUT SignerInfo *psi)
{
Attribute *poatr;
DWORD i;
ICM_Free(psi->encryptedDigest.value);
ICM_FreeOssCertIdentifier(&psi->sid);
for (i=psi->authenticatedAttributes.count,
poatr = psi->authenticatedAttributes.value;
i>0;
i--, poatr++)
ICM_Free(poatr->attributeValue.value);
for (i=psi->unauthAttributes.count,
poatr=psi->unauthAttributes.value;
i>0;
i--, poatr++)
ICM_Free( poatr->attributeValue.value);
}
//+-------------------------------------------------------------------------
// Set a SignerInfos
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_SetAsnSignerInfos(
IN PCMSG_SIGNED_ENCODE_INFO psmei,
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN OPTIONAL LPSTR pszInnerContentObjID,
OUT SignerInfos *psis,
OUT BOOL *pfHasCmsSignerId)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
DWORD i;
DWORD cAuthAttr;
DWORD cUnauthAttr;
PCMSG_SIGNER_ENCODE_INFO psei;
SignerInfo *psi = NULL;
Attribute *pAuthAttr;
Attribute *pUnauthAttr;
DWORD cSigners = psmei->cSigners;
PCMSG_SIGNER_ENCODE_INFO rgSigners = psmei->rgSigners;
*pfHasCmsSignerId = FALSE;
psis->value = NULL;
psis->count = 0;
if (0 == cSigners)
goto SuccessReturn;
// NB - Each SignerInfo gets a non-empty authenticatedAttributes
// if the inner contentType is not data (passed in) or if
// there are authenticated attributes passed in. In this case,
// we reserve two Attribute slots at the beginning of the array
// for the content-type and message-digest Attribute values.
for (i=cSigners, psei=rgSigners, cAuthAttr=0, cUnauthAttr=0;
i>0;
i--,
#ifdef CMS_PKCS7
psei = (PCMSG_SIGNER_ENCODE_INFO) ((BYTE *) psei + psei->cbSize)) {
#else
psei++) {
#endif // CMS_PKCS7
if (!ICM_IsData( pszInnerContentObjID) ||
psei->cAuthAttr ||
(dwFlags & CMSG_AUTHENTICATED_ATTRIBUTES_FLAG))
cAuthAttr += psei->cAuthAttr + 2; // reserve 2
cUnauthAttr += psei->cUnauthAttr;
}
psi = (SignerInfo *)ICM_AllocZero( cSigners * sizeof( SignerInfo) +
cAuthAttr * sizeof( Attribute) +
cUnauthAttr * sizeof( Attribute)
);
if (NULL == psi)
goto SignerInfoAllocError;
psis->count = cSigners;
psis->value = psi;
pAuthAttr = (Attribute *)(psis->value + cSigners);
pUnauthAttr = pAuthAttr + cAuthAttr;
for (i=cSigners, psei=rgSigners, psi=psis->value; i>0; i--,
#ifdef CMS_PKCS7
psei = (PCMSG_SIGNER_ENCODE_INFO) ((BYTE *) psei + psei->cbSize),
#else
psei++,
#endif // CMS_PKCS7
psi++) {
if (!ICM_FillAsnSignerInfo(
psei,
pcmi,
dwFlags,
pszInnerContentObjID,
psi,
&pAuthAttr,
&pUnauthAttr))
goto FillAsnSignerInfoError;
if (CMSG_SIGNER_INFO_CMS_VERSION <= psi->version)
*pfHasCmsSignerId = TRUE;
}
SuccessReturn:
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(SignerInfoAllocError) // error already set
TRACE_ERROR(FillAsnSignerInfoError) // error already set
}
#ifdef CMS_PKCS7
BOOL
WINAPI
ICM_IsDuplicateSignerEncodeHashAlgorithm(
IN PCMSG_SIGNER_ENCODE_INFO rgSigners,
IN PCMSG_SIGNER_ENCODE_INFO pNewSigner,
OUT OPTIONAL DWORD *pdwPrevIndex
)
{
PCRYPT_ALGORITHM_IDENTIFIER pNewHashAlg = &pNewSigner->HashAlgorithm;
PCMSG_SIGNER_ENCODE_INFO pPrevSigner;
DWORD dwPrevIndex;
pPrevSigner = rgSigners;
dwPrevIndex = 0;
while (pPrevSigner < pNewSigner) {
PCRYPT_ALGORITHM_IDENTIFIER pPrevHashAlg = &pPrevSigner->HashAlgorithm;
if (0 == strcmp(pNewHashAlg->pszObjId, pPrevHashAlg->pszObjId)
&&
pNewHashAlg->Parameters.cbData ==
pPrevHashAlg->Parameters.cbData
&&
(0 == pNewHashAlg->Parameters.cbData ||
0 == memcmp(pNewHashAlg->Parameters.pbData,
pPrevHashAlg->Parameters.pbData,
pNewHashAlg->Parameters.cbData))) {
break;
}
assert(STRUCT_CBSIZE(CMSG_SIGNER_ENCODE_INFO, rgUnauthAttr) <=
pPrevSigner->cbSize);
assert(pPrevSigner->cbSize == pNewSigner->cbSize);
pPrevSigner = (PCMSG_SIGNER_ENCODE_INFO) ((BYTE *) pPrevSigner +
pPrevSigner->cbSize);
dwPrevIndex++;
}
if (pdwPrevIndex)
*pdwPrevIndex = dwPrevIndex;
return pPrevSigner < pNewSigner;
}
//+-------------------------------------------------------------------------
// Set Signer DigestAlgorithmIdentifiers and create the SignerEncode and
// Hash lists
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_SetAsnSignerDigestInfo(
IN PCMSG_SIGNED_ENCODE_INFO psmei,
IN OUT PCRYPT_MSG_INFO pcmi,
IN OUT DigestAlgorithmIdentifiers *podais
)
{
BOOL fRet;
DigestAlgorithmIdentifier *podai = NULL;
DWORD cDigests = 0;
DWORD cSigners = psmei->cSigners;
if (cSigners) {
DWORD i;
PCMSG_SIGNER_ENCODE_INFO psei;
PSIGNER_ENCODE_DATA_INFO rgSignerEncodeDataInfo;
podai = (DigestAlgorithmIdentifier *) ICM_AllocZero(
cSigners * sizeof(DigestAlgorithmIdentifier));
if (NULL == podai)
goto OutOfMemory;
rgSignerEncodeDataInfo = (PSIGNER_ENCODE_DATA_INFO) ICM_AllocZero(
cSigners * sizeof(SIGNER_ENCODE_DATA_INFO));
if (NULL == rgSignerEncodeDataInfo)
goto OutOfMemory;
pcmi->cSignerEncodeDataInfo = cSigners;
pcmi->rgSignerEncodeDataInfo = rgSignerEncodeDataInfo;
if (NULL == (pcmi->pHashList = new CHashList))
goto OutOfMemory;
for (i = 0, psei = psmei->rgSigners; i < cSigners; i++,
psei = (PCMSG_SIGNER_ENCODE_INFO) ((BYTE *) psei + psei->cbSize)) {
DWORD dwPrevIndex;
ICM_HASH_INFO HashInfo; ZEROSTRUCT(HashInfo);
CHashNode *pHashNode;
assert(STRUCT_CBSIZE(CMSG_SIGNER_ENCODE_INFO, rgUnauthAttr) <=
psei->cbSize);
assert(psei->hCryptProv);
if (STRUCT_CBSIZE(CMSG_SIGNER_ENCODE_INFO, rgUnauthAttr) >
psei->cbSize || 0 == psei->hCryptProv)
goto InvalidArg;
if (ICM_IsDuplicateSignerEncodeHashAlgorithm(
psmei->rgSigners,
psei,
&dwPrevIndex
)) {
assert(dwPrevIndex < i);
pHashNode = rgSignerEncodeDataInfo[dwPrevIndex].pHashNode;
} else {
if (!ICM_MsgAsn1ToAlgorithmIdentifier(
pcmi,
&psei->HashAlgorithm,
&podai[cDigests]))
goto MsgAsn1ToAlgorithmIdentifierError;
cDigests++;
if (!(ICM_GetCAPI(
CRYPT_HASH_ALG_OID_GROUP_ID,
&psei->HashAlgorithm,
&HashInfo.dwAlgoCAPI) ||
ICM_GetCAPI(
CRYPT_SIGN_ALG_OID_GROUP_ID,
&psei->HashAlgorithm,
&HashInfo.dwAlgoCAPI)))
goto GetCAPIError;
if (!CryptCreateHash(
psei->hCryptProv,
HashInfo.dwAlgoCAPI,
NULL, // hKey - optional for MAC
0, // dwFlags
&HashInfo.hHash))
goto CreateHashError;
if (NULL == (pHashNode = new CHashNode)) {
DWORD dwErr = GetLastError();
CryptDestroyHash(HashInfo.hHash);
SetLastError(dwErr);
goto OutOfMemory;
}
pHashNode->SetData(&HashInfo);
pcmi->pHashList->InsertTail(pHashNode);
}
rgSignerEncodeDataInfo[i].hCryptProv = psei->hCryptProv;
rgSignerEncodeDataInfo[i].dwKeySpec = psei->dwKeySpec;
rgSignerEncodeDataInfo[i].pHashNode = pHashNode;
}
assert(cDigests);
}
podais->count = cDigests;
podais->value = podai;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
ICM_Free(podai);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(MsgAsn1ToAlgorithmIdentifierError)
SET_ERROR(InvalidArg, E_INVALIDARG)
SET_ERROR(GetCAPIError, CRYPT_E_UNKNOWN_ALGO)
TRACE_ERROR(CreateHashError)
}
//+-------------------------------------------------------------------------
// Open a signed message for encoding
//--------------------------------------------------------------------------
HCRYPTMSG
WINAPI
ICM_OpenToEncodeSignedData(
IN DWORD dwEncodingType,
IN DWORD dwFlags,
IN void const *pvMsgEncodeInfo,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo)
{
DWORD dwError = ERROR_SUCCESS;
PCRYPT_MSG_INFO pcmi = NULL;
PCMSG_SIGNED_ENCODE_INFO psmei;
PCERT_BLOB pcert;
PCRL_BLOB pcrl;
SignedData *psd = NULL;
Certificate *pOssCert;
CertificateRevocationList *pOssCrl;
DWORD i;
DWORD cbCert;
PBYTE pbCert;
DWORD cbCrl;
PBYTE pbCrl;
DWORD cAttrCertEncoded;
BOOL fHasCmsSignerId;
psmei = (PCMSG_SIGNED_ENCODE_INFO)pvMsgEncodeInfo;
assert( psmei->cbSize >= STRUCT_CBSIZE(CMSG_SIGNED_ENCODE_INFO,
rgCrlEncoded));
if (psmei->cbSize < STRUCT_CBSIZE(CMSG_SIGNED_ENCODE_INFO, rgCrlEncoded))
goto InvalidArg;
for (i=psmei->cCertEncoded, pcert=psmei->rgCertEncoded, cbCert=0;
i>0;
i--, pcert++)
cbCert += pcert->cbData;
for (i=psmei->cCrlEncoded, pcrl=psmei->rgCrlEncoded, cbCrl=0;
i>0;
i--, pcrl++)
cbCrl += pcrl->cbData;
if (psmei->cbSize >= STRUCT_CBSIZE(CMSG_SIGNED_ENCODE_INFO,
rgAttrCertEncoded)) {
cAttrCertEncoded = psmei->cAttrCertEncoded;
for (i=cAttrCertEncoded, pcert=psmei->rgAttrCertEncoded;
i>0;
i--, pcert++)
cbCert += pcert->cbData;
} else
cAttrCertEncoded = 0;
psd = (SignedData *)ICM_AllocZero(
sizeof( SignedData) +
psmei->cCertEncoded * sizeof( Certificate) +
cAttrCertEncoded * sizeof( Certificate) +
psmei->cCrlEncoded * sizeof( CertificateRevocationList) +
cbCert +
cbCrl);
if (NULL == psd)
goto SignedDataAllocError;
// digest algorithms filled in as part of ICM_SetAsnSignerDigestInfo
// contentInfo filled in later, when we see the content
// certificates
if (0 != psmei->cCertEncoded || 0 != cAttrCertEncoded) {
psd->bit_mask |= certificates_present;
psd->certificates.count = psmei->cCertEncoded;
psd->certificates.count += cAttrCertEncoded;
#ifdef OSS_CRYPT_ASN1
psd->certificates.certificates = (Certificate *)(psd + 1);
#else
psd->certificates.value = (Certificate *)(psd + 1);
#endif // OSS_CRYPT_ASN1
pbCert = (PBYTE)psd +
sizeof( SignedData) +
psmei->cCertEncoded * sizeof( Certificate) +
cAttrCertEncoded * sizeof( Certificate) +
psmei->cCrlEncoded * sizeof( CertificateRevocationList);
for (i=psmei->cCertEncoded, pcert=psmei->rgCertEncoded,
#ifdef OSS_CRYPT_ASN1
pOssCert=psd->certificates.certificates;
#else
pOssCert=psd->certificates.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pcert++, pOssCert++) {
pOssCert->length = pcert->cbData;
memcpy( pbCert, pcert->pbData, pcert->cbData);
pOssCert->value = pbCert;
pbCert += pcert->cbData;
}
for (i=cAttrCertEncoded, pcert=psmei->rgAttrCertEncoded;
i>0;
i--, pcert++, pOssCert++) {
pOssCert->length = pcert->cbData;
memcpy( pbCert, pcert->pbData, pcert->cbData);
if (pcert->cbData)
// Change tag from SEQUENCE to [1] IMPLICIT
*pbCert = ICM_TAG_CONSTRUCTED_CONTEXT_1;
pOssCert->value = pbCert;
pbCert += pcert->cbData;
}
}
// crls
if (0 != psmei->cCrlEncoded) {
psd->bit_mask |= crls_present;
psd->crls.count = psmei->cCrlEncoded;
if (0 != psmei->cCertEncoded || 0 != cAttrCertEncoded)
#ifdef OSS_CRYPT_ASN1
psd->crls.crls = (CertificateRevocationList *)
(psd->certificates.certificates +
#else
psd->crls.value = (CertificateRevocationList *)
(psd->certificates.value +
#endif // OSS_CRYPT_ASN1
(psmei->cCertEncoded + cAttrCertEncoded));
else
#ifdef OSS_CRYPT_ASN1
psd->crls.crls = (CertificateRevocationList *) (psd + 1);
#else
psd->crls.value = (CertificateRevocationList *) (psd + 1);
#endif // OSS_CRYPT_ASN1
pbCrl = (PBYTE)psd +
sizeof( SignedData) +
psmei->cCertEncoded * sizeof( Certificate) +
cAttrCertEncoded * sizeof( Certificate) +
psmei->cCrlEncoded * sizeof( CertificateRevocationList) +
cbCert;
#ifdef OSS_CRYPT_ASN1
for (i=psmei->cCrlEncoded, pcrl=psmei->rgCrlEncoded, pOssCrl=psd->crls.crls;
#else
for (i=psmei->cCrlEncoded, pcrl=psmei->rgCrlEncoded, pOssCrl=psd->crls.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pcrl++, pOssCrl++) {
pOssCrl->length = pcrl->cbData;
memcpy( pbCrl, pcrl->pbData, pcrl->cbData);
pOssCrl->value = pbCrl;
pbCrl += pcrl->cbData;
}
}
if (NULL == (pcmi = (PCRYPT_MSG_INFO)ICM_AllocZero(
sizeof( CRYPT_MSG_INFO))))
goto OutOfMemory;
// signerInfos
if (!ICM_SetAsnSignerInfos(psmei, pcmi, dwFlags, pszInnerContentObjID,
&psd->signerInfos, &fHasCmsSignerId))
goto SetAsnSignerInfosError;
// version
if (0 < cAttrCertEncoded || fHasCmsSignerId) {
if (ICM_IsData(pszInnerContentObjID))
dwFlags &= ~CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
else
dwFlags |= CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
} else if (dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG) {
if (ICM_IsData(pszInnerContentObjID))
dwFlags &= ~CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
}
// If encapsulated other than id-data or has attribute certs or has
// CMS signers, then, CMS version
if ((dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG) ||
0 < cAttrCertEncoded || fHasCmsSignerId)
psd->version = CMSG_SIGNED_DATA_CMS_VERSION;
else
psd->version = CMSG_SIGNED_DATA_PKCS_1_5_VERSION;
pcmi->dwEncodingType = dwEncodingType;
pcmi->dwMsgType = CMSG_SIGNED;
pcmi->dwFlags = dwFlags;
pcmi->pvMsg = psd;
pcmi->fEncoding = TRUE;
pcmi->dwPhase = PHASE_FIRST_ONGOING;
if (pszInnerContentObjID &&
(NULL == (pcmi->pszInnerContentObjID = (LPSTR)ICM_DupMem(
pszInnerContentObjID,
ICM_StrLen(pszInnerContentObjID) + 1))))
goto DupInnerContentObjIDError;
if (pStreamInfo &&
(NULL == (pcmi->pStreamInfo = (PCMSG_STREAM_INFO)ICM_DupMem(
pStreamInfo,
sizeof(*pStreamInfo)))))
goto DupStreamInfoError;
if (!ICM_SetAsnSignerDigestInfo(
psmei,
pcmi,
&psd->digestAlgorithms
))
goto SetAsnSignerDigestInfoError;
if (pcmi->pStreamInfo && !ICMS_OpenToEncodeSignedData( pcmi, psmei))
goto StreamOpenToEncodeSignedDataError;
CommonReturn:
ICM_SetLastError(dwError);
return (HCRYPTMSG)pcmi;
ErrorReturn:
dwError = GetLastError();
if (psd) {
if (psd->signerInfos.value) {
SignerInfo *psi;
for (i=psd->signerInfos.count, psi=psd->signerInfos.value;
i>0;
i--, psi++)
ICM_FreeAsnSignerInfo(psi);
ICM_Free(psd->signerInfos.value);
}
ICM_Free(psd);
}
if (pcmi) {
if (pcmi->pFreeList)
delete pcmi->pFreeList;
if (pcmi->pHashList)
delete pcmi->pHashList;
ICM_Free(pcmi->rgSignerEncodeDataInfo);
ICM_Free(pcmi->pszInnerContentObjID);
ICM_Free(pcmi->pStreamInfo);
ICM_Free(pcmi);
pcmi = NULL;
}
goto CommonReturn;
SET_ERROR(InvalidArg,E_INVALIDARG)
TRACE_ERROR(DupInnerContentObjIDError) // error already set
TRACE_ERROR(DupStreamInfoError) // error already set
TRACE_ERROR(SetAsnSignerInfosError) // error already set
TRACE_ERROR(SetAsnSignerDigestInfoError) // error already set
TRACE_ERROR(SignedDataAllocError) // error already set
TRACE_ERROR(OutOfMemory) // error already set
TRACE_ERROR(StreamOpenToEncodeSignedDataError) // error already set
}
#else
//+-------------------------------------------------------------------------
// Open a signed message for encoding
//--------------------------------------------------------------------------
HCRYPTMSG
WINAPI
ICM_OpenToEncodeSignedData(
IN DWORD dwEncodingType,
IN DWORD dwFlags,
IN void const *pvMsgEncodeInfo,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo)
{
DWORD dwError = ERROR_SUCCESS;
PCRYPT_MSG_INFO pcmi = NULL;
PCMSG_SIGNED_ENCODE_INFO psmei;
PCERT_BLOB pcert;
PCRL_BLOB pcrl;
SignedData *psd = NULL;
Certificate *pOssCert;
CertificateRevocationList *pOssCrl;
DWORD i;
DWORD cDigestAlgorithms;
HCRYPTPROV hCryptProv;
DWORD dwKeySpec;
CRYPT_ALGORITHM_IDENTIFIER aiDigest;
ICM_HASH_INFO HashInfo; ZEROSTRUCT(HashInfo);
CHashNode *pHashNode;
DWORD cbCert;
PBYTE pbCert;
DWORD cbCrl;
PBYTE pbCrl;
BOOL fHasCmsSignerId;
#ifdef CMS_PKCS7
DWORD cAttrCertEncoded;
#endif // CMS_PKCS7
psmei = (PCMSG_SIGNED_ENCODE_INFO)pvMsgEncodeInfo;
assert( 2 > psmei->cSigners);
if (!( 2 > psmei->cSigners))
goto TooManySignersError;
#ifdef CMS_PKCS7
assert( psmei->cbSize >= offsetof(CMSG_SIGNED_ENCODE_INFO,
cAttrCertEncoded));
if (psmei->cbSize < offsetof(CMSG_SIGNED_ENCODE_INFO, cAttrCertEncoded))
#else
assert( psmei->cbSize >= sizeof(CMSG_SIGNED_ENCODE_INFO));
if (psmei->cbSize < sizeof(CMSG_SIGNED_ENCODE_INFO))
#endif
goto InvalidArg;
for (i=psmei->cCertEncoded, pcert=psmei->rgCertEncoded, cbCert=0;
i>0;
i--, pcert++)
cbCert += pcert->cbData;
for (i=psmei->cCrlEncoded, pcrl=psmei->rgCrlEncoded, cbCrl=0;
i>0;
i--, pcrl++)
cbCrl += pcrl->cbData;
#ifdef CMS_PKCS7
if (psmei->cbSize > offsetof(CMSG_SIGNED_ENCODE_INFO, rgAttrCertEncoded)) {
cAttrCertEncoded = psmei->cAttrCertEncoded;
for (i=cAttrCertEncoded, pcert=psmei->rgAttrCertEncoded;
i>0;
i--, pcert++)
cbCert += pcert->cbData;
} else
cAttrCertEncoded = 0;
#endif // CMS_PKCS7
psd = (SignedData *)ICM_AllocZero(
sizeof( SignedData) +
psmei->cCertEncoded * sizeof( Certificate) +
#ifdef CMS_PKCS7
cAttrCertEncoded * sizeof( Certificate) +
#endif // CMS_PKCS7
psmei->cCrlEncoded * sizeof( CertificateRevocationList) +
cbCert +
cbCrl);
if (NULL == psd)
goto SignedDataAllocError;
psd->bit_mask = 0;
psd->signerInfos.value = NULL;
psd->contentInfo.content.value = NULL;
// version
#ifdef CMS_PKCS7
if (0 < cAttrCertEncoded) {
if (ICM_IsData(pszInnerContentObjID))
dwFlags &= ~CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
else
dwFlags |= CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
} else if (dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG) {
if (ICM_IsData(pszInnerContentObjID))
dwFlags &= ~CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
}
// If encapsulated other than id-data or has attribute certs, then,
// version = 3
if ((dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG) ||
0 < cAttrCertEncoded)
psd->version = CMSG_SIGNED_DATA_CMS_VERSION;
else
psd->version = CMSG_SIGNED_DATA_PKCS_1_5_VERSION;
#else
psd->version = 1;
#endif // CMS_PKCS7
// digest algorithms
if (!ICM_SetAsnDigestAlgorithmIdentifiers(
&psd->digestAlgorithms,
&aiDigest,
psmei->cSigners,
psmei->rgSigners,
&hCryptProv,
&dwKeySpec))
goto SetAsnDigestAlgorithmIdentifiersError;
// contentInfo filled in later, when we see the content
// certificates
if (0 != psmei->cCertEncoded
#ifdef CMS_PKCS7
|| 0 != cAttrCertEncoded
#endif // CMS_PKCS7
) {
psd->bit_mask |= certificates_present;
psd->certificates.count = psmei->cCertEncoded;
#ifdef CMS_PKCS7
psd->certificates.count += cAttrCertEncoded;
#endif // CMS_PKCS7
#ifdef OSS_CRYPT_ASN1
psd->certificates.certificates = (Certificate *)(psd + 1);
#else
psd->certificates.value = (Certificate *)(psd + 1);
#endif // OSS_CRYPT_ASN1
pbCert = (PBYTE)psd +
sizeof( SignedData) +
psmei->cCertEncoded * sizeof( Certificate) +
#ifdef CMS_PKCS7
cAttrCertEncoded * sizeof( Certificate) +
#endif // CMS_PKCS7
psmei->cCrlEncoded * sizeof( CertificateRevocationList);
for (i=psmei->cCertEncoded, pcert=psmei->rgCertEncoded,
#ifdef OSS_CRYPT_ASN1
pOssCert=psd->certificates.certificates;
#else
pOssCert=psd->certificates.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pcert++, pOssCert++) {
pOssCert->length = pcert->cbData;
memcpy( pbCert, pcert->pbData, pcert->cbData);
pOssCert->value = pbCert;
pbCert += pcert->cbData;
}
#ifdef CMS_PKCS7
for (i=cAttrCertEncoded, pcert=psmei->rgAttrCertEncoded;
i>0;
i--, pcert++, pOssCert++) {
pOssCert->length = pcert->cbData;
memcpy( pbCert, pcert->pbData, pcert->cbData);
if (pcert->cbData)
// Change tag from SEQUENCE to [1] IMPLICIT
*pbCert = ICM_TAG_CONSTRUCTED_CONTEXT_1;
pOssCert->value = pbCert;
pbCert += pcert->cbData;
}
#endif // CMS_PKCS7
}
// crls
if (0 != psmei->cCrlEncoded) {
psd->bit_mask |= crls_present;
psd->crls.count = psmei->cCrlEncoded;
if (0 != psmei->cCertEncoded
#ifdef CMS_PKCS7
|| 0 != cAttrCertEncoded
#endif // CMS_PKCS7
)
#ifdef OSS_CRYPT_ASN1
psd->crls.crls = (CertificateRevocationList *)
(psd->certificates.certificates +
#else
psd->crls.value = (CertificateRevocationList *)
(psd->certificates.value +
#endif // OSS_CRYPT_ASN1
(psmei->cCertEncoded
#ifdef CMS_PKCS7
+ cAttrCertEncoded
#endif // CMS_PKCS7
));
else
#ifdef OSS_CRYPT_ASN1
psd->crls.crls = (CertificateRevocationList *) (psd + 1);
#else
psd->crls.value = (CertificateRevocationList *) (psd + 1);
#endif // OSS_CRYPT_ASN1
pbCrl = (PBYTE)psd +
sizeof( SignedData) +
psmei->cCertEncoded * sizeof( Certificate) +
#ifdef CMS_PKCS7
cAttrCertEncoded * sizeof( Certificate) +
#endif // CMS_PKCS7
psmei->cCrlEncoded * sizeof( CertificateRevocationList) +
cbCert;
#ifdef OSS_CRYPT_ASN1
for (i=psmei->cCrlEncoded, pcrl=psmei->rgCrlEncoded, pOssCrl=psd->crls.crls;
#else
for (i=psmei->cCrlEncoded, pcrl=psmei->rgCrlEncoded, pOssCrl=psd->crls.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pcrl++, pOssCrl++) {
pOssCrl->length = pcrl->cbData;
memcpy( pbCrl, pcrl->pbData, pcrl->cbData);
pOssCrl->value = pbCrl;
pbCrl += pcrl->cbData;
}
}
// signerInfos
// psd->signerInfos.count = psmei->cSigners;
// psd->signerInfos.value = (SignerInfo *)
// (psd->crls.crls + psmei->cCrlEncoded);
if (!ICM_SetAsnSignerInfos( psmei, pcmi, dwFlags, pszInnerContentObjID,
&psd->signerInfos, &fHasCmsSignerId))
goto SetAsnSignerInfosError;
cDigestAlgorithms = psmei->cSigners;
if (NULL == (pcmi = (PCRYPT_MSG_INFO)ICM_AllocZero( sizeof( CRYPT_MSG_INFO))))
goto OutOfMemory;
pcmi->hCryptProv = hCryptProv;
if (0 == hCryptProv)
pcmi->fDefaultCryptProv = TRUE;
pcmi->dwKeySpec = dwKeySpec;
pcmi->dwEncodingType = dwEncodingType;
pcmi->dwMsgType = CMSG_SIGNED;
pcmi->dwFlags = dwFlags;
pcmi->pvMsg = psd;
pcmi->fEncoding = TRUE;
pcmi->dwPhase = PHASE_FIRST_ONGOING;
if (pszInnerContentObjID &&
(NULL == (pcmi->pszInnerContentObjID = (LPSTR)ICM_DupMem(
pszInnerContentObjID,
ICM_StrLen(pszInnerContentObjID) + 1))))
goto DupInnerContentObjIDError;
if (pStreamInfo &&
(NULL == (pcmi->pStreamInfo = (PCMSG_STREAM_INFO)ICM_DupMem(
pStreamInfo,
sizeof(*pStreamInfo)))))
goto DupStreamInfoError;
if (psmei->cSigners) {
if (!(ICM_GetCAPI(
CRYPT_HASH_ALG_OID_GROUP_ID,
&aiDigest,
&HashInfo.dwAlgoCAPI) ||
ICM_GetCAPI(
CRYPT_SIGN_ALG_OID_GROUP_ID,
&aiDigest,
&HashInfo.dwAlgoCAPI)))
goto GetCAPIError;
HashInfo.hCryptProv = hCryptProv;
if (!CryptCreateHash(
HashInfo.hCryptProv,
HashInfo.dwAlgoCAPI,
NULL, // hKey - optional for MAC
0, // dwFlags
&HashInfo.hHash))
goto CreateHashError;
if (NULL == (pcmi->pHashList = new CHashList))
goto NewHashListError;
if (NULL == (pHashNode = new CHashNode))
goto NewHashNodeError;
pHashNode->SetData( &HashInfo);
pcmi->pHashList->InsertTail( pHashNode);
}
if (pcmi->pStreamInfo && !ICMS_OpenToEncodeSignedData( pcmi, psmei))
goto StreamOpenToEncodeSignedDataError;
CommonReturn:
ICM_SetLastError(dwError);
return (HCRYPTMSG)pcmi;
ErrorReturn:
dwError = GetLastError();
ICM_Free( psd);
ICM_Free( pcmi);
pcmi = NULL;
goto CommonReturn;
SET_ERROR(TooManySignersError,E_INVALIDARG)
SET_ERROR(NewHashListError,E_OUTOFMEMORY)
SET_ERROR(NewHashNodeError,E_OUTOFMEMORY)
SET_ERROR(InvalidArg,E_INVALIDARG)
SET_ERROR(GetCAPIError,CRYPT_E_UNKNOWN_ALGO)
TRACE_ERROR(DupInnerContentObjIDError) // error already set
TRACE_ERROR(DupStreamInfoError) // error already set
TRACE_ERROR(SetAsnSignerInfosError) // error already set
TRACE_ERROR(SetAsnDigestAlgorithmIdentifiersError) // error already set
TRACE_ERROR(SignedDataAllocError) // error already set
TRACE_ERROR(OutOfMemory) // error already set
TRACE_ERROR(CreateHashError) // error already set
TRACE_ERROR(StreamOpenToEncodeSignedDataError) // error already set
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Open a data message for encoding
//--------------------------------------------------------------------------
HCRYPTMSG
WINAPI
ICM_OpenToEncodeData(
IN DWORD dwEncodingType,
IN DWORD dwFlags,
IN void const *pvMsgEncodeInfo,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo)
{
DWORD dwError = ERROR_SUCCESS;
PCRYPT_MSG_INFO pcmi = NULL;
OctetStringType *poos = NULL;
if (pvMsgEncodeInfo)
goto EncodeInfoPresentError;
if (NULL == (poos = (OctetStringType *)ICM_AllocZero( sizeof( OctetStringType))))
goto AllocOctetStringTypeError;
if (NULL == (pcmi = (PCRYPT_MSG_INFO)ICM_AllocZero( sizeof( CRYPT_MSG_INFO))))
goto AllocMsgInfoError;
pcmi->dwEncodingType = dwEncodingType;
pcmi->dwMsgType = CMSG_DATA;
// pcmi->hCryptProv = 0;
pcmi->fDefaultCryptProv = TRUE;
pcmi->dwFlags = dwFlags;
pcmi->pvMsg = poos;
pcmi->fEncoding = TRUE;
pcmi->dwPhase = PHASE_FIRST_ONGOING;
pcmi->pStreamInfo = (PCMSG_STREAM_INFO)ICM_DupMem(
pStreamInfo,
sizeof(*pStreamInfo));
if (pcmi->pStreamInfo && !ICMS_OpenToEncodeData( pcmi))
goto StreamOpenToEncodeDataError;
CommonReturn:
ICM_SetLastError(dwError);
return (HCRYPTMSG)pcmi;
ErrorReturn:
dwError = GetLastError();
ICM_Free( poos);
if (pcmi) {
ICM_Free(pcmi->pStreamInfo);
ICM_Free( pcmi);
}
pcmi = NULL;
goto CommonReturn;
SET_ERROR(EncodeInfoPresentError,E_INVALIDARG)
TRACE_ERROR(AllocMsgInfoError) // error already set
TRACE_ERROR(AllocOctetStringTypeError) // error already set
TRACE_ERROR(StreamOpenToEncodeDataError) // error already set
}
//+-------------------------------------------------------------------------
// Open a digested message for encoding
//--------------------------------------------------------------------------
HCRYPTMSG
WINAPI
ICM_OpenToEncodeDigestedData(
IN DWORD dwEncodingType,
IN DWORD dwFlags,
IN void const *pvMsgEncodeInfo,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo)
{
DWORD dwError = ERROR_SUCCESS;
PCRYPT_MSG_INFO pcmi = NULL;
PCMSG_HASHED_ENCODE_INFO pdmei;
DigestedData *pdd = NULL;
ICM_HASH_INFO HashInfo; ZEROSTRUCT(HashInfo);
CHashNode *pHashNode;
pdmei = (PCMSG_HASHED_ENCODE_INFO)pvMsgEncodeInfo;
assert( pdmei->cbSize >= sizeof(CMSG_HASHED_ENCODE_INFO));
assert( pdmei->pvHashAuxInfo == NULL);
if (pdmei->cbSize < sizeof(CMSG_HASHED_ENCODE_INFO) ||
pdmei->pvHashAuxInfo != NULL)
goto InvalidArg;
pcmi = (PCRYPT_MSG_INFO)ICM_AllocZero( sizeof( CRYPT_MSG_INFO));
if (NULL == pcmi)
goto OutOfMemory;
pdd = (DigestedData *)ICM_AllocZero( sizeof( DigestedData));
if (NULL == pdd)
goto DigestedDataAllocError;
// version
#ifdef CMS_PKCS7
if (dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG) {
if (ICM_IsData(pszInnerContentObjID))
dwFlags &= ~CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
}
// If encapsulated other than id-data, then, version = 2
if (dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
pdd->version = CMSG_HASHED_DATA_V2;
else
pdd->version = CMSG_HASHED_DATA_V0;
#else
pdd->version = 0;
#endif // CMS_PKCS7
// digest algorithm
if (!ICM_MsgAsn1ToAlgorithmIdentifier(
pcmi,
&pdmei->HashAlgorithm,
&pdd->digestAlgorithm))
goto MsgAsn1ToAlgorithmIdentifierError;
// contentInfo filled in later, when we see the content
if (pdmei->hCryptProv)
pcmi->hCryptProv = pdmei->hCryptProv;
else {
pcmi->fDefaultCryptProv = TRUE;
pcmi->hCryptProv = I_CryptGetDefaultCryptProv(0);
if (0 == pcmi->hCryptProv)
goto GetDefaultCryptProvError;
}
pcmi->dwEncodingType = dwEncodingType;
pcmi->dwMsgType = CMSG_HASHED;
pcmi->dwFlags = dwFlags;
pcmi->pvMsg = pdd;
pcmi->fEncoding = TRUE;
pcmi->dwPhase = PHASE_FIRST_ONGOING;
pcmi->pszInnerContentObjID = (LPSTR)ICM_DupMem(
pszInnerContentObjID,
ICM_StrLen(pszInnerContentObjID) + 1);
pcmi->pStreamInfo = (PCMSG_STREAM_INFO)ICM_DupMem(
pStreamInfo,
sizeof(*pStreamInfo));
if (!ICM_GetCAPI(
CRYPT_HASH_ALG_OID_GROUP_ID,
&pdmei->HashAlgorithm,
&HashInfo.dwAlgoCAPI))
goto GetCAPIError;
#ifndef CMS_PKCS7
HashInfo.hCryptProv = pcmi->hCryptProv;
#endif // CMS_PKCS7
if (!CryptCreateHash(
pcmi->hCryptProv,
HashInfo.dwAlgoCAPI,
NULL, // hKey - optional for MAC
0, // dwFlags
&HashInfo.hHash))
goto CreateHashError;
if (NULL == (pcmi->pHashList = new CHashList) ||
NULL == (pHashNode = new CHashNode)) {
DWORD dwErr = GetLastError();
CryptDestroyHash(HashInfo.hHash);
SetLastError(dwErr);
goto NewHashListOrNodeError;
}
pHashNode->SetData( &HashInfo);
pcmi->pHashList->InsertTail( pHashNode);
CommonReturn:
ICM_SetLastError(dwError);
return (HCRYPTMSG)pcmi;
ErrorReturn:
dwError = GetLastError();
ICM_Free( pdd);
if (pcmi) {
#ifdef CMS_PKCS7
if (pcmi->pFreeList)
delete pcmi->pFreeList;
#endif // CMS_PKCS7
if (pcmi->pHashList)
delete pcmi->pHashList;
ICM_Free(pcmi->pszInnerContentObjID);
ICM_Free(pcmi->pStreamInfo);
ICM_Free( pcmi);
pcmi = NULL;
}
goto CommonReturn;
SET_ERROR(InvalidArg,E_INVALIDARG)
TRACE_ERROR(GetDefaultCryptProvError)
SET_ERROR(GetCAPIError,CRYPT_E_UNKNOWN_ALGO)
SET_ERROR(NewHashListOrNodeError,E_OUTOFMEMORY)
TRACE_ERROR(MsgAsn1ToAlgorithmIdentifierError) // error already set
TRACE_ERROR(DigestedDataAllocError) // error already set
TRACE_ERROR(CreateHashError) // error already set
TRACE_ERROR(OutOfMemory) // error already set
}
#ifdef CMS_PKCS7
//+-------------------------------------------------------------------------
// Export the hContentEncryptKey from the ContentEncrypt
// provider and import into the specified provider
//--------------------------------------------------------------------------
HCRYPTKEY
WINAPI
ICM_ExportContentEncryptKeyAndImport(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN HCRYPTPROV hImportProv
)
{
DWORD dwError = ERROR_SUCCESS;
HCRYPTPROV hExportProv = pContentEncryptInfo->hCryptProv;
HCRYPTHASH hHash = 0;
HCRYPTKEY hDeriveKey = 0;
HCRYPTKEY hImportContentEncryptKey = 0;
#define BASE_DATA_LENGTH 8
BYTE rgbBaseData[BASE_DATA_LENGTH];
PBYTE pbContentKey = NULL;
DWORD cbContentKey = 0;
DWORD dwImportFlags;
DWORD dwAlgIdEncrypt;
DWORD dwBitLen;
BYTE rgbIV[IV_MAX_LENGTH];
DWORD cbIV;
const DWORD dw40BitLen = 40;
// Generate derive key to use to encrypt and export the content encrypt key
if (!CryptGenRandom(hExportProv, BASE_DATA_LENGTH, rgbBaseData))
goto GenRandomError;
if (!CryptCreateHash(hExportProv, CALG_SHA1, 0, 0, &hHash))
goto ExportCreateHashError;
if (!CryptHashData(hHash, rgbBaseData, BASE_DATA_LENGTH, 0))
goto ExportHashDataError;
if (!CryptDeriveKey(
hExportProv,
CALG_RC2,
hHash,
40 << 16, // dwFlags, dwBitLen in upper WORD
&hDeriveKey))
goto ExportDeriveKeyError;
CryptSetKeyParam(
hDeriveKey,
KP_EFFECTIVE_KEYLEN,
(PBYTE) &dw40BitLen,
0); // dwFlags
// Export the content encrypt key
if (!CryptExportKey(
pContentEncryptInfo->hContentEncryptKey,
hDeriveKey,
SYMMETRICWRAPKEYBLOB,
0, // dwFlags
NULL,
&cbContentKey))
goto ExportKeyError;
if (NULL == (pbContentKey = (PBYTE) ICM_Alloc(cbContentKey)))
goto AllocError;
if (!CryptExportKey(
pContentEncryptInfo->hContentEncryptKey,
hDeriveKey,
SYMMETRICWRAPKEYBLOB,
0, // dwFlags
pbContentKey,
&cbContentKey))
goto ExportKeyError;
// Generate derive key to use to decrypt and import the content encrypt key
CryptDestroyKey(hDeriveKey);
hDeriveKey = 0;
CryptDestroyHash(hHash);
hHash = 0;
if (!CryptCreateHash(hImportProv, CALG_SHA1, 0, 0, &hHash))
goto ImportCreateHashError;
if (!CryptHashData(hHash, rgbBaseData, BASE_DATA_LENGTH, 0))
goto ImportHashDataError;
if (!CryptDeriveKey(
hImportProv,
CALG_RC2,
hHash,
40 << 16, // dwFlags, dwBitLen in upper WORD
&hDeriveKey))
goto ImportDeriveKeyError;
CryptSetKeyParam(
hDeriveKey,
KP_EFFECTIVE_KEYLEN,
(PBYTE) &dw40BitLen,
0); // dwFlags
// Decrypt and import the content encrypt key
dwImportFlags = CRYPT_EXPORTABLE;
if (!ICM_IsSP3CompatibleEncrypt(pContentEncryptInfo))
dwImportFlags |= CRYPT_NO_SALT;
if (!CryptImportKey(
hImportProv,
pbContentKey,
cbContentKey,
hDeriveKey,
dwImportFlags,
&hImportContentEncryptKey))
goto ImportKeyError;
// Need to re-set effective key length and IV
if (!ICM_GetEncryptParameters(
&pContentEncryptInfo->ContentEncryptionAlgorithm,
&dwAlgIdEncrypt,
&dwBitLen,
rgbIV,
&cbIV))
goto GetEncryptParametersError;
if (CALG_RC2 == dwAlgIdEncrypt && 0 != dwBitLen)
// Silently ignore any errors. Not supported in earlier versions
CryptSetKeyParam(
hImportContentEncryptKey,
KP_EFFECTIVE_KEYLEN,
(PBYTE) &dwBitLen,
0); // dwFlags
if (0 != cbIV) {
if (CALG_RC4 == dwAlgIdEncrypt) {
// For RC4, set the SALT, not the IV
CRYPT_DATA_BLOB SaltBlob;
SaltBlob.pbData = rgbIV;
SaltBlob.cbData = cbIV;
if (!CryptSetKeyParam(
hImportContentEncryptKey,
KP_SALT_EX,
(PBYTE) &SaltBlob,
0)) // dwFlags
goto SetSaltExError;
} else {
if (!CryptSetKeyParam(
hImportContentEncryptKey,
KP_IV,
rgbIV,
0)) // dwFlags
goto SetIVError;
}
}
CommonReturn:
if (hDeriveKey)
CryptDestroyKey(hDeriveKey);
if (hHash)
CryptDestroyHash(hHash);
ICM_Free(pbContentKey);
ICM_SetLastError(dwError);
return hImportContentEncryptKey;
ErrorReturn:
dwError = GetLastError();
if (hImportContentEncryptKey) {
CryptDestroyKey(hImportContentEncryptKey);
hImportContentEncryptKey = 0;
}
goto CommonReturn;
TRACE_ERROR(GenRandomError)
TRACE_ERROR(ExportCreateHashError)
TRACE_ERROR(ExportHashDataError)
TRACE_ERROR(ExportDeriveKeyError)
TRACE_ERROR(ExportKeyError)
TRACE_ERROR(AllocError)
TRACE_ERROR(ImportCreateHashError)
TRACE_ERROR(ImportHashDataError)
TRACE_ERROR(ImportDeriveKeyError)
TRACE_ERROR(ImportKeyError)
TRACE_ERROR(GetEncryptParametersError)
TRACE_ERROR(SetSaltExError)
TRACE_ERROR(SetIVError)
}
//+-------------------------------------------------------------------------
// Export the encrypted content encrypt key using the KeyTrans or KeyAgree
// key.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ExportEncryptedKey(
IN HCRYPTKEY hContentEncryptKey,
IN HCRYPTKEY hPubKey,
IN DWORD dwBlobType,
IN BOOL fSP3CompatibleEncrypt,
OUT PCRYPT_DATA_BLOB pEncryptedKey
)
{
BOOL fRet;
PBYTE pbCspEncryptedKey = NULL;
DWORD cbCspEncryptedKey;
if (!CryptExportKey(
hContentEncryptKey,
hPubKey,
dwBlobType,
0, // dwFlags
NULL,
&cbCspEncryptedKey))
goto ExportEncryptedKeyError;
if (NULL == (pbCspEncryptedKey = (PBYTE) ICM_AllocA(cbCspEncryptedKey)))
goto AllocError;
if (!CryptExportKey(
hContentEncryptKey,
hPubKey,
dwBlobType,
0, // dwFlags
pbCspEncryptedKey,
&cbCspEncryptedKey))
goto ExportEncryptedKeyError;
assert(cbCspEncryptedKey >
(sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER)));
cbCspEncryptedKey -= sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER);
if (NULL == (pEncryptedKey->pbData = (PBYTE) ICM_Alloc(cbCspEncryptedKey)))
goto AllocError;
pEncryptedKey->cbData = cbCspEncryptedKey;
if (SYMMETRICWRAPKEYBLOB == dwBlobType || fSP3CompatibleEncrypt)
// Don't byte reverse
memcpy(pEncryptedKey->pbData,
pbCspEncryptedKey +
(sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER)),
cbCspEncryptedKey);
else
ICM_ReverseCopy(pEncryptedKey->pbData,
pbCspEncryptedKey +
(sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER)),
cbCspEncryptedKey);
fRet = TRUE;
CommonReturn:
ICM_FreeA(pbCspEncryptedKey);
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(AllocError)
TRACE_ERROR(ExportEncryptedKeyError)
}
BOOL
WINAPI
ICM_IsSameRecipientPublicKeyAlgorithm(
IN PCRYPT_ALGORITHM_IDENTIFIER paiPubKey1,
IN PCRYPT_ALGORITHM_IDENTIFIER paiPubKey2
)
{
DWORD dwAlgIdPubKey1;
DWORD dwAlgIdPubKey2;
if (0 == strcmp(paiPubKey1->pszObjId, paiPubKey2->pszObjId))
return TRUE;
ICM_GetCAPI(
CRYPT_PUBKEY_ALG_OID_GROUP_ID,
paiPubKey1,
&dwAlgIdPubKey1);
ICM_GetCAPI(
CRYPT_PUBKEY_ALG_OID_GROUP_ID,
paiPubKey2,
&dwAlgIdPubKey2);
if (dwAlgIdPubKey1 == dwAlgIdPubKey2)
return TRUE;
// If we don't know about either public key, default to being the same.
if (0 == dwAlgIdPubKey1 || 0 == dwAlgIdPubKey2)
return TRUE;
return FALSE;
}
//+-------------------------------------------------------------------------
// Default export of the encryption key for key transport recipient
//--------------------------------------------------------------------------
BOOL
WINAPI
#ifdef DEBUG_CRYPT_ASN1
ICMTest_DefaultExportKeyTrans(
#else
ICM_DefaultExportKeyTrans(
#endif
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTransEncodeInfo,
IN OUT PCMSG_KEY_TRANS_ENCRYPT_INFO pKeyTransEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
HCRYPTPROV hKeyTransProv = 0;
HCRYPTKEY hContentEncryptKey = 0;
CERT_PUBLIC_KEY_INFO PublicKeyInfo;
HCRYPTKEY hPubKey = 0;
hKeyTransProv = pKeyTransEncodeInfo->hCryptProv;
if (0 == hKeyTransProv) {
if (0 == pKeyTransEncryptInfo->dwRecipientIndex)
hKeyTransProv = pContentEncryptInfo->hCryptProv;
else {
// Check if the type of and public key algorithm for this
// recipient is the same as the first recipient's.
PCMSG_RECIPIENT_ENCODE_INFO prei;
prei = &pContentEncryptInfo->rgCmsRecipients[0];
if (CMSG_KEY_TRANS_RECIPIENT == prei->dwRecipientChoice &&
ICM_IsSameRecipientPublicKeyAlgorithm(
&prei->pKeyTrans->KeyEncryptionAlgorithm,
&pKeyTransEncryptInfo->KeyEncryptionAlgorithm))
hKeyTransProv = pContentEncryptInfo->hCryptProv;
else {
// Get default provider associated with the encryption
// and public key algorithms
DWORD dwAlgIdPubKey;
DWORD dwAlgIdEncrypt;
BYTE rgbIV[IV_MAX_LENGTH];
DWORD cbIV;
DWORD dwBitLen;
if (!ICM_GetEncryptParameters(
&pContentEncryptInfo->ContentEncryptionAlgorithm,
&dwAlgIdEncrypt,
&dwBitLen,
rgbIV,
&cbIV))
goto GetEncryptParametersError;
ICM_GetCAPI(
CRYPT_PUBKEY_ALG_OID_GROUP_ID,
&pKeyTransEncryptInfo->KeyEncryptionAlgorithm,
&dwAlgIdPubKey);
hKeyTransProv = I_CryptGetDefaultCryptProvForEncrypt(
dwAlgIdPubKey, dwAlgIdEncrypt, dwBitLen);
if (0 == hKeyTransProv)
goto GetDefaultCryptProvError;
}
}
}
if (hKeyTransProv != pContentEncryptInfo->hCryptProv) {
// Need to export the hContentEncryptKey from the ContentEncrypt
// provider and import into the KeyTrans provider
hContentEncryptKey = ICM_ExportContentEncryptKeyAndImport(
pContentEncryptInfo,
hKeyTransProv);
if (0 == hContentEncryptKey)
goto ImportContentKeyError;
} else
hContentEncryptKey = pContentEncryptInfo->hContentEncryptKey;
PublicKeyInfo.Algorithm = pKeyTransEncryptInfo->KeyEncryptionAlgorithm;
PublicKeyInfo.PublicKey = pKeyTransEncodeInfo->RecipientPublicKey;
if (!CryptImportPublicKeyInfo(
hKeyTransProv,
X509_ASN_ENCODING,
&PublicKeyInfo,
&hPubKey))
goto ImportPubKeyError;
if (!ICM_ExportEncryptedKey(
hContentEncryptKey,
hPubKey,
SIMPLEBLOB,
ICM_IsSP3CompatibleEncrypt(pContentEncryptInfo),
&pKeyTransEncryptInfo->EncryptedKey))
goto ExportEncryptedKeyError;
fRet = TRUE;
CommonReturn:
if (hKeyTransProv != pContentEncryptInfo->hCryptProv &&
hContentEncryptKey)
CryptDestroyKey(hContentEncryptKey);
if (hPubKey)
CryptDestroyKey(hPubKey);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetEncryptParametersError)
TRACE_ERROR(GetDefaultCryptProvError)
TRACE_ERROR(ImportContentKeyError)
TRACE_ERROR(ImportPubKeyError)
TRACE_ERROR(ExportEncryptedKeyError)
}
BOOL
WINAPI
ICM_ExportKeyTrans(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTransEncodeInfo,
IN OUT PCMSG_KEY_TRANS_ENCRYPT_INFO pKeyTransEncryptInfo
)
{
BOOL fRet;
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr = NULL;
LPCSTR pszKeyEncryptOID =
pKeyTransEncryptInfo->KeyEncryptionAlgorithm.pszObjId;
if (CryptGetOIDFunctionAddress(
hExportKeyTransFuncSet,
X509_ASN_ENCODING,
pszKeyEncryptOID,
0, // dwFlags
&pvFuncAddr,
&hFuncAddr)) {
fRet = ((PFN_CMSG_EXPORT_KEY_TRANS) pvFuncAddr)(
pContentEncryptInfo,
pKeyTransEncodeInfo,
pKeyTransEncryptInfo,
0, // dwFlags
NULL // pvReserved
);
} else if ((NULL == pKeyTransEncodeInfo->hCryptProv ||
pKeyTransEncodeInfo->hCryptProv ==
pContentEncryptInfo->hCryptProv)
&&
CryptGetOIDFunctionAddress(
hOldStyleExportEncryptKeyFuncSet,
X509_ASN_ENCODING,
pszKeyEncryptOID,
0, // dwFlags
&pvFuncAddr,
&hFuncAddr)
&&
#ifdef DEBUG_CRYPT_ASN1
0 == (ICMTest_GetDebugCryptAsn1Flags() &
DEBUG_OSS_CRYPT_ASN1_SAME_ENCRYPT_FLAG)
&&
#endif // DEBUG_CRYPT_ASN1
(void *) ICM_DefaultExportEncryptKey != pvFuncAddr) {
CERT_PUBLIC_KEY_INFO PublicKeyInfo;
PBYTE pbData;
DWORD rgcbData[2] = {0, 0};
if (ICM_IsSP3CompatibleEncrypt(pContentEncryptInfo))
rgcbData[1] = CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG;
PublicKeyInfo.Algorithm = pKeyTransEncryptInfo->KeyEncryptionAlgorithm;
PublicKeyInfo.PublicKey = pKeyTransEncodeInfo->RecipientPublicKey;
fRet = ((PFN_CMSG_EXPORT_ENCRYPT_KEY) pvFuncAddr)(
pContentEncryptInfo->hCryptProv,
pContentEncryptInfo->hContentEncryptKey,
&PublicKeyInfo,
NULL, // pbData
rgcbData);
if (fRet) {
if (NULL == (pbData = (PBYTE) ICM_Alloc(rgcbData[0])))
fRet = FALSE;
else {
fRet = ((PFN_CMSG_EXPORT_ENCRYPT_KEY) pvFuncAddr)(
pContentEncryptInfo->hCryptProv,
pContentEncryptInfo->hContentEncryptKey,
&PublicKeyInfo,
pbData,
rgcbData);
if (fRet) {
pKeyTransEncryptInfo->EncryptedKey.pbData = pbData;
pKeyTransEncryptInfo->EncryptedKey.cbData = rgcbData[0];
} else
ICM_Free(pbData);
}
}
} else
fRet = ICM_DefaultExportKeyTrans(
pContentEncryptInfo,
pKeyTransEncodeInfo,
pKeyTransEncryptInfo,
0, // dwFlags
NULL // pvReserved
);
if (hFuncAddr)
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
return fRet;
}
//+-------------------------------------------------------------------------
// Get the CAPI ALG_ID corresponding to the wrap encryption OID.
//
// For RC2, if the ASN.1 encryption algorithm has any parameters, decode to
// get the key bit length.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetWrapEncryptParameters(
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
OUT PDWORD pdwAlgIdEncrypt,
OUT PDWORD pdwBitLen // 0 => default length
)
{
BOOL fRet;
*pdwBitLen = 0;
if (!ICM_GetCAPI(
CRYPT_ENCRYPT_ALG_OID_GROUP_ID,
paiEncrypt,
pdwAlgIdEncrypt))
goto GetCAPIError;
if (CALG_RC2 == *pdwAlgIdEncrypt) {
// Check if more than just the NULL parameters
if (2 < paiEncrypt->Parameters.cbData) {
PBYTE pbEncoded = paiEncrypt->Parameters.pbData;
DWORD cbEncoded = paiEncrypt->Parameters.cbData;
// Try to decode as an integer containing the RC2 version
int iVersion = 0;
DWORD cbStructInfo = sizeof(iVersion);
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_INTEGER,
pbEncoded,
cbEncoded,
0, // dwFlags
&iVersion,
&cbStructInfo))
goto RC2VersionDecodeError;
if (!ICM_RC2VersionToBitLength(iVersion, pdwBitLen))
goto RC2VersionToBitLengthError;
} else
*pdwBitLen = 40;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(GetCAPIError, CRYPT_E_UNKNOWN_ALGO)
TRACE_ERROR(RC2VersionDecodeError)
TRACE_ERROR(RC2VersionToBitLengthError)
}
//+-------------------------------------------------------------------------
// Get the CAPI ALG_ID and bit length by decoding the DH Encryption Parameters
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetDhWrapEncryptParameters(
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
OUT LPSTR *ppszAllocWrapOID,
OUT PDWORD pdwAlgIdWrap,
OUT PDWORD pdwBitLen // 0 => default length
)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
AlgorithmIdentifier *poai = NULL;
CRYPT_ALGORITHM_IDENTIFIER ai; ZEROSTRUCT(ai);
// Decode the DH KeyEncryption Parameters to get the Wrap Encryption
// Algorithm
if (0 == paiEncrypt->Parameters.cbData)
goto NoDhWrapParametersError;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&poai,
AlgorithmIdentifier_PDU,
paiEncrypt->Parameters.pbData,
paiEncrypt->Parameters.cbData)))
goto Asn1DecodeAlgorithmIdentifierError;
if (!ICM_Asn1FromAlgorithmIdentifier(poai, &ai))
goto Asn1FromAlgorithmIdentifierError;
if (!ICM_GetWrapEncryptParameters(&ai, pdwAlgIdWrap, pdwBitLen))
goto GetWrapEncryptParametersError;
*ppszAllocWrapOID = ai.pszObjId;
fRet = TRUE;
CommonReturn:
PkiAsn1FreeInfo(pDec, AlgorithmIdentifier_PDU, poai);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
ICM_Free(ai.pszObjId);
*ppszAllocWrapOID = NULL;
*pdwBitLen = 0;
*pdwAlgIdWrap = 0;
fRet = FALSE;
goto CommonReturn;
SET_ERROR(NoDhWrapParametersError, CRYPT_E_UNKNOWN_ALGO)
SET_ERROR_VAR(Asn1DecodeAlgorithmIdentifierError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(Asn1FromAlgorithmIdentifierError)
TRACE_ERROR(GetWrapEncryptParametersError)
}
//+-------------------------------------------------------------------------
// Get the CAPI ALG_ID corresponding to the wrap encryption OID. Generate
// default parameters for and encode. For RC2, encode as RC2ParameterVersion
// integer.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_CreateDefaultWrapEncryptParameters(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN OUT PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PVOID pvEncryptAuxInfo,
OUT PDWORD pdwAlgIdEncrypt,
OUT PDWORD pdwBitLen // 0 => default length
)
{
BOOL fRet;
assert(0 == paiEncrypt->Parameters.cbData);
*pdwBitLen = 0;
if (!ICM_GetCAPI(
CRYPT_ENCRYPT_ALG_OID_GROUP_ID,
paiEncrypt,
pdwAlgIdEncrypt))
goto GetCAPIError;
if (CALG_RC2 == *pdwAlgIdEncrypt) {
PCMSG_RC2_AUX_INFO pAuxInfo =
(PCMSG_RC2_AUX_INFO) pvEncryptAuxInfo;
CRYPT_ENCODE_PARA EncodePara;
int iVersion;
if (pAuxInfo && pAuxInfo->cbSize >= sizeof(CMSG_RC2_AUX_INFO)) {
DWORD dwVersion;
*pdwBitLen = pAuxInfo->dwBitLen & AUX_INFO_BIT_LENGTH_MASK;
if (!ICM_BitLengthToRC2Version(*pdwBitLen, &dwVersion))
goto BitLengthToRC2VersionError;
iVersion = dwVersion;
} else {
iVersion = CRYPT_RC2_40BIT_VERSION;
*pdwBitLen = 40;
}
ZEROSTRUCT(EncodePara);
EncodePara.cbSize = sizeof(EncodePara);
EncodePara.pfnAlloc = pContentEncryptInfo->pfnAlloc;
EncodePara.pfnFree = pContentEncryptInfo->pfnFree;
if (!CryptEncodeObjectEx(
X509_ASN_ENCODING,
X509_INTEGER,
&iVersion,
CRYPT_ENCODE_ALLOC_FLAG,
&EncodePara,
(void *) &paiEncrypt->Parameters.pbData,
&paiEncrypt->Parameters.cbData
)) goto EncodeError;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(GetCAPIError, CRYPT_E_UNKNOWN_ALGO)
TRACE_ERROR(BitLengthToRC2VersionError)
TRACE_ERROR(EncodeError)
}
//+-------------------------------------------------------------------------
// Get the CAPI ALG_ID corresponding to the wrap encryption OID.
// Encode the DH EncryptionAlgorithmIdentifier parameters which is the encoded
// WrapAlgorithmIdentifier.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_CreateDefaultDhWrapEncryptParameters(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN OUT PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PCRYPT_ALGORITHM_IDENTIFIER paiWrap,
IN PVOID pvWrapAuxInfo,
OUT PDWORD pdwAlgIdWrap,
OUT PDWORD pdwBitLen // 0 => default length
)
{
BOOL fRet;
CRYPT_ALGORITHM_IDENTIFIER aiWrap; ZEROSTRUCT(aiWrap);
AlgorithmIdentifier oaiWrap;
assert(0 == paiEncrypt->Parameters.cbData);
if (0 == paiWrap->Parameters.cbData) {
aiWrap = *paiWrap;
if (!ICM_CreateDefaultWrapEncryptParameters(
pContentEncryptInfo,
&aiWrap,
pvWrapAuxInfo,
pdwAlgIdWrap,
pdwBitLen))
goto CreateDefaultWrapEncryptParametersError;
paiWrap = &aiWrap;
} else {
if (!ICM_GetWrapEncryptParameters(
paiWrap,
pdwAlgIdWrap,
pdwBitLen))
goto GetWrapEncryptParametersError;
}
// Encode the Wrap Algorithm Identifier
if (!ICM_Asn1ToAlgorithmIdentifier(
paiWrap,
&oaiWrap))
goto Asn1ToAlgorithmIdentifierError;
if (!ICM_Asn1Encode(
AlgorithmIdentifier_PDU,
&oaiWrap,
&paiEncrypt->Parameters))
goto EncodeAlgorithmIdentifierError;
fRet = TRUE;
CommonReturn:
ICM_Free(aiWrap.Parameters.pbData);
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(CreateDefaultWrapEncryptParametersError)
TRACE_ERROR(GetWrapEncryptParametersError)
TRACE_ERROR(Asn1ToAlgorithmIdentifierError)
TRACE_ERROR(EncodeAlgorithmIdentifierError)
}
BOOL
WINAPI
ICM_PadEncodedOctets(
IN DWORD cbMaxContents,
IN OUT BYTE **ppbEncoded,
IN OUT DWORD *pcbEncoded
)
{
BOOL fRet;
DWORD cbEncoded = *pcbEncoded;
DWORD cbMaxEncoded;
DWORD cbLength;
ICM_GetLengthOctets(cbMaxContents, NULL, &cbLength);
cbMaxEncoded = 1 + cbLength + cbMaxContents;
if (cbMaxEncoded > cbEncoded) {
BYTE *pbMaxEncoded;
BYTE *pbEncoded;
if (NULL == (pbMaxEncoded = (BYTE *) ICM_Alloc(cbMaxEncoded)))
goto OutOfMemory;
pbEncoded = *ppbEncoded;
memcpy(pbMaxEncoded, pbEncoded, cbEncoded);
memset(pbMaxEncoded + cbEncoded, 0, cbMaxEncoded - cbEncoded);
ICM_Free(pbEncoded);
*ppbEncoded = pbMaxEncoded;
*pcbEncoded = cbMaxEncoded;
} else if (cbMaxEncoded < cbEncoded)
goto InvalidMaxEncodedLength;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
SET_ERROR(InvalidMaxEncodedLength, ERROR_INVALID_DATA)
}
#ifndef DH1
#define DH1 (((DWORD)'D'<<8)+((DWORD)'H'<<16)+((DWORD)'1'<<24))
#endif
HCRYPTKEY
WINAPI
ICM_GenerateEphemeralDh(
IN HCRYPTPROV hProv,
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO pKeyAgreeEncodeInfo,
IN OUT PCMSG_KEY_AGREE_ENCRYPT_INFO pKeyAgreeEncryptInfo,
OUT DWORD *pcbP
)
{
DWORD dwError = ERROR_SUCCESS;
HCRYPTKEY hEphemeralKey = 0;
PCRYPT_ALGORITHM_IDENTIFIER paiEphemeral =
pKeyAgreeEncodeInfo->pEphemeralAlgorithm;
PCERT_PUBLIC_KEY_INFO pPubKeyInfo =
&pKeyAgreeEncryptInfo->OriginatorPublicKeyInfo;
PCERT_X942_DH_PARAMETERS pDhParameters = NULL;
PUBLICKEYSTRUC *pPubKeyStruc = NULL;
DWORD cbPubKeyStruc;
BYTE *pbKeyBlob;
DHPUBKEY *pCspPubKey;
DWORD cbP;
PCRYPT_UINT_BLOB pGBlob;
BYTE *pbY;
DWORD cbY;
CRYPT_UINT_BLOB YBlob;
CRYPT_ENCODE_PARA EncodePara;
assert(CMSG_KEY_AGREE_EPHEMERAL_KEY_CHOICE ==
pKeyAgreeEncodeInfo->dwKeyChoice);
if (NULL == (pDhParameters =
(PCERT_X942_DH_PARAMETERS) ICM_AllocAndDecodeObject(
X942_DH_PARAMETERS,
paiEphemeral->Parameters.pbData,
paiEphemeral->Parameters.cbData)))
goto DhParametersDecodeError;
cbP = pDhParameters->p.cbData;
*pcbP = cbP;
if (!CryptGenKey(
hProv,
CALG_DH_EPHEM,
((cbP * 8) << 16) | CRYPT_EXPORTABLE | CRYPT_PREGEN,
&hEphemeralKey))
goto GenEphemeralKeyError;
if (!CryptSetKeyParam(
hEphemeralKey,
KP_P,
(PBYTE) &pDhParameters->p,
0)) // dwFlags
goto SetPError;
// Note, the length of G can be less than length P. Pad with leading
// zeroes in little endian form.
if (pDhParameters->g.cbData >= cbP)
pGBlob = &pDhParameters->g;
else {
DWORD cbG = pDhParameters->g.cbData;
// We are done using P parameter. Overwrite with the G parameter and
// pad with leading zeroes in little endian form.
pGBlob = &pDhParameters->p;
memcpy(pGBlob->pbData, pDhParameters->g.pbData, cbG);
memset(pGBlob->pbData + cbG, 0, cbP - cbG);
}
if (!CryptSetKeyParam(
hEphemeralKey,
KP_G,
(PBYTE) pGBlob,
0)) // dwFlags
goto SetGError;
if (0 < pDhParameters->q.cbData) {
if (!CryptSetKeyParam(
hEphemeralKey,
KP_Q,
(PBYTE) &pDhParameters->q,
0)) // dwFlags
goto SetQError;
}
if (!CryptSetKeyParam(
hEphemeralKey,
KP_X,
NULL, // pbData
0)) // dwFlags
goto SetXError;
// Export the public key to get Y
cbPubKeyStruc = 0;
if (!CryptExportKey(
hEphemeralKey,
0, // hPubKey
PUBLICKEYBLOB,
0, // dwFlags
NULL, // pbData
&cbPubKeyStruc
) || (cbPubKeyStruc == 0))
goto ExportPublicKeyBlobError;
if (NULL == (pPubKeyStruc = (PUBLICKEYSTRUC *) ICM_Alloc(cbPubKeyStruc)))
goto OutOfMemory;
if (!CryptExportKey(
hEphemeralKey,
0, // hPubKey
PUBLICKEYBLOB,
0, // dwFlags
(BYTE *) pPubKeyStruc,
&cbPubKeyStruc
))
goto ExportPublicKeyBlobError;
// The CAPI public key representation consists of the following sequence:
// - PUBLICKEYSTRUC
// - DHPUBKEY
// - rgbY[cbKey]
pbKeyBlob = (BYTE *) pPubKeyStruc;
pCspPubKey = (DHPUBKEY *) (pbKeyBlob + sizeof(PUBLICKEYSTRUC));
pbY = pbKeyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(DHPUBKEY);
cbY = pCspPubKey->bitlen / 8;
if (cbPubKeyStruc < sizeof(PUBLICKEYSTRUC) + sizeof(DHPUBKEY) + cbY)
goto InvalidEphemeralKey;
if (pPubKeyStruc->bType != PUBLICKEYBLOB)
goto InvalidEphemeralKey;
if (pCspPubKey->magic != DH1)
goto InvalidEphemeralKey;
if (cbY != cbP)
goto InvalidEphemeralKey;
ZEROSTRUCT(EncodePara);
EncodePara.cbSize = sizeof(EncodePara);
EncodePara.pfnAlloc = pContentEncryptInfo->pfnAlloc;
EncodePara.pfnFree = pContentEncryptInfo->pfnFree;
YBlob.pbData = pbY;
YBlob.cbData = cbY;
if (!CryptEncodeObjectEx(
X509_ASN_ENCODING,
X509_DH_PUBLICKEY,
&YBlob,
CRYPT_ENCODE_ALLOC_FLAG,
&EncodePara,
(void *) &pPubKeyInfo->PublicKey.pbData,
&pPubKeyInfo->PublicKey.cbData
))
goto EncodeDHPublicKeyError;
pKeyAgreeEncryptInfo->dwOriginatorChoice =
CMSG_KEY_AGREE_ORIGINATOR_PUBLIC_KEY;
pPubKeyInfo->Algorithm.pszObjId = paiEphemeral->pszObjId;
pKeyAgreeEncryptInfo->dwFlags |=
CMSG_KEY_AGREE_ENCRYPT_FREE_PUBKEY_BITS_FLAG;
if (pContentEncryptInfo->dwEncryptFlags &
CMSG_CONTENT_ENCRYPT_PAD_ENCODED_LEN_FLAG) {
if (!ICM_PadEncodedOctets(
cbY + 1,
&pPubKeyInfo->PublicKey.pbData,
&pPubKeyInfo->PublicKey.cbData
))
goto PadEncodedOctetsError;
}
CommonReturn:
ICM_Free(pDhParameters);
ICM_Free(pPubKeyStruc);
ICM_SetLastError(dwError);
return hEphemeralKey;
ErrorReturn:
dwError = GetLastError();
if (hEphemeralKey) {
CryptDestroyKey(hEphemeralKey);
hEphemeralKey = 0;
}
goto CommonReturn;
TRACE_ERROR(DhParametersDecodeError)
TRACE_ERROR(GenEphemeralKeyError)
TRACE_ERROR(SetPError)
TRACE_ERROR(SetGError)
TRACE_ERROR(SetQError)
TRACE_ERROR(SetXError)
TRACE_ERROR(ExportPublicKeyBlobError)
SET_ERROR(InvalidEphemeralKey, NTE_BAD_PUBLIC_KEY)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(EncodeDHPublicKeyError)
TRACE_ERROR(PadEncodedOctetsError)
}
HCRYPTKEY
WINAPI
ICM_ImportDhAgreeKey(
IN HCRYPTPROV hKeyAgreeProv,
IN HCRYPTKEY hMyKey,
IN DWORD cbP,
IN PCRYPT_BIT_BLOB pPublicKey,
IN LPSTR pszWrapOID,
IN ALG_ID AlgidWrap,
IN DWORD dwBitLen,
IN PCRYPT_DATA_BLOB pUserKeyingMaterial
)
{
DWORD dwError = ERROR_SUCCESS;
HCRYPTKEY hAgreeKey = 0;
PCRYPT_UINT_BLOB pDhPubKey = NULL;
PBYTE pbKeyBlob = NULL;
DWORD cbKeyBlob;
PUBLICKEYSTRUC *pPubKeyStruc;
DHPUBKEY *pCspPubKey;
DWORD cbY;
PBYTE pbKey;
CMS_DH_KEY_INFO CmsDhKeyInfo; ZEROSTRUCT(CmsDhKeyInfo);
if (NULL == (pDhPubKey = (PCRYPT_UINT_BLOB) ICM_AllocAndDecodeObject(
X509_DH_PUBLICKEY,
pPublicKey->pbData,
pPublicKey->cbData)))
goto DecodePubKeyError;
// The CAPI public key representation consists of the following sequence:
// - PUBLICKEYSTRUC
// - DHPUBKEY
// - rgbY[cbP]
cbY = pDhPubKey->cbData;
if (0 == cbY || cbY > cbP)
goto InvalidDhPubKeyError;
cbKeyBlob = sizeof(PUBLICKEYSTRUC) + sizeof(DHPUBKEY) + cbP;
if (NULL == (pbKeyBlob = (PBYTE) ICM_Alloc(cbKeyBlob)))
goto OutOfMemory;
pPubKeyStruc = (PUBLICKEYSTRUC *) pbKeyBlob;
pCspPubKey = (DHPUBKEY *) (pbKeyBlob + sizeof(PUBLICKEYSTRUC));
pbKey = pbKeyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(DHPUBKEY);
// PUBLICKEYSTRUC
pPubKeyStruc->bType = PUBLICKEYBLOB;
pPubKeyStruc->bVersion = CUR_BLOB_VERSION;
pPubKeyStruc->reserved = 0;
pPubKeyStruc->aiKeyAlg = CALG_DH_SF;
// DHPUBKEY
pCspPubKey->magic = DH1;
pCspPubKey->bitlen = cbP * 8;
// rgbY[cbP]
memcpy(pbKey, pDhPubKey->pbData, cbY);
if (cbP > cbY)
memset(pbKey + cbY, 0, cbP - cbY);
if (!CryptImportKey(
hKeyAgreeProv,
pbKeyBlob,
cbKeyBlob,
hMyKey,
0, // dwFlags
&hAgreeKey)) {
hAgreeKey = 0;
goto ImportKeyError;
}
CmsDhKeyInfo.dwVersion = sizeof(CmsDhKeyInfo);
CmsDhKeyInfo.Algid = AlgidWrap;
CmsDhKeyInfo.pszContentEncObjId = pszWrapOID;
CmsDhKeyInfo.PubInfo = *pUserKeyingMaterial;
// CmsDhKeyInfo.pReserved
if (!CryptSetKeyParam(
hAgreeKey,
KP_CMS_DH_KEY_INFO,
(PBYTE) &CmsDhKeyInfo,
(CALG_RC2 == AlgidWrap) ? (dwBitLen << 16) : 0)) // dwFlags
goto SetCmsDhKeyInfoError;
if (CALG_RC2 == AlgidWrap && 0 != dwBitLen) {
if (!CryptSetKeyParam(
hAgreeKey,
KP_EFFECTIVE_KEYLEN,
(PBYTE) &dwBitLen,
0)) // dwFlags
goto SetEffectiveKeyLenError;
}
CommonReturn:
ICM_Free(pDhPubKey);
ICM_Free(pbKeyBlob);
ICM_SetLastError(dwError);
return hAgreeKey;
ErrorReturn:
dwError = GetLastError();
if (hAgreeKey) {
CryptDestroyKey(hAgreeKey);
hAgreeKey = 0;
}
goto CommonReturn;
TRACE_ERROR(DecodePubKeyError)
SET_ERROR(InvalidDhPubKeyError, E_INVALIDARG)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(ImportKeyError)
TRACE_ERROR(SetCmsDhKeyInfoError)
TRACE_ERROR(SetEffectiveKeyLenError)
}
BOOL
WINAPI
ICM_DefaultExportKeyAgree(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO pKeyAgreeEncodeInfo,
IN OUT PCMSG_KEY_AGREE_ENCRYPT_INFO pKeyAgreeEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
HCRYPTPROV hKeyAgreeProv = 0; // Doesn't need to be released
HCRYPTKEY hContentEncryptKey = 0;
HCRYPTKEY hEphemeralKey = 0;
HCRYPTKEY hAgreeKey = 0;
DWORD cbP;
PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt =
&pKeyAgreeEncryptInfo->KeyEncryptionAlgorithm;
LPSTR pszAllocWrapOID = NULL;
LPSTR pszWrapOID;
DWORD dwAlgIdWrap;
DWORD dwBitLen;
DWORD cRecipient;
PCMSG_KEY_AGREE_KEY_ENCRYPT_INFO *ppRecipientEncryptInfo;
PCMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO *ppRecipientEncodeInfo;
assert(CMSG_KEY_AGREE_EPHEMERAL_KEY_CHOICE ==
pKeyAgreeEncodeInfo->dwKeyChoice);
if (CMSG_KEY_AGREE_EPHEMERAL_KEY_CHOICE != pKeyAgreeEncodeInfo->dwKeyChoice)
goto InvalidKeyAgreeKeyChoice;
if (0 == paiEncrypt->Parameters.cbData) {
PCRYPT_ALGORITHM_IDENTIFIER paiWrap =
&pKeyAgreeEncodeInfo->KeyWrapAlgorithm;
if (!ICM_CreateDefaultDhWrapEncryptParameters(
pContentEncryptInfo,
paiEncrypt,
paiWrap,
pKeyAgreeEncodeInfo->pvKeyWrapAuxInfo,
&dwAlgIdWrap,
&dwBitLen))
goto CreateDefaultDhWrapEncryptParametersError;
assert(paiEncrypt->Parameters.cbData);
pKeyAgreeEncryptInfo->dwFlags |= CMSG_KEY_AGREE_ENCRYPT_FREE_PARA_FLAG;
pszWrapOID = paiWrap->pszObjId;
} else {
if (!ICM_GetDhWrapEncryptParameters(
paiEncrypt,
&pszAllocWrapOID,
&dwAlgIdWrap,
&dwBitLen))
goto GetDhWrapEncryptParametersError;
pszWrapOID = pszAllocWrapOID;
}
hKeyAgreeProv = pKeyAgreeEncodeInfo->hCryptProv;
if (0 == hKeyAgreeProv) {
if (0 == pKeyAgreeEncryptInfo->dwRecipientIndex)
hKeyAgreeProv = pContentEncryptInfo->hCryptProv;
else {
// Check if the type of and public key algorithm for this
// recipient is the same as the first recipient's.
PCMSG_RECIPIENT_ENCODE_INFO prei;
prei = &pContentEncryptInfo->rgCmsRecipients[0];
if (CMSG_KEY_AGREE_RECIPIENT == prei->dwRecipientChoice &&
ICM_IsSameRecipientPublicKeyAlgorithm(
&prei->pKeyAgree->KeyEncryptionAlgorithm,
paiEncrypt))
hKeyAgreeProv = pContentEncryptInfo->hCryptProv;
else {
// Get default provider associated with the
// key encryption algorithm
DWORD dwAlgIdPubKey;
if (!ICM_GetCAPI(
CRYPT_PUBKEY_ALG_OID_GROUP_ID,
paiEncrypt,
&dwAlgIdPubKey))
goto GetPublicKeyAlgIdError;
hKeyAgreeProv = I_CryptGetDefaultCryptProvForEncrypt(
dwAlgIdPubKey, dwAlgIdWrap, dwBitLen);
if (0 == hKeyAgreeProv)
goto GetDefaultCryptProvError;
}
}
}
if (hKeyAgreeProv != pContentEncryptInfo->hCryptProv) {
// Need to export the hContentEncryptKey from the ContentEncrypt
// provider and import into the KeyAgree provider
hContentEncryptKey = ICM_ExportContentEncryptKeyAndImport(
pContentEncryptInfo,
hKeyAgreeProv);
if (0 == hContentEncryptKey)
goto ImportContentKeyError;
} else
hContentEncryptKey = pContentEncryptInfo->hContentEncryptKey;
if (0 == (hEphemeralKey = ICM_GenerateEphemeralDh(
hKeyAgreeProv,
pContentEncryptInfo,
pKeyAgreeEncodeInfo,
pKeyAgreeEncryptInfo,
&cbP)))
goto GenerateEphemeralDhError;
cRecipient = pKeyAgreeEncryptInfo->cKeyAgreeKeyEncryptInfo;
ppRecipientEncryptInfo = pKeyAgreeEncryptInfo->rgpKeyAgreeKeyEncryptInfo;
ppRecipientEncodeInfo = pKeyAgreeEncodeInfo->rgpRecipientEncryptedKeys;
for ( ; 0 < cRecipient;
cRecipient--,
ppRecipientEncryptInfo++,
ppRecipientEncodeInfo++) {
if (0 == (hAgreeKey = ICM_ImportDhAgreeKey(
hKeyAgreeProv,
hEphemeralKey,
cbP,
&(*ppRecipientEncodeInfo)->RecipientPublicKey,
pszWrapOID,
dwAlgIdWrap,
dwBitLen,
&pKeyAgreeEncodeInfo->UserKeyingMaterial
)))
goto ImportDhAgreeKeyError;
if (!ICM_ExportEncryptedKey(
hContentEncryptKey,
hAgreeKey,
SYMMETRICWRAPKEYBLOB,
FALSE, // fAllowSP3CompatibleEncrypt
&(*ppRecipientEncryptInfo)->EncryptedKey))
goto ExportEncryptedKeyError;
CryptDestroyKey(hAgreeKey);
hAgreeKey = 0;
}
fRet = TRUE;
CommonReturn:
ICM_Free(pszAllocWrapOID);
if (hKeyAgreeProv != pContentEncryptInfo->hCryptProv &&
hContentEncryptKey)
CryptDestroyKey(hContentEncryptKey);
if (hAgreeKey)
CryptDestroyKey(hAgreeKey);
if (hEphemeralKey)
CryptDestroyKey(hEphemeralKey);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidKeyAgreeKeyChoice, E_INVALIDARG)
TRACE_ERROR(CreateDefaultDhWrapEncryptParametersError)
TRACE_ERROR(GetDhWrapEncryptParametersError)
TRACE_ERROR(GetPublicKeyAlgIdError)
TRACE_ERROR(GetDefaultCryptProvError)
TRACE_ERROR(ImportContentKeyError)
TRACE_ERROR(GenerateEphemeralDhError)
TRACE_ERROR(ImportDhAgreeKeyError)
TRACE_ERROR(ExportEncryptedKeyError)
}
BOOL
WINAPI
ICM_ExportKeyAgree(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO pKeyAgreeEncodeInfo,
IN OUT PCMSG_KEY_AGREE_ENCRYPT_INFO pKeyAgreeEncryptInfo
)
{
BOOL fRet;
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (CryptGetOIDFunctionAddress(
hExportKeyAgreeFuncSet,
X509_ASN_ENCODING,
pKeyAgreeEncryptInfo->KeyEncryptionAlgorithm.pszObjId,
0, // dwFlags
&pvFuncAddr,
&hFuncAddr)) {
fRet = ((PFN_CMSG_EXPORT_KEY_AGREE) pvFuncAddr)(
pContentEncryptInfo,
pKeyAgreeEncodeInfo,
pKeyAgreeEncryptInfo,
0, // dwFlags
NULL // pvReserved
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
} else
fRet = ICM_DefaultExportKeyAgree(
pContentEncryptInfo,
pKeyAgreeEncodeInfo,
pKeyAgreeEncryptInfo,
0, // dwFlags
NULL // pvReserved
);
return fRet;
}
BOOL
WINAPI
ICM_DefaultExportMailList(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO pMailListEncodeInfo,
IN OUT PCMSG_MAIL_LIST_ENCRYPT_INFO pMailListEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
HCRYPTPROV hMailListProv = 0; // not released
HCRYPTKEY hContentEncryptKey = 0; // destroy if exported/imported
HCRYPTKEY hKeyEncryptionKey = 0; // not destroyed
PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt =
&pMailListEncryptInfo->KeyEncryptionAlgorithm;
DWORD dwAlgIdEncrypt;
DWORD dwBitLen;
hMailListProv = pMailListEncodeInfo->hCryptProv;
switch (pMailListEncodeInfo->dwKeyChoice) {
case CMSG_MAIL_LIST_HANDLE_KEY_CHOICE:
hKeyEncryptionKey = pMailListEncodeInfo->hKeyEncryptionKey;
assert(hMailListProv && hKeyEncryptionKey);
if (0 == hMailListProv || 0 == hKeyEncryptionKey)
goto InvalidMailListHandleKeyPara;
break;
default:
goto InvalidMailListKeyChoice;
}
if (0 == paiEncrypt->Parameters.cbData) {
if (!ICM_CreateDefaultWrapEncryptParameters(
pContentEncryptInfo,
paiEncrypt,
pMailListEncodeInfo->pvKeyEncryptionAuxInfo,
&dwAlgIdEncrypt,
&dwBitLen))
goto CreateDefaultWrapEncryptParametersError;
if (paiEncrypt->Parameters.cbData)
pMailListEncryptInfo->dwFlags |=
CMSG_MAIL_LIST_ENCRYPT_FREE_PARA_FLAG;
} else {
if (!ICM_GetWrapEncryptParameters(
paiEncrypt,
&dwAlgIdEncrypt,
&dwBitLen))
goto GetWrapEncryptParametersError;
}
if (hMailListProv != pContentEncryptInfo->hCryptProv) {
// Need to export the hContentEncryptKey from the ContentEncrypt
// provider and import into the MailList provider
hContentEncryptKey = ICM_ExportContentEncryptKeyAndImport(
pContentEncryptInfo,
hMailListProv);
if (0 == hContentEncryptKey)
goto ImportContentKeyError;
} else
hContentEncryptKey = pContentEncryptInfo->hContentEncryptKey;
if (CALG_RC2 == dwAlgIdEncrypt && 0 != dwBitLen)
// Silently ignore any errors. Not supported in earlier versions
CryptSetKeyParam(
hKeyEncryptionKey,
KP_EFFECTIVE_KEYLEN,
(PBYTE) &dwBitLen,
0); // dwFlags
if (!ICM_ExportEncryptedKey(
hContentEncryptKey,
hKeyEncryptionKey,
SYMMETRICWRAPKEYBLOB,
FALSE, // fAllowSP3CompatibleEncrypt
&pMailListEncryptInfo->EncryptedKey))
goto ExportEncryptedKeyError;
fRet = TRUE;
CommonReturn:
if (hMailListProv != pContentEncryptInfo->hCryptProv &&
hContentEncryptKey)
CryptDestroyKey(hContentEncryptKey);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidMailListHandleKeyPara, E_INVALIDARG)
SET_ERROR(InvalidMailListKeyChoice, E_INVALIDARG)
TRACE_ERROR(CreateDefaultWrapEncryptParametersError)
TRACE_ERROR(GetWrapEncryptParametersError)
TRACE_ERROR(ImportContentKeyError)
TRACE_ERROR(ExportEncryptedKeyError)
}
BOOL
WINAPI
ICM_ExportMailList(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO pMailListEncodeInfo,
IN OUT PCMSG_MAIL_LIST_ENCRYPT_INFO pMailListEncryptInfo
)
{
BOOL fRet;
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (CryptGetOIDFunctionAddress(
hExportMailListFuncSet,
X509_ASN_ENCODING,
pMailListEncryptInfo->KeyEncryptionAlgorithm.pszObjId,
0, // dwFlags
&pvFuncAddr,
&hFuncAddr)) {
fRet = ((PFN_CMSG_EXPORT_MAIL_LIST) pvFuncAddr)(
pContentEncryptInfo,
pMailListEncodeInfo,
pMailListEncryptInfo,
0, // dwFlags
NULL // pvReserved
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
} else
fRet = ICM_DefaultExportMailList(
pContentEncryptInfo,
pMailListEncodeInfo,
pMailListEncryptInfo,
0, // dwFlags
NULL // pvReserved
);
return fRet;
}
//+-------------------------------------------------------------------------
// Default export of the encryption key
//
// Note, pcbData[1] contains dwEncryptFlags, where,
// CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG may be set to disable the reversing
// of the encoded, encrypted symmetric key.
//
// rgcbData[1] is the dwEncryptFlags passed from ICM_DefaultGenEncryptKey
//
// OldStyle
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultExportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN HCRYPTKEY hEncryptKey,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
OUT PBYTE pbData,
IN OUT DWORD rgcbData[2])
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
HCRYPTKEY hPubKey = NULL;
CRYPT_DATA_BLOB EncryptedKey; ZEROSTRUCT(EncryptedKey);
DWORD cb;
if (!CryptImportPublicKeyInfo(
hCryptProv,
X509_ASN_ENCODING,
pPublicKeyInfo,
&hPubKey))
goto ImportKeyError;
if (!ICM_ExportEncryptedKey(
hEncryptKey,
hPubKey,
SIMPLEBLOB,
0 != (rgcbData[1] & CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG),
&EncryptedKey))
goto ExportEncryptedKeyError;
fRet = TRUE;
cb = EncryptedKey.cbData;
if (pbData) {
if (rgcbData[0] < cb) {
SetLastError((DWORD) ERROR_MORE_DATA);
fRet = FALSE;
} else
memcpy(pbData, EncryptedKey.pbData, cb);
}
CommonReturn:
rgcbData[0] = cb;
ICM_Free(EncryptedKey.pbData);
if (hPubKey)
CryptDestroyKey(hPubKey);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
cb = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(ImportKeyError)
TRACE_ERROR(ExportEncryptedKeyError)
}
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
PCMSG_RECIPIENT_ENCODE_INFO
WINAPI
ICM_CreateCmsRecipientEncodeInfos(
IN DWORD cRecipients,
IN PCERT_INFO *rgpCertInfoRecipients
)
{
PCMSG_RECIPIENT_ENCODE_INFO rgCmsRecipients = NULL;
PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO rgKeyTrans;
DWORD cbCmsRecipients;
DWORD i;
assert(cRecipients && rgpCertInfoRecipients);
cbCmsRecipients = sizeof(CMSG_RECIPIENT_ENCODE_INFO) * cRecipients +
sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO) * cRecipients;
if (NULL == (rgCmsRecipients = (PCMSG_RECIPIENT_ENCODE_INFO) ICM_AllocZero(
cbCmsRecipients)))
return NULL;
rgKeyTrans = (PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO)
(((PBYTE) rgCmsRecipients) +
sizeof(CMSG_RECIPIENT_ENCODE_INFO) * cRecipients);
for (i = 0; i < cRecipients; i++) {
rgCmsRecipients[i].dwRecipientChoice = CMSG_KEY_TRANS_RECIPIENT;
rgCmsRecipients[i].pKeyTrans = &rgKeyTrans[i];
rgKeyTrans[i].cbSize = sizeof(CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO);
rgKeyTrans[i].KeyEncryptionAlgorithm =
rgpCertInfoRecipients[i]->SubjectPublicKeyInfo.Algorithm;
// rgKeyTrans[i].pvKeyEncryptionAuxInfo =
// rgKeyTrans[i].hCryptProv =
rgKeyTrans[i].RecipientPublicKey =
rgpCertInfoRecipients[i]->SubjectPublicKeyInfo.PublicKey;
ICM_GetCertIdFromCertInfo(rgpCertInfoRecipients[i],
&rgKeyTrans[i].RecipientId);
}
return rgCmsRecipients;
}
void
WINAPI
ICM_FreeContentEncryptInfo(
IN PCMSG_ENVELOPED_ENCODE_INFO pEnvelopedEncodeInfo,
IN OUT PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo
)
{
DWORD dwErr = GetLastError();
if (pEnvelopedEncodeInfo->rgpRecipients) {
ICM_Free(pContentEncryptInfo->rgCmsRecipients);
pContentEncryptInfo->rgCmsRecipients = NULL;
}
if (pContentEncryptInfo->hContentEncryptKey) {
CryptDestroyKey(pContentEncryptInfo->hContentEncryptKey);
pContentEncryptInfo->hContentEncryptKey = 0;
}
if (pContentEncryptInfo->dwFlags &
CMSG_CONTENT_ENCRYPT_RELEASE_CONTEXT_FLAG) {
pContentEncryptInfo->dwFlags &=
~CMSG_CONTENT_ENCRYPT_RELEASE_CONTEXT_FLAG;
assert(pContentEncryptInfo->hCryptProv);
CryptReleaseContext(pContentEncryptInfo->hCryptProv, 0);
pContentEncryptInfo->hCryptProv = 0;
}
if (pContentEncryptInfo->dwFlags &
CMSG_CONTENT_ENCRYPT_FREE_PARA_FLAG) {
pContentEncryptInfo->dwFlags &=
~CMSG_CONTENT_ENCRYPT_FREE_PARA_FLAG;
assert(
pContentEncryptInfo->ContentEncryptionAlgorithm.Parameters.cbData
&&
pContentEncryptInfo->ContentEncryptionAlgorithm.Parameters.pbData);
ICM_Free(
pContentEncryptInfo->ContentEncryptionAlgorithm.Parameters.pbData);
pContentEncryptInfo->ContentEncryptionAlgorithm.Parameters.cbData = 0;
pContentEncryptInfo->ContentEncryptionAlgorithm.Parameters.pbData = NULL;
}
SetLastError(dwErr);
}
BOOL
WINAPI
ICM_InitializeContentEncryptInfo(
IN PCMSG_ENVELOPED_ENCODE_INFO pEnvelopedEncodeInfo,
OUT PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo
)
{
BOOL fRet;
DWORD cRecipients;
memset(pContentEncryptInfo, 0, sizeof(*pContentEncryptInfo));
pContentEncryptInfo->cbSize = sizeof(*pContentEncryptInfo);
pContentEncryptInfo->hCryptProv =
pEnvelopedEncodeInfo->hCryptProv;
pContentEncryptInfo->ContentEncryptionAlgorithm =
pEnvelopedEncodeInfo->ContentEncryptionAlgorithm;
pContentEncryptInfo->pvEncryptionAuxInfo =
pEnvelopedEncodeInfo->pvEncryptionAuxInfo;
pContentEncryptInfo->pfnAlloc = ICM_Alloc;
pContentEncryptInfo->pfnFree = ICM_Free;
// pContentEncryptInfo->dwEncryptFlags =
// pContentEncryptInfo->hContentEncryptKey =
// pContentEncryptInfo->dwFlags =
cRecipients = pEnvelopedEncodeInfo->cRecipients;
pContentEncryptInfo->cRecipients = cRecipients;
if (0 == cRecipients)
;
else if (pEnvelopedEncodeInfo->rgpRecipients) {
if (NULL == (pContentEncryptInfo->rgCmsRecipients =
ICM_CreateCmsRecipientEncodeInfos(
cRecipients, pEnvelopedEncodeInfo->rgpRecipients)))
goto CreateCmsRecipientEncodeInfosError;
} else {
if (sizeof(CMSG_ENVELOPED_ENCODE_INFO) > pEnvelopedEncodeInfo->cbSize)
goto MissingCmsRecipients;
pContentEncryptInfo->rgCmsRecipients =
pEnvelopedEncodeInfo->rgCmsRecipients;
if (NULL == pContentEncryptInfo->rgCmsRecipients)
goto MissingCmsRecipients;
}
if (!ICM_GenContentEncryptKey(pContentEncryptInfo))
goto GenContentEncryptKeyError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
ICM_FreeContentEncryptInfo(pEnvelopedEncodeInfo, pContentEncryptInfo);
fRet = FALSE;
goto CommonReturn;
SET_ERROR(MissingCmsRecipients, E_INVALIDARG)
TRACE_ERROR(CreateCmsRecipientEncodeInfosError)
TRACE_ERROR(GenContentEncryptKeyError)
}
//+-------------------------------------------------------------------------
// Oss set/free functions
//
// Assumption: upon entry to the set functions, the Oss data structure has
// already been zeroed.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_SetOssAny(
IN PCRYPT_DATA_BLOB pAny,
IN OUT Any *pOssAny
)
{
if (NULL == (pOssAny->value =
(unsigned char *) ICM_DupMem(pAny->pbData, pAny->cbData)))
return FALSE;
pOssAny->length = pAny->cbData;
return TRUE;
}
void
WINAPI
ICM_FreeOssAny(
IN OUT Any *pOssAny
)
{
if (pOssAny->value) {
ICM_Free(pOssAny->value);
pOssAny->value = NULL;
}
}
BOOL
WINAPI
ICM_SetOssHugeInteger(
IN PCRYPT_INTEGER_BLOB pHugeInteger,
IN OUT HugeIntegerType *pOssHugeInteger
)
{
return PkiAsn1SetHugeInteger(
pHugeInteger,
&pOssHugeInteger->length,
&pOssHugeInteger->value
);
}
void
WINAPI
ICM_FreeOssHugeInteger(
IN OUT HugeIntegerType *pOssHugeInteger
)
{
if (pOssHugeInteger->value) {
PkiAsn1FreeHugeInteger(pOssHugeInteger->value);
pOssHugeInteger->value = NULL;
}
}
BOOL
WINAPI
ICM_SetOssOctetString(
IN PCRYPT_DATA_BLOB pOctetString,
IN OUT OctetStringType *pOssOctetString
)
{
if (NULL == (pOssOctetString->value =
(unsigned char *) ICM_DupMem(
pOctetString->pbData, pOctetString->cbData)))
return FALSE;
pOssOctetString->length = pOctetString->cbData;
return TRUE;
}
void
WINAPI
ICM_FreeOssOctetString(
IN OUT OctetStringType *pOssOctetString
)
{
if (pOssOctetString->value) {
ICM_Free(pOssOctetString->value);
pOssOctetString->value = NULL;
}
}
BOOL
WINAPI
ICM_SetOssBitString(
IN PCRYPT_BIT_BLOB pBitString,
IN OUT BitStringType *pOssBitString
)
{
CRYPT_BIT_BLOB BitString = *pBitString;
if (NULL == (BitString.pbData = (PBYTE) ICM_DupMem(
BitString.pbData, BitString.cbData)))
return FALSE;
PkiAsn1SetBitString(&BitString, &pOssBitString->length,
&pOssBitString->value);
return TRUE;
}
void
WINAPI
ICM_FreeOssBitString(
IN OUT BitStringType *pOssBitString
)
{
if (pOssBitString->value) {
ICM_Free(pOssBitString->value);
pOssBitString->value = NULL;
}
}
static BYTE abDerNULL[] = {5, 0};
BOOL
WINAPI
ICM_SetOssAlgorithmIdentifier(
IN PCRYPT_ALGORITHM_IDENTIFIER pai,
IN OUT AlgorithmIdentifier *pOssAlgId
)
{
BOOL fRet;
PBYTE pbData;
DWORD cbData;
pOssAlgId->algorithm.count = SIZE_OSS_OID;
if (!PkiAsn1ToObjectIdentifier(
pai->pszObjId,
&pOssAlgId->algorithm.count,
pOssAlgId->algorithm.value))
goto PkiAsn1ToObjectIdentifierError;
pOssAlgId->bit_mask = parameters_present;
pbData = pai->Parameters.pbData;
cbData = pai->Parameters.cbData;
if (0 == cbData) {
pOssAlgId->parameters.length = sizeof(abDerNULL);
pOssAlgId->parameters.value = abDerNULL;
} else {
if (NULL == (pOssAlgId->parameters.value =
(unsigned char *) ICM_DupMem(pbData, cbData)))
goto OutOfMemory;
pOssAlgId->parameters.length = cbData;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(PkiAsn1ToObjectIdentifierError, CRYPT_E_OID_FORMAT)
TRACE_ERROR(OutOfMemory)
}
void
WINAPI
ICM_FreeOssAlgorithmIdentifier(
IN OUT AlgorithmIdentifier *pOssAlgId
)
{
unsigned char *value;
#ifdef OSS_CRYPT_ASN1
value = pOssAlgId->parameters.value;
#else
value = (unsigned char *) pOssAlgId->parameters.value;
#endif // OSS_CRYPT_ASN1
if (value && value != abDerNULL) {
ICM_Free(value);
pOssAlgId->parameters.value = NULL;
}
}
BOOL
WINAPI
ICM_SetOssOtherKeyAttribute(
IN PCRYPT_ATTRIBUTE_TYPE_VALUE pOtherAttr,
IN OUT OtherKeyAttribute *pOssOtherAttr
)
{
BOOL fRet;
pOssOtherAttr->keyAttrId.count = SIZE_OSS_OID;
if (!PkiAsn1ToObjectIdentifier(
pOtherAttr->pszObjId,
&pOssOtherAttr->keyAttrId.count,
pOssOtherAttr->keyAttrId.value))
goto PkiAsn1ToObjectIdentifierError;
if (pOtherAttr->Value.cbData) {
if (!ICM_SetOssAny(&pOtherAttr->Value, &pOssOtherAttr->keyAttr))
goto SetOssAnyError;
pOssOtherAttr->bit_mask |= keyAttr_present;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(PkiAsn1ToObjectIdentifierError, CRYPT_E_OID_FORMAT)
TRACE_ERROR(SetOssAnyError)
}
void
WINAPI
ICM_FreeOssOtherKeyAttribute(
OUT OtherKeyAttribute *pOssOtherAttr
)
{
ICM_FreeOssAny(&pOssOtherAttr->keyAttr);
}
void
WINAPI
ICM_FreeOssIssuerAndSerialNumber(
IN OUT IssuerAndSerialNumber *pOssIssuerAndSerialNumber
)
{
ICM_FreeOssAny(&pOssIssuerAndSerialNumber->issuer);
ICM_FreeOssHugeInteger(&pOssIssuerAndSerialNumber->serialNumber);
}
BOOL
WINAPI
ICM_SetOssIssuerAndSerialNumber(
IN PCERT_ISSUER_SERIAL_NUMBER pIssuerAndSerialNumber,
IN OUT IssuerAndSerialNumber *pOssIssuerAndSerialNumber
)
{
BOOL fRet;
if (!ICM_SetOssAny(&pIssuerAndSerialNumber->Issuer,
&pOssIssuerAndSerialNumber->issuer))
goto SetOssAnyError;
if (!ICM_SetOssHugeInteger(&pIssuerAndSerialNumber->SerialNumber,
&pOssIssuerAndSerialNumber->serialNumber))
goto SetOssHugeIntegerError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
ICM_FreeOssIssuerAndSerialNumber(pOssIssuerAndSerialNumber);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(SetOssAnyError)
TRACE_ERROR(SetOssHugeIntegerError)
}
BOOL
WINAPI
ICM_SetOssCertIdentifier(
IN PCERT_ID pCertId,
IN OUT CertIdentifier *pOssCertId
)
{
BOOL fRet;
switch (pCertId->dwIdChoice) {
case CERT_ID_ISSUER_SERIAL_NUMBER:
if (!ICM_SetOssIssuerAndSerialNumber(
&pCertId->IssuerSerialNumber,
&pOssCertId->u.issuerAndSerialNumber
))
goto SetOssIssuerAndSerialNumberError;
break;
case CERT_ID_KEY_IDENTIFIER:
if (!ICM_SetOssOctetString(
&pCertId->KeyId,
&pOssCertId->u.subjectKeyIdentifier
))
goto SetOssOctetStringError;
break;
default:
goto InvalidIdChoice;
}
assert(CERT_ID_ISSUER_SERIAL_NUMBER == issuerAndSerialNumber_chosen);
assert(CERT_ID_KEY_IDENTIFIER == subjectKeyIdentifier_chosen);
pOssCertId->choice = (unsigned short) pCertId->dwIdChoice;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(SetOssIssuerAndSerialNumberError)
TRACE_ERROR(SetOssOctetStringError)
SET_ERROR(InvalidIdChoice, E_INVALIDARG)
}
void
WINAPI
ICM_FreeOssCertIdentifier(
IN OUT CertIdentifier *pOssCertId
)
{
switch (pOssCertId->choice) {
case issuerAndSerialNumber_chosen:
ICM_FreeOssIssuerAndSerialNumber(
&pOssCertId->u.issuerAndSerialNumber);
break;
case subjectKeyIdentifier_chosen:
ICM_FreeOssOctetString(&pOssCertId->u.subjectKeyIdentifier);
break;
default:
break;
}
pOssCertId->choice = 0;
}
void
WINAPI
ICM_FreeOssOriginatorCertIdentifierOrKey(
IN OUT OriginatorIdentifierOrKey *pOssOriginator
)
{
switch (pOssOriginator->choice) {
case issuerAndSerialNumber_chosen:
ICM_FreeOssIssuerAndSerialNumber(
&pOssOriginator->u.issuerAndSerialNumber);
break;
case subjectKeyIdentifier_chosen:
ICM_FreeOssOctetString(
&pOssOriginator->u.subjectKeyIdentifier);
break;
case originatorKey_chosen:
ICM_FreeOssAlgorithmIdentifier(
&pOssOriginator->u.originatorKey.algorithm);
ICM_FreeOssBitString(
&pOssOriginator->u.originatorKey.publicKey);
break;
default:
break;
}
pOssOriginator->choice = 0;
}
BOOL
WINAPI
ICM_SetOssOriginatorCertIdentifier(
IN PCERT_ID pCertId,
IN OUT OriginatorIdentifierOrKey *pOssOriginator
)
{
BOOL fRet;
switch (pCertId->dwIdChoice) {
case CERT_ID_ISSUER_SERIAL_NUMBER:
if (!ICM_SetOssIssuerAndSerialNumber(
&pCertId->IssuerSerialNumber,
&pOssOriginator->u.issuerAndSerialNumber
))
goto SetOssIssuerAndSerialNumberError;
pOssOriginator->choice = issuerAndSerialNumber_chosen;
break;
case CERT_ID_KEY_IDENTIFIER:
if (!ICM_SetOssOctetString(
&pCertId->KeyId,
&pOssOriginator->u.subjectKeyIdentifier
))
goto SetOssOctetStringError;
pOssOriginator->choice = subjectKeyIdentifier_chosen;
break;
default:
goto InvalidIdChoice;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(SetOssIssuerAndSerialNumberError)
TRACE_ERROR(SetOssOctetStringError)
SET_ERROR(InvalidIdChoice, E_INVALIDARG)
}
BOOL
WINAPI
ICM_SetOssOriginatorPublicKey(
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
IN OUT OriginatorIdentifierOrKey *pOssOriginator
)
{
BOOL fRet;
PCRYPT_ALGORITHM_IDENTIFIER pai = &pPublicKeyInfo->Algorithm;
AlgorithmIdentifier *pOssAlgId = &pOssOriginator->u.originatorKey.algorithm;
pOssOriginator->choice = originatorKey_chosen;
if (!ICM_SetOssAlgorithmIdentifier(
pai,
pOssAlgId
))
goto SetOssAlgorithmIdentifierError;
if (0 == pai->Parameters.cbData) {
DWORD dwFlags;
PCCRYPT_OID_INFO pOIDInfo;
dwFlags = 0;
if (pOIDInfo = CryptFindOIDInfo(
CRYPT_OID_INFO_OID_KEY,
pai->pszObjId,
CRYPT_PUBKEY_ALG_OID_GROUP_ID)) {
if (1 <= pOIDInfo->ExtraInfo.cbData / sizeof(DWORD)) {
DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
dwFlags = pdwExtra[0];
}
}
if (dwFlags & CRYPT_OID_NO_NULL_ALGORITHM_PARA_FLAG) {
// NO NULL parameters
pOssAlgId->bit_mask &= ~parameters_present;
pOssAlgId->parameters.length = 0;
pOssAlgId->parameters.value = NULL;
}
}
if (!ICM_SetOssBitString(
&pPublicKeyInfo->PublicKey,
&pOssOriginator->u.originatorKey.publicKey
))
goto SetOssBitStringError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
ICM_FreeOssOriginatorCertIdentifierOrKey(pOssOriginator);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(SetOssAlgorithmIdentifierError)
TRACE_ERROR(SetOssBitStringError)
}
//+-------------------------------------------------------------------------
// Free the Oss KeyTransRecipientInfo
//--------------------------------------------------------------------------
void
WINAPI
ICM_FreeOssKeyTransRecipientInfo(
IN OUT KeyTransRecipientInfo *pori
)
{
ICM_FreeOssCertIdentifier(&pori->rid);
ICM_FreeOssAlgorithmIdentifier(&pori->keyEncryptionAlgorithm);
ICM_Free(pori->encryptedKey.value);
pori->encryptedKey.value = NULL;
}
//+-------------------------------------------------------------------------
// Fill the Oss KeyTransRecipientInfo
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FillOssKeyTransRecipientInfo(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTransEncodeInfo,
IN DWORD dwRecipientIndex,
IN OUT KeyTransRecipientInfo *pori,
#ifdef OSS_CRYPT_ASN1
IN OUT int *pEnvelopedDataVersion
#else
IN OUT ASN1int32_t *pEnvelopedDataVersion
#endif // OSS_CRYPT_ASN1
)
{
BOOL fRet;
CMSG_KEY_TRANS_ENCRYPT_INFO KeyTransEncryptInfo;
memset(&KeyTransEncryptInfo, 0, sizeof(KeyTransEncryptInfo));
KeyTransEncryptInfo.cbSize = sizeof(KeyTransEncryptInfo);
KeyTransEncryptInfo.dwRecipientIndex = dwRecipientIndex;
KeyTransEncryptInfo.KeyEncryptionAlgorithm =
pKeyTransEncodeInfo->KeyEncryptionAlgorithm;
// KeyTransEncryptInfo.EncryptedKey =
// KeyTransEncryptInfo.dwFlags =
if (!ICM_ExportKeyTrans(
pContentEncryptInfo,
pKeyTransEncodeInfo,
&KeyTransEncryptInfo
))
goto ExportKeyTransError;
pori->encryptedKey.length = KeyTransEncryptInfo.EncryptedKey.cbData;
pori->encryptedKey.value = KeyTransEncryptInfo.EncryptedKey.pbData;
if (CERT_ID_ISSUER_SERIAL_NUMBER ==
pKeyTransEncodeInfo->RecipientId.dwIdChoice)
pori->version = CMSG_KEY_TRANS_PKCS_1_5_VERSION;
else {
pori->version = CMSG_KEY_TRANS_CMS_VERSION;
*pEnvelopedDataVersion = CMSG_ENVELOPED_DATA_CMS_VERSION;
}
if (!ICM_SetOssCertIdentifier(
&pKeyTransEncodeInfo->RecipientId,
&pori->rid
))
goto SetOssCertIdentifierError;
if (!ICM_SetOssAlgorithmIdentifier(
&KeyTransEncryptInfo.KeyEncryptionAlgorithm,
&pori->keyEncryptionAlgorithm
))
goto SetOssAlgorithmIdentifierError;
fRet = TRUE;
CommonReturn:
if (KeyTransEncryptInfo.dwFlags & CMSG_KEY_TRANS_ENCRYPT_FREE_PARA_FLAG)
ICM_Free(KeyTransEncryptInfo.KeyEncryptionAlgorithm.Parameters.pbData);
return fRet;
ErrorReturn:
ICM_FreeOssKeyTransRecipientInfo(pori);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(ExportKeyTransError)
TRACE_ERROR(SetOssCertIdentifierError)
TRACE_ERROR(SetOssAlgorithmIdentifierError)
}
//+-------------------------------------------------------------------------
// Free the Oss KeyAgreeRecipientInfo
//--------------------------------------------------------------------------
void
WINAPI
ICM_FreeOssKeyAgreeRecipientInfo(
IN OUT KeyAgreeRecipientInfo *pori
)
{
RecipientEncryptedKey *porek;
unsigned int count;
ICM_FreeOssOriginatorCertIdentifierOrKey(&pori->originator);
ICM_FreeOssOctetString(&pori->ukm);
ICM_FreeOssAlgorithmIdentifier(&pori->keyEncryptionAlgorithm);
porek = pori->recipientEncryptedKeys.value;
if (NULL == porek)
return;
for (count = pori->recipientEncryptedKeys.count;
0 < count; count--, porek++) {
switch (porek->rid.choice) {
case issuerAndSerialNumber_chosen:
ICM_FreeOssIssuerAndSerialNumber(
&porek->rid.u.issuerAndSerialNumber);
break;
case rKeyId_chosen:
ICM_FreeOssOctetString(
&porek->rid.u.rKeyId.subjectKeyIdentifier);
ICM_FreeOssOtherKeyAttribute(&porek->rid.u.rKeyId.other);
break;
}
ICM_Free(porek->encryptedKey.value);
porek->encryptedKey.value = NULL;
}
ICM_Free(pori->recipientEncryptedKeys.value);
}
//+-------------------------------------------------------------------------
// Fill the Oss KeyAgreeRecipientInfo
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FillOssKeyAgreeRecipientInfo(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO pKeyAgreeEncodeInfo,
IN DWORD dwRecipientIndex,
IN OUT KeyAgreeRecipientInfo *pori
)
{
BOOL fRet;
DWORD i;
CMSG_KEY_AGREE_ENCRYPT_INFO KeyAgreeEncryptInfo;
DWORD cKeyAgreeKeyEncryptInfo;
PCMSG_KEY_AGREE_KEY_ENCRYPT_INFO *rgpKeyAgreeKeyEncryptInfo = NULL;
PCMSG_KEY_AGREE_KEY_ENCRYPT_INFO pKeyAgreeKeyEncryptInfo;
RecipientEncryptedKey *porek;
memset(&KeyAgreeEncryptInfo, 0, sizeof(KeyAgreeEncryptInfo));
KeyAgreeEncryptInfo.cbSize = sizeof(KeyAgreeEncryptInfo);
KeyAgreeEncryptInfo.dwRecipientIndex = dwRecipientIndex;
KeyAgreeEncryptInfo.KeyEncryptionAlgorithm =
pKeyAgreeEncodeInfo->KeyEncryptionAlgorithm;
KeyAgreeEncryptInfo.UserKeyingMaterial =
pKeyAgreeEncodeInfo->UserKeyingMaterial;
// KeyAgreeEncryptInfo.dwOriginatorChoice =
// union
// KeyAgreeEncryptInfo.OriginatorCertId =
// KeyAgreeEncryptInfo.OriginatorPublicKeyInfo =
// KeyAgreeEncryptInfo.cKeyAgreeKeyEncryptInfo =
// KeyAgreeEncryptInfo.rgpKeyAgreeKeyEncryptInfo =
// KeyAgreeEncryptInfo.dwFlags =
cKeyAgreeKeyEncryptInfo = pKeyAgreeEncodeInfo->cRecipientEncryptedKeys;
if (0 == cKeyAgreeKeyEncryptInfo)
goto NoKeyAgreeKeys;
if (NULL == (pori->recipientEncryptedKeys.value =
(RecipientEncryptedKey *) ICM_AllocZero(
cKeyAgreeKeyEncryptInfo * sizeof(RecipientEncryptedKey))))
goto OutOfMemory;
pori->recipientEncryptedKeys.count = cKeyAgreeKeyEncryptInfo;
if (NULL == (rgpKeyAgreeKeyEncryptInfo =
(PCMSG_KEY_AGREE_KEY_ENCRYPT_INFO *) ICM_AllocZero(
cKeyAgreeKeyEncryptInfo *
sizeof(PCMSG_KEY_AGREE_KEY_ENCRYPT_INFO) +
cKeyAgreeKeyEncryptInfo *
sizeof(CMSG_KEY_AGREE_KEY_ENCRYPT_INFO))))
goto OutOfMemory;
pKeyAgreeKeyEncryptInfo =
PCMSG_KEY_AGREE_KEY_ENCRYPT_INFO (((PBYTE) rgpKeyAgreeKeyEncryptInfo) +
cKeyAgreeKeyEncryptInfo * sizeof(PCMSG_KEY_AGREE_KEY_ENCRYPT_INFO));
for (i = 0; i < cKeyAgreeKeyEncryptInfo; i++, pKeyAgreeKeyEncryptInfo++) {
rgpKeyAgreeKeyEncryptInfo[i] = pKeyAgreeKeyEncryptInfo;
pKeyAgreeKeyEncryptInfo->cbSize =
sizeof(CMSG_KEY_AGREE_KEY_ENCRYPT_INFO);
}
KeyAgreeEncryptInfo.cKeyAgreeKeyEncryptInfo = cKeyAgreeKeyEncryptInfo;
KeyAgreeEncryptInfo.rgpKeyAgreeKeyEncryptInfo = rgpKeyAgreeKeyEncryptInfo;
if (!ICM_ExportKeyAgree(
pContentEncryptInfo,
pKeyAgreeEncodeInfo,
&KeyAgreeEncryptInfo
))
goto ExportKeyAgreeError;
for (i = 0, porek = pori->recipientEncryptedKeys.value;
i < cKeyAgreeKeyEncryptInfo; i++, porek++) {
porek->encryptedKey.length =
rgpKeyAgreeKeyEncryptInfo[i]->EncryptedKey.cbData;
porek->encryptedKey.value =
rgpKeyAgreeKeyEncryptInfo[i]->EncryptedKey.pbData;
}
pori->version = CMSG_KEY_AGREE_VERSION;
switch (KeyAgreeEncryptInfo.dwOriginatorChoice) {
case CMSG_KEY_AGREE_ORIGINATOR_CERT:
if (!ICM_SetOssOriginatorCertIdentifier(
&KeyAgreeEncryptInfo.OriginatorCertId,
&pori->originator
))
goto SetOssOriginatorCertIdentifierError;
break;
case CMSG_KEY_AGREE_ORIGINATOR_PUBLIC_KEY:
if (!ICM_SetOssOriginatorPublicKey(
&KeyAgreeEncryptInfo.OriginatorPublicKeyInfo,
&pori->originator
))
goto SetOssOriginatorPublicKeyError;
break;
default:
goto InvalidOriginatorChoice;
}
if (KeyAgreeEncryptInfo.UserKeyingMaterial.cbData) {
if (!ICM_SetOssOctetString(
&KeyAgreeEncryptInfo.UserKeyingMaterial,
&pori->ukm
))
goto SetOssUserKeyingMaterialError;
pori->bit_mask |= ukm_present;
}
if (!ICM_SetOssAlgorithmIdentifier(
&KeyAgreeEncryptInfo.KeyEncryptionAlgorithm,
&pori->keyEncryptionAlgorithm
))
goto SetOssAlgorithmIdentifierError;
for (i = 0, porek = pori->recipientEncryptedKeys.value;
i < cKeyAgreeKeyEncryptInfo; i++, porek++) {
PCMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO pEncryptedKeyEncodeInfo =
pKeyAgreeEncodeInfo->rgpRecipientEncryptedKeys[i];
switch (pEncryptedKeyEncodeInfo->RecipientId.dwIdChoice) {
case CERT_ID_ISSUER_SERIAL_NUMBER:
if (!ICM_SetOssIssuerAndSerialNumber(
&pEncryptedKeyEncodeInfo->RecipientId.IssuerSerialNumber,
&porek->rid.u.issuerAndSerialNumber
))
goto SetOssIssuerAndSerialNumberError;
porek->rid.choice = issuerAndSerialNumber_chosen;
break;
case CERT_ID_KEY_IDENTIFIER:
if (!ICM_SetOssOctetString(
&pEncryptedKeyEncodeInfo->RecipientId.KeyId,
&porek->rid.u.rKeyId.subjectKeyIdentifier
))
goto SetOssOctetStringError;
porek->rid.choice = rKeyId_chosen;
if (pEncryptedKeyEncodeInfo->Date.dwLowDateTime ||
pEncryptedKeyEncodeInfo->Date.dwHighDateTime) {
if (!PkiAsn1ToGeneralizedTime(
&pEncryptedKeyEncodeInfo->Date,
&porek->rid.u.rKeyId.date
))
goto ConvToGeneralizedTimeError;
porek->rid.u.rKeyId.bit_mask |= date_present;
}
if (pEncryptedKeyEncodeInfo->pOtherAttr) {
if (!ICM_SetOssOtherKeyAttribute(
pEncryptedKeyEncodeInfo->pOtherAttr,
&porek->rid.u.rKeyId.other
))
goto SetOssOtherKeyAttributeError;
porek->rid.u.rKeyId.bit_mask |= other_present;
}
break;
default:
goto InvalidRecipientIdChoice;
}
}
fRet = TRUE;
CommonReturn:
ICM_Free(rgpKeyAgreeKeyEncryptInfo);
if (KeyAgreeEncryptInfo.dwFlags & CMSG_KEY_AGREE_ENCRYPT_FREE_PARA_FLAG)
ICM_Free(KeyAgreeEncryptInfo.KeyEncryptionAlgorithm.Parameters.pbData);
if (KeyAgreeEncryptInfo.dwFlags &
CMSG_KEY_AGREE_ENCRYPT_FREE_MATERIAL_FLAG)
ICM_Free(KeyAgreeEncryptInfo.UserKeyingMaterial.pbData);
if (KeyAgreeEncryptInfo.dwFlags &
CMSG_KEY_AGREE_ENCRYPT_FREE_PUBKEY_ALG_FLAG)
ICM_Free(
KeyAgreeEncryptInfo.OriginatorPublicKeyInfo.Algorithm.pszObjId);
if (KeyAgreeEncryptInfo.dwFlags &
CMSG_KEY_AGREE_ENCRYPT_FREE_PUBKEY_PARA_FLAG)
ICM_Free(
KeyAgreeEncryptInfo.OriginatorPublicKeyInfo.Algorithm.Parameters.pbData);
if (KeyAgreeEncryptInfo.dwFlags &
CMSG_KEY_AGREE_ENCRYPT_FREE_PUBKEY_BITS_FLAG)
ICM_Free(KeyAgreeEncryptInfo.OriginatorPublicKeyInfo.PublicKey.pbData);
return fRet;
ErrorReturn:
ICM_FreeOssKeyAgreeRecipientInfo(pori);
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidOriginatorChoice, E_INVALIDARG)
SET_ERROR(NoKeyAgreeKeys, E_INVALIDARG)
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(ExportKeyAgreeError)
TRACE_ERROR(SetOssOriginatorCertIdentifierError)
TRACE_ERROR(SetOssOriginatorPublicKeyError)
TRACE_ERROR(SetOssUserKeyingMaterialError)
TRACE_ERROR(SetOssAlgorithmIdentifierError)
TRACE_ERROR(SetOssIssuerAndSerialNumberError)
TRACE_ERROR(SetOssOctetStringError)
TRACE_ERROR(ConvToGeneralizedTimeError)
TRACE_ERROR(SetOssOtherKeyAttributeError)
SET_ERROR(InvalidRecipientIdChoice, E_INVALIDARG)
}
//+-------------------------------------------------------------------------
// Free the Oss MailListRecipientInfo
//--------------------------------------------------------------------------
void
WINAPI
ICM_FreeOssMailListRecipientInfo(
IN OUT MailListRecipientInfo *pori
)
{
ICM_FreeOssOctetString(&pori->mlid.kekIdentifier);
ICM_FreeOssOtherKeyAttribute(&pori->mlid.other);
ICM_FreeOssAlgorithmIdentifier(&pori->keyEncryptionAlgorithm);
ICM_Free(pori->encryptedKey.value);
pori->encryptedKey.value = NULL;
}
//+-------------------------------------------------------------------------
// Fill the Oss MailListRecipientInfo
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FillOssMailListRecipientInfo(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO pMailListEncodeInfo,
IN DWORD dwRecipientIndex,
IN OUT MailListRecipientInfo *pori
)
{
BOOL fRet;
CMSG_MAIL_LIST_ENCRYPT_INFO MailListEncryptInfo;
memset(&MailListEncryptInfo, 0, sizeof(MailListEncryptInfo));
MailListEncryptInfo.cbSize = sizeof(MailListEncryptInfo);
MailListEncryptInfo.dwRecipientIndex = dwRecipientIndex;
MailListEncryptInfo.KeyEncryptionAlgorithm =
pMailListEncodeInfo->KeyEncryptionAlgorithm;
// MailListEncryptInfo.EncryptedKey =
// MailListEncryptInfo.dwFlags =
if (!ICM_ExportMailList(
pContentEncryptInfo,
pMailListEncodeInfo,
&MailListEncryptInfo
))
goto ExportMailListError;
pori->encryptedKey.length = MailListEncryptInfo.EncryptedKey.cbData;
pori->encryptedKey.value = MailListEncryptInfo.EncryptedKey.pbData;
pori->version = CMSG_MAIL_LIST_VERSION;
if (!ICM_SetOssOctetString(
&pMailListEncodeInfo->KeyId,
&pori->mlid.kekIdentifier
))
goto SetOssOctetStringError;
if (pMailListEncodeInfo->Date.dwLowDateTime ||
pMailListEncodeInfo->Date.dwHighDateTime) {
if (!PkiAsn1ToGeneralizedTime(
&pMailListEncodeInfo->Date,
&pori->mlid.date
))
goto ConvToGeneralizedTimeError;
pori->mlid.bit_mask |= date_present;
}
if (pMailListEncodeInfo->pOtherAttr) {
if (!ICM_SetOssOtherKeyAttribute(
pMailListEncodeInfo->pOtherAttr,
&pori->mlid.other
))
goto SetOssOtherKeyAttributeError;
pori->mlid.bit_mask |= other_present;
}
if (!ICM_SetOssAlgorithmIdentifier(
&MailListEncryptInfo.KeyEncryptionAlgorithm,
&pori->keyEncryptionAlgorithm
))
goto SetOssAlgorithmIdentifierError;
fRet = TRUE;
CommonReturn:
if (MailListEncryptInfo.dwFlags & CMSG_MAIL_LIST_ENCRYPT_FREE_PARA_FLAG)
ICM_Free(MailListEncryptInfo.KeyEncryptionAlgorithm.Parameters.pbData);
return fRet;
ErrorReturn:
ICM_FreeOssMailListRecipientInfo(pori);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(ExportMailListError)
TRACE_ERROR(SetOssOctetStringError)
TRACE_ERROR(ConvToGeneralizedTimeError)
TRACE_ERROR(SetOssOtherKeyAttributeError)
TRACE_ERROR(SetOssAlgorithmIdentifierError)
}
//+-------------------------------------------------------------------------
// Free the Oss CmsRecipientInfos
//--------------------------------------------------------------------------
void
WINAPI
ICM_FreeOssCmsRecipientInfos(
IN OUT CmsRecipientInfos *poris
)
{
DWORD i;
CmsRecipientInfo *pori;
if (NULL == poris->value)
return;
for (i = 0, pori = poris->value; i < poris->count; i++, pori++) {
switch (pori->choice) {
case keyTransRecipientInfo_chosen:
ICM_FreeOssKeyTransRecipientInfo(
&pori->u.keyTransRecipientInfo);
break;
case keyAgreeRecipientInfo_chosen:
ICM_FreeOssKeyAgreeRecipientInfo(
&pori->u.keyAgreeRecipientInfo);
break;
case mailListRecipientInfo_chosen:
ICM_FreeOssMailListRecipientInfo(
&pori->u.mailListRecipientInfo);
break;
case 0:
default:
break;
}
}
ICM_Free(poris->value);
poris->value = NULL;
}
//+-------------------------------------------------------------------------
// Fill the Oss CmsRecipientInfos
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FillOssCmsRecipientInfos(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN OUT CmsRecipientInfos *poris,
#ifdef OSS_CRYPT_ASN1
IN OUT int *pEnvelopedDataVersion
#else
IN OUT ASN1int32_t *pEnvelopedDataVersion
#endif // OSS_CRYPT_ASN1
)
{
BOOL fRet;
DWORD cRecipients;
PCMSG_RECIPIENT_ENCODE_INFO rgCmsRecipients;
CmsRecipientInfo *pori = NULL;
DWORD i;
cRecipients = pContentEncryptInfo->cRecipients;
if (0 == cRecipients)
goto SuccessReturn;
rgCmsRecipients = pContentEncryptInfo->rgCmsRecipients;
assert(cRecipients && rgCmsRecipients);
if (NULL == (poris->value = (CmsRecipientInfo *) ICM_AllocZero(
cRecipients * sizeof(CmsRecipientInfo))))
goto OutOfMemory;
poris->count = cRecipients;
for (i = 0, pori = poris->value; i < cRecipients; i++, pori++) {
switch (rgCmsRecipients[i].dwRecipientChoice) {
case CMSG_KEY_TRANS_RECIPIENT:
if (!ICM_FillOssKeyTransRecipientInfo(
pContentEncryptInfo,
rgCmsRecipients[i].pKeyTrans,
i,
&pori->u.keyTransRecipientInfo,
pEnvelopedDataVersion
))
goto FillOssKeyTransRecipientInfoError;
pori->choice = keyTransRecipientInfo_chosen;
break;
case CMSG_KEY_AGREE_RECIPIENT:
if (!ICM_FillOssKeyAgreeRecipientInfo(
pContentEncryptInfo,
rgCmsRecipients[i].pKeyAgree,
i,
&pori->u.keyAgreeRecipientInfo
))
goto FillOssKeyAgreeRecipientInfoError;
pori->choice = keyAgreeRecipientInfo_chosen;
*pEnvelopedDataVersion = CMSG_ENVELOPED_DATA_CMS_VERSION;
break;
case CMSG_MAIL_LIST_RECIPIENT:
if (!ICM_FillOssMailListRecipientInfo(
pContentEncryptInfo,
rgCmsRecipients[i].pMailList,
i,
&pori->u.mailListRecipientInfo
))
goto FillOssMailLIstRecipientInfoError;
pori->choice = mailListRecipientInfo_chosen;
*pEnvelopedDataVersion = CMSG_ENVELOPED_DATA_CMS_VERSION;
break;
default:
goto InvalidRecipientChoice;
}
}
SuccessReturn:
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
ICM_FreeOssCmsRecipientInfos(poris);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(FillOssKeyTransRecipientInfoError)
TRACE_ERROR(FillOssKeyAgreeRecipientInfoError)
TRACE_ERROR(FillOssMailLIstRecipientInfoError)
SET_ERROR(InvalidRecipientChoice, E_INVALIDARG)
}
//+-------------------------------------------------------------------------
// Open an enveloped message for encoding
//--------------------------------------------------------------------------
HCRYPTMSG
WINAPI
ICM_OpenToEncodeEnvelopedData(
IN DWORD dwEncodingType,
IN DWORD dwFlags,
IN void const *pvMsgEncodeInfo,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo)
{
DWORD dwError = ERROR_SUCCESS;
PCRYPT_MSG_INFO pcmi = NULL;
PCMSG_ENVELOPED_ENCODE_INFO pemei =
(PCMSG_ENVELOPED_ENCODE_INFO) pvMsgEncodeInfo;
CmsEnvelopedData *ped = NULL;
EncryptedContentInfo *peci;
CMSG_CONTENT_ENCRYPT_INFO ContentEncryptInfo;
ZEROSTRUCT(ContentEncryptInfo);
DWORD i;
PCERT_BLOB pcert;
PCRL_BLOB pcrl;
Certificate *pOssCert;
CertificateRevocationList *pOssCrl;
DWORD cbCert = 0;
PBYTE pbCert;
DWORD cbCrl;
PBYTE pbCrl;
DWORD cbOriginatorInfo;
DWORD cUnprotectedAttr;
assert(pemei->cbSize >= STRUCT_CBSIZE(CMSG_ENVELOPED_ENCODE_INFO,
rgpRecipients));
if (pemei->cbSize <
STRUCT_CBSIZE(CMSG_ENVELOPED_ENCODE_INFO, rgpRecipients))
goto InvalidArg;
if (pemei->cbSize >= sizeof(CMSG_ENVELOPED_ENCODE_INFO)) {
for (i=pemei->cCertEncoded, pcert=pemei->rgCertEncoded, cbCert=0;
i>0;
i--, pcert++)
cbCert += pcert->cbData;
for (i=pemei->cAttrCertEncoded, pcert=pemei->rgAttrCertEncoded;
i>0;
i--, pcert++)
cbCert += pcert->cbData;
for (i=pemei->cCrlEncoded, pcrl=pemei->rgCrlEncoded, cbCrl=0;
i>0;
i--, pcrl++)
cbCrl += pcrl->cbData;
cbOriginatorInfo =
pemei->cCertEncoded * sizeof(Certificate) +
pemei->cAttrCertEncoded * sizeof(Certificate) +
pemei->cCrlEncoded * sizeof(CertificateRevocationList) +
cbCert + cbCrl;
cUnprotectedAttr = pemei->cUnprotectedAttr;
} else {
cbOriginatorInfo = 0;
cUnprotectedAttr = 0;
}
ped = (CmsEnvelopedData *)ICM_AllocZero(
sizeof(CmsEnvelopedData) + cbOriginatorInfo);
if (NULL == ped)
goto CmsEnvelopedDataAllocError;
// pcmi
pcmi = (PCRYPT_MSG_INFO)ICM_AllocZero(sizeof(CRYPT_MSG_INFO));
if (NULL == pcmi)
goto PcmiAllocError;
// pcmi->hCryptProv
// pcmi->fDefaultCryptProv
pcmi->dwEncodingType = dwEncodingType;
pcmi->dwMsgType = CMSG_ENVELOPED;
pcmi->dwFlags = dwFlags;
pcmi->pvMsg = ped;
pcmi->fEncoding = TRUE;
pcmi->dwPhase = PHASE_FIRST_ONGOING;
if (pszInnerContentObjID &&
(NULL == (pcmi->pszInnerContentObjID = (LPSTR)ICM_DupMem(
pszInnerContentObjID,
ICM_StrLen(pszInnerContentObjID) + 1))))
goto DupInnerContentObjIDError;
if (pStreamInfo &&
(NULL == (pcmi->pStreamInfo = (PCMSG_STREAM_INFO)ICM_DupMem(
pStreamInfo,
sizeof(*pStreamInfo)))))
goto DupStreamInfoError;
// version
if (0 < cbOriginatorInfo || 0 < cUnprotectedAttr)
ped->version = CMSG_ENVELOPED_DATA_CMS_VERSION;
else
ped->version = CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION;
if (0 < cbOriginatorInfo) {
OriginatorInfo *poi = &ped->originatorInfo;
// originatorInfo
ped->bit_mask |= originatorInfo_present;
// certificates
if (0 != pemei->cCertEncoded || 0 != pemei->cAttrCertEncoded) {
poi->bit_mask |= certificates_present;
poi->certificates.count = pemei->cCertEncoded +
pemei->cAttrCertEncoded;
#ifdef OSS_CRYPT_ASN1
poi->certificates.certificates = (Certificate *)(ped + 1);
#else
poi->certificates.value = (Certificate *)(ped + 1);
#endif // OSS_CRYPT_ASN1
pbCert = (PBYTE)ped +
sizeof( CmsEnvelopedData) +
pemei->cCertEncoded * sizeof( Certificate) +
pemei->cAttrCertEncoded * sizeof( Certificate) +
pemei->cCrlEncoded * sizeof( CertificateRevocationList);
for (i=pemei->cCertEncoded, pcert=pemei->rgCertEncoded,
#ifdef OSS_CRYPT_ASN1
pOssCert=poi->certificates.certificates;
#else
pOssCert=poi->certificates.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pcert++, pOssCert++) {
pOssCert->length = pcert->cbData;
memcpy( pbCert, pcert->pbData, pcert->cbData);
pOssCert->value = pbCert;
pbCert += pcert->cbData;
}
for (i=pemei->cAttrCertEncoded, pcert=pemei->rgAttrCertEncoded;
i>0;
i--, pcert++, pOssCert++) {
pOssCert->length = pcert->cbData;
memcpy( pbCert, pcert->pbData, pcert->cbData);
if (pcert->cbData)
// Change tag from SEQUENCE to [1] IMPLICIT
*pbCert = ICM_TAG_CONSTRUCTED_CONTEXT_1;
pOssCert->value = pbCert;
pbCert += pcert->cbData;
}
}
// crls
if (0 != pemei->cCrlEncoded) {
poi->bit_mask |= crls_present;
poi->crls.count = pemei->cCrlEncoded;
if (0 != pemei->cCertEncoded || 0 != pemei->cAttrCertEncoded)
#ifdef OSS_CRYPT_ASN1
poi->crls.crls = (CertificateRevocationList *)
(poi->certificates.certificates +
#else
poi->crls.value = (CertificateRevocationList *)
(poi->certificates.value +
#endif // OSS_CRYPT_ASN1
(pemei->cCertEncoded + pemei->cAttrCertEncoded));
else
#ifdef OSS_CRYPT_ASN1
poi->crls.crls = (CertificateRevocationList *) (ped + 1);
#else
poi->crls.value = (CertificateRevocationList *) (ped + 1);
#endif // OSS_CRYPT_ASN1
pbCrl = (PBYTE)ped +
sizeof( CmsEnvelopedData) +
pemei->cCertEncoded * sizeof( Certificate) +
pemei->cAttrCertEncoded * sizeof( Certificate) +
pemei->cCrlEncoded * sizeof( CertificateRevocationList) +
cbCert;
#ifdef OSS_CRYPT_ASN1
for (i=pemei->cCrlEncoded, pcrl=pemei->rgCrlEncoded, pOssCrl=poi->crls.crls;
#else
for (i=pemei->cCrlEncoded, pcrl=pemei->rgCrlEncoded, pOssCrl=poi->crls.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pcrl++, pOssCrl++) {
pOssCrl->length = pcrl->cbData;
memcpy( pbCrl, pcrl->pbData, pcrl->cbData);
pOssCrl->value = pbCrl;
pbCrl += pcrl->cbData;
}
}
}
if (0 < cUnprotectedAttr) {
Attribute *poatr;
PCRYPT_ATTRIBUTE patr;
if (NULL == (poatr = (Attribute *) ICM_AllocZero(
cUnprotectedAttr * sizeof(Attribute))))
goto UnprotectedAttrsAllocError;
ped->unprotectedAttrs.value = poatr;
ped->unprotectedAttrs.count = cUnprotectedAttr;
ped->bit_mask |= unprotectedAttrs_present;
for (i=cUnprotectedAttr, patr=pemei->rgUnprotectedAttr;
i>0;
i--, patr++, poatr++) {
if (!ICM_Asn1ToAttribute(patr, poatr))
goto Asn1ToAttributeError;
}
}
if (!ICM_InitializeContentEncryptInfo(pemei, &ContentEncryptInfo))
goto InitializeContentEncryptInfoError;
// assert(ContentEncryptInfo.hCryptProv);
pcmi->hCryptProv = ContentEncryptInfo.hCryptProv;
assert(ContentEncryptInfo.hContentEncryptKey);
pcmi->hkeyContentCrypt = ContentEncryptInfo.hContentEncryptKey;
if (pStreamInfo && CMSG_INDEFINITE_LENGTH != pStreamInfo->cbContent)
ContentEncryptInfo.dwEncryptFlags |=
CMSG_CONTENT_ENCRYPT_PAD_ENCODED_LEN_FLAG;
if (!ICM_FillOssCmsRecipientInfos(
&ContentEncryptInfo,
&ped->recipientInfos,
&ped->version
))
goto FillOssCmsRecipientInfosError;
// Is encryptedContent encapsulated ???
if (ped->version > CMSG_ENVELOPED_DATA_PKCS_1_5_VERSION) {
if (ICM_IsData(pszInnerContentObjID))
pcmi->dwFlags &= ~CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
else
pcmi->dwFlags |= CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
} else if (pcmi->dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG) {
if (ICM_IsData(pszInnerContentObjID))
pcmi->dwFlags &= ~CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
else
ped->version = CMSG_ENVELOPED_DATA_CMS_VERSION;
}
// encryptedContentInfo
// (.encryptedContent filled in during update)
peci = &ped->encryptedContentInfo;
peci->bit_mask = encryptedContent_present;
peci->contentType.count =
sizeof(peci->contentType.value)/sizeof(peci->contentType.value[0]);
if (!PkiAsn1ToObjectIdentifier(
pszInnerContentObjID ? pszInnerContentObjID : pszObjIdDataType,
&peci->contentType.count,
peci->contentType.value))
goto PkiAsn1ToObjectIdentifierError;
if (!ICM_MsgAsn1ToAlgorithmIdentifier(
pcmi,
&ContentEncryptInfo.ContentEncryptionAlgorithm,
&peci->contentEncryptionAlgorithm))
goto MsgAsn1ToAlgorithmIdentifierError;
if (pStreamInfo && !ICMS_OpenToEncodeEnvelopedData( pcmi, pemei))
goto StreamOpenToEncodeEnvelopedDataError;
// From here to CommonReturn, NO Errors
if (ContentEncryptInfo.hCryptProv == pemei->hCryptProv) {
// assert(ContentEncryptInfo.hCryptProv);
assert(0 == (ContentEncryptInfo.dwFlags &
CMSG_CONTENT_ENCRYPT_RELEASE_CONTEXT_FLAG));
} else {
if (pcmi->dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) {
pcmi->dwFlags &= ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
CryptReleaseContext(pemei->hCryptProv, 0);
}
}
if (ContentEncryptInfo.dwFlags &
CMSG_CONTENT_ENCRYPT_RELEASE_CONTEXT_FLAG) {
pcmi->dwFlags |= CMSG_CRYPT_RELEASE_CONTEXT_FLAG;
ContentEncryptInfo.dwFlags &=
~CMSG_CONTENT_ENCRYPT_RELEASE_CONTEXT_FLAG;
}
ContentEncryptInfo.hContentEncryptKey = 0;
CommonReturn:
ICM_FreeContentEncryptInfo(pemei, &ContentEncryptInfo);
ICM_SetLastError(dwError);
return (HCRYPTMSG) pcmi;
ErrorReturn:
dwError = GetLastError();
if (ped) {
ICM_FreeOssCmsRecipientInfos(&ped->recipientInfos);
if (ped->unprotectedAttrs.value) {
Attribute *poatr;
for (i=ped->unprotectedAttrs.count,
poatr=ped->unprotectedAttrs.value;
i>0;
i--, poatr++) {
ICM_Free(poatr->attributeValue.value);
}
ICM_Free(ped->unprotectedAttrs.value);
}
ICM_Free(ped);
}
if (pcmi) {
if (pcmi->pFreeList)
delete pcmi->pFreeList;
ICM_Free(pcmi->pszInnerContentObjID);
ICM_Free(pcmi->pStreamInfo);
ICM_Free(pcmi);
pcmi = NULL;
}
goto CommonReturn;
SET_ERROR(InvalidArg,E_INVALIDARG)
SET_ERROR(PkiAsn1ToObjectIdentifierError,CRYPT_E_OID_FORMAT)
TRACE_ERROR(DupInnerContentObjIDError)
TRACE_ERROR(DupStreamInfoError)
TRACE_ERROR(CmsEnvelopedDataAllocError)
TRACE_ERROR(PcmiAllocError)
TRACE_ERROR(UnprotectedAttrsAllocError)
TRACE_ERROR(Asn1ToAttributeError)
TRACE_ERROR(InitializeContentEncryptInfoError)
TRACE_ERROR(FillOssCmsRecipientInfosError)
TRACE_ERROR(MsgAsn1ToAlgorithmIdentifierError)
TRACE_ERROR(StreamOpenToEncodeEnvelopedDataError)
}
#else
//+-------------------------------------------------------------------------
// Default export of the encryption key
//
// Note, pcbData[1] contains dwEncryptFlags, where,
// CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG may be set to disable the reversing
// of the encoded, encrypted symmetric key.
//
// rgcbData[1] is the dwEncryptFlags passed from ICM_DefaultGenEncryptKey
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultExportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN HCRYPTKEY hEncryptKey,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
OUT PBYTE pbData,
IN OUT DWORD rgcbData[2])
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
HCRYPTKEY hPubKey = NULL;
PBYTE pb = NULL;
DWORD cb;
if (!CryptImportPublicKeyInfo(
hCryptProv,
X509_ASN_ENCODING,
pPublicKeyInfo,
&hPubKey))
goto ImportKeyError;
if (!CryptExportKey(
hEncryptKey,
hPubKey,
SIMPLEBLOB,
0, // dwFlags
NULL,
&cb))
goto ExportKeySizeError;
if (NULL == (pb = (PBYTE)ICM_AllocA( cb)))
goto ExportKeyAllocError;
if (!CryptExportKey(
hEncryptKey,
hPubKey,
SIMPLEBLOB,
0, // dwFlags
pb,
&cb))
goto ExportKeyError;
assert( cb > (sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER)));
cb -= sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER);
fRet = TRUE;
if (pbData) {
if (rgcbData[0] < cb) {
SetLastError((DWORD) ERROR_MORE_DATA);
fRet = FALSE;
} else if (0 < cb) {
if (rgcbData[1] & CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG)
// Don't byte reverse
memcpy(pbData,
pb + (sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER)),
cb);
else
ICM_ReverseCopy(pbData,
pb + (sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER)),
cb);
}
}
CommonReturn:
rgcbData[0] = cb;
ICM_FreeA(pb);
if (hPubKey)
CryptDestroyKey(hPubKey);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
cb = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(ImportKeyError)
TRACE_ERROR(ExportKeySizeError)
TRACE_ERROR(ExportKeyAllocError)
TRACE_ERROR(ExportKeyError)
}
//+-------------------------------------------------------------------------
// Export of the encryption key
//
// rgcbData[1] is the dwEncryptFlags passed from ICM_GenEncryptKey
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ExportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN HCRYPTKEY hEncryptKey,
IN PCERT_PUBLIC_KEY_INFO pPublicKeyInfo,
OUT PBYTE pbData,
IN OUT DWORD rgcbData[2])
{
BOOL fResult;
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (CryptGetOIDFunctionAddress(
hExportEncryptKeyFuncSet,
X509_ASN_ENCODING,
pPublicKeyInfo->Algorithm.pszObjId,
0, // dwFlags
&pvFuncAddr,
&hFuncAddr)) {
fResult = ((PFN_CMSG_EXPORT_ENCRYPT_KEY) pvFuncAddr)(
hCryptProv,
hEncryptKey,
pPublicKeyInfo,
pbData,
rgcbData);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
} else
fResult = ICM_DefaultExportEncryptKey(
hCryptProv,
hEncryptKey,
pPublicKeyInfo,
pbData,
rgcbData);
return fResult;
}
// This size is good up through a 2048 bit exchange key
#define EXPORT_ENCRYPT_KEY_LENGTH 256
//+-------------------------------------------------------------------------
// Fill the RecipientInfos
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FillRecipientInfos(
IN HCRYPTPROV hCryptProv,
IN HCRYPTKEY hKeyContent,
IN DWORD cRecipients,
IN PCERT_INFO *rgpRecipients,
IN OUT RecipientInfos *pris,
IN DWORD dwEncryptFlags)
{
BOOL fRet;
PCERT_INFO *ppci;
RecipientInfo *pri;
PBYTE pb = NULL;
DWORD rgcb[2]; // rgcb[1] is updated with dwEncryptFlags
DWORD cTryAgain;
DWORD i;
PBYTE pbSerialNumber;
DWORD cbSerialNumber = 0;
for (i=cRecipients, ppci=rgpRecipients; i>0; i--, ppci++)
cbSerialNumber += (*ppci)->SerialNumber.cbData;
pris->value = (RecipientInfo *)ICM_AllocZero(
cRecipients * sizeof( RecipientInfo) +
cbSerialNumber);
if (NULL == pris->value)
goto RecipientInfoAllocError;
pris->count = cRecipients;
pbSerialNumber = (PBYTE)(pris->value + cRecipients);
for (i=cRecipients, ppci=rgpRecipients, pri=pris->value;
i>0;
i--, ppci++, pri++) {
// version
pri->version = 0;
// issuerAndSerialNumber
pri->issuerAndSerialNumber.issuer.length = (*ppci)->Issuer.cbData;
pri->issuerAndSerialNumber.issuer.value = (*ppci)->Issuer.pbData;
pri->issuerAndSerialNumber.serialNumber.length = (*ppci)->SerialNumber.cbData;
pb = pbSerialNumber;
pbSerialNumber += (*ppci)->SerialNumber.cbData;
ICM_ReverseCopy(
pb,
(*ppci)->SerialNumber.pbData,
(*ppci)->SerialNumber.cbData);
pri->issuerAndSerialNumber.serialNumber.value = pb;
// keyEncryptionAlgorithm
if (!ICM_Asn1ToAlgorithmIdentifier(
&(*ppci)->SubjectPublicKeyInfo.Algorithm,
&pri->keyEncryptionAlgorithm))
goto Asn1ToAlgorithmIdentifierError;
rgcb[0] = EXPORT_ENCRYPT_KEY_LENGTH;
rgcb[1] = dwEncryptFlags;
cTryAgain = 1;
while (TRUE) {
if (NULL == (pb = (PBYTE)ICM_Alloc(rgcb[0])))
goto ExportKeyAllocError;
if (ICM_ExportEncryptKey(
hCryptProv,
hKeyContent,
&(*ppci)->SubjectPublicKeyInfo,
pb,
rgcb))
break;
ICM_Free(pb);
if (rgcb[0] && cTryAgain--)
continue;
else
goto ExportKeyError;
}
pri->encryptedKey.length = rgcb[0];
pri->encryptedKey.value = pb;
pb = NULL;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
// Need to free EncrytedKey for each recipient
ICM_Free( pris->value);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(RecipientInfoAllocError)
TRACE_ERROR(Asn1ToAlgorithmIdentifierError)
TRACE_ERROR(ExportKeyAllocError)
TRACE_ERROR(ExportKeyError)
}
//+-------------------------------------------------------------------------
// Open an enveloped message for encoding
//--------------------------------------------------------------------------
HCRYPTMSG
WINAPI
ICM_OpenToEncodeEnvelopedData(
IN DWORD dwEncodingType,
IN DWORD dwFlags,
IN void const *pvMsgEncodeInfo,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo)
{
DWORD dwError = ERROR_SUCCESS;
PCRYPT_MSG_INFO pcmi = NULL;
PCMSG_ENVELOPED_ENCODE_INFO pemei = (PCMSG_ENVELOPED_ENCODE_INFO)pvMsgEncodeInfo;
EnvelopedData *ped = NULL;
EncryptedContentInfo *peci;
DWORD dwAlgoCAPI;
CRYPT_ALGORITHM_IDENTIFIER ContentEncryptionAlgorithm;
PBYTE pbEncryptParameters = NULL;
// rgcbEncryptParameters[1] contains dwEncryptFlags
DWORD rgcbEncryptParameters[2];
assert( pemei->cbSize >= sizeof(CMSG_ENVELOPED_ENCODE_INFO));
assert( 0 != pemei->cRecipients);
if (pemei->cbSize < sizeof(CMSG_ENVELOPED_ENCODE_INFO) ||
0 == pemei->cRecipients)
goto InvalidArg;
ped = (EnvelopedData *)ICM_AllocZero( sizeof( EnvelopedData));
if (NULL == ped)
goto EnvelopedDataAllocError;
// pcmi
pcmi = (PCRYPT_MSG_INFO)ICM_AllocZero( sizeof( CRYPT_MSG_INFO));
if (NULL == pcmi)
goto PcmiAllocError;
pcmi->hCryptProv = pemei->hCryptProv;
if (0 == pcmi->hCryptProv)
pcmi->fDefaultCryptProv = TRUE;
pcmi->dwEncodingType = dwEncodingType;
pcmi->dwMsgType = CMSG_ENVELOPED;
pcmi->dwFlags = dwFlags;
pcmi->pvMsg = ped;
pcmi->fEncoding = TRUE;
pcmi->dwPhase = PHASE_FIRST_ONGOING;
if (pszInnerContentObjID &&
(NULL == (pcmi->pszInnerContentObjID = (LPSTR)ICM_DupMem(
pszInnerContentObjID,
ICM_StrLen(pszInnerContentObjID) + 1))))
goto DupInnerContentObjIDError;
if (pStreamInfo &&
(NULL == (pcmi->pStreamInfo = (PCMSG_STREAM_INFO)ICM_DupMem(
pStreamInfo,
sizeof(*pStreamInfo)))))
goto DupStreamInfoError;
// version
ped->version = 0;
// recipientInfos
// Use first recipients public key info
ContentEncryptionAlgorithm = pemei->ContentEncryptionAlgorithm;
rgcbEncryptParameters[0] = 0;
rgcbEncryptParameters[1] = 0;
if (!ICM_GenEncryptKey(
&pcmi->hCryptProv,
&ContentEncryptionAlgorithm,
pemei->pvEncryptionAuxInfo,
&pemei->rgpRecipients[0]->SubjectPublicKeyInfo,
ICM_Alloc,
&pcmi->hkeyContentCrypt, // not freed for an error
&pbEncryptParameters,
rgcbEncryptParameters))
goto GenKeyError;
if (rgcbEncryptParameters[0] && pbEncryptParameters) {
pcmi->pbEncryptParameters = pbEncryptParameters;
ContentEncryptionAlgorithm.Parameters.pbData = pbEncryptParameters;
ContentEncryptionAlgorithm.Parameters.cbData = rgcbEncryptParameters[0];
} else if (pbEncryptParameters) {
ICM_Free(pbEncryptParameters);
pbEncryptParameters = NULL;
}
if (!ICM_FillRecipientInfos(
pcmi->hCryptProv,
pcmi->hkeyContentCrypt,
pemei->cRecipients,
pemei->rgpRecipients,
&ped->recipientInfos,
rgcbEncryptParameters[1])) // dwEncryptFlags
goto FillRecipientInfosError;
// encryptedContentInfo
// (.encryptedContent filled in during update)
peci = &ped->encryptedContentInfo;
peci->bit_mask = encryptedContent_present;
peci->contentType.count = sizeof(peci->contentType.value)/sizeof(peci->contentType.value[0]);
if (!PkiAsn1ToObjectIdentifier(
pszInnerContentObjID ? pszInnerContentObjID : pszObjIdDataType,
&peci->contentType.count,
peci->contentType.value))
goto PkiAsn1ToObjectIdentifierError;
if (!ICM_Asn1ToAlgorithmIdentifier(
&ContentEncryptionAlgorithm,
&peci->contentEncryptionAlgorithm))
goto Asn1ToAlgorithmIdentifierError;
if (pStreamInfo && !ICMS_OpenToEncodeEnvelopedData( pcmi, pemei))
goto StreamOpenToEncodeEnvelopedDataError;
CommonReturn:
ICM_SetLastError(dwError);
return (HCRYPTMSG)pcmi;
ErrorReturn:
dwError = GetLastError();
ICM_Free( pbEncryptParameters);
ICM_Free( ped);
ICM_Free( pcmi);
pcmi = NULL;
goto CommonReturn;
SET_ERROR(PkiAsn1ToObjectIdentifierError,CRYPT_E_OID_FORMAT)
SET_ERROR(InvalidArg,E_INVALIDARG)
TRACE_ERROR(DupInnerContentObjIDError) // error already set
TRACE_ERROR(DupStreamInfoError) // error already set
TRACE_ERROR(EnvelopedDataAllocError) // error already set
TRACE_ERROR(PcmiAllocError) // error already set
TRACE_ERROR(GenKeyError) // error already set
TRACE_ERROR(FillRecipientInfosError) // error already set
TRACE_ERROR(Asn1ToAlgorithmIdentifierError) // error already set
TRACE_ERROR(StreamOpenToEncodeEnvelopedDataError) // error already set
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Open a signed and enveloped message for encoding
//--------------------------------------------------------------------------
#if 0
HCRYPTMSG
WINAPI
ICM_OpenToEncodeSignedAndEnvelopedData(
IN DWORD dwEncodingType,
IN DWORD dwFlags,
IN void *pvMsgEncodeInfo,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo)
{
DWORD dwError = ERROR_SUCCESS;
HCRYPTPROV hCryptProv;
DWORD dwKeySpec;
PCRYPT_MSG_INFO pcmi = NULL;
PCMSG_SIGNED_AND_ENVELOPED_ENCODE_INFO psemei;
SignedAndEnvelopedData *psed = NULL;
ContentEncryptionAlgorithmIdentifier *pceai;
DWORD dwVersion = 1;
HCRYPTKEY hkeyContentEncryption;
PCERT_BLOB pcert;
PCRL_BLOB pcrl;
DWORD i;
CRYPT_ALGORITHM_IDENTIFIER aiDigest;
DWORD dwAlgoCAPISign;
DWORD dwAlgoCAPIEncrypt;
psemei = (PCMSG_SIGNED_AND_ENVELOPED_ENCODE_INFO)pvMsgEncodeInfo;
psed = new SignedAndEnvelopedData;
assert( 1 == psemei->SignedInfo.cSigners); // just for now
assert( psemei->cbSize >= sizeof(CMSG_SIGNED_AND_ENVELOPED_ENCODE_INFO));
if (psemei->cbSize < sizeof(CMSG_SIGNED_AND_ENVELOPED_ENCODE_INFO))
goto InvalidArg;
// version
psed->version.Write( &dwVersion);
// recipientInfos
if (!ICM_GetCAPI(
CRYPT_ENCRYPT_ALG_OID_GROUP_ID,
&psemei->ContentEncryptionAlgorithm,
&dwAlgoCAPIEncrypt))
goto GetCAPIEncryptError;
if (!CryptGenKey(
psemei->EnvelopedInfo.hCryptProv,
dwAlgoCAPIEncrypt,
CRYPT_EXPORTABLE, // dwFlags
&hkeyContentEncryption))
goto GenKeyError;
if (!ICM_FillRecipientInfos(
psemei->EnvelopedInfo.hCryptProv,
hkeyContentEncryption,
psemei->EnvelopedInfo.cRecipients,
psemei->EnvelopedInfo.rgpRecipients,
psed->recipientInfos,
dwEncryptFlags))
goto FillRecipientInfosError;
// digestAlgorithms
if (!ICM_SetAsnDigestAlgorithmIdentifiers(
psed->digestAlgorithms,
&aiDigest,
psemei->SignedInfo.cSigners,
psemei->SignedInfo.rgSigners,
&hCryptProv,
&dwKeySpec))
goto SetAsnDigestAlgorithmIdentifiersError;
// encryptedContentInfo.contentEncryptionAlgorithm
// (.encryptedContent and .encryptedContent filled in during update)
pceai = &psed->encryptedContentInfo.contentEncryptionAlgorithm;
pceai->algorithm = psemei->EnvelopedInfo.ContentEncryptionAlgorithm.pszObjId;
if (0 != psemei->EnvelopedInfo.ContentEncryptionAlgorithm.Parameters.cbData) {
if (0 > pceai->parameters.Decode(
psemei->EnvelopedInfo.ContentEncryptionAlgorithm.Parameters.pbData))
goto ContentEncryptionAlgorithmParametersDecodeError;
}
// certificates
for (i=psemei->SignedInfo.cCertEncoded, pcert=psemei->SignedInfo.rgCertEncoded;
i>0;
i--, pcert++) {
if (0 > psed->certificates[ psed->certificates.Add()].Decode( pcert->pbData))
goto BadParameter;
}
// crls
for (i=psemei->SignedInfo.cCrlEncoded, pcrl=psemei->SignedInfo.rgCrlEncoded;
i>0;
i--, pcrl++) {
if (0 > psed->crls[ psed->crls.Add()].Decode( pcrl->pbData))
goto BadParameter;
}
// signerInfos
if (!ICM_SetAsnSignerInfos(
psed->signerInfos,
dwFlags,
psemei->SignedInfo.cSigners,
psemei->SignedInfo.rgSigners))
goto SetAsnSignerInfosError;
// pcmi
pcmi = (PCRYPT_MSG_INFO)ICM_AllocZero( sizeof( CRYPT_MSG_INFO));
if (NULL == pcmi)
goto OutOfMemory;
pcmi->hCryptProv = hCryptProv;
if (0 == hCryptProv)
pcmi->fDefaultCryptProv = TRUE;
pcmi->dwKeySpec = dwKeySpec;
pcmi->dwEncodingType = dwEncodingType;
pcmi->dwMsgType = CMSG_SIGNED_AND_ENVELOPED;
pcmi->dwFlags = dwFlags;
pcmi->pvMsg = psed;
pcmi->fEncoding = TRUE;
pcmi->dwPhase = PHASE_FIRST_ONGOING;
pcmi->pszInnerContentObjID = ICM_DupMem(
pszInnerContentObjID,
ICM_StrLen(pszInnerContentObjID) + 1);
pcmi->pStreamInfo = ICM_DupMem( pStreamInfo, sizeof(*pStreamInfo));
// pcmi->cDigestAlgorithms = 1; // temp
if (!(ICM_GetCAPI(
CRYPT_HASH_ALG_OID_GROUP_ID,
&aiDigest,
&dwAlgoCAPISign) ||
ICM_GetCAPI(
CRYPT_SIGN_ALG_OID_GROUP_ID,
&aiDigest,
&dwAlgoCAPISign)))
goto GetCAPISignError;
pcmi->adwDigestAlgorithms[0] = dwAlgoCAPISign;
pcmi->hkeyContentCrypt = hkeyContentEncryption;
if (!CryptCreateHash(
hCryptProv, // s/b various per array
dwAlgoCAPISign, // s/b various per array
NULL, // hKey - optional for MAC
0, // dwFlags
&pcmi->ahHash[0]))
goto CreateHashError;
CommonReturn:
ICM_SetLastError(dwError);
return (HCRYPTMSG)pcmi;
ErrorReturn:
dwError = GetLastError();
if (psed)
delete psed;
ICM_Free( pcmi);
pcmi = NULL;
goto CommonReturn;
SET_ERROR(InvalidArg,E_INVALIDARG)
TRACE_ERROR(FillRecipientInfosError) // error already set
TRACE_ERROR(SetAsnDigestAlgorithmIdentifiersError) // error already set
TRACE_ERROR(OutOfMemory) // error already set
SET_ERROR(GetCAPIEncryptError,CRYPT_E_UNKNOWN_ALGO)
TRACE_ERROR(GenKeyError) // error already set
TRACE_ERROR(BadParameter)
TRACE_ERROR(ContentEncryptionAlgorithmParametersDecodeError)
TRACE_ERROR(SetAsnSignerInfosError)
TRACE_ERROR(GetCAPISignError)
TRACE_ERROR(CreateHashError)
}
#endif
//+-------------------------------------------------------------------------
// Open a cryptographic message for encoding
//
// If CMSG_BARE_CONTENT_FLAG is specified for a streamed message,
// the streamed output will not have an outer ContentInfo wrapper. This
// makes it suitable to be streamed into an enclosing message.
//
// The pStreamInfo parameter needs to be set to stream the encoded message
// output.
//--------------------------------------------------------------------------
HCRYPTMSG
WINAPI
#ifdef DEBUG_CRYPT_ASN1_MASTER
ICMTest_NewCryptMsgOpenToEncode(
#else
CryptMsgOpenToEncode(
#endif
IN DWORD dwEncodingType,
IN DWORD dwFlags,
IN DWORD dwMsgType,
IN void const *pvMsgEncodeInfo,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo)
{
HCRYPTMSG hcrmsg = NULL;
if (GET_CMSG_ENCODING_TYPE(dwEncodingType) != PKCS_7_ASN_ENCODING)
goto InvalidEncoding;
switch (dwMsgType) {
case CMSG_DATA:
hcrmsg = ICM_OpenToEncodeData(
dwEncodingType,
dwFlags,
pvMsgEncodeInfo,
pStreamInfo);
break;
case CMSG_SIGNED:
hcrmsg = ICM_OpenToEncodeSignedData(
dwEncodingType,
dwFlags,
pvMsgEncodeInfo,
pszInnerContentObjID,
pStreamInfo);
break;
case CMSG_ENVELOPED:
hcrmsg = ICM_OpenToEncodeEnvelopedData(
dwEncodingType,
dwFlags,
pvMsgEncodeInfo,
pszInnerContentObjID,
pStreamInfo);
break;
case CMSG_SIGNED_AND_ENVELOPED:
#if 0
hcrmsg = ICM_OpenToEncodeSignedAndEnvelopedData(
dwEncodingType,
dwFlags,
pvMsgEncodeInfo,
pszInnerContentObjID,
pStreamInfo);
break;
#endif
goto MessageTypeNotSupportedYet;
case CMSG_HASHED:
hcrmsg = ICM_OpenToEncodeDigestedData(
dwEncodingType,
dwFlags,
pvMsgEncodeInfo,
pszInnerContentObjID,
pStreamInfo);
break;
case CMSG_ENCRYPTED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
CommonReturn:
if (hcrmsg) {
PCRYPT_MSG_INFO pcmi = (PCRYPT_MSG_INFO) hcrmsg;
pcmi->lRefCnt = 1;
if (!Pki_InitializeCriticalSection( &pcmi->CriticalSection)) {
pcmi->fInitializedCriticalSection = FALSE;
CryptMsgClose(hcrmsg);
hcrmsg = NULL;
} else
pcmi->fInitializedCriticalSection = TRUE;
}
return hcrmsg;
ErrorReturn:
hcrmsg = NULL;
goto CommonReturn;
SET_ERROR(InvalidEncoding,E_INVALIDARG)
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(InvalidMsgType,CRYPT_E_INVALID_MSG_TYPE)
}
//+-------------------------------------------------------------------------
// Open a cryptographic message for decoding
//
// hCryptProv specifies the crypto provider to use for hashing and/or
// decrypting the message. If hCryptProv is NULL, a default crypt provider
// is used.
//
// Currently pRecipientInfo isn't used and should be set to NULL.
//
// The pStreamInfo parameter needs to be set to stream the decoded content
// output.
//--------------------------------------------------------------------------
HCRYPTMSG
WINAPI
#ifdef DEBUG_CRYPT_ASN1_MASTER
ICMTest_NewCryptMsgOpenToDecode(
#else
CryptMsgOpenToDecode(
#endif
IN DWORD dwEncodingType,
IN DWORD dwFlags,
IN DWORD dwMsgType,
IN HCRYPTPROV hCryptProv,
IN PCERT_INFO pRecipientInfo,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo)
{
DWORD dwError = ERROR_SUCCESS;
HCRYPTMSG hcrmsg;
PCRYPT_MSG_INFO pcmi = NULL;
if (GET_CMSG_ENCODING_TYPE(dwEncodingType) != PKCS_7_ASN_ENCODING)
goto InvalidEncodingTypeError;
if (NULL != pRecipientInfo)
goto RecipientInfoNotSupportedYet;
if (NULL == (pcmi = (PCRYPT_MSG_INFO)ICM_AllocZero( sizeof( CRYPT_MSG_INFO))))
goto AllocCmsgError;
if (0 == hCryptProv) {
pcmi->fDefaultCryptProv = TRUE;
pcmi->hCryptProv = I_CryptGetDefaultCryptProv(0);
if (0 == pcmi->hCryptProv)
goto GetDefaultCryptProvError;
} else
pcmi->hCryptProv = hCryptProv;
pcmi->dwEncodingType = dwEncodingType;
pcmi->dwMsgType = dwMsgType;
pcmi->dwFlags = dwFlags;
pcmi->dwPhase = PHASE_FIRST_ONGOING;
if (pStreamInfo &&
(NULL == (pcmi->pStreamInfo = (PCMSG_STREAM_INFO)ICM_DupMem(
pStreamInfo,
sizeof(*pStreamInfo)))))
goto DupStreamInfoError;
if (!Pki_InitializeCriticalSection( &pcmi->CriticalSection))
goto InitializeCriticalSectionError;
pcmi->fInitializedCriticalSection = TRUE;
pcmi->lRefCnt = 1;
hcrmsg = (HCRYPTMSG)pcmi;
CommonReturn:
ICM_SetLastError(dwError);
return hcrmsg;
ErrorReturn:
dwError = GetLastError();
ICM_Free( pcmi);
hcrmsg = NULL;
goto CommonReturn;
SET_ERROR(InvalidEncodingTypeError,E_INVALIDARG)
SET_ERROR(RecipientInfoNotSupportedYet,E_INVALIDARG)
TRACE_ERROR(AllocCmsgError) // error already set
TRACE_ERROR(GetDefaultCryptProvError) // error already set
TRACE_ERROR(DupStreamInfoError) // error already set
TRACE_ERROR(InitializeCriticalSectionError) // error already set
}
//+-------------------------------------------------------------------------
// Duplicate a cryptographic message handle
//--------------------------------------------------------------------------
HCRYPTMSG
WINAPI
#ifdef DEBUG_CRYPT_ASN1_MASTER
ICMTest_NewCryptMsgDuplicate(
#else
CryptMsgDuplicate(
#endif
IN HCRYPTMSG hCryptMsg
)
{
PCRYPT_MSG_INFO pcmi = (PCRYPT_MSG_INFO)hCryptMsg;
if (pcmi)
InterlockedIncrement(&pcmi->lRefCnt);
return hCryptMsg;
}
//+-------------------------------------------------------------------------
// Close a cryptographic message handle
//
// NB- Must preserve LastError.
//--------------------------------------------------------------------------
BOOL
WINAPI
#ifdef DEBUG_CRYPT_ASN1_MASTER
ICMTest_NewCryptMsgClose(
#else
CryptMsgClose(
#endif
IN HCRYPTMSG hCryptMsg)
{
DWORD dwError;
BOOL fRet;
PCRYPT_MSG_INFO pcmi = (PCRYPT_MSG_INFO)hCryptMsg;
PCMSG_STREAM_INFO pcsi;
if (NULL == hCryptMsg)
return TRUE;
if (0 != InterlockedDecrement(&pcmi->lRefCnt))
return TRUE;
// Preserve LastError
dwError = GetLastError();
pcsi = pcmi->pStreamInfo;
switch (pcmi->dwMsgType) {
case CMSG_DATA:
{
OctetStringType *poos = (OctetStringType *)pcmi->pvMsg;
if (!poos)
break;
if (pcmi->fEncoding) {
ICM_Free( poos->value);
ICM_Free( poos);
} else {
PkiAsn1FreeInfo( ICM_GetDecoder(), OctetStringType_PDU, poos);
}
break;
}
case CMSG_SIGNED:
{
SignedData *psd = (SignedData *)pcmi->pvMsg;
if (!(psd || pcmi->psdi))
break;
if (pcmi->fEncoding) {
if (psd->signerInfos.value) {
SignerInfo *psi;
DWORD i;
for (i=psd->signerInfos.count, psi=psd->signerInfos.value;
i>0;
i--, psi++)
ICM_FreeAsnSignerInfo(psi);
ICM_Free( psd->signerInfos.value);
}
if (ICM_IsAddInnerContentOctetWrapper(pcmi) &&
psd->contentInfo.content.length &&
psd->contentInfo.content.value)
PkiAsn1FreeEncoded( ICM_GetEncoder(),
psd->contentInfo.content.value);
if (psd->digestAlgorithms.count && psd->digestAlgorithms.value)
ICM_Free( psd->digestAlgorithms.value);
ICM_Free( psd);
ICM_Free( pcmi->pszInnerContentObjID);
} else {
// decoding
delete pcmi->psdi->pAlgidList;
delete pcmi->psdi->pCertificateList;
delete pcmi->psdi->pCrlList;
delete pcmi->psdi->pSignerList;
ICM_Free( pcmi->psdi->pci);
ICM_Free( pcmi->psdi);
}
if (pcmi->pHashList)
delete pcmi->pHashList;
#ifdef CMS_PKCS7
if (pcmi->rgSignerEncodeDataInfo) {
assert(pcmi->cSignerEncodeDataInfo);
if (pcmi->dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) {
DWORD i;
for (i = 0; i < pcmi->cSignerEncodeDataInfo; i++) {
if (pcmi->rgSignerEncodeDataInfo[i].hCryptProv)
CryptReleaseContext(
pcmi->rgSignerEncodeDataInfo[i].hCryptProv, 0);
}
}
ICM_Free(pcmi->rgSignerEncodeDataInfo);
}
#endif // CMS_PKCS7
break;
}
case CMSG_ENVELOPED:
{
#ifdef CMS_PKCS7
CmsEnvelopedData *ped = (CmsEnvelopedData *)pcmi->pvMsg;
#else
EnvelopedData *ped = (EnvelopedData *)pcmi->pvMsg;
RecipientInfo *pri;
#endif // CMS_PKCS7
DWORD i;
if (pcmi->hkeyContentCrypt)
CryptDestroyKey( pcmi->hkeyContentCrypt);
ICM_Free( pcmi->Plaintext.pbData);
#ifndef CMS_PKCS7
ICM_Free( pcmi->pbEncryptParameters);
#endif // CMS_PKCS7
if (pcmi->fEncoding) {
#ifdef CMS_PKCS7
ICM_FreeOssCmsRecipientInfos(&ped->recipientInfos);
if (ped->unprotectedAttrs.value) {
Attribute *poatr;
for (i=ped->unprotectedAttrs.count,
poatr=ped->unprotectedAttrs.value;
i>0;
i--, poatr++) {
ICM_Free(poatr->attributeValue.value);
}
ICM_Free(ped->unprotectedAttrs.value);
}
#else
for (i=ped->recipientInfos.count, pri=ped->recipientInfos.value;
i>0;
i--, pri++)
ICM_Free( pri->encryptedKey.value);
ICM_Free( ped->recipientInfos.value);
#endif // CMS_PKCS7
ICM_Free( ped->encryptedContentInfo.encryptedContent.value);
ICM_Free( ped);
ICM_Free( pcmi->pszInnerContentObjID);
} else {
// decoding
#ifdef CMS_PKCS7
if (NULL != pcmi->pCertificateList)
delete pcmi->pCertificateList;
if (NULL != pcmi->pCrlList)
delete pcmi->pCrlList;
#endif // CMS_PKCS7
if (pcsi) {
ICM_Free( ped);
} else {
#ifdef CMS_PKCS7
PkiAsn1FreeInfo( ICM_GetDecoder(), CmsEnvelopedData_PDU, ped);
#else
PkiAsn1FreeInfo( ICM_GetDecoder(), EnvelopedData_PDU, ped);
#endif // CMS_PKCS7
}
}
break;
}
case CMSG_HASHED:
{
DigestedData *pdd = (DigestedData *)pcmi->pvMsg;
if (pcmi->fEncoding) {
if (ICM_IsAddInnerContentOctetWrapper(pcmi) &&
pdd->contentInfo.content.length &&
pdd->contentInfo.content.value)
PkiAsn1FreeEncoded( ICM_GetEncoder(),
pdd->contentInfo.content.value);
ICM_Free ((DigestedData *)pcmi->pvMsg);
ICM_Free( pcmi->pszInnerContentObjID);
} else {
// decoding
PkiAsn1FreeInfo( ICM_GetDecoder(), DigestedData_PDU,
(DigestedData *)pcmi->pvMsg);
}
if (pcmi->pHashList)
delete pcmi->pHashList;
break;
}
case CMSG_SIGNED_AND_ENVELOPED:
case CMSG_ENCRYPTED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
fRet = TRUE;
CommonReturn:
#ifdef CMS_PKCS7
if (pcmi->pFreeList)
delete pcmi->pFreeList;
#endif // CMS_PKCS7
if (pcmi->plDecodeInfo)
delete pcmi->plDecodeInfo;
ICM_Free( pcmi->pStreamInfo);
ICM_Free( pcmi->bufOutput.pbData);
ICM_Free( pcmi->bufCrypt.pbData);
ICM_Free( pcmi->bufPendingCrypt.pbData);
ICM_Free( pcmi->bufDecode.pbData);
ICM_Free( pcmi->bufEncode.pbData);
if (pcmi->pooid)
PkiAsn1FreeDecoded(ICM_GetDecoder(), pcmi->pooid,
ObjectIdentifierType_PDU);
if ((pcmi->dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG) &&
!pcmi->fDefaultCryptProv && pcmi->hCryptProv)
CryptReleaseContext(pcmi->hCryptProv, 0);
if (pcmi->hCryptProvContentCrypt)
CryptReleaseContext(pcmi->hCryptProvContentCrypt, 0);
if (pcmi->fInitializedCriticalSection)
DeleteCriticalSection( &pcmi->CriticalSection);
ICM_Free( hCryptMsg);
SetLastError(dwError); // Preserve LastError
return fRet;
ErrorReturn:
fRet = TRUE;
goto CommonReturn;
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
TRACE_ERROR(InvalidMsgType)
}
//+-------------------------------------------------------------------------
// Since the encoding might be indefinite-length encoded,
// decode and re-encode as DER.
//
// Returns: FALSE iff fails
//
// NB: The caller of this routine needs to call
// PkiAsn1FreeEncoded( ICM_GetEncoder(), pbOut);
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ReEncodeAsOctetDER(
IN PBYTE pbIn,
IN DWORD cbIn,
OUT PBYTE *ppbOut,
OUT DWORD *pcbOut)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
PVOID pvMsg = NULL;
DWORD dwExceptionCode;
// Handle MappedFile Exceptions
__try {
if (0 != (Asn1Err = PkiAsn1Decode(pDec, (void **)&pvMsg,
OctetStringType_PDU, pbIn, cbIn)))
goto DecodeInnerContentError;
if (0 != (Asn1Err = PkiAsn1Encode(ICM_GetEncoder(), pvMsg,
OctetStringType_PDU, ppbOut, pcbOut)))
goto EncodeInnerContentError;
fRet = TRUE;
} __except(EXCEPTION_EXECUTE_HANDLER) {
dwExceptionCode = GetExceptionCode();
goto ExceptionError;
}
CommonReturn:
PkiAsn1FreeInfo(pDec, OctetStringType_PDU, pvMsg);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
*ppbOut = NULL;
*pcbOut = 0;
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(DecodeInnerContentError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(EncodeInnerContentError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(ExceptionError, dwExceptionCode)
}
//+-------------------------------------------------------------------------
// Update the digest
//
// Returns:
// FALSE iff error
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_UpdateDigest(
IN HCRYPTHASH hHash,
IN const BYTE *pbData,
IN DWORD cbData)
{
BOOL fRet;
if (0 != cbData)
fRet = CryptHashData(
hHash,
pbData,
cbData,
0); // dwFlags
else
fRet = TRUE;
if (!fRet)
goto HashDataError;
CommonReturn:
return fRet;
ErrorReturn:
goto CommonReturn;
TRACE_ERROR(HashDataError) // error already set
}
//+-------------------------------------------------------------------------
// Update the digests in a list
//
// Returns:
// FALSE iff error
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_UpdateListDigest(
IN CHashList *pHashList,
IN const BYTE *pbData,
IN DWORD cbData)
{
BOOL fRet;
CHashNode *pnHash;
if (pHashList) {
for (pnHash=pHashList->Head(); pnHash; pnHash=pnHash->Next()) {
if (!ICM_UpdateDigest( pnHash->Data()->hHash, pbData, cbData))
goto UpdateDigestError;
}
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(UpdateDigestError) // error already set
}
//+-------------------------------------------------------------------------
// Alloc and sign a hash.
//
// Returns: FALSE iff failed
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_AllocAndSignHash(
IN HCRYPTHASH hHash,
IN DWORD dwKeySpec,
IN DWORD dwAlgIdPubKey,
IN DWORD dwPubKeyFlags,
IN BOOL fMaxLength,
OUT PBYTE *ppbSignature,
OUT DWORD *pcbSignature)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PBYTE pbSignature = NULL;
DWORD cbSignature = 0;
if (dwKeySpec == 0)
dwKeySpec = AT_SIGNATURE;
if (CALG_NO_SIGN == dwAlgIdPubKey) {
if (!CryptGetHashParam(
hHash,
HP_HASHVAL,
NULL,
&cbSignature,
0)) // dwFlags
goto GetHashParamSizeError;
if (NULL == (pbSignature = (PBYTE)ICM_Alloc( cbSignature)))
goto AllocHashParamError;
if (!CryptGetHashParam(
hHash,
HP_HASHVAL,
pbSignature,
&cbSignature,
0)) // dwFlags
goto GetHashParamError;
} else if (CALG_DSS_SIGN == dwAlgIdPubKey &&
0 == (dwPubKeyFlags & CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG)) {
DWORD cbData;
BYTE rgbDssSignature[CERT_DSS_SIGNATURE_LEN];
cbData = sizeof(rgbDssSignature);
if (!CryptSignHash(
hHash,
dwKeySpec,
NULL, // sDescription
0, // dwFlags
rgbDssSignature,
&cbData
)) goto SignHashError;
assert(cbData == sizeof(rgbDssSignature));
if (NULL == (pbSignature = (PBYTE)ICM_Alloc(
CERT_MAX_ASN_ENCODED_DSS_SIGNATURE_LEN)))
goto AllocSignatureError;
// Convert from the CSP signature format to an ASN.1 sequence of
// two integers
cbSignature = CERT_MAX_ASN_ENCODED_DSS_SIGNATURE_LEN;
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_DSS_SIGNATURE,
rgbDssSignature,
pbSignature,
&cbSignature
)) goto EncodeDssSignatureError;
if (fMaxLength) {
int cbRemain;
assert(CERT_MAX_ASN_ENCODED_DSS_SIGNATURE_LEN >= cbSignature);
cbRemain = CERT_MAX_ASN_ENCODED_DSS_SIGNATURE_LEN - cbSignature;
if (cbRemain > 0) {
memset(pbSignature + cbSignature, 0, cbRemain);
cbSignature = CERT_MAX_ASN_ENCODED_DSS_SIGNATURE_LEN;
}
}
} else {
if (!CryptSignHash(
hHash,
dwKeySpec,
NULL, // description ?
0, // dwFlags
NULL, // pbSignature
&cbSignature))
goto SignHashSizeError;
if (NULL == (pbSignature = (PBYTE)ICM_Alloc( cbSignature)))
goto AllocSignatureError;
if (!CryptSignHash(
hHash,
dwKeySpec,
NULL, // description ?
0, // dwFlags
pbSignature,
&cbSignature))
goto SignHashError;
ICM_ReverseInPlace( pbSignature, cbSignature);
}
fRet = TRUE;
CommonReturn:
*ppbSignature = pbSignature;
*pcbSignature = cbSignature;
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
ICM_Free( pbSignature);
pbSignature = NULL;
cbSignature = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetHashParamSizeError) // error already set
TRACE_ERROR(AllocHashParamError) // error already set
TRACE_ERROR(GetHashParamError) // error already set
TRACE_ERROR(SignHashSizeError) // error already set
TRACE_ERROR(AllocSignatureError) // error already set
TRACE_ERROR(SignHashError) // error already set
TRACE_ERROR(EncodeDssSignatureError) // error already set
}
//+-------------------------------------------------------------------------
// Get the hash of a blob.
//
// Returns: FALSE iff failed
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetBlobHash(
IN HCRYPTPROV hCryptProv,
IN DWORD dwDigestAlgorithm,
IN PBYTE pb,
IN DWORD cb,
OUT HCRYPTHASH *phHash)
{
BOOL fRet;
HCRYPTHASH hHash;
if (!CryptCreateHash(
hCryptProv,
dwDigestAlgorithm,
NULL, // hKey - optional for MAC
0, // dwFlags
&hHash))
goto CreateHashError;
if (!ICM_UpdateDigest( hHash, pb, cb))
goto UpdateDigestError;
fRet = TRUE;
CommonReturn:
*phHash = hHash;
return fRet;
ErrorReturn:
hHash = NULL;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(CreateHashError) // error already set
TRACE_ERROR(UpdateDigestError) // error already set
}
//+-------------------------------------------------------------------------
// Get the hash of an OSS Attributes. This is used to hash the authenticated
// attributes for a Signed or SignedAndEnveloped message.
//
// Returns: FALSE iff failed
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetAttrsHash(
IN DWORD dwDigestAlgorithm,
IN HCRYPTPROV hCryptProv,
IN Attributes *possAttrs,
OUT HCRYPTHASH *phHash)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
ASN1error_e Asn1Err;
ASN1encoding_t pEnc = ICM_GetEncoder();
PBYTE pbEncoded = NULL;
DWORD cbEncoded;
HCRYPTHASH hHash;
if (!CryptCreateHash(
hCryptProv,
dwDigestAlgorithm,
NULL, // hKey - optional for MAC
0, // dwFlags
&hHash))
goto CreateHashError;
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
possAttrs,
Attributes_PDU,
&pbEncoded,
&cbEncoded)))
goto EncodeAttributesError;
if (!ICM_UpdateDigest(
hHash,
pbEncoded,
cbEncoded))
goto UpdateDigestAttributesError;
fRet = TRUE;
CommonReturn:
PkiAsn1FreeEncoded(pEnc, pbEncoded);
*phHash = hHash;
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
hHash = NULL;
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(EncodeAttributesError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(CreateHashError) // error already set
TRACE_ERROR(UpdateDigestAttributesError) // error already set
}
//+-------------------------------------------------------------------------
// Compare 2 OSS object id's.
//
// Returns: FALSE iff !equal
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_EqualObjectIDs(
IN ObjectID *poid1,
IN ObjectID *poid2)
{
BOOL fRet;
DWORD i;
PDWORD pdw1;
PDWORD pdw2;
if (poid1->count != poid2->count)
goto Unequal;
for (i=poid1->count, pdw1=poid1->value, pdw2=poid2->value;
(i>0) && (*pdw1==*pdw2);
i--, pdw1++, pdw2++)
;
if (i>0)
goto Unequal;
fRet = TRUE; // equal
CommonReturn:
return fRet;
Unequal:
fRet = FALSE; // !equal
goto CommonReturn;
}
//+-------------------------------------------------------------------------
// Get the value of an Attribute of a given type.
//
// Returns: FALSE iff fails
//
// NB- Does not set error
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetAttrValue(
IN Attributes *poatrs,
IN ObjectID *poid,
OUT Any *panyValue)
{
BOOL fRet;
DWORD i;
Attribute *poatr;
for (i=poatrs->count, poatr=poatrs->value; i>0; i--, poatr++) {
if (ICM_EqualObjectIDs( &poatr->attributeType, poid))
break;
}
if (0 == i)
goto AttributeNotFoundError;
*panyValue = *poatr->attributeValue.value;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
panyValue->length = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(AttributeNotFoundError)
}
//+-------------------------------------------------------------------------
// Fill in the content-type and message-digest authenticated attributes,
// which are required in a SignedData or SignedAndEnvelopedData message.
//
// Returns: FALSE iff failed
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FillReqAuthAttrs(
IN OPTIONAL LPSTR pszInnerContentObjID,
IN CHashNode *pnHash,
IN OUT Attribute *possAttr)
{
BOOL fRet;
CRYPT_ATTRIBUTE atr;
CRYPT_ATTR_BLOB atrblob;
ASN1error_e Asn1Err;
ASN1encoding_t pEnc = ICM_GetEncoder();
PBYTE pbEncoded;
DWORD cbEncoded;
ObjectID ossObjID;
OctetStringType ost;
// NB - When psi->authenticatedAttributes was created,
// the first 2 slots were reserved for the
// content-type and message-digest attributes.
// content-type attribute
ossObjID.count = sizeof(ossObjID.value)/sizeof(ossObjID.value[0]);
if (!PkiAsn1ToObjectIdentifier(
pszInnerContentObjID ? pszInnerContentObjID : pszObjIdDataType,
&ossObjID.count,
ossObjID.value))
goto ConvToObjectIdentifierError;
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
&ossObjID,
ObjectIdentifierType_PDU,
&pbEncoded,
&cbEncoded)))
goto EncodeObjectIdentifierError;
atr.pszObjId = pszObjIdContentType;
atr.cValue = 1;
atr.rgValue = &atrblob;
atrblob.cbData = cbEncoded;
atrblob.pbData = pbEncoded;
fRet = ICM_Asn1ToAttribute( &atr, possAttr);
PkiAsn1FreeEncoded(pEnc, pbEncoded);
if (!fRet)
goto ContentTypeAsn1ToAttributeError;
// message-digest attribute
if (!ICM_GetListHashValue( pnHash, (DWORD*)&ost.length, &ost.value))
goto GetHashValueError;
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
&ost,
OctetStringType_PDU,
&pbEncoded,
&cbEncoded)))
goto EncodeOctetStringError;
atr.pszObjId = pszObjIdMessageDigest;
atr.cValue = 1;
atr.rgValue = &atrblob;
atrblob.cbData = cbEncoded;
atrblob.pbData = pbEncoded;
fRet = ICM_Asn1ToAttribute( &atr, possAttr + 1);
PkiAsn1FreeEncoded(pEnc, pbEncoded);
if (!fRet)
goto MsgDigestAsn1ToAttributeError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(EncodeObjectIdentifierError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(EncodeOctetStringError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(ConvToObjectIdentifierError,CRYPT_E_OID_FORMAT)
TRACE_ERROR(ContentTypeAsn1ToAttributeError) // error already set
TRACE_ERROR(GetHashValueError) // error already set
TRACE_ERROR(MsgDigestAsn1ToAttributeError) // error already set
}
//+-------------------------------------------------------------------------
// Fill the inner ContentInfo.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FillInnerContentInfo(
OUT ContentInfo *pci,
IN OPTIONAL LPSTR pszInnerID,
IN DWORD cbData,
IN const BYTE *pbData,
IN BOOL fAddInnerContentOctetWrapper // CMS_PKCS7
)
{
BOOL fRet;
ASN1error_e Asn1Err;
PBYTE pbEncoded;
DWORD cbEncoded;
OctetStringType ost;
pci->contentType.count = sizeof(pci->contentType.value)/sizeof(pci->contentType.value[0]);
if (!PkiAsn1ToObjectIdentifier(
pszInnerID ? pszInnerID : pszObjIdDataType,
&pci->contentType.count,
pci->contentType.value))
goto PkiAsn1ToObjectIdentifierError;
if (0 != cbData) {
pci->bit_mask |= content_present;
if (!fAddInnerContentOctetWrapper) {
pci->content.length = cbData;
pci->content.value = (PBYTE)pbData;
} else {
ost.length = cbData;
ost.value = (PBYTE)pbData;
if (0 != (Asn1Err = PkiAsn1Encode(
ICM_GetEncoder(),
&ost,
OctetStringType_PDU,
&pbEncoded,
&cbEncoded)))
goto EncodeOctetStringError;
pci->content.length = cbEncoded;
pci->content.value = pbEncoded;
}
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(PkiAsn1ToObjectIdentifierError,CRYPT_E_OID_FORMAT)
SET_ERROR_VAR(EncodeOctetStringError, PkiAsn1ErrToHr(Asn1Err))
}
#ifdef CMS_PKCS7
//+-------------------------------------------------------------------------
// Fill in the encrypted digest in a signer info.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FillSignerEncryptedDigest(
IN SignerInfo *psi,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN PSIGNER_ENCODE_DATA_INFO pSignerEncodeDataInfo,
IN BOOL fMaxLength)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
HCRYPTHASH hHash;
HCRYPTHASH hHashAttr = NULL;
HCRYPTHASH hHashDup = NULL;
PBYTE pbSignature = NULL;
DWORD cbSignature;
CHashNode *pnHash = pSignerEncodeDataInfo->pHashNode;
PICM_HASH_INFO pHashInfo = pnHash->Data();
PCCRYPT_OID_INFO pOIDInfo;
DWORD dwAlgIdPubKey;
DWORD dwPubKeyFlags;
if (psi->bit_mask & authenticatedAttributes_present) {
if (!ICM_FillReqAuthAttrs(
pszInnerContentObjID,
pSignerEncodeDataInfo->pHashNode,
psi->authenticatedAttributes.value))
goto FillReqAuthAttrsError;
if (!ICM_GetAttrsHash(
pHashInfo->dwAlgoCAPI,
pSignerEncodeDataInfo->hCryptProv,
&psi->authenticatedAttributes,
&hHashAttr))
goto GetAuthAttrsHashError;
hHash = hHashAttr;
} else {
if (!ICM_DupListHash( pnHash, pSignerEncodeDataInfo->hCryptProv,
&hHashDup))
goto DupListHashError;
hHash = hHashDup;
}
dwAlgIdPubKey = 0;
dwPubKeyFlags = 0;
if (pOIDInfo = ICM_GetOssOIDInfo(CRYPT_PUBKEY_ALG_OID_GROUP_ID,
&psi->digestEncryptionAlgorithm)) {
dwAlgIdPubKey = pOIDInfo->Algid;
if (1 <= pOIDInfo->ExtraInfo.cbData / sizeof(DWORD)) {
DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
dwPubKeyFlags = pdwExtra[0];
}
} else if (pOIDInfo = ICM_GetOssOIDInfo(CRYPT_SIGN_ALG_OID_GROUP_ID,
&psi->digestEncryptionAlgorithm)) {
DWORD cExtra = pOIDInfo->ExtraInfo.cbData / sizeof(DWORD);
DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
if (1 <= cExtra) {
dwAlgIdPubKey = pdwExtra[0];
if (2 <= cExtra)
dwPubKeyFlags = pdwExtra[1];
}
}
if (!ICM_AllocAndSignHash( hHash, pSignerEncodeDataInfo->dwKeySpec,
dwAlgIdPubKey, dwPubKeyFlags, fMaxLength,
&pbSignature, &cbSignature))
goto AllocAndSignHashError;
psi->encryptedDigest.length = cbSignature;
psi->encryptedDigest.value = pbSignature;
pbSignature = NULL;
fRet = TRUE;
CommonReturn:
if (hHashAttr)
CryptDestroyHash( hHashAttr);
if (hHashDup)
CryptDestroyHash( hHashDup);
ICM_Free(pbSignature);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(FillReqAuthAttrsError) // error already set
TRACE_ERROR(GetAuthAttrsHashError) // error already set
TRACE_ERROR(DupListHashError) // error already set
TRACE_ERROR(AllocAndSignHashError) // error already set
}
BOOL
WINAPI
ICM_FillSignerEncodeEncryptedDigests(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fMaxLength)
{
LPSTR pszInnerContentObjID = pcmi->pszInnerContentObjID;
DWORD cSignerEncodeDataInfo = pcmi->cSignerEncodeDataInfo;
PSIGNER_ENCODE_DATA_INFO pSignerEncodeDataInfo =
pcmi->rgSignerEncodeDataInfo;
SignedData *psd = (SignedData *)pcmi->pvMsg;
SignerInfo *psi = psd->signerInfos.value;
assert(psd->signerInfos.count == cSignerEncodeDataInfo);
for ( ; 0 < cSignerEncodeDataInfo;
cSignerEncodeDataInfo--,
pSignerEncodeDataInfo++,
psi++) {
if (!ICM_FillSignerEncryptedDigest(
psi,
pszInnerContentObjID,
pSignerEncodeDataInfo,
fMaxLength))
return FALSE;
}
return TRUE;
}
#else
//+-------------------------------------------------------------------------
// Fill in the encrypted digest in a signer info.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FillSignerEncryptedDigest(
IN SignerInfo *psi,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN CHashNode *pnHash,
IN DWORD dwKeySpec,
IN BOOL fMaxLength)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
HCRYPTHASH hHash;
HCRYPTHASH hHashAttr = NULL;
HCRYPTHASH hHashDup = NULL;
PBYTE pbSignature = NULL;
DWORD cbSignature;
PICM_HASH_INFO pHashInfo = pnHash->Data();
PCCRYPT_OID_INFO pOIDInfo;
DWORD dwAlgIdPubKey;
DWORD dwPubKeyFlags;
if (psi->bit_mask & authenticatedAttributes_present) {
if (!ICM_FillReqAuthAttrs(
pszInnerContentObjID,
pnHash,
psi->authenticatedAttributes.value))
goto FillReqAuthAttrsError;
if (!ICM_GetAttrsHash(
pHashInfo->dwAlgoCAPI,
pHashInfo->hCryptProv,
&psi->authenticatedAttributes,
&hHashAttr))
goto GetAuthAttrsHashError;
hHash = hHashAttr;
} else {
if (!ICM_DupListHash( pnHash, pHashInfo->hCryptProv, &hHashDup))
goto DupListHashError;
hHash = hHashDup;
}
dwAlgIdPubKey = 0;
dwPubKeyFlags = 0;
if (pOIDInfo = ICM_GetOssOIDInfo(CRYPT_PUBKEY_ALG_OID_GROUP_ID,
&psi->digestEncryptionAlgorithm)) {
dwAlgIdPubKey = pOIDInfo->Algid;
if (1 <= pOIDInfo->ExtraInfo.cbData / sizeof(DWORD)) {
DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
dwPubKeyFlags = pdwExtra[0];
}
}
if (!ICM_AllocAndSignHash( hHash, dwKeySpec,
dwAlgIdPubKey, dwPubKeyFlags, fMaxLength,
&pbSignature, &cbSignature))
goto AllocAndSignHashError;
psi->encryptedDigest.length = cbSignature;
psi->encryptedDigest.value = pbSignature;
pbSignature = NULL;
fRet = TRUE;
CommonReturn:
if (hHashAttr)
CryptDestroyHash( hHashAttr);
if (hHashDup)
CryptDestroyHash( hHashDup);
ICM_Free(pbSignature);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(FillReqAuthAttrsError) // error already set
TRACE_ERROR(GetAuthAttrsHashError) // error already set
TRACE_ERROR(DupListHashError) // error already set
TRACE_ERROR(AllocAndSignHashError) // error already set
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Update the content of a signed message.
//
// Assume all more-deeply-nested messages are DER-encoded.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_UpdateEncodingSignedData(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal)
{
BOOL fRet;
SignedData *psd = (SignedData *)pcmi->pvMsg;
LPSTR pszInnerContentObjID = pcmi->pszInnerContentObjID;
PBYTE pb;
DWORD cb;
PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
BOOL fAddInnerContentOctetWrapper; // CMS_PKCS7
if (pcsi) {
if (!ICMS_UpdateEncodingSignedData( pcmi, (PBYTE)pbData, cbData, fFinal))
goto StreamUpdateEncodingSignedDataError;
} else {
psd->contentInfo.bit_mask = 0;
fAddInnerContentOctetWrapper = ICM_IsAddInnerContentOctetWrapper(pcmi);
if (0 == (pcmi->dwFlags & CMSG_DETACHED_FLAG) &&
!fAddInnerContentOctetWrapper && pbData) {
// must be encoded, hash only the contents octets
if (0 > Asn1UtilExtractContent(
(PBYTE)pbData,
cbData,
&cb,
(const BYTE **)&pb))
goto ExtractContentError;
} else {
cb = cbData;
pb = (PBYTE)pbData;
}
if (!ICM_UpdateListDigest( pcmi->pHashList, pb, cb))
goto UpdateDigestError;
if (fFinal) {
if (pcmi->dwFlags & CMSG_DETACHED_FLAG) {
if (!ICM_FillInnerContentInfo(
&psd->contentInfo,
pszInnerContentObjID,
0, // cbData
NULL, // pbData
FALSE)) // fAddInnerContentOctetWrapper
goto DetachedFillInnerContentInfoError;
} else {
if (!ICM_FillInnerContentInfo(
&psd->contentInfo,
pszInnerContentObjID,
cbData,
(PBYTE)pbData,
fAddInnerContentOctetWrapper
))
goto FillInnerContentInfoError;
}
#ifdef CMS_PKCS7
if (pcmi->rgSignerEncodeDataInfo) {
BOOL fMaxLength =
(0 != (pcmi->dwFlags & CMSG_MAX_LENGTH_FLAG));
if (!ICM_FillSignerEncodeEncryptedDigests(
pcmi,
fMaxLength))
goto FillSignerEncodeEncryptedDigestsError;
}
#else
if (pcmi->pHashList) {
BOOL fMaxLength =
(0 != (pcmi->dwFlags & CMSG_MAX_LENGTH_FLAG));
if (!ICM_FillSignerEncryptedDigest(
psd->signerInfos.value,
pszInnerContentObjID,
pcmi->pHashList->Head(),
pcmi->dwKeySpec,
fMaxLength))
goto FillSignerEncryptedDigestError;
}
#endif // CMS_PKCS7
}
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(ExtractContentError,CRYPT_E_UNEXPECTED_ENCODING)
TRACE_ERROR(UpdateDigestError) // error already set
TRACE_ERROR(DetachedFillInnerContentInfoError) // error already set
TRACE_ERROR(FillInnerContentInfoError) // error already set
TRACE_ERROR(StreamUpdateEncodingSignedDataError) // error already set
#ifdef CMS_PKCS7
TRACE_ERROR(FillSignerEncodeEncryptedDigestsError) // error already set
#else
TRACE_ERROR(FillSignerEncryptedDigestError) // error already set
#endif // CMS_PKCS7
}
//+-------------------------------------------------------------------------
// Update the content of a data message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_UpdateEncodingData(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
OctetStringType *poos = (OctetStringType *)pcmi->pvMsg;
PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
if (!pcsi) {
if (!fFinal)
goto NotFinalNotSupportedError;
poos->length = cbData;
if (NULL == (poos->value = (PBYTE)ICM_DupMem( (PBYTE)pbData, cbData)))
goto AllocOctetStringError;
}
if (pcsi && !ICMS_UpdateEncodingData( pcmi, (PBYTE)pbData, cbData, fFinal))
goto StreamUpdateEncodingDataError;
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
ICM_Free( poos->value);
fRet = FALSE;
goto CommonReturn;
SET_ERROR(NotFinalNotSupportedError,E_INVALIDARG)
TRACE_ERROR(AllocOctetStringError) // error already set
TRACE_ERROR(StreamUpdateEncodingDataError) // error already set
}
//+-------------------------------------------------------------------------
// Update the content of a digested message.
//
// Assume all more-deeply-nested messages are DER-encoded.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_UpdateEncodingDigestedData(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal)
{
BOOL fRet;
DigestedData *pdd = (DigestedData *)pcmi->pvMsg;
PBYTE pb;
DWORD cb;
LPSTR pszInnerContentObjID = pcmi->pszInnerContentObjID;
BOOL fAddInnerContentOctetWrapper; // CMS_PKCS7
pdd->contentInfo.bit_mask = 0;
if (pcmi->dwFlags & CMSG_DETACHED_FLAG) {
// must be non-encoded
if (!ICM_UpdateListDigest( pcmi->pHashList, pbData, cbData))
goto DetachedUpdateDigestError;
if (!ICM_FillInnerContentInfo(
&pdd->contentInfo,
pszInnerContentObjID,
0, // cbData
NULL, // pbData
FALSE // fAddInnerContentOctetWrapper
))
goto DetachedFillInnerContentInfoError;
} else {
fAddInnerContentOctetWrapper = ICM_IsAddInnerContentOctetWrapper(pcmi);
if (!fAddInnerContentOctetWrapper && pbData) {
// must be encoded, hash only the contents octets
if (0 > Asn1UtilExtractContent( (PBYTE)pbData, cbData, &cb,
(const BYTE **)&pb))
goto ExtractContentError;
} else {
cb = cbData;
pb = (PBYTE)pbData;
}
if (!ICM_UpdateListDigest( pcmi->pHashList, pb, cb))
goto UpdateDigestError;
if (!ICM_FillInnerContentInfo(
&pdd->contentInfo,
pszInnerContentObjID,
cbData,
(PBYTE)pbData,
fAddInnerContentOctetWrapper
))
goto FillInnerContentInfoError;
}
if (PHASE_FIRST_FINAL == pcmi->dwPhase) {
if (!ICM_GetListHashValue(
pcmi->pHashList->Head(),
(DWORD*)&pdd->digest.length,
&pdd->digest.value))
goto GetHashValueError;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(ExtractContentError,CRYPT_E_UNEXPECTED_ENCODING)
TRACE_ERROR(DetachedUpdateDigestError) // error already set
TRACE_ERROR(UpdateDigestError) // error already set
TRACE_ERROR(DetachedFillInnerContentInfoError) // error already set
TRACE_ERROR(FillInnerContentInfoError) // error already set
TRACE_ERROR(GetHashValueError) // error already set
fFinal;
}
//+-------------------------------------------------------------------------
// Get the block size for an encryption algorithm
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetKeyBlockSize(
IN HCRYPTKEY hkeyEncrypt,
OUT PDWORD pcbBlockSize,
OUT OPTIONAL PBOOL pfBlockCipher)
{
BOOL fRet;
BOOL fBlockCipher;
DWORD cbBlockSize;
DWORD cbKeyParamLen;
// Get key's blocksize.
// Encryption will pad the output data to be blocksize aligned,
// in the case of a block cipher.
cbBlockSize = 0;
cbKeyParamLen = sizeof( cbBlockSize);
if (!CryptGetKeyParam(
hkeyEncrypt,
KP_BLOCKLEN,
(PBYTE)&cbBlockSize,
&cbKeyParamLen,
0)) // dwFlags
goto GetKeyParamError;
if (0 == cbBlockSize) {
// stream cipher
fBlockCipher = FALSE;
cbBlockSize = 8; // convenient size
} else {
// block cipher
fBlockCipher = TRUE;
cbBlockSize /= 8; // convert from bits to bytes
}
fRet = TRUE;
CommonReturn:
*pcbBlockSize = cbBlockSize;
if (pfBlockCipher)
*pfBlockCipher = fBlockCipher;
return fRet;
ErrorReturn:
cbBlockSize = 0;
fBlockCipher = FALSE;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetKeyParamError) // error already set
}
//+-------------------------------------------------------------------------
// Encrypt a buffer
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_EncryptBuffer(
IN HCRYPTKEY hkeyEncrypt,
HCRYPTHASH hHash,
IN const BYTE *pbPlain,
IN DWORD cbPlain,
OUT PBYTE *ppbCipher,
OUT PDWORD pcbCipher)
{
BOOL fRet;
const BYTE *pbIn;
DWORD cbIn;
PBYTE pbOut;
DWORD cbOut;
PBYTE pbOutBuf = NULL;
DWORD cbPlainRemain;
DWORD cbBufRemain;
DWORD cbBlockLen;
BOOL fBlockCipher;
if (!ICM_GetKeyBlockSize( hkeyEncrypt, &cbBlockLen, &fBlockCipher))
goto GetKeyBlockSizeError;
// encrypt
cbBufRemain = cbPlain;
if (fBlockCipher) {
cbBufRemain += cbBlockLen;
cbBufRemain -= cbBufRemain % cbBlockLen;
}
if (NULL == (pbOutBuf = (PBYTE)ICM_Alloc( cbBufRemain)))
goto OutOfMemory;
for (pbIn=pbPlain, pbOut=pbOutBuf, cbPlainRemain=cbPlain;
(cbIn = min( cbBlockLen, cbPlainRemain)) > 0;
pbIn += cbIn, pbOut += cbOut,
cbPlainRemain -= cbIn, cbBufRemain -= cbOut) {
memcpy( pbOut, pbIn, cbIn);
cbOut = cbIn;
if (!CryptEncrypt(
hkeyEncrypt,
hHash,
cbPlainRemain <= cbBlockLen, // fFinal
0, // dwFlags
pbOut,
&cbOut,
cbBufRemain))
goto EncryptError;
}
*ppbCipher = pbOutBuf;
*pcbCipher = (DWORD)(pbOut - pbOutBuf);
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
if(NULL != pbOutBuf)
ICM_Free(pbOutBuf);
*ppbCipher = NULL;
*pcbCipher = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetKeyBlockSizeError) // error already set
TRACE_ERROR(EncryptError) // error already set
TRACE_ERROR(OutOfMemory) // error already set
}
//+-------------------------------------------------------------------------
// Encrypt and store the content of a message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_EncryptContent(
IN HCRYPTKEY hkeyContentEncryption,
HCRYPTHASH hHash,
OUT EncryptedContentInfo *peci,
IN const BYTE *pbPlain,
IN DWORD cbPlain)
{
BOOL fRet;
PBYTE pbCipher = NULL;
DWORD cbCipher;
if (!ICM_EncryptBuffer(
hkeyContentEncryption,
hHash,
pbPlain,
cbPlain,
&pbCipher,
&cbCipher))
goto EncryptBufferError;
if (0 != cbCipher) {
peci->bit_mask |= encryptedContent_present;
peci->encryptedContent.length = cbCipher;
peci->encryptedContent.value = pbCipher;
} else
ICM_Free(pbCipher);
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(EncryptBufferError) // error already set
}
//+-------------------------------------------------------------------------
// Update the content of a signed and enveloped message.
//
// Assume all more-deeply-nested messages are DER-encoded.
//--------------------------------------------------------------------------
#if 0
BOOL
WINAPI
ICM_UpdateEncodingSignedAndEnvelopedData(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
EncryptedContentInfo *peci;
SignedAndEnvelopedData *psed;
DWORD i;
DWORD iMax;
PBYTE pbSignature;
DWORD cbSignature;
PBYTE pbEncryptedSignature;
DWORD cbEncryptedSignature;
psed = (SignedAndEnvelopedData *)(pcmi->pvMsg);
peci = &psed->encryptedContentInfo;
// Require inner type to be Data for now
peci->contentType = aoidMessages[ CMSG_DATA - 1];
// Alloc a bigger buffer with padding and copy input to it
// encrypt the content and store it
if (!ICM_EncryptContent(
pcmi->hkeyContentCrypt,
pcmi->ahHash[0], // select the right hHash
peci,
pbData,
cbData))
goto EncryptError;
assert( 1 == psed->signerInfos.Count());
for (i=0, iMax=psed->signerInfos.Count(); i<iMax; i++) {
// Should use a stack buffer, unless it is too small
if (!CryptSignHash(
pcmi->ahHash[i],
(pcmi->dwKeySpec == 0) ? AT_SIGNATURE : pcmi->dwKeySpec,
NULL, // description ?
0, // dwFlags
NULL, // pbSignature
&cbSignature))
goto GetSignatureSizeError;
pbSignature = (PBYTE)ICM_AllocA( cbSignature);
if (NULL == pbSignature)
goto AllocSignatureError;
if (!CryptSignHash(
pcmi->ahHash[i],
(pcmi->dwKeySpec == 0) ? AT_SIGNATURE : pcmi->dwKeySpec,
NULL, // description ?
0, // dwFlags
pbSignature,
&cbSignature))
goto SignHashError;
// encrypt the signature
if (!ICM_EncryptBuffer(
pcmi->hkeyContentCrypt,
NULL,
pbSignature,
cbSignature,
&pbEncryptedSignature,
&cbEncryptedSignature))
goto EncryptError;
ICM_FreeA( pbSignature);
pbSignature = NULL;
if (0 > psed->signerInfos[i].encryptedDigest.Write(
pbEncryptedSignature,
cbEncryptedSignature))
goto EncryptedDigestWriteError;
ICM_Free( pbEncryptedSignature);
pbEncryptedSignature = NULL;
}
fRet = TRUE;
CommonReturn:
ICM_FreeA( pbSignature);
ICM_Free( pbEncryptedSignature);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(EncryptError)
TRACE_ERROR(GetSignatureSizeError)
TRACE_ERROR(AllocSignatureError)
TRACE_ERROR(SignHashError)
TRACE_ERROR(EncryptedDigestWriteError)
}
#endif
//+-------------------------------------------------------------------------
// Update the content of an enveloped message.
//
// Assume all more-deeply-nested messages are DER-encoded.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_UpdateEncodingEnvelopedData(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal)
{
BOOL fRet;
PBYTE pb;
DWORD cb;
#ifdef CMS_PKCS7
EncryptedContentInfo *peci = &((CmsEnvelopedData *)pcmi->pvMsg)->encryptedContentInfo;
#else
EncryptedContentInfo *peci = &((EnvelopedData *)pcmi->pvMsg)->encryptedContentInfo;
#endif // CMS_PKCS7
PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
if (pcsi) {
if (!ICMS_UpdateEncodingEnvelopedData(
pcmi,
pbData,
cbData,
fFinal))
goto StreamUpdateEncodingEnvelopedDataError;
} else {
if (!fFinal)
goto InvalidArg;
// encrypt the content
if (!ICM_IsAddInnerContentOctetWrapper(pcmi)) {
if (0 > Asn1UtilExtractContent( (PBYTE)pbData, cbData, &cb, (const BYTE **)&pb))
goto ExtractContentError;
} else {
pb = (PBYTE)pbData;
cb = cbData;
}
if (!ICM_EncryptContent(
pcmi->hkeyContentCrypt,
NULL, // hHash
peci,
pb,
cb))
goto EncryptError;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg,E_INVALIDARG)
SET_ERROR(ExtractContentError,CRYPT_E_UNEXPECTED_ENCODING)
TRACE_ERROR(EncryptError) // error already set
TRACE_ERROR(StreamUpdateEncodingEnvelopedDataError) // error already set
}
//+-------------------------------------------------------------------------
// Convert Any to blob and insert at the tail of a blob list
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_InsertTailBlob(
IN OUT CBlobList *pBlobList,
IN Any *pAny)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
CBlobNode *pnBlob = NULL;
PBYTE pb = NULL;
DWORD cb;
CRYPT_DATA_BLOB blob;
if (NULL == (pnBlob = new CBlobNode))
goto NewCBlobNodeError;
cb = pAny->length;
if (NULL == (pb = (PBYTE)ICM_Alloc( cb)))
goto AllocError;
memcpy( pb, pAny->value, cb);
blob.cbData = cb;
blob.pbData = pb;
pnBlob->SetData( &blob);
pBlobList->InsertTail( pnBlob);
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
ICM_Free( pb);
goto CommonReturn;
SET_ERROR(NewCBlobNodeError,E_OUTOFMEMORY)
TRACE_ERROR(AllocError) // error already set
}
//+-------------------------------------------------------------------------
// Use a 0-based index to delete a blob from a list
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DelBlobByIndex(
IN OUT CBlobList *pBlobList,
IN DWORD dwIndex)
{
BOOL fRet;
CBlobNode *pnBlob = pBlobList->Nth( dwIndex);
if (NULL == pnBlob)
goto IndexTooLargeError;
pBlobList->Remove( pnBlob);
delete pnBlob;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(IndexTooLargeError,CRYPT_E_INVALID_INDEX)
}
//+-------------------------------------------------------------------------
// Convert Any to blob and insert at the tail of a signer list
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_InsertTailSigner(
IN OUT CSignerList *pSignerList,
IN Any *pAny)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
CSignerNode *pnSigner = NULL;
PBYTE pb = NULL;
DWORD cb;
SIGNER_DATA_INFO sdi; ZEROSTRUCT(sdi);
if (NULL == (pnSigner = new CSignerNode))
goto NewCSignerNodeError;
cb = pAny->length;
if (NULL == (pb = (PBYTE)ICM_Alloc( cb)))
goto AllocError;
memcpy( pb, pAny->value, cb);
sdi.blob.cbData = cb;
sdi.blob.pbData = pb;
pnSigner->SetData( &sdi);
pSignerList->InsertTail( pnSigner);
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
ICM_Free( pb);
fRet = FALSE;
goto CommonReturn;
SET_ERROR(NewCSignerNodeError,E_OUTOFMEMORY)
TRACE_ERROR(AllocError) // error already set
}
//+-------------------------------------------------------------------------
// Convert a signed message to list form
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetListSignedData(
IN OUT PCRYPT_MSG_INFO pcmi,
IN SignedDataWithBlobs *psdb)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
Any *pAny;
DWORD cb;
DWORD i;
PSIGNED_DATA_INFO psdi = NULL;
if (NULL == (psdi = (PSIGNED_DATA_INFO)ICM_AllocZero(
sizeof(SIGNED_DATA_INFO))))
goto SdiAllocError;
if (NULL == (psdi->pAlgidList = new CBlobList))
goto NewAlgidListError;
if (NULL == (psdi->pCertificateList = new CBlobList))
goto NewCertificateListError;
if (NULL == (psdi->pCrlList = new CBlobList))
goto NewCrlListError;
if (NULL == (psdi->pSignerList = new CSignerList))
goto NewSignerListError;
// version
psdi->version = psdb->version;
// digestAlgorithms
for (i=psdb->digestAlgorithms.count, pAny=psdb->digestAlgorithms.value;
i>0;
i--, pAny++) {
if (!ICM_InsertTailBlob( psdi->pAlgidList, pAny))
goto DigestAlgorithmInsertTailBlobError;
}
// contentInfo
cb = 0;
ICM_GetOssContentInfoData(
(ContentInfo *)&psdb->contentInfo, // same, except for NOCOPY
NULL,
&cb);
if (cb == 0)
goto GetContentInfoDataSizeError;
if (NULL == (psdi->pci = (PCONTENT_INFO)ICM_Alloc(cb)))
goto AllocContentInfoError;
if (!ICM_GetOssContentInfoData(
(ContentInfo *)&psdb->contentInfo, // same, except for NOCOPY
psdi->pci,
&cb))
goto GetContentInfoDataError;
// certificates
if (psdb->bit_mask & certificates_present) {
#ifdef OSS_CRYPT_ASN1
for (i=psdb->certificates.count, pAny=psdb->certificates.certificates;
#else
for (i=psdb->certificates.count, pAny=psdb->certificates.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pAny++) {
if (!ICM_InsertTailBlob( psdi->pCertificateList, pAny))
goto CertInsertTailBlobError;
}
}
// crls
if (psdb->bit_mask & crls_present) {
#ifdef OSS_CRYPT_ASN1
for (i=psdb->crls.count, pAny=psdb->crls.crls;
#else
for (i=psdb->crls.count, pAny=psdb->crls.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pAny++) {
if (!ICM_InsertTailBlob( psdi->pCrlList, pAny))
goto CrlInsertTailBlobError;
}
}
// signerInfos
for (i=psdb->signerInfos.count, pAny=psdb->signerInfos.value;
i>0;
i--, pAny++) {
if (!ICM_InsertTailSigner( psdi->pSignerList, pAny))
goto SignerInfoInsertTailBlobError;
}
fRet = TRUE;
CommonReturn:
pcmi->psdi = psdi;
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
if (NULL != psdi) {
if(NULL != psdi->pSignerList)
delete psdi->pSignerList;
if(NULL != psdi->pCrlList)
delete psdi->pCrlList;
if(NULL != psdi->pCertificateList)
delete psdi->pCertificateList;
if(NULL != psdi->pAlgidList)
delete psdi->pAlgidList;
ICM_Free( psdi);
psdi = NULL;
}
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(DigestAlgorithmInsertTailBlobError) // error already set
TRACE_ERROR(GetContentInfoDataSizeError) // error already set
TRACE_ERROR(AllocContentInfoError) // error already set
TRACE_ERROR(GetContentInfoDataError) // error already set
TRACE_ERROR(CertInsertTailBlobError) // error already set
TRACE_ERROR(CrlInsertTailBlobError) // error already set
TRACE_ERROR(SignerInfoInsertTailBlobError) // error already set
SET_ERROR(NewSignerListError,E_OUTOFMEMORY)
SET_ERROR(NewCrlListError,E_OUTOFMEMORY)
SET_ERROR(NewCertificateListError,E_OUTOFMEMORY)
SET_ERROR(NewAlgidListError,E_OUTOFMEMORY)
SET_ERROR(SdiAllocError,E_OUTOFMEMORY)
}
//+-------------------------------------------------------------------------
// Get the CAPI algid from an encoded AlgidBlob
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetCapiFromAlgidBlob(
IN PCRYPT_DATA_BLOB pAlgidBlob,
OUT PDWORD pdwAlgidCapi)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
AlgorithmIdentifier *poai = NULL;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&poai,
AlgorithmIdentifier_PDU,
pAlgidBlob->pbData,
pAlgidBlob->cbData)))
goto Asn1DecodeAlgorithmIdentifierError;
if (!(ICM_GetOssCAPI( CRYPT_HASH_ALG_OID_GROUP_ID, poai, pdwAlgidCapi) ||
ICM_GetOssCAPI( CRYPT_SIGN_ALG_OID_GROUP_ID, poai, pdwAlgidCapi)))
goto GetCAPIError;
fRet = TRUE;
CommonReturn:
PkiAsn1FreeInfo(pDec, AlgorithmIdentifier_PDU, poai);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
*pdwAlgidCapi = 0;
goto CommonReturn;
SET_ERROR_VAR(Asn1DecodeAlgorithmIdentifierError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(GetCAPIError,CRYPT_E_UNKNOWN_ALGO)
}
//+-------------------------------------------------------------------------
// Create a hash list from a list of hash algid's
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_CreateHashList(
IN HCRYPTPROV hCryptProv,
IN OUT CHashList **ppHashList,
IN CBlobList *pAlgidList)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
CHashList *pHashList;
CBlobNode *pBlobNode;
CHashNode *pHashNode;
ICM_HASH_INFO HashInfo; ZEROSTRUCT(HashInfo);
if (NULL == (pHashList = new CHashList))
goto NewHashListError;
if (hCryptProv) {
for (pBlobNode=pAlgidList->Head();
pBlobNode;
pBlobNode=pBlobNode->Next()) {
if (!ICM_GetCapiFromAlgidBlob(
pBlobNode->Data(),
&HashInfo.dwAlgoCAPI))
goto GetCAPIError;
#ifndef CMS_PKCS7
HashInfo.hCryptProv = hCryptProv;
#endif // CMS_PKCS7
if (!CryptCreateHash(
hCryptProv,
HashInfo.dwAlgoCAPI,
NULL, // hKey - optional for MAC
0, // dwFlags
&HashInfo.hHash))
goto CreateHashError;
if (NULL == (pHashNode = new CHashNode))
goto NewHashNodeError;
pHashNode->SetData( &HashInfo);
pHashList->InsertTail( pHashNode);
}
}
fRet = TRUE;
CommonReturn:
*ppHashList = pHashList;
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
pHashList = NULL;
fRet = FALSE;
goto CommonReturn;
SET_ERROR(NewHashListError,E_OUTOFMEMORY)
SET_ERROR(NewHashNodeError,E_OUTOFMEMORY)
TRACE_ERROR(GetCAPIError) // error already set
TRACE_ERROR(CreateHashError) // error already set
}
//+-------------------------------------------------------------------------
// Update for decoding a signed message
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_UpdateDecodingSignedData(
IN OUT PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
SignedDataWithBlobs *psdb = NULL;
PBYTE pb = NULL;
DWORD cb;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
PBYTE pbDER = NULL;
DWORD cbDER;
ICM_HASH_INFO HashInfo; ZEROSTRUCT(HashInfo);
DWORD dwExceptionCode;
// Handle MappedFile Exceptions
__try {
if (PHASE_FIRST_FINAL == pcmi->dwPhase) {
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&psdb,
SignedDataWithBlobs_PDU,
pbData,
cbData)))
goto Asn1DecodeSignedDataError;
if (!ICM_GetListSignedData( pcmi, psdb))
goto GetListSignedDataError;
if (!ICM_CreateHashList(
pcmi->hCryptProv,
&pcmi->pHashList,
pcmi->psdi->pAlgidList))
goto CreateHashListError;
if (pcmi->psdi->pci->content.cbData) {
// Get the address & count of the contents octets of the DER
// encoding of the content. Since the content might be
// indefinite-length encoded, decode and re-encode as DER.
pb = pcmi->psdi->pci->content.pbData;
cb = pcmi->psdi->pci->content.cbData;
if (0 == strcmp(pszObjIdDataType,
pcmi->psdi->pci->pszContentType)
#ifdef CMS_PKCS7
|| pcmi->psdi->version >= CMSG_SIGNED_DATA_CMS_VERSION
#endif // CMS_PKCS7
) {
if (!ICM_ReEncodeAsOctetDER(
pb,
cb,
&pbDER,
&cbDER
))
goto ReEncodeAsOctetDERError;
if (pbDER) {
pb = pbDER;
cb = cbDER;
}
}
if (0 > Asn1UtilExtractContent( pb, cb, &cb, (const BYTE **)&pb))
goto ExtractContentError;
} else {
cb = 0;
}
} else {
assert (pcmi->dwFlags & CMSG_DETACHED_FLAG);
if (!(pcmi->dwFlags & CMSG_DETACHED_FLAG))
goto NonFinalNotDetachedError;
pb = (PBYTE)pbData;
cb = cbData;
}
if (!ICM_UpdateListDigest( pcmi->pHashList, pb, cb))
goto UpdateDigestError;
fRet = TRUE;
} __except(EXCEPTION_EXECUTE_HANDLER) {
dwExceptionCode = GetExceptionCode();
goto ExceptionError;
}
CommonReturn:
PkiAsn1FreeEncoded(ICM_GetEncoder(), pbDER);
PkiAsn1FreeInfo(pDec, SignedDataWithBlobs_PDU, psdb);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(Asn1DecodeSignedDataError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(ExtractContentError,CRYPT_E_UNEXPECTED_ENCODING)
SET_ERROR(NonFinalNotDetachedError,CRYPT_E_MSG_ERROR)
TRACE_ERROR(GetListSignedDataError) // error already set
TRACE_ERROR(CreateHashListError) // error already set
TRACE_ERROR(ReEncodeAsOctetDERError) // error already set
TRACE_ERROR(UpdateDigestError) // error already set
SET_ERROR_VAR(ExceptionError, dwExceptionCode)
}
#ifdef CMS_PKCS7
//+-------------------------------------------------------------------------
// Update for decoding an enveloped message
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_UpdateDecodingEnvelopedData(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
CmsEnvelopedData *ped = NULL;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
assert (PHASE_FIRST_FINAL == pcmi->dwPhase);
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **) &ped,
CmsEnvelopedData_PDU,
pbData,
cbData)))
goto Asn1DecodeError;
pcmi->pvMsg = ped;
if (NULL == (pcmi->pCertificateList = new CBlobList))
goto NewCertificateListError;
if (NULL == (pcmi->pCrlList = new CBlobList))
goto NewCrlListError;
if (ped->bit_mask & originatorInfo_present) {
OriginatorInfo *poi = &ped->originatorInfo;
DWORD i;
Any *pAny;
// certificates
if (poi->bit_mask & certificates_present) {
#ifdef OSS_CRYPT_ASN1
for (i=poi->certificates.count, pAny=poi->certificates.certificates;
#else
for (i=poi->certificates.count, pAny=poi->certificates.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pAny++) {
if (!ICM_InsertTailBlob( pcmi->pCertificateList, pAny))
goto CertInsertTailBlobError;
}
}
// crls
if (poi->bit_mask & crls_present) {
#ifdef OSS_CRYPT_ASN1
for (i=poi->crls.count, pAny=poi->crls.crls;
#else
for (i=poi->crls.count, pAny=poi->crls.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pAny++) {
if (!ICM_InsertTailBlob( pcmi->pCrlList, pAny))
goto CrlInsertTailBlobError;
}
}
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
if (NULL != pcmi->pCertificateList) {
delete pcmi->pCertificateList;
pcmi->pCertificateList = NULL;
}
if (NULL != pcmi->pCrlList) {
delete pcmi->pCrlList;
pcmi->pCrlList = NULL;
}
goto CommonReturn;
SET_ERROR_VAR(Asn1DecodeError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(NewCertificateListError,E_OUTOFMEMORY)
SET_ERROR(NewCrlListError,E_OUTOFMEMORY)
TRACE_ERROR(CertInsertTailBlobError)
TRACE_ERROR(CrlInsertTailBlobError)
}
#else
//+-------------------------------------------------------------------------
// Update for decoding an enveloped message
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_UpdateDecodingEnvelopedData(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData)
{
BOOL fRet;
EnvelopedData *ped = NULL;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
assert (PHASE_FIRST_FINAL == pcmi->dwPhase);
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&ped,
EnvelopedData_PDU,
pbData,
cbData)))
goto Asn1DecodeError;
pcmi->pvMsg = ped;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(Asn1DecodeError, PkiAsn1ErrToHr(Asn1Err))
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Find the HashNode corresponding to a CAPI Algid
//
// NB- Does not fail.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FindHashNodeFromCapiAlgid(
IN CHashList *pHashList,
IN DWORD dwAlgoCAPI,
OUT CHashNode **ppnHash)
{
CHashNode *pnHash;
for (pnHash=pHashList->Head(); pnHash; pnHash=pnHash->Next()) {
if (dwAlgoCAPI == pnHash->Data()->dwAlgoCAPI)
break;
}
*ppnHash = pnHash;
if(pnHash == NULL) {
SetLastError((DWORD) CRYPT_E_UNKNOWN_ALGO);
return FALSE;
}
return TRUE;
}
//+-------------------------------------------------------------------------
// Find the HashNode corresponding to an encoded Algid
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FindHashNodeFromEncodedAlgo(
IN CHashList *pHashList,
IN PCRYPT_DATA_BLOB pblobEncodedAlgorithm,
OUT CHashNode **ppnHash)
{
BOOL fRet;
DWORD dwAlgoCAPI;
if (!ICM_GetCapiFromAlgidBlob(
pblobEncodedAlgorithm,
&dwAlgoCAPI))
goto GetCAPIError;
fRet = ICM_FindHashNodeFromCapiAlgid( pHashList, dwAlgoCAPI, ppnHash);
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
*ppnHash = NULL;
goto CommonReturn;
TRACE_ERROR(GetCAPIError) // error already set
}
//+-------------------------------------------------------------------------
// Update for decoding a digested message
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_UpdateDecodingDigestedData(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
DigestedData *pdd = NULL;
PBYTE pb = NULL;
DWORD cb;
PBYTE pbDER = NULL;
DWORD cbDER;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
ICM_HASH_INFO HashInfo; ZEROSTRUCT(HashInfo);
CHashNode *pHashNode;
if (PHASE_FIRST_FINAL == pcmi->dwPhase) {
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&pdd,
DigestedData_PDU,
pbData,
cbData)))
goto Asn1DecodeError;
pcmi->pvMsg = pdd;
if (!ICM_GetOssCAPI(
CRYPT_HASH_ALG_OID_GROUP_ID,
&pdd->digestAlgorithm,
&HashInfo.dwAlgoCAPI))
goto GetCAPIError;
#ifndef CMS_PKCS7
HashInfo.hCryptProv = pcmi->hCryptProv;
#endif // CMS_PKCS7
if (!CryptCreateHash(
pcmi->hCryptProv,
HashInfo.dwAlgoCAPI,
NULL, // hKey - optional for MAC
0, // dwFlags
&HashInfo.hHash))
goto CreateHashError;
if (NULL == (pcmi->pHashList = new CHashList))
goto NewHashListError;
if (NULL == (pHashNode = new CHashNode))
goto NewHashNodeError;
pHashNode->SetData( &HashInfo);
pcmi->pHashList->InsertTail( pHashNode);
if (pdd->contentInfo.bit_mask & content_present) {
// Get the address & count of the contents octets of the DER
// encoding of the content. Since the content might be
// indefinite-length encoded, decode and re-encode as DER.
pb = (PBYTE)pdd->contentInfo.content.value;
cb = (DWORD)pdd->contentInfo.content.length;
if (ICM_EqualObjectIDs(
&pdd->contentInfo.contentType,
&aoidMessages[ CMSG_DATA - 1])
#ifdef CMS_PKCS7
|| pdd->version >= CMSG_HASHED_DATA_V2
#endif // CMS_PKCS7
) {
if (!ICM_ReEncodeAsOctetDER(
pb,
cb,
&pbDER,
&cbDER
))
goto ReEncodeAsOctetDERError;
if (pbDER) {
pb = pbDER;
cb = cbDER;
}
}
if (0 > Asn1UtilExtractContent( pb, cb, &cb, (const BYTE **)&pb))
goto ExtractContentError;
} else {
cb = 0;
}
} else {
assert (pcmi->dwFlags & CMSG_DETACHED_FLAG);
if (!(pcmi->dwFlags & CMSG_DETACHED_FLAG))
goto NonFinalNotDetachedError;
pb = (PBYTE)pbData;
cb = cbData;
}
if (!ICM_UpdateListDigest( pcmi->pHashList, pb, cb))
goto UpdateDigestError;
fRet = TRUE;
CommonReturn:
PkiAsn1FreeEncoded(ICM_GetEncoder(), pbDER);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
PkiAsn1FreeInfo(pDec, DigestedData_PDU, pdd);
pcmi->pvMsg = NULL;
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(Asn1DecodeError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(GetCAPIError,CRYPT_E_UNKNOWN_ALGO)
SET_ERROR(NewHashListError,E_OUTOFMEMORY)
SET_ERROR(NewHashNodeError,E_OUTOFMEMORY)
SET_ERROR(ExtractContentError,CRYPT_E_UNEXPECTED_ENCODING)
SET_ERROR(NonFinalNotDetachedError,CRYPT_E_MSG_ERROR)
TRACE_ERROR(CreateHashError) // error already set
TRACE_ERROR(UpdateDigestError) // error already set
TRACE_ERROR(ReEncodeAsOctetDERError) // error already set
}
//+-------------------------------------------------------------------------
// Update for decoding a data message
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_UpdateDecodingData(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
OctetStringType *poos = NULL;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
if (PHASE_FIRST_FINAL != pcmi->dwPhase)
goto NonFirstFinalError;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&poos,
OctetStringType_PDU,
pbData,
cbData)))
goto Asn1DecodeError;
pcmi->pvMsg = poos;
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
PkiAsn1FreeInfo(pDec, OctetStringType_PDU, poos);
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(Asn1DecodeError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(NonFirstFinalError,CRYPT_E_MSG_ERROR)
}
//+-------------------------------------------------------------------------
// Write a buffer to a file
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_WriteBufToFile(
LPCSTR pszFileName,
PBYTE pbData,
DWORD cbData)
{
BOOL fRet;
HANDLE hFile;
DWORD cbWritten;
if( INVALID_HANDLE_VALUE == (hFile = CreateFile( pszFileName, GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, 0, NULL))) {
goto CreateFileError;
}
if (!WriteFile( hFile, pbData, cbData, &cbWritten, NULL) ||
(cbWritten != cbData)) {
goto WriteFileError;
}
CloseHandle( hFile);
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(CreateFileError)
TRACE_ERROR(WriteFileError)
}
//+-------------------------------------------------------------------------
// Update the content of a cryptographic message. Depending on how the
// message was opened, the content is either encoded or decoded.
//
// This function is repetitively called to append to the message content.
// fFinal is set to identify the last update. On fFinal, the encode/decode
// is completed. The encoded/decoded content and the decoded parameters
// are valid until the open and all duplicated handles are closed.
//--------------------------------------------------------------------------
BOOL
WINAPI
#ifdef DEBUG_CRYPT_ASN1_MASTER
ICMTest_NewCryptMsgUpdate(
#else
CryptMsgUpdate(
#endif
IN HCRYPTMSG hCryptMsg,
IN const BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PCRYPT_MSG_INFO pcmi = (PCRYPT_MSG_INFO)hCryptMsg;
ContentInfo *pci = NULL;
ASN1error_e Asn1Err;
PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
DWORD dwExceptionCode;
ICM_Lock( pcmi); // Single thread access to HCRYPTMSG
// Handle MappedFile Exceptions
__try {
if (!ICM_AdvanceMsgPhase( &pcmi->dwPhase, fFinal))
goto AdvancePhaseError;
if (pcmi->fEncoding) {
if (!(((pcmi->dwFlags & CMSG_DETACHED_FLAG) &&
(PHASE_FIRST_ONGOING == pcmi->dwPhase)) ||
(pcsi && (pcmi->dwPhase < PHASE_SECOND_ONGOING)) ||
(PHASE_FIRST_FINAL == pcmi->dwPhase)))
goto EncodingPhaseError;
switch (pcmi->dwMsgType) {
case CMSG_DATA:
fRet = ICM_UpdateEncodingData(
pcmi,
pbData,
cbData,
fFinal);
break;
case CMSG_SIGNED:
fRet = ICM_UpdateEncodingSignedData(
pcmi,
pbData,
cbData,
fFinal);
break;
case CMSG_ENVELOPED:
fRet = ICM_UpdateEncodingEnvelopedData(
pcmi,
pbData,
cbData,
fFinal);
break;
case CMSG_HASHED:
fRet = ICM_UpdateEncodingDigestedData(
pcmi,
pbData,
cbData,
fFinal);
break;
case CMSG_SIGNED_AND_ENVELOPED:
#if 0
fRet = ICM_UpdateEncodingSignedAndEnvelopedData(
pcmi,
pbData,
cbData,
fFinal);
break;
#endif
case CMSG_ENCRYPTED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
} else {
// decode
ASN1decoding_t pDec = ICM_GetDecoder();
LONG lth;
PBYTE pb;
DWORD cb;
if (pcsi) {
if (pcmi->dwPhase < PHASE_SECOND_ONGOING) {
fRet = ICMS_UpdateDecoding( pcmi, pbData, cbData, fFinal);
if (fRet)
goto CommonReturn;
else
goto ErrorReturn;
}
// else
// streaming detached
}
if (PHASE_FIRST_ONGOING == pcmi->dwPhase)
goto FirstOngoingDecodeError;
if ((0 == (pcmi->dwFlags & CMSG_DETACHED_FLAG)) &&
(PHASE_FIRST_FINAL != pcmi->dwPhase))
goto SecondOngoingNonDetachedError;
if ((PHASE_FIRST_FINAL == pcmi->dwPhase) &&
(0 == pcmi->dwMsgType)) {
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&pci,
ContentInfoNC_PDU,
pbData,
cbData)))
goto Asn1DecodeContentInfoError;
if (0 == (lth = ICM_ObjIdToIndex( &pci->contentType)))
goto InvalidMsgType;
pcmi->dwMsgType = (DWORD)lth;
pb = (PBYTE)pci->content.value;
cb = pci->content.length;
} else {
pb = (PBYTE)pbData;
cb = cbData;
}
switch (pcmi->dwMsgType) {
case CMSG_DATA:
fRet = ICM_UpdateDecodingData( pcmi, pb, cb);
break;
case CMSG_SIGNED:
fRet = ICM_UpdateDecodingSignedData( pcmi, pb, cb);
break;
case CMSG_ENVELOPED:
fRet = ICM_UpdateDecodingEnvelopedData( pcmi, pb, cb);
break;
case CMSG_HASHED:
fRet = ICM_UpdateDecodingDigestedData( pcmi, pb, cb);
break;
case CMSG_SIGNED_AND_ENVELOPED:
case CMSG_ENCRYPTED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
}
if (!fRet)
goto ErrorReturn;
} __except(EXCEPTION_EXECUTE_HANDLER) {
dwExceptionCode = GetExceptionCode();
goto ExceptionError;
}
CommonReturn:
if (pci)
PkiAsn1FreeInfo(ICM_GetDecoder(), ContentInfoNC_PDU, pci);
ICM_Unlock( pcmi);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(EncodingPhaseError,CRYPT_E_MSG_ERROR)
SET_ERROR(FirstOngoingDecodeError,CRYPT_E_MSG_ERROR)
SET_ERROR(SecondOngoingNonDetachedError,CRYPT_E_MSG_ERROR)
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(InvalidMsgType,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR_VAR(Asn1DecodeContentInfoError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(AdvancePhaseError) // error already set
SET_ERROR_VAR(ExceptionError, dwExceptionCode)
}
BOOL
WINAPI
ICM_VerifySignature(
IN HCRYPTHASH hHash,
IN HCRYPTKEY hPubKey,
IN DWORD dwPubKeyAlgId,
IN DWORD dwPubKeyFlags,
IN PBYTE pbEncryptedDigest,
IN DWORD cbEncryptedDigest)
{
BOOL fRet;
BYTE rgbDssSignature[CERT_DSS_SIGNATURE_LEN];
PBYTE pb = NULL;
if (CALG_NO_SIGN == dwPubKeyAlgId) {
DWORD cbData;
// The encrypted digest isn't signed. It should be the same as
// the calculated hash
if (!CryptGetHashParam(
hHash,
HP_HASHVAL,
NULL,
&cbData,
0)) // dwFlags
goto GetHashParamSizeError;
if (NULL == (pb = (PBYTE)ICM_AllocA( cbData)))
goto AllocHashParamError;
if (!CryptGetHashParam(
hHash,
HP_HASHVAL,
pb,
&cbData,
0)) // dwFlags
goto GetHashParamError;
// Compare the calculated hash with the "encrypted digest"
if (cbData != cbEncryptedDigest ||
0 != memcmp(pb, pbEncryptedDigest, cbData))
goto NoSignHashCompareError;
fRet = TRUE;
goto CommonReturn;
}
if (CALG_DSS_SIGN == dwPubKeyAlgId &&
0 == (dwPubKeyFlags & CRYPT_OID_INHIBIT_SIGNATURE_FORMAT_FLAG)) {
DWORD cbData;
// Convert from ASN.1 sequence of two integers to the CSP signature
// format.
cbData = sizeof(rgbDssSignature);
if (!CryptDecodeObject(
X509_ASN_ENCODING,
X509_DSS_SIGNATURE,
pbEncryptedDigest,
cbEncryptedDigest,
0, // dwFlags
rgbDssSignature,
&cbData
))
goto DecodeError;
pbEncryptedDigest = rgbDssSignature;
assert(cbData == sizeof(rgbDssSignature));
cbEncryptedDigest = sizeof(rgbDssSignature);
} else {
if (NULL == (pb = (PBYTE)ICM_AllocA( cbEncryptedDigest)))
goto AllocError;
ICM_ReverseCopy( pb, pbEncryptedDigest, cbEncryptedDigest);
pbEncryptedDigest = pb;
}
fRet = CryptVerifySignature(
hHash,
pbEncryptedDigest,
cbEncryptedDigest,
hPubKey,
NULL, // pwszDescription
0); // dwFlags
CommonReturn:
ICM_FreeA(pb);
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetHashParamSizeError)
TRACE_ERROR(AllocHashParamError)
TRACE_ERROR(GetHashParamError)
SET_ERROR(NoSignHashCompareError, NTE_BAD_SIGNATURE)
TRACE_ERROR(DecodeError)
TRACE_ERROR(AllocError)
}
//+-------------------------------------------------------------------------
// Verify a signature using the authenticated attributes blob
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_VerifySignatureAuthAttrBlob(
IN PCRYPT_MSG_INFO pcmi,
IN CSignerNode *pSignerNode,
IN HCRYPTPROV hCryptProv,
IN HCRYPTKEY hPubKey,
IN DWORD dwDigestAlgorithm,
IN DWORD dwPubKeyAlgorithm,
IN DWORD dwPubKeyFlags,
IN PBYTE pbEncryptedDigest,
IN DWORD cbEncryptedDigest)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
SignerInfoWithAABlob *psiaab = NULL;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
CRYPT_DATA_BLOB DataBlob;
HCRYPTHASH hHashAttrBlob = NULL;
PBYTE pb = NULL;
DWORD cb;
DataBlob = pSignerNode->Data()->blob;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&psiaab,
SignerInfoWithAABlob_PDU,
DataBlob.pbData,
DataBlob.cbData)))
goto Asn1DecodeSignerInfoWithAABlobError;
cb = psiaab->authenticatedAttributes.length;
if (NULL == (pb = (PBYTE)ICM_AllocA(cb)))
goto AuthenticatedAttributesAllocError;
memcpy( pb, psiaab->authenticatedAttributes.value, cb);
// The encoded blob should contain 0xa0 ([0] IMPLICIT) as the tag,
// but the tag needs to be 0x31 (SET OF) for the hash computation.
if (*pb != (ICM_TAG_CONTEXT_0 | ICM_TAG_CONSTRUCTED)) // [0] IMPLICIT
goto AuthAttrsTagError;
*pb = ICM_TAG_SET; // SET OF
if (!ICM_GetBlobHash(
hCryptProv,
dwDigestAlgorithm,
pb,
cb,
&hHashAttrBlob))
goto HashAttrBlobError;
if (!ICM_VerifySignature(
hHashAttrBlob,
hPubKey,
dwPubKeyAlgorithm,
dwPubKeyFlags,
pbEncryptedDigest,
cbEncryptedDigest))
goto VerifySignatureError;
fRet = TRUE;
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfoWithAABlob_PDU, psiaab);
if (hHashAttrBlob)
CryptDestroyHash( hHashAttrBlob);
ICM_FreeA(pb);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(Asn1DecodeSignerInfoWithAABlobError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(AuthAttrsTagError,CRYPT_E_BAD_ENCODE)
TRACE_ERROR(AuthenticatedAttributesAllocError) // error already set
TRACE_ERROR(HashAttrBlobError) // error already set
TRACE_ERROR(VerifySignatureError) // error already set
}
#ifdef CMS_PKCS7
BOOL
WINAPI
ICM_GetVerifySignatureStuff(
IN DWORD dwSignerType,
void *pvSigner,
IN OUT HCRYPTPROV *phCryptProv,
OUT HCRYPTKEY *phPubKey,
OUT DWORD *pdwPubKeyAlgId,
OUT DWORD *pdwPubKeyFlags)
{
BOOL fRet;
PCCRYPT_OID_INFO pOIDInfo;
HCRYPTPROV hCryptProv;
PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL; // not allocated
CERT_PUBLIC_KEY_INFO PubKeyInfo;
BYTE *pbAllocPubKeyPara = NULL;
*pdwPubKeyAlgId = 0;
*pdwPubKeyFlags = 0;
switch (dwSignerType) {
case CMSG_VERIFY_SIGNER_PUBKEY:
pPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) pvSigner;
break;
case CMSG_VERIFY_SIGNER_CHAIN:
{
PCCERT_CHAIN_CONTEXT pChain = (PCCERT_CHAIN_CONTEXT) pvSigner;
// All chains have at least the leaf certificate context
assert(pChain->cChain && pChain->rgpChain[0]->cElement);
pvSigner =
(void *) pChain->rgpChain[0]->rgpElement[0]->pCertContext;
dwSignerType = CMSG_VERIFY_SIGNER_CERT;
}
// fall through
case CMSG_VERIFY_SIGNER_CERT:
{
PCCERT_CONTEXT pSigner = (PCCERT_CONTEXT) pvSigner;
PCRYPT_OBJID_BLOB pPara;
pPubKeyInfo = &pSigner->pCertInfo->SubjectPublicKeyInfo;
pPara = &pPubKeyInfo->Algorithm.Parameters;
// Check if the public key parameters were omitted
// from the encoded certificate. If omitted, try
// to use the certificate's CERT_PUBKEY_ALG_PARA_PROP_ID
// property.
if (0 == pPara->cbData ||
ICM_TAG_NULL_OCTETS == *pPara->pbData) {
DWORD cbData;
if (CertGetCertificateContextProperty(
pSigner,
CERT_PUBKEY_ALG_PARA_PROP_ID,
NULL, // pvData
&cbData) && 0 < cbData
&&
(pbAllocPubKeyPara = (BYTE *) ICM_Alloc(
cbData))
&&
CertGetCertificateContextProperty(
pSigner,
CERT_PUBKEY_ALG_PARA_PROP_ID,
pbAllocPubKeyPara,
&cbData)) {
PubKeyInfo = *pPubKeyInfo;
PubKeyInfo.Algorithm.Parameters.pbData =
pbAllocPubKeyPara;
PubKeyInfo.Algorithm.Parameters.cbData = cbData;
pPubKeyInfo = &PubKeyInfo;
}
}
}
break;
case CMSG_VERIFY_SIGNER_NULL:
break;
default:
goto InvalidSignerType;
}
if (CMSG_VERIFY_SIGNER_NULL == dwSignerType)
;
else if (pOIDInfo = CryptFindOIDInfo(
CRYPT_OID_INFO_OID_KEY,
pPubKeyInfo->Algorithm.pszObjId,
CRYPT_PUBKEY_ALG_OID_GROUP_ID
)) {
DWORD cExtra = pOIDInfo->ExtraInfo.cbData / sizeof(DWORD);
DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
*pdwPubKeyAlgId = pOIDInfo->Algid;
if (1 <= cExtra)
*pdwPubKeyFlags = pdwExtra[0];
}
hCryptProv = *phCryptProv;
if (0 == hCryptProv) {
hCryptProv = I_CryptGetDefaultCryptProv(*pdwPubKeyAlgId);
if (0 == hCryptProv)
goto GetDefaultCryptProvError;
*phCryptProv = hCryptProv;
}
if (CMSG_VERIFY_SIGNER_NULL == dwSignerType) {
// The signature is simply the hash octets
*pdwPubKeyAlgId = CALG_NO_SIGN;
*phPubKey = NULL;
// import the signer's public key
} else if (!CryptImportPublicKeyInfo(
hCryptProv,
X509_ASN_ENCODING,
pPubKeyInfo,
phPubKey))
goto ImportKeyFailed;
fRet = TRUE;
CommonReturn:
ICM_Free(pbAllocPubKeyPara);
return fRet;
ErrorReturn:
fRet = FALSE;
*phPubKey = 0;
goto CommonReturn;
SET_ERROR(InvalidSignerType, E_INVALIDARG)
TRACE_ERROR(GetDefaultCryptProvError) // error already set
TRACE_ERROR(ImportKeyFailed) // error already set
}
BOOL
WINAPI
ICM_FindSignerInfo(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwIndex,
OUT PVOID *ppv);
//+-------------------------------------------------------------------------
// Verify a signature
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlVerifySignatureEx(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA pPara
)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
SignerInfoWithBlobs *psib = NULL;
CSignerNode *pSignerNode = NULL;
HCRYPTHASH hHashAttr = NULL;
HCRYPTHASH hHashDup = NULL;
HCRYPTHASH hHash = NULL;
HCRYPTKEY hPubKey = NULL;
HCRYPTPROV hCryptProv; // doen't need to be released
DWORD dwPubKeyAlgId;
DWORD dwPubKeyFlags;
PBYTE pbHash;
ULONG cb;
Any anyValue;
DWORD cbMessageDigest;
PBYTE pbMessageDigest;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
CRYPT_DATA_BLOB DataBlob;
CHashNode *pnHash;
PICM_HASH_INFO pHashInfo;
if (!ICM_FindSignerInfo(pcmi, pPara->dwSignerIndex, (PVOID *)&pSignerNode))
goto FindSignerInfoError;
DataBlob = pSignerNode->Data()->blob;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&psib,
SignerInfoWithBlobs_PDU,
DataBlob.pbData,
DataBlob.cbData)))
goto DecodeSignerInfoWithBlobsError;
if (!ICM_FindHashNodeFromEncodedAlgo(
pcmi->pHashList,
(PCRYPT_DATA_BLOB)&psib->digestAlgorithm,
&pnHash))
goto GetHashNodeFromEncodedAlgoError;
pHashInfo = pnHash->Data();
if (pPara->hCryptProv)
hCryptProv = pPara->hCryptProv;
else if (pcmi->fDefaultCryptProv)
hCryptProv = 0;
else
hCryptProv = pcmi->hCryptProv;
if (!ICM_GetVerifySignatureStuff(
pPara->dwSignerType,
pPara->pvSigner,
&hCryptProv,
&hPubKey,
&dwPubKeyAlgId,
&dwPubKeyFlags)) goto GetSignatureStuffError;
if (psib->bit_mask & authAttributes_present) {
// find the message digest attr value
if (!ICM_GetAttrValue(
(Attributes *)&psib->authAttributes, // same, except for NOCOPY
&oidMessageDigest,
&anyValue))
goto FindAttrError;
// find the message digest octets
if (!Asn1UtilExtractContent(
#ifdef OSS_CRYPT_ASN1
anyValue.value,
#else
(const BYTE *) anyValue.value,
#endif // OSS_CRYPT_ASN1
anyValue.length,
&cbMessageDigest,
(const BYTE **)&pbMessageDigest))
goto ExtractContentError;
// get the hash value computed on the data
if (!ICM_GetListHashValue( pnHash, &cb, &pbHash))
goto GetHashValueError;
// hash sizes equal?
if (cb != cbMessageDigest)
goto HashCompareSizeError;
// hash octets equal?
if (memcmp( pbMessageDigest, pbHash, cb))
goto HashCompareValueError;
// Now that we have verified the message digest octets,
// get the hash of the authenticated attributes.
// Should check the content type attribute as well.
if (!ICM_GetAttrsHash(
pHashInfo->dwAlgoCAPI,
hCryptProv,
(Attributes *)&psib->authAttributes, // same, except for NOCOPY
&hHashAttr))
goto GetAuthAttrsHashError;
hHash = hHashAttr;
} else {
if (!ICM_DupListHash( pnHash, hCryptProv, &hHashDup))
goto DupListHashError;
hHash = hHashDup;
}
// verify the hash, signature, and public key are consistent
fRet = ICM_VerifySignature(
hHash,
hPubKey,
dwPubKeyAlgId,
dwPubKeyFlags,
psib->encryptedDigest.value,
psib->encryptedDigest.length);
if (!fRet && hHashAttr) {
// The hash of the authenticated attributes failed.
// Maybe they hashed incorrectly-DER-encoded authenticated attributes
// and gave us that encoding. Hash and verify the actual encoding of
// the authattrs that they gave us. There is a bug in IE3.0 which hits
// this path, due to a bug in the then-current OSS libraries.
fRet = ICM_VerifySignatureAuthAttrBlob(
pcmi,
pSignerNode,
hCryptProv,
hPubKey,
pHashInfo->dwAlgoCAPI,
dwPubKeyAlgId,
dwPubKeyFlags,
psib->encryptedDigest.value,
psib->encryptedDigest.length);
}
if (!fRet)
goto VerifySignatureError;
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, psib);
if (hPubKey)
CryptDestroyKey(hPubKey);
if (hHashAttr)
CryptDestroyHash( hHashAttr);
if (hHashDup)
CryptDestroyHash( hHashDup);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
// if (hHash && (0 == (pcmi->dwFlags & CMSG_DETACHED_FLAG)))
// CryptDestroyHash( hHash);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(FindSignerInfoError) // error already set
SET_ERROR(FindAttrError,CRYPT_E_AUTH_ATTR_MISSING)
SET_ERROR(HashCompareSizeError,CRYPT_E_HASH_VALUE)
SET_ERROR(HashCompareValueError,CRYPT_E_HASH_VALUE)
SET_ERROR(ExtractContentError,CRYPT_E_UNEXPECTED_ENCODING)
SET_ERROR_VAR(DecodeSignerInfoWithBlobsError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(GetHashValueError) // error already set
TRACE_ERROR(GetAuthAttrsHashError) // error already set
TRACE_ERROR(GetSignatureStuffError) // error already set
TRACE_ERROR(GetHashNodeFromEncodedAlgoError) // error already set
TRACE_ERROR(DupListHashError) // error already set
TRACE_ERROR(VerifySignatureError) // error already set
dwFlags;
}
//+-------------------------------------------------------------------------
// Verify a signature
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlVerifySignature(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN PCERT_INFO pci)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
SignerInfoWithBlobs *psib = NULL;
CSignerNode *pSignerNode = NULL;
ULONG cbIssuer;
PBYTE pb = NULL;
ULONG cb;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
CRYPT_DATA_BLOB DataBlob;
CertIdentifier *pOssCertId = NULL;
IssuerAndSerialNumber *pisn; // not allocated
DWORD dwSignerIndex;
CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA ExPara;
ZEROSTRUCT(ExPara);
ExPara.cbSize = sizeof(ExPara);
// ExPara.hCryptProv =
// ExPara.dwSignerIndex =
ExPara.dwSignerType = CMSG_VERIFY_SIGNER_PUBKEY;
ExPara.pvSigner = (void *) &pci->SubjectPublicKeyInfo;
cb = pci->SerialNumber.cbData;
if (NULL == (pb = (PBYTE)ICM_AllocA( cb)))
goto SerialNumberAllocError;
cbIssuer = pci->Issuer.cbData;
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
{
for (pSignerNode=pcmi->psdi->pSignerList->Head(), dwSignerIndex = 0;
pSignerNode;
pSignerNode = pSignerNode->Next(), dwSignerIndex++) {
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, psib);
psib = NULL;
PkiAsn1FreeInfo(pDec, CertIdentifier_PDU, pOssCertId);
pOssCertId = NULL;
DataBlob = pSignerNode->Data()->blob;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&psib,
SignerInfoWithBlobs_PDU,
DataBlob.pbData,
DataBlob.cbData)))
goto DecodeSignerInfoWithBlobsError;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&pOssCertId,
CertIdentifier_PDU,
(BYTE *) psib->sid.value,
psib->sid.length)))
goto DecodeCertIdentifierError;
switch (pOssCertId->choice) {
case issuerAndSerialNumber_chosen:
pisn = &pOssCertId->u.issuerAndSerialNumber;
if (pisn->issuer.length != cbIssuer)
break;
if (0 != memcmp( pci->Issuer.pbData,
pisn->issuer.value, cbIssuer))
break;
// We need to add an integer method to compare
// big-endian internal to a little-endian external
// value.
if (pisn->serialNumber.length != cb)
break;
ICM_ReverseCopy( pb, pisn->serialNumber.value, cb);
if (0 == memcmp( pb, pci->SerialNumber.pbData, cb))
goto VerifyFoundSigner;
break;
case subjectKeyIdentifier_chosen:
// Go for it. See if we are able to verify using
// the public key for this signer
ExPara.dwSignerIndex = dwSignerIndex;
fRet = ICM_ControlVerifySignatureEx(
pcmi,
dwFlags,
&ExPara
);
if (fRet)
goto CommonReturn;
break;
}
}
// No signer was found
break;
}
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
assert(NULL == pSignerNode);
goto SignerNotFound;
VerifyFoundSigner:
ExPara.dwSignerIndex = dwSignerIndex;
fRet = ICM_ControlVerifySignatureEx(
pcmi,
dwFlags,
&ExPara
);
if (!fRet)
goto ErrorReturn;
CommonReturn:
ICM_FreeA( pb);
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, psib);
PkiAsn1FreeInfo(pDec, CertIdentifier_PDU, pOssCertId);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(InvalidMsgType,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR_VAR(DecodeCertIdentifierError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(DecodeSignerInfoWithBlobsError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(SignerNotFound,CRYPT_E_SIGNER_NOT_FOUND)
TRACE_ERROR(SerialNumberAllocError) // error already set
}
#else
BOOL
WINAPI
ICM_GetVerifySignatureStuff(
IN PCERT_INFO pci,
IN OUT HCRYPTPROV *phCryptProv,
OUT HCRYPTKEY *phPubKey,
OUT DWORD *pdwPubKeyAlgId,
OUT DWORD *pdwPubKeyFlags)
{
BOOL fRet;
PCCRYPT_OID_INFO pOIDInfo;
HCRYPTPROV hCryptProv;
*pdwPubKeyAlgId = 0;
*pdwPubKeyFlags = 0;
if (pOIDInfo = CryptFindOIDInfo(
CRYPT_OID_INFO_OID_KEY,
pci->SubjectPublicKeyInfo.Algorithm.pszObjId,
CRYPT_PUBKEY_ALG_OID_GROUP_ID
)) {
DWORD cExtra = pOIDInfo->ExtraInfo.cbData / sizeof(DWORD);
DWORD *pdwExtra = (DWORD *) pOIDInfo->ExtraInfo.pbData;
*pdwPubKeyAlgId = pOIDInfo->Algid;
if (1 <= cExtra)
*pdwPubKeyFlags = pdwExtra[0];
}
hCryptProv = *phCryptProv;
if (0 == hCryptProv) {
hCryptProv = I_CryptGetDefaultCryptProv(*pdwPubKeyAlgId);
if (0 == hCryptProv)
goto GetDefaultCryptProvError;
*phCryptProv = hCryptProv;
}
// import the signer's public key
if (!CryptImportPublicKeyInfo(
hCryptProv,
X509_ASN_ENCODING,
&pci->SubjectPublicKeyInfo,
phPubKey))
goto ImportKeyFailed;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
*phPubKey = 0;
goto CommonReturn;
TRACE_ERROR(GetDefaultCryptProvError) // error already set
TRACE_ERROR(ImportKeyFailed) // error already set
}
//+-------------------------------------------------------------------------
// Verify a signature
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlVerifySignature(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN PCERT_INFO pci)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
SignerInfoWithBlobs *psib = NULL;
CSignerNode *pSignerNode = NULL;
SignerInfo *psi = NULL;
Any *pc; // &content
HCRYPTHASH hHashAttr = NULL;
HCRYPTHASH hHashDup = NULL;
HCRYPTHASH hHash = NULL;
HCRYPTKEY hPubKey = NULL;
HCRYPTPROV hCryptProv;
DWORD dwPubKeyAlgId;
DWORD dwPubKeyFlags;
ULONG cbIssuer;
PBYTE pbHash;
PBYTE pb = NULL;
ULONG cb;
Any anyValue;
DWORD cbMessageDigest;
PBYTE pbMessageDigest;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
CRYPT_DATA_BLOB DataBlob;
IssuerAndSerialNumber *pisn = NULL;
CHashNode *pnHash;
PICM_HASH_INFO pHashInfo;
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
{
pc = (Any *)&pcmi->psdi->pci->content;
cb = pci->SerialNumber.cbData;
if (NULL == (pb = (PBYTE)ICM_AllocA( cb)))
goto SerialNumberAllocError;
cbIssuer = pci->Issuer.cbData;
for (pSignerNode=pcmi->psdi->pSignerList->Head();
pSignerNode;
pSignerNode = pSignerNode->Next()) {
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, psib);
psib = NULL;
PkiAsn1FreeInfo(pDec, IssuerAndSerialNumber_PDU, pisn);
pisn = NULL;
DataBlob = pSignerNode->Data()->blob;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&psib,
SignerInfoWithBlobs_PDU,
DataBlob.pbData,
DataBlob.cbData)))
goto DecodeSignerInfoWithBlobsError;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&pisn,
IssuerAndSerialNumber_PDU,
(BYTE *) psib->issuerAndSerialNumber.value,
psib->issuerAndSerialNumber.length)))
goto DecodeIssuerAndSerialNumberError;
if (pisn->issuer.length != cbIssuer)
continue;
if (0 != memcmp( pci->Issuer.pbData, pisn->issuer.value, cbIssuer))
continue;
// We need to add an integer method to compare big-endian
// internal to a little-endian external value.
if (pisn->serialNumber.length != cb)
continue;
ICM_ReverseCopy( pb, pisn->serialNumber.value, cb);
if (0 != memcmp( pb, pci->SerialNumber.pbData, cb))
continue;
break;
}
// The matching signer (if found) is in psib
// If no signer found, pSignerNode == NULL
ICM_FreeA( pb);
pb = NULL;
break;
}
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
if (NULL == pSignerNode)
goto SignerNotFound;
if (!ICM_FindHashNodeFromEncodedAlgo(
pcmi->pHashList,
(PCRYPT_DATA_BLOB)&psib->digestAlgorithm,
&pnHash))
goto GetHashNodeFromEncodedAlgoError;
pHashInfo = pnHash->Data();
if (pcmi->fDefaultCryptProv)
hCryptProv = 0;
else
hCryptProv = pcmi->hCryptProv;
if (!ICM_GetVerifySignatureStuff(
pci,
&hCryptProv,
&hPubKey,
&dwPubKeyAlgId,
&dwPubKeyFlags)) goto GetSignatureStuffError;
if (psib->bit_mask & authAttributes_present) {
// find the message digest attr value
if (!ICM_GetAttrValue(
(Attributes *)&psib->authAttributes, // same, except for NOCOPY
&oidMessageDigest,
&anyValue))
goto FindAttrError;
// find the message digest octets
if (!Asn1UtilExtractContent(
(BYTE *) anyValue.value,
anyValue.length,
&cbMessageDigest,
(const BYTE **)&pbMessageDigest))
goto ExtractContentError;
// get the hash value computed on the data
if (!ICM_GetListHashValue( pnHash, &cb, &pbHash))
goto GetHashValueError;
// hash sizes equal?
if (cb != cbMessageDigest)
goto HashCompareSizeError;
// hash octets equal?
if (memcmp( pbMessageDigest, pbHash, cb))
goto HashCompareValueError;
// Now that we have verified the message digest octets,
// get the hash of the authenticated attributes.
// Should check the content type attribute as well.
if (!ICM_GetAttrsHash(
pHashInfo->dwAlgoCAPI,
hCryptProv,
(Attributes *)&psib->authAttributes, // same, except for NOCOPY
&hHashAttr))
goto GetAuthAttrsHashError;
hHash = hHashAttr;
} else {
if (!ICM_DupListHash( pnHash, hCryptProv, &hHashDup))
goto DupListHashError;
hHash = hHashDup;
}
// verify the hash, signature, and public key are consistent
fRet = ICM_VerifySignature(
hHash,
hPubKey,
dwPubKeyAlgId,
dwPubKeyFlags,
psib->encryptedDigest.value,
psib->encryptedDigest.length);
if (!fRet && hHashAttr) {
// The hash of the authenticated attributes failed.
// Maybe they hashed incorrectly-DER-encoded authenticated attributes
// and gave us that encoding. Hash and verify the actual encoding of
// the authattrs that they gave us. There is a bug in IE3.0 which hits
// this path, due to a bug in the then-current OSS libraries.
fRet = ICM_VerifySignatureAuthAttrBlob(
pcmi,
pSignerNode,
hCryptProv,
hPubKey,
pHashInfo->dwAlgoCAPI,
dwPubKeyAlgId,
dwPubKeyFlags,
psib->encryptedDigest.value,
psib->encryptedDigest.length);
}
if (!fRet)
goto VerifySignatureError;
CommonReturn:
ICM_FreeA( pb);
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, psib);
PkiAsn1FreeInfo(pDec, IssuerAndSerialNumber_PDU, pisn);
if (hPubKey)
CryptDestroyKey(hPubKey);
if (hHashAttr)
CryptDestroyHash( hHashAttr);
if (hHashDup)
CryptDestroyHash( hHashDup);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
// if (hHash && (0 == (pcmi->dwFlags & CMSG_DETACHED_FLAG)))
// CryptDestroyHash( hHash);
fRet = FALSE;
goto CommonReturn;
SET_ERROR(FindAttrError,CRYPT_E_AUTH_ATTR_MISSING)
SET_ERROR(HashCompareSizeError,CRYPT_E_HASH_VALUE)
SET_ERROR(HashCompareValueError,CRYPT_E_HASH_VALUE)
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(InvalidMsgType,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(ExtractContentError,CRYPT_E_UNEXPECTED_ENCODING)
SET_ERROR_VAR(DecodeSignerInfoWithBlobsError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(DecodeIssuerAndSerialNumberError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(SignerNotFound,CRYPT_E_SIGNER_NOT_FOUND)
TRACE_ERROR(SerialNumberAllocError) // error already set
TRACE_ERROR(GetHashValueError) // error already set
TRACE_ERROR(GetAuthAttrsHashError) // error already set
TRACE_ERROR(GetSignatureStuffError) // error already set
TRACE_ERROR(GetHashNodeFromEncodedAlgoError) // error already set
TRACE_ERROR(DupListHashError) // error already set
TRACE_ERROR(VerifySignatureError) // error already set
dwFlags;
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Verify a digest
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlVerifyDigest(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
BYTE *pbComputedDigest = NULL;
DWORD cbComputedDigest = 0;
BYTE *pbDigest = NULL;
DWORD cbDigest = 0;
if (CMSG_HASHED != pcmi->dwMsgType)
goto InvalidMsgTypeError;
// get the computed digest
CryptMsgGetParam(
(HCRYPTMSG)pcmi,
CMSG_COMPUTED_HASH_PARAM,
0, // dwIndex
NULL, // pvData
&cbComputedDigest);
if (0 == cbComputedDigest)
goto EmptyComputedDigestError;
if (NULL == (pbComputedDigest = (PBYTE)ICM_AllocA( cbComputedDigest)))
goto ComputedDigestAllocError;
if (!CryptMsgGetParam(
(HCRYPTMSG)pcmi,
CMSG_COMPUTED_HASH_PARAM,
0, // dwIndex
pbComputedDigest,
&cbComputedDigest))
goto GetComputedDigestError;
// get the digest from the message
CryptMsgGetParam(
(HCRYPTMSG)pcmi,
CMSG_HASH_DATA_PARAM,
0, // dwIndex
NULL, // pvData
&cbDigest);
if (0 == cbDigest)
goto EmptyDigestError;
if (NULL == (pbDigest = (PBYTE)ICM_AllocA( cbDigest)))
goto DigestAllocError;
if (!CryptMsgGetParam(
(HCRYPTMSG)pcmi,
CMSG_HASH_DATA_PARAM,
0, // dwIndex
pbDigest,
&cbDigest))
goto GetDigestError;
// compare the computed digest to the digest from the message
if (cbComputedDigest != cbDigest)
goto DigestSizesUnequalError;
if (0 != memcmp( pbDigest, pbComputedDigest, cbDigest))
goto DigestsDifferError;
fRet = TRUE;
CommonReturn:
ICM_FreeA( pbComputedDigest);
ICM_FreeA( pbDigest);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(EmptyComputedDigestError) // error already set
TRACE_ERROR(ComputedDigestAllocError) // error already set
TRACE_ERROR(GetComputedDigestError) // error already set
TRACE_ERROR(EmptyDigestError) // error already set
TRACE_ERROR(DigestAllocError) // error already set
TRACE_ERROR(GetDigestError) // error already set
SET_ERROR(DigestSizesUnequalError,CRYPT_E_HASH_VALUE)
SET_ERROR(DigestsDifferError,CRYPT_E_HASH_VALUE)
SET_ERROR(InvalidMsgTypeError,CRYPT_E_INVALID_MSG_TYPE)
dwFlags;
}
#ifdef CMS_PKCS7
CmsRecipientInfos *
WINAPI
ICM_GetDecodedCmsRecipientInfos(
IN PCRYPT_MSG_INFO pcmi
)
{
PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
CmsRecipientInfos *pris = NULL;
if (pcmi->fEncoding)
goto InvalidMsgType;
if (pcsi && (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_RECIPINFOS)))
goto StreamMsgNotReadyError;
if (NULL == pcmi->pvMsg)
goto NotUpdated;
switch (pcmi->dwMsgType) {
case CMSG_ENVELOPED:
pris = &((CmsEnvelopedData *)pcmi->pvMsg)->recipientInfos;
break;
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
CommonReturn:
return pris;
ErrorReturn:
goto CommonReturn;
SET_ERROR(InvalidMsgType, CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(NotUpdated, CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(StreamMsgNotReadyError, CRYPT_E_STREAM_MSG_NOT_READY)
SET_ERROR(MessageTypeNotSupportedYet, CRYPT_E_INVALID_MSG_TYPE)
}
BOOL
WINAPI
ICM_ConvertPkcsToCmsRecipientIndex(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwPkcsIndex,
OUT DWORD *pdwCmsIndex
)
{
BOOL fRet;
CmsRecipientInfos *pris;
CmsRecipientInfo *pri;
DWORD dwCount;
DWORD dwCmsIndex;
DWORD i;
if (NULL == (pris = ICM_GetDecodedCmsRecipientInfos(pcmi)))
goto GetDecodedCmsRecipientsError;
dwCount = pris->count;
pri = pris->value;
dwCmsIndex = dwPkcsIndex;
i = 0;
for ( ; 0 < dwCount; dwCount--, pri++) {
if (keyTransRecipientInfo_chosen != pri->choice) {
// Advance past non KeyTrans recipients
dwCmsIndex++;
} else {
if (i == dwPkcsIndex)
goto SuccessReturn;
else
i++;
}
}
goto IndexTooBig;
SuccessReturn:
fRet = TRUE;
CommonReturn:
*pdwCmsIndex = dwCmsIndex;
return fRet;
ErrorReturn:
fRet = FALSE;
dwCmsIndex = 0xFFFFFFFF;
goto CommonReturn;
TRACE_ERROR(GetDecodedCmsRecipientsError)
SET_ERROR(IndexTooBig, CRYPT_E_INVALID_INDEX)
}
BOOL
WINAPI
ICM_ConvertCmsToPkcsRecipientIndex(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwCmsIndex,
OUT DWORD *pdwPkcsIndex
)
{
BOOL fRet;
CmsRecipientInfos *pris;
CmsRecipientInfo *pri;
DWORD dwCount;
DWORD dwPkcsIndex;
DWORD i;
if (NULL == (pris = ICM_GetDecodedCmsRecipientInfos(pcmi)))
goto GetDecodedCmsRecipientsError;
dwCount = pris->count;
if (dwCmsIndex >= dwCount)
goto InvalidCmsIndex;
pri = &pris->value[dwCmsIndex];
if (keyTransRecipientInfo_chosen != pri->choice)
goto InvalidPkcsIndex;
pri = pris->value;
dwPkcsIndex = 0;
for (i = 0; i < dwCmsIndex; i++, pri++) {
if (keyTransRecipientInfo_chosen == pri->choice)
dwPkcsIndex++;
}
fRet = TRUE;
CommonReturn:
*pdwPkcsIndex = dwPkcsIndex;
return fRet;
ErrorReturn:
fRet = FALSE;
dwPkcsIndex = 0xFFFFFFFF;
goto CommonReturn;
TRACE_ERROR(GetDecodedCmsRecipientsError)
SET_ERROR(InvalidCmsIndex, CRYPT_E_INVALID_INDEX)
SET_ERROR(InvalidPkcsIndex, CRYPT_E_INVALID_INDEX)
}
BOOL
WINAPI
ICM_GetPkcsRecipientCount(
IN PCRYPT_MSG_INFO pcmi,
OUT DWORD *pdwPkcsCount
)
{
BOOL fRet;
CmsRecipientInfos *pris;
CmsRecipientInfo *pri;
DWORD dwCount;
DWORD dwPkcsCount;
if (NULL == (pris = ICM_GetDecodedCmsRecipientInfos(pcmi)))
goto GetDecodedCmsRecipientsError;
dwCount = pris->count;
pri = pris->value;
dwPkcsCount = 0;
for ( ; 0 < dwCount; dwCount--, pri++) {
if (keyTransRecipientInfo_chosen == pri->choice)
dwPkcsCount++;
}
fRet = TRUE;
CommonReturn:
*pdwPkcsCount = dwPkcsCount;
return fRet;
ErrorReturn:
dwPkcsCount = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetDecodedCmsRecipientsError)
}
typedef BOOL (WINAPI *PFN_ICM_IMPORT_CONTENT_ENCRYPT_KEY) (
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN void *pvDecryptPara,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved,
OUT HCRYPTKEY *phContentEncryptKey
);
BOOL
WINAPI
ICM_ImportContentEncryptKey(
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN void *pvDecryptPara,
IN HCRYPTOIDFUNCADDR hImportContentEncryptKeyFuncSet,
IN LPSTR pszKeyEncryptionOID,
IN PFN_ICM_IMPORT_CONTENT_ENCRYPT_KEY pDefaultImportContentEncryptKey,
OUT HCRYPTKEY *phContentEncryptKey
)
{
BOOL fRet;
DWORD i;
#define IMPORT_CONTENT_ENCRYPT_OID_CNT 3
LPSTR rgpszOID[IMPORT_CONTENT_ENCRYPT_OID_CNT] = {
NULL, // pszKeyEncryptOID!pszContentEncryptOID
pszKeyEncryptionOID,
pContentEncryptionAlgorithm->pszObjId
};
DWORD cch;
LPSTR psz;
cch = strlen(rgpszOID[1]) + 1 + strlen(rgpszOID[2]) + 1;
if (NULL == (psz = (LPSTR) ICM_Alloc(cch))) {
*phContentEncryptKey = 0;
return FALSE;
}
strcpy(psz, rgpszOID[1]);
strcat(psz, "!");
strcat(psz, rgpszOID[2]);
rgpszOID[0] = psz;
for (i = 0; i < IMPORT_CONTENT_ENCRYPT_OID_CNT; i++) {
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (CryptGetOIDFunctionAddress(
hImportContentEncryptKeyFuncSet,
X509_ASN_ENCODING,
rgpszOID[i],
0, // dwFlags
&pvFuncAddr,
&hFuncAddr)) {
fRet = ((PFN_ICM_IMPORT_CONTENT_ENCRYPT_KEY) pvFuncAddr)(
pContentEncryptionAlgorithm,
pvDecryptPara,
0, // dwFlags
NULL, // pvReserved
phContentEncryptKey
);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
if (fRet || E_NOTIMPL != GetLastError())
goto CommonReturn;
}
}
fRet = pDefaultImportContentEncryptKey(
pContentEncryptionAlgorithm,
pvDecryptPara,
0, // dwFlags
NULL, // pvReserved
phContentEncryptKey
);
CommonReturn:
ICM_Free(rgpszOID[0]);
return fRet;
}
HCRYPTKEY
WINAPI
ICM_ImportEncryptedKey(
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN HCRYPTPROV hCryptProv,
IN HCRYPTKEY hUserKey,
IN ALG_ID aiEncAlg,
IN BYTE bType,
IN PCRYPT_DATA_BLOB pEncryptedKey
)
{
BOOL fRet;
DWORD dwError;
HCRYPTKEY hEncryptKey = 0;
DWORD dwAlgIdEncrypt;
DWORD dwBitLen;
BYTE rgbIV[IV_MAX_LENGTH];
DWORD cbIV;
PBYTE pbCspKey = NULL;
DWORD cbCspKey;
PUBLICKEYSTRUC *ppks;
PSIMPLEBLOBHEADER psbh;
if (!ICM_GetEncryptParameters(
pContentEncryptionAlgorithm,
&dwAlgIdEncrypt,
&dwBitLen,
rgbIV,
&cbIV))
goto GetEncryptParametersError;
cbCspKey = sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER) +
pEncryptedKey->cbData;
if (NULL == (pbCspKey = (PBYTE)ICM_AllocA( cbCspKey)))
goto CspKeyAllocError;
ppks = (PUBLICKEYSTRUC *)pbCspKey;
ppks->bType = bType;
ppks->bVersion = CUR_BLOB_VERSION;
ppks->reserved = 0;
ppks->aiKeyAlg = dwAlgIdEncrypt;
psbh = (PSIMPLEBLOBHEADER)(ppks + 1);
psbh->aiEncAlg = aiEncAlg;
if (SYMMETRICWRAPKEYBLOB == bType)
memcpy( (PBYTE)(psbh+1), pEncryptedKey->pbData,
pEncryptedKey->cbData);
else
ICM_ReverseCopy( (PBYTE)(psbh+1), pEncryptedKey->pbData,
pEncryptedKey->cbData);
fRet = CryptImportKey(
hCryptProv,
pbCspKey,
cbCspKey,
hUserKey,
CRYPT_NO_SALT, // dwFlags
&hEncryptKey);
if (!fRet) {
hEncryptKey = 0;
goto ImportKeyFailed;
}
if (CALG_RC2 == dwAlgIdEncrypt && 0 != dwBitLen)
// Silently ignore any errors. Not supported in earlier versions
CryptSetKeyParam(
hEncryptKey,
KP_EFFECTIVE_KEYLEN,
(PBYTE) &dwBitLen,
0); // dwFlags
if (0 != cbIV) {
if (CALG_RC4 == dwAlgIdEncrypt) {
// For RC4, set the SALT, not the IV
BOOL fRC4Salt = TRUE;
if (IV_LENGTH == cbIV) {
// Old implementations of 40 bit or 128 bit RC4 set the
// IV which was ignored and didn't set the salt.
// Get the bit length of the imported key and don't
// set the salt for 40 or 128 bit RC4.
DWORD dwRC4BitLen;
DWORD cbKeyParamLen;
dwRC4BitLen = 0;
cbKeyParamLen = sizeof(dwRC4BitLen);
if (!CryptGetKeyParam(
hEncryptKey,
KP_KEYLEN,
(PBYTE) &dwRC4BitLen,
&cbKeyParamLen,
0 // dwFlags
) || 40 == dwRC4BitLen || 128 == dwRC4BitLen)
fRC4Salt = FALSE;
}
if (fRC4Salt) {
CRYPT_DATA_BLOB SaltBlob;
SaltBlob.pbData = rgbIV;
SaltBlob.cbData = cbIV;
if (!CryptSetKeyParam(
hEncryptKey,
KP_SALT_EX,
(PBYTE) &SaltBlob,
0)) // dwFlags
goto SetSaltExError;
}
} else {
if (!CryptSetKeyParam(
hEncryptKey,
KP_IV,
rgbIV,
0)) // dwFlags
goto SetIVError;
}
}
CommonReturn:
ICM_FreeA(pbCspKey);
return hEncryptKey;
ErrorReturn:
if (hEncryptKey) {
dwError = GetLastError();
CryptDestroyKey(hEncryptKey);
SetLastError(dwError);
hEncryptKey = 0;
}
goto CommonReturn;
TRACE_ERROR(GetEncryptParametersError)
TRACE_ERROR(ImportKeyFailed)
TRACE_ERROR(CspKeyAllocError)
TRACE_ERROR(SetSaltExError)
TRACE_ERROR(SetIVError)
}
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
BOOL
WINAPI
#ifdef DEBUG_CRYPT_ASN1
ICMTest_DefaultImportKeyTrans(
#else
ICM_DefaultImportKeyTrans(
#endif
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA pKeyTransDecryptPara,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved,
OUT HCRYPTKEY *phContentEncryptKey
)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
HCRYPTKEY hUserKey = 0;
PCMSG_KEY_TRANS_RECIPIENT_INFO pri = pKeyTransDecryptPara->pKeyTrans;
HCRYPTPROV hCryptProv = pKeyTransDecryptPara->hCryptProv;
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (CryptGetOIDFunctionAddress(
hOldStyleImportEncryptKeyFuncSet,
X509_ASN_ENCODING,
pContentEncryptionAlgorithm->pszObjId,
0, // dwFlags
&pvFuncAddr,
&hFuncAddr)) {
if ((void *) ICM_DefaultImportEncryptKey == pvFuncAddr)
fRet = FALSE;
#ifdef DEBUG_CRYPT_ASN1
else if (0 == (ICMTest_GetDebugCryptAsn1Flags() &
DEBUG_OSS_CRYPT_ASN1_SAME_ENCRYPT_FLAG))
fRet = FALSE;
#endif // DEBUG_CRYPT_ASN1
else
fRet = ((PFN_CMSG_IMPORT_ENCRYPT_KEY) pvFuncAddr)(
hCryptProv,
pKeyTransDecryptPara->dwKeySpec,
pContentEncryptionAlgorithm,
&pri->KeyEncryptionAlgorithm,
pri->EncryptedKey.pbData,
pri->EncryptedKey.cbData,
phContentEncryptKey);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
if (fRet)
return TRUE;
}
if (0 != pKeyTransDecryptPara->dwKeySpec) {
// Get private key to use.
if (!CryptGetUserKey(
hCryptProv,
pKeyTransDecryptPara->dwKeySpec,
&hUserKey)) {
hUserKey = 0;
goto GetUserKeyFailed;
}
}
// else
// Use the provider's default private key for decrypting
if (0 == (*phContentEncryptKey = ICM_ImportEncryptedKey(
pContentEncryptionAlgorithm,
hCryptProv,
hUserKey,
CALG_RSA_KEYX,
SIMPLEBLOB,
&pri->EncryptedKey
)))
goto ImportEncryptedKeyError;
fRet = TRUE;
CommonReturn:
if (hUserKey)
CryptDestroyKey(hUserKey);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetUserKeyFailed)
TRACE_ERROR(ImportEncryptedKeyError)
}
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultImportKeyAgree(
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN PCMSG_CTRL_KEY_AGREE_DECRYPT_PARA pKeyAgreeDecryptPara,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved,
OUT HCRYPTKEY *phContentEncryptKey
)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
HCRYPTPROV hKeyAgreeProv = 0; // Doesn't need to be released
HCRYPTKEY hMyKey = 0;
HCRYPTKEY hAgreeKey = 0;
DWORD cbP;
DWORD dwKeySpec;
LPSTR pszWrapOID = NULL;
DWORD dwAlgIdWrap;
DWORD dwBitLen;
PCMSG_KEY_AGREE_RECIPIENT_INFO pri = pKeyAgreeDecryptPara->pKeyAgree;
hKeyAgreeProv = pKeyAgreeDecryptPara->hCryptProv;
dwKeySpec = pKeyAgreeDecryptPara->dwKeySpec;
if (0 == dwKeySpec)
dwKeySpec = AT_KEYEXCHANGE;
// Get my private Diffie Hellman key
if (!CryptGetUserKey(
hKeyAgreeProv,
pKeyAgreeDecryptPara->dwKeySpec,
&hMyKey)) {
hMyKey = 0;
goto GetMyKeyFailed;
}
// Get the length of P
cbP = 0;
if (!CryptGetKeyParam(
hMyKey,
KP_P,
NULL, // pbData
&cbP,
0 // dwFlags
) || 0 == cbP)
goto GetPLengthError;
if (!ICM_GetDhWrapEncryptParameters(
&pri->KeyEncryptionAlgorithm,
&pszWrapOID, // allocated
&dwAlgIdWrap,
&dwBitLen))
goto GetDhWrapEncryptParametersError;
if (0 == (hAgreeKey = ICM_ImportDhAgreeKey(
hKeyAgreeProv,
hMyKey,
cbP,
&pKeyAgreeDecryptPara->OriginatorPublicKey,
pszWrapOID,
dwAlgIdWrap,
dwBitLen,
&pri->UserKeyingMaterial
)))
goto ImportDhAgreeKeyError;
if (0 == (*phContentEncryptKey = ICM_ImportEncryptedKey(
pContentEncryptionAlgorithm,
hKeyAgreeProv,
hAgreeKey,
dwAlgIdWrap,
SYMMETRICWRAPKEYBLOB,
&pri->rgpRecipientEncryptedKeys[
pKeyAgreeDecryptPara->dwRecipientEncryptedKeyIndex]->EncryptedKey
)))
goto ImportEncryptedKeyError;
fRet = TRUE;
CommonReturn:
ICM_Free(pszWrapOID);
if (hAgreeKey)
CryptDestroyKey(hAgreeKey);
if (hMyKey)
CryptDestroyKey(hMyKey);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetMyKeyFailed)
TRACE_ERROR(GetPLengthError)
TRACE_ERROR(GetDhWrapEncryptParametersError)
TRACE_ERROR(ImportDhAgreeKeyError)
TRACE_ERROR(ImportEncryptedKeyError)
}
//+-------------------------------------------------------------------------
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultImportMailList(
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN PCMSG_CTRL_MAIL_LIST_DECRYPT_PARA pMailListDecryptPara,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved,
OUT HCRYPTKEY *phContentEncryptKey
)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
HCRYPTPROV hMailListProv = 0; // not released
HCRYPTKEY hKeyEncryptionKey = 0; // not destroyed
PCMSG_MAIL_LIST_RECIPIENT_INFO pri = pMailListDecryptPara->pMailList;
DWORD dwAlgIdEncrypt;
DWORD dwBitLen;
hMailListProv = pMailListDecryptPara->hCryptProv;
switch (pMailListDecryptPara->dwKeyChoice) {
case CMSG_MAIL_LIST_HANDLE_KEY_CHOICE:
hKeyEncryptionKey = pMailListDecryptPara->hKeyEncryptionKey;
assert(hMailListProv && hKeyEncryptionKey);
if (0 == hMailListProv || 0 == hKeyEncryptionKey)
goto InvalidMailListHandleKeyPara;
break;
default:
goto InvalidMailListKeyChoice;
}
if (!ICM_GetWrapEncryptParameters(
&pri->KeyEncryptionAlgorithm,
&dwAlgIdEncrypt,
&dwBitLen))
goto GetWrapEncryptParametersError;
if (CALG_RC2 == dwAlgIdEncrypt && 0 != dwBitLen)
// Silently ignore any errors. Not supported in earlier versions
CryptSetKeyParam(
hKeyEncryptionKey,
KP_EFFECTIVE_KEYLEN,
(PBYTE) &dwBitLen,
0); // dwFlags
if (0 == (*phContentEncryptKey = ICM_ImportEncryptedKey(
pContentEncryptionAlgorithm,
hMailListProv,
hKeyEncryptionKey,
dwAlgIdEncrypt,
SYMMETRICWRAPKEYBLOB,
&pri->EncryptedKey
)))
goto ImportEncryptedKeyError;
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidMailListHandleKeyPara, E_INVALIDARG)
SET_ERROR(InvalidMailListKeyChoice, E_INVALIDARG)
TRACE_ERROR(GetWrapEncryptParametersError)
TRACE_ERROR(ImportEncryptedKeyError)
}
//+-------------------------------------------------------------------------
// Default import of the encryption key (OldStyle)
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultImportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN DWORD dwKeySpec,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PCRYPT_ALGORITHM_IDENTIFIER paiPubKey,
IN PBYTE pbEncodedKey,
IN DWORD cbEncodedKey,
OUT HCRYPTKEY *phEncryptKey)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
HCRYPTKEY hUserKey = 0;
CRYPT_DATA_BLOB EncryptedKey;
if (0 != dwKeySpec) {
// Get private key to use.
if (!CryptGetUserKey(
hCryptProv,
dwKeySpec,
&hUserKey)) {
hUserKey = 0;
goto GetUserKeyFailed;
}
}
// else
// Use the provider's default private key for decrypting
EncryptedKey.cbData = cbEncodedKey;
EncryptedKey.pbData = pbEncodedKey;
if (0 == (*phEncryptKey = ICM_ImportEncryptedKey(
paiEncrypt,
hCryptProv,
hUserKey,
CALG_RSA_KEYX,
SIMPLEBLOB,
&EncryptedKey
)))
goto ImportEncryptedKeyError;
fRet = TRUE;
CommonReturn:
if (hUserKey)
CryptDestroyKey(hUserKey);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetUserKeyFailed)
TRACE_ERROR(ImportEncryptedKeyError)
}
//+-------------------------------------------------------------------------
// Decrypt the content using any CMS recipient type
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlCmsDecrypt(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN void *pvDecryptPara,
IN HCRYPTPROV hCryptProv,
IN DWORD dwRecipientIndex,
IN HCRYPTOIDFUNCADDR hImportContentEncryptKeyFuncSet,
IN LPSTR pszKeyEncryptionOID,
IN PFN_ICM_IMPORT_CONTENT_ENCRYPT_KEY pDefaultImportContentEncryptKey
)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
EncryptedContentInfo *peci = NULL;
HCRYPTKEY hkeySeal = NULL;
PBYTE pbData = NULL;
LONG cbData;
AlgorithmIdentifier *paiOssContentEncryption;
PCRYPT_ALGORITHM_IDENTIFIER paiContentEncryption = NULL;
PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
if( pcmi->Plaintext.pbData)
goto MessageAlreadyDecrypted;
switch (pcmi->dwMsgType) {
case CMSG_ENVELOPED:
{
CmsEnvelopedData *ped;
ped = (CmsEnvelopedData *)pcmi->pvMsg;
if (NULL == ped)
goto NotUpdated;
if (dwRecipientIndex >= ped->recipientInfos.count)
goto RecipientIndexTooLarge;
peci = &ped->encryptedContentInfo;
paiOssContentEncryption =
&ped->encryptedContentInfo.contentEncryptionAlgorithm;
break;
}
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
if (NULL == (paiContentEncryption = ICM_AllocAndGetALGORITHM_IDENTIFIER(
paiOssContentEncryption)))
goto GetEncryptAlgorithmError;
if (!ICM_ImportContentEncryptKey(
paiContentEncryption,
pvDecryptPara,
hImportContentEncryptKeyFuncSet,
pszKeyEncryptionOID,
pDefaultImportContentEncryptKey,
&hkeySeal))
goto ImportKeyError;
if (pcsi) {
if (!ICMS_SetDecryptKey( pcmi, hkeySeal))
goto SetDecryptKeyError; // NB- Do not trash err from callback!
hkeySeal = NULL;
} else {
// NB- For common bulk encryption algos,
// sizeof(plaintext)<=sizeof(ciphertext)
if (peci->bit_mask & encryptedContent_present)
cbData = peci->encryptedContent.length;
else
cbData = 0;
if (NULL == (pbData = (PBYTE)ICM_Alloc( cbData)))
goto EncryptedContentAllocError;
if (cbData ) {
memcpy( pbData, peci->encryptedContent.value, cbData);
if (!CryptDecrypt(
hkeySeal,
NULL,
TRUE, // fFinal
0, // dwFlags
pbData,
(PDWORD)&cbData))
goto DecryptError;
}
CryptDestroyKey( hkeySeal);
hkeySeal = NULL;
pcmi->Plaintext.cbData = cbData;
pcmi->Plaintext.pbData = pbData;
pbData = NULL;
}
if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
pcmi->hCryptProvContentCrypt = hCryptProv;
pcmi->dwDecryptedRecipientIndex = dwRecipientIndex;
fRet = TRUE;
CommonReturn:
ICM_Free(paiContentEncryption);
ICM_Free(pbData);
if (hkeySeal)
CryptDestroyKey( hkeySeal);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(MessageAlreadyDecrypted,CRYPT_E_ALREADY_DECRYPTED)
SET_ERROR(RecipientIndexTooLarge, CRYPT_E_INVALID_INDEX)
SET_ERROR(NotUpdated, CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(InvalidMsgType, CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
TRACE_ERROR(GetEncryptAlgorithmError)
TRACE_ERROR(ImportKeyError)
TRACE_ERROR(EncryptedContentAllocError)
TRACE_ERROR(SetDecryptKeyError)
TRACE_ERROR(DecryptError)
}
//+-------------------------------------------------------------------------
// Decrypt the content using only a PKCS 1.5 recipient type
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlPkcsDecrypt(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN PCMSG_CTRL_DECRYPT_PARA pmcdp
)
{
BOOL fRet;
CMSG_CTRL_KEY_TRANS_DECRYPT_PARA KeyTransDecryptPara;
PCMSG_CMS_RECIPIENT_INFO pRecipientInfo = NULL;
DWORD dwCmsIndex;
assert( pmcdp->cbSize >= sizeof(*pmcdp));
if (pmcdp->cbSize < sizeof(*pmcdp))
goto InvalidArg;
if (!ICM_ConvertPkcsToCmsRecipientIndex(
pcmi, pmcdp->dwRecipientIndex, &dwCmsIndex))
goto ConvertPkcsToCmsRecipientIndexError;
if (NULL == (pRecipientInfo =
(PCMSG_CMS_RECIPIENT_INFO) ICM_AllocAndGetParam(
pcmi, CMSG_CMS_RECIPIENT_INFO_PARAM, dwCmsIndex)))
goto GetCmsRecipientInfoParamError;
assert(CMSG_KEY_TRANS_RECIPIENT == pRecipientInfo->dwRecipientChoice);
memset(&KeyTransDecryptPara, 0, sizeof(KeyTransDecryptPara));
KeyTransDecryptPara.cbSize = sizeof(KeyTransDecryptPara);
KeyTransDecryptPara.hCryptProv = pmcdp->hCryptProv;
KeyTransDecryptPara.dwKeySpec = pmcdp->dwKeySpec;
KeyTransDecryptPara.pKeyTrans = pRecipientInfo->pKeyTrans;
KeyTransDecryptPara.dwRecipientIndex = dwCmsIndex;
fRet = ICM_ControlCmsDecrypt(
pcmi,
dwFlags,
&KeyTransDecryptPara,
KeyTransDecryptPara.hCryptProv,
dwCmsIndex,
hImportKeyTransFuncSet,
KeyTransDecryptPara.pKeyTrans->KeyEncryptionAlgorithm.pszObjId,
(PFN_ICM_IMPORT_CONTENT_ENCRYPT_KEY) ICM_DefaultImportKeyTrans
);
CommonReturn:
ICM_Free(pRecipientInfo);
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(ConvertPkcsToCmsRecipientIndexError)
TRACE_ERROR(GetCmsRecipientInfoParamError)
}
#else
//+-------------------------------------------------------------------------
// Default import of the encryption key
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_DefaultImportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN DWORD dwKeySpec,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PCRYPT_ALGORITHM_IDENTIFIER paiPubKey,
IN PBYTE pbEncodedKey,
IN DWORD cbEncodedKey,
OUT HCRYPTKEY *phEncryptKey)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
HCRYPTKEY hEncryptKey = 0;
HCRYPTKEY hUserKey = 0;
DWORD dwAlgIdEncrypt;
DWORD dwAlgIdPubKey;
PBYTE pbCspKey = NULL;
DWORD cbCspKey;
PUBLICKEYSTRUC *ppks;
PSIMPLEBLOBHEADER psbh;
BYTE rgbIV[IV_LENGTH];
DWORD cbIV;
DWORD dwBitLen;
if (!ICM_GetEncryptParameters(
paiEncrypt,
&dwAlgIdEncrypt,
&dwBitLen,
rgbIV,
&cbIV))
goto GetEncryptParametersError;
#if 0
if (!ICM_GetOssCAPI(
CRYPT_PUBKEY_ALG_OID_GROUP_ID,
paiPubKey,
&dwAlgIdPubKey))
goto PubKeyGetCAPIError;
#else
// We have no idea what the right values are for the alg id's here.
dwAlgIdPubKey = CALG_RSA_KEYX;
#endif
cbCspKey = cbEncodedKey + sizeof(PUBLICKEYSTRUC) + sizeof(SIMPLEBLOBHEADER);
if (NULL == (pbCspKey = (PBYTE)ICM_AllocA( cbCspKey)))
goto CspKeyAllocError;
ppks = (PUBLICKEYSTRUC *)pbCspKey;
ppks->bType = SIMPLEBLOB;
ppks->bVersion = CUR_BLOB_VERSION;
ppks->reserved = 0;
ppks->aiKeyAlg = dwAlgIdEncrypt;
psbh = (PSIMPLEBLOBHEADER)(ppks + 1);
psbh->aiEncAlg = dwAlgIdPubKey;
ICM_ReverseCopy( (PBYTE)(psbh+1), pbEncodedKey, cbEncodedKey);
if (0 != dwKeySpec) {
// Get private key to use.
if (!CryptGetUserKey(
hCryptProv,
dwKeySpec,
&hUserKey)) {
hUserKey = 0;
goto GetUserKeyFailed;
}
}
// else
// Use the provider's default private key for decrypting
fRet = CryptImportKey(
hCryptProv,
pbCspKey,
cbCspKey,
hUserKey,
CRYPT_NO_SALT, // dwFlags
&hEncryptKey);
if (!fRet) {
dwError = GetLastError();
if (hUserKey) {
if (NTE_BAD_FLAGS == dwError)
// Try without salt. Previous versions didn't support
// CRYPT_NO_SALT flag
fRet = CryptImportKey(
hCryptProv,
pbCspKey,
cbCspKey,
hUserKey,
0, // dwFlags
&hEncryptKey);
if (!fRet) {
// Try without using the specified user key. Many versions of
// the CSP don't allow a non-null hUserKey parameter.
fRet = CryptImportKey(
hCryptProv,
pbCspKey,
cbCspKey,
0, // hUserKey
CRYPT_NO_SALT, // dwFlags
&hEncryptKey);
if (!fRet)
dwError = GetLastError();
}
}
if (!fRet && NTE_BAD_FLAGS == dwError)
// Try without user key and without CRYPT_NO_SALT flag
fRet = CryptImportKey(
hCryptProv,
pbCspKey,
cbCspKey,
0, // hUserKey
0, // dwFlags
&hEncryptKey);
if (!fRet && 2 >= paiEncrypt->Parameters.cbData) {
// Try importing as an NT4.0 SP3 encypted key that wasn't byte
// reversed and with zero salt.
memcpy( (PBYTE)(psbh+1), pbEncodedKey, cbEncodedKey);
fRet = CryptImportKey(
hCryptProv,
pbCspKey,
cbCspKey,
hUserKey,
0, // dwFlags
&hEncryptKey);
if (!fRet && hUserKey) {
// Try without using the specified user key.
fRet = CryptImportKey(
hCryptProv,
pbCspKey,
cbCspKey,
0, // hUserKey
0, // dwFlags
&hEncryptKey);
}
}
if (!fRet) {
hEncryptKey = 0;
goto ImportKeyFailed;
}
}
if (CALG_RC2 == dwAlgIdEncrypt && 0 != dwBitLen)
// Silently ignore any errors. Not supported in earlier versions
CryptSetKeyParam(
hEncryptKey,
KP_EFFECTIVE_KEYLEN,
(PBYTE) &dwBitLen,
0); // dwFlags
if (0 != cbIV) {
if (!CryptSetKeyParam(
hEncryptKey,
KP_IV,
rgbIV,
0)) // dwFlags
goto SetKeyParamError;
}
fRet = TRUE;
CommonReturn:
ICM_FreeA(pbCspKey);
if (hUserKey)
CryptDestroyKey(hUserKey);
ICM_SetLastError(dwError);
*phEncryptKey = hEncryptKey;
return fRet;
ErrorReturn:
dwError = GetLastError();
if (hEncryptKey) {
CryptDestroyKey(hEncryptKey);
hEncryptKey = 0;
}
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetEncryptParametersError)
//SET_ERROR(PubKeyGetCAPIError,CRYPT_E_UNKNOWN_ALGO)
TRACE_ERROR(GetUserKeyFailed)
TRACE_ERROR(ImportKeyFailed)
TRACE_ERROR(CspKeyAllocError)
TRACE_ERROR(SetKeyParamError)
}
//+-------------------------------------------------------------------------
// Import the encryption key
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ImportEncryptKey(
IN HCRYPTPROV hCryptProv,
IN DWORD dwKeySpec,
IN PCRYPT_ALGORITHM_IDENTIFIER paiEncrypt,
IN PCRYPT_ALGORITHM_IDENTIFIER paiPubKey,
IN PBYTE pbEncodedKey,
IN DWORD cbEncodedKey,
OUT HCRYPTKEY *phEncryptKey)
{
BOOL fResult;
void *pvFuncAddr;
HCRYPTOIDFUNCADDR hFuncAddr;
if (CryptGetOIDFunctionAddress(
hImportEncryptKeyFuncSet,
X509_ASN_ENCODING,
paiEncrypt->pszObjId,
0, // dwFlags
&pvFuncAddr,
&hFuncAddr)) {
fResult = ((PFN_CMSG_IMPORT_ENCRYPT_KEY) pvFuncAddr)(
hCryptProv,
dwKeySpec,
paiEncrypt,
paiPubKey,
pbEncodedKey,
cbEncodedKey,
phEncryptKey);
CryptFreeOIDFunctionAddress(hFuncAddr, 0);
} else
fResult = ICM_DefaultImportEncryptKey(
hCryptProv,
dwKeySpec,
paiEncrypt,
paiPubKey,
pbEncodedKey,
cbEncodedKey,
phEncryptKey);
return fResult;
}
//+-------------------------------------------------------------------------
// Decrypt the content
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlDecrypt(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN void *pvCtrlPara)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PCMSG_CTRL_DECRYPT_PARA pmcdp;
RecipientInfo *pri = NULL;
EncryptedContentInfo *peci = NULL;
HCRYPTKEY hkeySeal = NULL;
PBYTE pbData = NULL;
LONG cbData;
AlgorithmIdentifier *paiOssContentEncryption;
PCRYPT_ALGORITHM_IDENTIFIER paiContentEncryption = NULL;
AlgorithmIdentifier *paiOssKeyEncryption;
PCRYPT_ALGORITHM_IDENTIFIER paiKeyEncryption = NULL;
PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
pmcdp = (PCMSG_CTRL_DECRYPT_PARA)pvCtrlPara;
assert( pmcdp->cbSize >= sizeof(CMSG_CTRL_DECRYPT_PARA));
if (pmcdp->cbSize < sizeof(CMSG_CTRL_DECRYPT_PARA))
goto InvalidArg;
if (dwFlags & CMSG_CRYPT_RELEASE_CONTEXT_FLAG)
pcmi->hCryptProvContentCrypt = pmcdp->hCryptProv;
if( pcmi->Plaintext.pbData)
goto MessageAlreadyDecrypted;
switch (pcmi->dwMsgType) {
case CMSG_ENVELOPED:
{
EnvelopedData *ped;
ped = (EnvelopedData *)pcmi->pvMsg;
peci = &ped->encryptedContentInfo;
if (pmcdp->dwRecipientIndex >= ped->recipientInfos.count)
goto RecipientIndexTooLarge;
pri = ped->recipientInfos.value + pmcdp->dwRecipientIndex;
paiOssContentEncryption =
&ped->encryptedContentInfo.contentEncryptionAlgorithm;
paiOssKeyEncryption = &pri->keyEncryptionAlgorithm;
break;
}
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
if (NULL == pri)
goto RecipientNotFound; // really NULL if not found?
if (NULL == (paiContentEncryption = ICM_AllocAndGetALGORITHM_IDENTIFIER(
paiOssContentEncryption)))
goto GetEncryptAlgorithmError;
if (NULL == (paiKeyEncryption = ICM_AllocAndGetALGORITHM_IDENTIFIER(
paiOssKeyEncryption)))
goto GetKeyAlgorithmError;
if (!ICM_ImportEncryptKey(
pmcdp->hCryptProv,
pmcdp->dwKeySpec,
paiContentEncryption,
paiKeyEncryption,
pri->encryptedKey.value,
pri->encryptedKey.length,
&hkeySeal))
goto ImportKeyError;
if (pcsi) {
if (!ICMS_SetDecryptKey( pcmi, hkeySeal))
goto SetDecryptKeyError; // NB- Do not trash err from callback!
hkeySeal = NULL;
} else {
// NB- For common bulk encryption algos,
// sizeof(plaintext)<=sizeof(ciphertext)
cbData = peci->encryptedContent.length;
if (NULL == (pbData = (PBYTE)ICM_Alloc( cbData)))
goto EncryptedContentAllocError;
memcpy( pbData, peci->encryptedContent.value, cbData);
if (!CryptDecrypt(
hkeySeal,
NULL,
TRUE, // fFinal
0, // dwFlags
pbData,
(PDWORD)&cbData))
goto DecryptError;
CryptDestroyKey( hkeySeal);
hkeySeal = NULL;
pcmi->Plaintext.cbData = cbData;
pcmi->Plaintext.pbData = pbData;
pbData = NULL;
}
pcmi->dwDecryptedRecipientIndex = pmcdp->dwRecipientIndex;
fRet = TRUE;
CommonReturn:
ICM_Free(paiContentEncryption);
ICM_Free(paiKeyEncryption);
ICM_Free( pbData);
if (hkeySeal)
CryptDestroyKey( hkeySeal);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg,E_INVALIDARG)
SET_ERROR(MessageAlreadyDecrypted,CRYPT_E_ALREADY_DECRYPTED)
SET_ERROR(RecipientIndexTooLarge,CRYPT_E_INVALID_INDEX)
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(InvalidMsgType,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(RecipientNotFound,CRYPT_E_RECIPIENT_NOT_FOUND)
TRACE_ERROR(GetEncryptAlgorithmError)
TRACE_ERROR(GetKeyAlgorithmError)
TRACE_ERROR(ImportKeyError)
TRACE_ERROR(EncryptedContentAllocError)
TRACE_ERROR(SetDecryptKeyError)
TRACE_ERROR(DecryptError)
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Hash the content of a message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_HashContent(
IN PCRYPT_MSG_INFO pcmi,
IN OUT HCRYPTHASH hHash)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
HCRYPTMSG hCryptMsg = (HCRYPTMSG)pcmi;
PBYTE pbAllocData = NULL;
PBYTE pbData;
DWORD cbData;
cbData = 0;
CryptMsgGetParam(
hCryptMsg,
CMSG_CONTENT_PARAM,
0, // dwIndex
NULL,
&cbData);
if (0 == cbData)
goto GetContentSizeError;
if (NULL == (pbAllocData = (PBYTE)ICM_Alloc(cbData)))
goto AllocContentError;
if (!CryptMsgGetParam(
hCryptMsg,
CMSG_CONTENT_PARAM,
0, // dwIndex
pbAllocData,
&cbData))
goto GetContentError;
pbData = pbAllocData;
if (0 != strcmp(pszObjIdDataType, pcmi->psdi->pci->pszContentType)
#ifdef CMS_PKCS7
&& pcmi->psdi->version < CMSG_SIGNED_DATA_CMS_VERSION
#endif // CMS_PKCS7
) {
// Leading tag and length octets aren't included in the digest
if (0 > Asn1UtilExtractContent( pbData, cbData, &cbData,
(const BYTE **)&pbData))
goto ExtractContentError;
}
if (!ICM_UpdateDigest( hHash, pbData, cbData))
goto UpdateDigestError;
fRet = TRUE;
CommonReturn:
ICM_Free( pbAllocData);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetContentSizeError) // error already set
TRACE_ERROR(AllocContentError) // error already set
TRACE_ERROR(GetContentError) // error already set
SET_ERROR(ExtractContentError,CRYPT_E_UNEXPECTED_ENCODING)
TRACE_ERROR(UpdateDigestError) // error already set
}
//+-------------------------------------------------------------------------
// Add a signer to a signed-data or signed-and-enveloped-data message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlAddSigner(
IN OUT PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN PCMSG_SIGNER_ENCODE_INFO psei)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
CHashNode *pnHash;
CSignerNode *pnSigner;
DWORD dwAlgoCAPI;
SignerInfo *psi = NULL;
Attribute *pAuthAttr;
DWORD cAuthAttr;
Attribute *pUnauthAttr;
DWORD cUnauthAttr;
LPSTR pszInnerContentObjID;
ICM_HASH_INFO HashInfo; ZEROSTRUCT(HashInfo);
AlgorithmIdentifier oaiHash;
CBlobNode *pnBlob;
CRYPT_DATA_BLOB blobHashAlgo; ZEROSTRUCT(blobHashAlgo);
SIGNER_DATA_INFO sdi; ZEROSTRUCT(sdi);
#ifdef CMS_PKCS7
SIGNER_ENCODE_DATA_INFO SignerEncodeDataInfo;
#endif // CMS_PKCS7
// if the hash algorithm matches one of the ones already in use,
// get that hash and encrypt it
// else
// hash the data again and add hash algo to top-level list
// [NB- must access data again]
// Search for a hash node with a matching hash algorithm
if (!(ICM_GetCAPI(
CRYPT_HASH_ALG_OID_GROUP_ID,
&psei->HashAlgorithm,
&dwAlgoCAPI) ||
ICM_GetCAPI(
CRYPT_SIGN_ALG_OID_GROUP_ID,
&psei->HashAlgorithm,
&dwAlgoCAPI)))
goto GetCAPIError;
// before, this could have never failed, but now it can
// only create a hash node if the hash didn't exists.
if (!ICM_FindHashNodeFromCapiAlgid( pcmi->pHashList, dwAlgoCAPI, &pnHash) &&
GetLastError() != CRYPT_E_UNKNOWN_ALGO)
goto FindHashNodeFromCapiAlgidError;
if (!pnHash) {
// New hash.
// 1. Create hash node
// 2. Hash the data
// 3. Add hash node to pcmi->pHashList
// 4. Encode this hash algo and add to pcmi->psdi->pAlgidList
HashInfo.dwAlgoCAPI = dwAlgoCAPI;
#ifndef CMS_PKCS7
HashInfo.hCryptProv = psei->hCryptProv;
#endif // CMS_PKCS7
if (!CryptCreateHash(
psei->hCryptProv,
HashInfo.dwAlgoCAPI,
NULL, // hKey - optional for MAC
0, // dwFlags
&HashInfo.hHash))
goto CreateHashError;
if (!ICM_HashContent( pcmi, HashInfo.hHash)) // hash content
goto HashContentError;
if (NULL == (pnHash = new CHashNode))
goto NewHashNodeError;
pnHash->SetData( &HashInfo);
pcmi->pHashList->InsertTail( pnHash);
// Convert the hash algorithm to a blob and
// add to pcmi->psdi->pAlgidList.
if (!ICM_MsgAsn1ToAlgorithmIdentifier(
pcmi,
&psei->HashAlgorithm,
&oaiHash))
goto MsgAsn1ToAlgorithmIdentifierError;
if (!ICM_Asn1Encode(
AlgorithmIdentifier_PDU,
&oaiHash,
&blobHashAlgo))
goto EncodeHashAlgorithmError;
if (NULL == (pnBlob = new CBlobNode))
goto NewBlobNodeError;
pnBlob->SetData( &blobHashAlgo);
pcmi->psdi->pAlgidList->InsertTail( pnBlob);
}
// Alloc and fill in a SignerInfo
pszInnerContentObjID = pcmi->psdi->pci->pszContentType;
if (!strcmp( pszInnerContentObjID, pszObjIdDataType))
pszInnerContentObjID = NULL;
// NB - Each SignerInfo gets a non-empty authenticatedAttributes
// if the inner contentType is not data (passed in) or if
// there are authenticated attributes passed in. In this case,
// we reserve two Attribute slots at the beginning of the array
// for the content-type and message-digest Attribute values.
cAuthAttr = 0;
if (pszInnerContentObjID ||
psei->cAuthAttr ||
(dwFlags & CMSG_AUTHENTICATED_ATTRIBUTES_FLAG)) {
cAuthAttr = psei->cAuthAttr + 2; // reserve 2
}
cUnauthAttr = psei->cUnauthAttr;
psi = (SignerInfo *)ICM_AllocZero( sizeof( SignerInfo) +
cAuthAttr * sizeof( Attribute) +
cUnauthAttr * sizeof( Attribute)
);
if (NULL == psi)
goto SignerInfoAllocError;
pAuthAttr = (Attribute *)(psi + 1);
pUnauthAttr = pAuthAttr + cAuthAttr;
if (!ICM_FillAsnSignerInfo(
psei,
pcmi,
dwFlags,
pszInnerContentObjID,
psi,
&pAuthAttr,
&pUnauthAttr))
goto FillAsnSignerInfoError;
#ifdef CMS_PKCS7
SignerEncodeDataInfo.hCryptProv = psei->hCryptProv;
SignerEncodeDataInfo.dwKeySpec = psei->dwKeySpec;
SignerEncodeDataInfo.pHashNode = pnHash;
if (!ICM_FillSignerEncryptedDigest(
psi,
pszInnerContentObjID,
&SignerEncodeDataInfo,
FALSE)) // fMaxLength
goto FillSignerEncryptedDigestError;
#else
if (!ICM_FillSignerEncryptedDigest(
psi,
pszInnerContentObjID,
pnHash,
psei->dwKeySpec,
FALSE)) // fMaxLength
goto FillSignerEncryptedDigestError;
#endif // CMS_PKCS7
// Encode the signer and add to pcmi->psdi->pSignerList.
if (!ICM_Asn1Encode(
SignerInfo_PDU,
psi,
&sdi.blob))
goto EncodeSignerInfoError;
if (NULL == (pnSigner = new CSignerNode))
goto NewSignerInfoBlobNodeError;
pnSigner->SetData( &sdi);
pcmi->psdi->pSignerList->InsertTail( pnSigner);
fRet = TRUE;
CommonReturn:
if (psi) {
ICM_FreeAsnSignerInfo(psi);
ICM_Free(psi);
}
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
ICM_Free(blobHashAlgo.pbData);
ICM_Free(sdi.blob.pbData);
if (HashInfo.hHash)
CryptDestroyHash(HashInfo.hHash);
fRet = FALSE;
goto CommonReturn;
SET_ERROR(GetCAPIError,CRYPT_E_UNKNOWN_ALGO)
SET_ERROR(NewHashNodeError,E_OUTOFMEMORY)
SET_ERROR(NewBlobNodeError,E_OUTOFMEMORY)
SET_ERROR(NewSignerInfoBlobNodeError,E_OUTOFMEMORY)
TRACE_ERROR(FindHashNodeFromCapiAlgidError) // error already set
TRACE_ERROR(CreateHashError) // error already set
TRACE_ERROR(HashContentError) // error already set
TRACE_ERROR(MsgAsn1ToAlgorithmIdentifierError) // error already set
TRACE_ERROR(EncodeHashAlgorithmError) // error already set
TRACE_ERROR(SignerInfoAllocError) // error already set
TRACE_ERROR(FillAsnSignerInfoError) // error already set
TRACE_ERROR(FillSignerEncryptedDigestError) // error already set
TRACE_ERROR(EncodeSignerInfoError) // error already set
}
//+-------------------------------------------------------------------------
// Add a CMS signer info to a signed-data message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlAddCmsSignerInfo(
IN OUT PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN PCMSG_CMS_SIGNER_INFO psi)
{
BOOL fRet;
CSignerNode *pnSigner;
SIGNER_DATA_INFO sdi; ZEROSTRUCT(sdi);
// Encode the signer
if (!ICM_CmsSignerInfoEncode(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CMS_SIGNER_INFO,
psi,
NULL, // pbEncoded
&sdi.blob.cbData
))
goto EncodeSignerInfoError;
if (NULL == (sdi.blob.pbData = (PBYTE) ICM_Alloc(sdi.blob.cbData)))
goto OutOfMemory;
if (!ICM_CmsSignerInfoEncode(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
CMS_SIGNER_INFO,
psi,
sdi.blob.pbData,
&sdi.blob.cbData
))
goto EncodeSignerInfoError;
// Add to pcmi->psdi->pSignerList.
if (NULL == (pnSigner = new CSignerNode))
goto NewSignerInfoBlobNodeError;
pnSigner->SetData( &sdi);
pcmi->psdi->pSignerList->InsertTail( pnSigner);
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
ICM_Free(sdi.blob.pbData);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(OutOfMemory)
TRACE_ERROR(EncodeSignerInfoError)
SET_ERROR(NewSignerInfoBlobNodeError,E_OUTOFMEMORY)
}
//+-------------------------------------------------------------------------
// Remove a signer from a signed-data or signed-and-enveloped-data message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlDelSigner(
IN OUT PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN DWORD dwIndex)
{
BOOL fRet;
CSignerNode *pnSigner = pcmi->psdi->pSignerList->Nth( dwIndex);
if (NULL == pnSigner)
goto IndexTooLargeError;
pcmi->psdi->pSignerList->Remove( pnSigner);
delete pnSigner;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(IndexTooLargeError,CRYPT_E_INVALID_INDEX)
dwFlags;
}
//+-------------------------------------------------------------------------
// Initialize the unauthenticated attributes list. Called before doing an
// add or delete.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_InitUnauthAttrList(
IN CSignerNode *pnSigner
)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
CBlobList *plBlob = NULL;
DWORD i;
SIGNER_DATA_INFO sdi;
SignerInfoWithAttrBlobs *posib = NULL;
Any *pAny;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
assert(pnSigner);
sdi = *pnSigner->Data();
if (NULL == sdi.pUnauthAttrList) {
if (NULL == (plBlob = new CBlobList))
goto NewUnauthAttrListError;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posib,
SignerInfoWithAttrBlobs_PDU,
sdi.blob.pbData,
sdi.blob.cbData)))
goto DecodeSignerInfoError;
if (posib->bit_mask & unauthAttributes_present) {
for (i=posib->unauthAttributes.count, pAny=posib->unauthAttributes.value;
i>0;
i--, pAny++)
if (!ICM_InsertTailBlob( plBlob, pAny))
goto InsertOldUnauthAttrBlobError;
}
sdi.pUnauthAttrList = plBlob;
pnSigner->SetData( &sdi);
}
fRet = TRUE;
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfoWithAttrBlobs_PDU, posib);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
if (plBlob)
delete plBlob;
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(DecodeSignerInfoError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(NewUnauthAttrListError,E_OUTOFMEMORY)
TRACE_ERROR(InsertOldUnauthAttrBlobError) // error already set
}
//+-------------------------------------------------------------------------
// Add an unauthenticated attribute to a SignerInfo of a signed-data or
// signed-and-enveloped-data message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlAddUnauthAttr(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN PCMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA pmcasuap)
{
BOOL fRet;
CSignerNode *pnSigner;
DWORD i;
for (i=pmcasuap->dwSignerIndex,
pnSigner=pcmi->psdi->pSignerList->Head();
(i>0) && pnSigner;
i--, pnSigner = pnSigner->Next())
;
if (NULL == pnSigner)
goto IndexTooLargeError;
if (!ICM_InitUnauthAttrList(pnSigner))
goto InitUnauthAttrListError;
assert(pnSigner->Data()->pUnauthAttrList);
if (!ICM_InsertTailBlob( pnSigner->Data()->pUnauthAttrList,
(Any *)&pmcasuap->blob))
goto InsertUnauthAttrBlobError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(IndexTooLargeError,CRYPT_E_INVALID_INDEX)
TRACE_ERROR(InitUnauthAttrListError) // error already set
TRACE_ERROR(InsertUnauthAttrBlobError) // error already set
dwFlags;
}
//+-------------------------------------------------------------------------
// Delete an unauthenticated attribute from a SignerInfo of a signed-data or
// signed-and-enveloped-data message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_ControlDelUnauthAttr(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwFlags,
IN PCMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA pmcdsuap)
{
BOOL fRet;
CSignerNode *pnSigner;
DWORD i;
for (i=pmcdsuap->dwSignerIndex,
pnSigner=pcmi->psdi->pSignerList->Head();
(i>0) && pnSigner;
i--, pnSigner = pnSigner->Next())
;
if (NULL == pnSigner)
goto IndexTooLargeError;
if (!ICM_InitUnauthAttrList(pnSigner))
goto InitUnauthAttrListError;
assert(pnSigner->Data()->pUnauthAttrList);
if (!ICM_DelBlobByIndex(
pnSigner->Data()->pUnauthAttrList,
pmcdsuap->dwUnauthAttrIndex))
goto DelBlobByIndexError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(IndexTooLargeError,CRYPT_E_INVALID_INDEX)
TRACE_ERROR(InitUnauthAttrListError) // error already set
TRACE_ERROR(DelBlobByIndexError) // error already set
dwFlags;
}
//+-------------------------------------------------------------------------
// Perform a special "control" function after the final CryptMsgUpdate of a
// encoded/decoded cryptographic message.
//
// The dwCtrlType parameter specifies the type of operation to be performed.
//
// The pvCtrlPara definition depends on the dwCtrlType value.
//
// See below for a list of the control operations and their pvCtrlPara
// type definition.
//--------------------------------------------------------------------------
BOOL
WINAPI
#ifdef DEBUG_CRYPT_ASN1_MASTER
ICMTest_NewCryptMsgControl(
#else
CryptMsgControl(
#endif
IN HCRYPTMSG hCryptMsg,
IN DWORD dwFlags,
IN DWORD dwCtrlType,
IN void const *pvCtrlPara)
{
BOOL fRet;
PCRYPT_MSG_INFO pcmi = (PCRYPT_MSG_INFO)hCryptMsg;
ICM_Lock( pcmi); // Single thread access to HCRYPTMSG
// Only support control for decoding
if (pcmi->fEncoding)
goto ControlForEncodingNotSupported;
switch (dwCtrlType) {
case CMSG_CTRL_VERIFY_SIGNATURE:
fRet = ICM_ControlVerifySignature(
pcmi,
dwFlags,
(PCERT_INFO)pvCtrlPara);
break;
#ifdef CMS_PKCS7
case CMSG_CTRL_VERIFY_SIGNATURE_EX:
fRet = ICM_ControlVerifySignatureEx(
pcmi,
dwFlags,
(PCMSG_CTRL_VERIFY_SIGNATURE_EX_PARA)pvCtrlPara);
break;
#endif // CMS_PKCS7
case CMSG_CTRL_DECRYPT:
#ifdef CMS_PKCS7
fRet = ICM_ControlPkcsDecrypt(
#else
fRet = ICM_ControlDecrypt(
#endif // CMS_PKCS7
pcmi,
dwFlags,
(PCMSG_CTRL_DECRYPT_PARA) pvCtrlPara);
break;
case CMSG_CTRL_VERIFY_HASH:
fRet = ICM_ControlVerifyDigest(
pcmi,
dwFlags);
break;
case CMSG_CTRL_ADD_SIGNER:
fRet = ICM_ControlAddSigner(
pcmi,
dwFlags,
(PCMSG_SIGNER_ENCODE_INFO)pvCtrlPara);
break;
case CMSG_CTRL_ADD_CMS_SIGNER_INFO:
fRet = ICM_ControlAddCmsSignerInfo(
pcmi,
dwFlags,
(PCMSG_CMS_SIGNER_INFO)pvCtrlPara);
break;
case CMSG_CTRL_DEL_SIGNER:
fRet = ICM_ControlDelSigner(
pcmi,
dwFlags,
*(PDWORD)pvCtrlPara);
break;
case CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR:
fRet = ICM_ControlAddUnauthAttr(
pcmi,
dwFlags,
(PCMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA)pvCtrlPara);
break;
case CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR:
fRet = ICM_ControlDelUnauthAttr(
pcmi,
dwFlags,
(PCMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA)pvCtrlPara);
break;
case CMSG_CTRL_ADD_CERT:
fRet = ICM_InsertTailBlob(
pcmi->psdi->pCertificateList,
(Any *)pvCtrlPara);
break;
case CMSG_CTRL_DEL_CERT:
{
DWORD dwIndex = *(PDWORD)pvCtrlPara;
#ifdef CMS_PKCS7
if (pcmi->psdi->version >= CMSG_SIGNED_DATA_CMS_VERSION)
// Advance index past attribute certs.
ICM_GetTaggedBlobAndAdvanceIndex(
pcmi->psdi->pCertificateList,
ICM_TAG_SEQ,
&dwIndex
);
#endif // CMS_PKCS7
fRet = ICM_DelBlobByIndex(
pcmi->psdi->pCertificateList,
dwIndex);
}
break;
#ifdef CMS_PKCS7
case CMSG_CTRL_ADD_ATTR_CERT:
{
Any *pAny = (Any *) pvCtrlPara;
Any AnyAttrCert;
BOOL fV3;
fV3 = (pcmi->psdi->version >= CMSG_SIGNED_DATA_CMS_VERSION);
if (!(fV3 || 0 != strcmp(pszObjIdDataType,
pcmi->psdi->pci->pszContentType)))
goto InvalidMsgTypeToAddAttrCert;
AnyAttrCert.length = pAny->length;
if (0 == AnyAttrCert.length)
goto InvalidParamError;
if (NULL == (AnyAttrCert.value = (unsigned char*) ICM_Alloc(
AnyAttrCert.length)))
goto AllocError;
memcpy(AnyAttrCert.value, pAny->value, AnyAttrCert.length);
#ifdef OSS_CRYPT_ASN1
*AnyAttrCert.value = ICM_TAG_CONSTRUCTED_CONTEXT_1;
#else
*((BYTE *) AnyAttrCert.value) = ICM_TAG_CONSTRUCTED_CONTEXT_1;
#endif // OSS_CRYPT_ASN1
fRet = ICM_InsertTailBlob(
pcmi->psdi->pCertificateList,
&AnyAttrCert);
if (fRet && !fV3)
pcmi->psdi->version = CMSG_SIGNED_DATA_CMS_VERSION;
ICM_Free(AnyAttrCert.value);
}
break;
case CMSG_CTRL_DEL_ATTR_CERT:
if (pcmi->psdi->version < CMSG_SIGNED_DATA_CMS_VERSION)
goto NoAttrCerts;
else {
DWORD dwIndex = *(PDWORD)pvCtrlPara;
// Advance index past certs.
ICM_GetTaggedBlobAndAdvanceIndex(
pcmi->psdi->pCertificateList,
ICM_TAG_CONSTRUCTED_CONTEXT_1,
&dwIndex
);
fRet = ICM_DelBlobByIndex(
pcmi->psdi->pCertificateList,
dwIndex);
}
break;
#endif // CMS_PKCS7
case CMSG_CTRL_ADD_CRL:
fRet = ICM_InsertTailBlob(
pcmi->psdi->pCrlList,
(Any *)pvCtrlPara);
break;
case CMSG_CTRL_DEL_CRL:
fRet = ICM_DelBlobByIndex(
pcmi->psdi->pCrlList,
*(PDWORD)pvCtrlPara);
break;
#ifdef CMS_PKCS7
case CMSG_CTRL_KEY_TRANS_DECRYPT:
{
PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA pmcdp =
(PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA) pvCtrlPara;
assert(pmcdp->cbSize >= sizeof(*pmcdp));
if (pmcdp->cbSize < sizeof(*pmcdp))
goto InvalidArg;
fRet = ICM_ControlCmsDecrypt(
pcmi,
dwFlags,
pmcdp,
pmcdp->hCryptProv,
pmcdp->dwRecipientIndex,
hImportKeyTransFuncSet,
pmcdp->pKeyTrans->KeyEncryptionAlgorithm.pszObjId,
(PFN_ICM_IMPORT_CONTENT_ENCRYPT_KEY) ICM_DefaultImportKeyTrans
);
}
break;
case CMSG_CTRL_KEY_AGREE_DECRYPT:
{
PCMSG_CTRL_KEY_AGREE_DECRYPT_PARA pmcdp =
(PCMSG_CTRL_KEY_AGREE_DECRYPT_PARA) pvCtrlPara;
assert(pmcdp->cbSize >= sizeof(*pmcdp));
if (pmcdp->cbSize < sizeof(*pmcdp))
goto InvalidArg;
fRet = ICM_ControlCmsDecrypt(
pcmi,
dwFlags,
pmcdp,
pmcdp->hCryptProv,
pmcdp->dwRecipientIndex,
hImportKeyAgreeFuncSet,
pmcdp->pKeyAgree->KeyEncryptionAlgorithm.pszObjId,
(PFN_ICM_IMPORT_CONTENT_ENCRYPT_KEY) ICM_DefaultImportKeyAgree
);
if (fRet)
pcmi->dwDecryptedRecipientEncryptedKeyIndex =
pmcdp->dwRecipientEncryptedKeyIndex;
}
break;
case CMSG_CTRL_MAIL_LIST_DECRYPT:
{
PCMSG_CTRL_MAIL_LIST_DECRYPT_PARA pmcdp =
(PCMSG_CTRL_MAIL_LIST_DECRYPT_PARA) pvCtrlPara;
assert(pmcdp->cbSize >= sizeof(*pmcdp));
if (pmcdp->cbSize < sizeof(*pmcdp))
goto InvalidArg;
fRet = ICM_ControlCmsDecrypt(
pcmi,
dwFlags,
pmcdp,
pmcdp->hCryptProv,
pmcdp->dwRecipientIndex,
hImportMailListFuncSet,
pmcdp->pMailList->KeyEncryptionAlgorithm.pszObjId,
(PFN_ICM_IMPORT_CONTENT_ENCRYPT_KEY) ICM_DefaultImportMailList
);
}
break;
#endif // CMS_PKCS7
default:
goto InvalidCtrlType;
}
CommonReturn:
ICM_Unlock( pcmi);
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(ControlForEncodingNotSupported,E_INVALIDARG)
SET_ERROR(InvalidCtrlType,CRYPT_E_CONTROL_TYPE)
#ifdef CMS_PKCS7
SET_ERROR(InvalidMsgTypeToAddAttrCert,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(InvalidParamError,E_INVALIDARG)
TRACE_ERROR(AllocError)
SET_ERROR(NoAttrCerts,CRYPT_E_INVALID_INDEX)
SET_ERROR(InvalidArg,E_INVALIDARG)
#endif // CMS_PKCS7
}
//+-------------------------------------------------------------------------
// Copy out a DWORD
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetDWORD(
IN DWORD dwValue,
OUT void *pvData,
IN OUT DWORD *pcbData)
{
return ICM_CopyOut(
(PBYTE)&dwValue,
sizeof(DWORD),
(PBYTE)pvData,
pcbData);
}
//+-------------------------------------------------------------------------
// Get Any
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssAny(
IN Any *pany,
OUT PCRYPT_DATA_BLOB pInfo,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra)
{
BOOL fResult = TRUE;
LONG lRemainExtra = *plRemainExtra;
BYTE *pbExtra = *ppbExtra;
LONG lAlignExtra;
LONG lData;
BOOL fNULL = FALSE;
PBYTE pbValue;
pbValue = (PBYTE) pany->value;
if ((pany->length == 2) &&
(pbValue[0] == 0x05) &&
(pbValue[1] == 0x00)) {
// Detected NULL encoding. Map to NULL blob.
fNULL = TRUE;
}
lData = fNULL ? 0 : pany->length;
lAlignExtra = INFO_LEN_ALIGN(lData);
lRemainExtra -= lAlignExtra;
if (lRemainExtra >= 0) {
if ((lData > 0) && !fNULL) {
pInfo->pbData = pbExtra;
pInfo->cbData = (DWORD) lData;
memcpy( pbExtra, pany->value, lData);
} else {
memset(pInfo, 0, sizeof(*pInfo));
}
pbExtra += lAlignExtra;
}
*plRemainExtra = lRemainExtra;
*ppbExtra = pbExtra;
return fResult;
}
//+-------------------------------------------------------------------------
// Get the data for an Attributes
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetAnyData(
IN Any *pAny,
OUT void *pvData,
IN OUT DWORD *pcbData)
{
BOOL fRet;
LONG lData;
LONG lRemainExtra;
PBYTE pbExtra;
PCRYPT_DATA_BLOB pBlob = (PCRYPT_DATA_BLOB)pvData;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CRYPT_DATA_BLOB));
lRemainExtra = (LONG)*pcbData - lData;
if (0 > lRemainExtra) {
pBlob = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)pBlob + lData;
}
if (!ICM_GetOssAny( pAny, pBlob, &pbExtra, &lRemainExtra))
goto GetOssAnyError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pvData, pcbData);
CommonReturn:
return fRet;
ErrorReturn:
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssAnyError) // error already set
}
//+-------------------------------------------------------------------------
// Get Object Identifier string
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssObjId(
IN ObjectID *poi,
OUT LPSTR *ppszObjId,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra)
{
BOOL fRet;
LONG lRemainExtra = *plRemainExtra;
BYTE *pbExtra = *ppbExtra;
LONG lAlignExtra;
LONG lObjId;
if (!PkiAsn1FromObjectIdentifier(
poi->count,
poi->value,
NULL,
(PDWORD)&lObjId))
goto PkiAsn1FromObjectIdentifierSizeError;
lAlignExtra = INFO_LEN_ALIGN(lObjId);
lRemainExtra -= lAlignExtra;
if (lRemainExtra >= 0) {
if(lObjId > 0) {
*ppszObjId = (LPSTR) pbExtra;
if (!PkiAsn1FromObjectIdentifier(
poi->count,
poi->value,
(LPSTR)pbExtra,
(PDWORD)&lObjId))
goto PkiAsn1FromObjectIdentifierError;
} else
*ppszObjId = NULL;
pbExtra += lAlignExtra;
}
fRet = TRUE;
CommonReturn:
*plRemainExtra = lRemainExtra;
*ppbExtra = pbExtra;
return fRet;
ErrorReturn:
*ppszObjId = NULL;
fRet = FALSE;
goto CommonReturn;
SET_ERROR(PkiAsn1FromObjectIdentifierSizeError,CRYPT_E_OID_FORMAT)
SET_ERROR(PkiAsn1FromObjectIdentifierError,CRYPT_E_OID_FORMAT)
}
//+-------------------------------------------------------------------------
// Get Oss HugeInteger
//--------------------------------------------------------------------------
void
inline
WINAPI
ICM_GetOssHugeInteger(
IN HugeIntegerType *pOssHugeInteger,
OUT PCRYPT_INTEGER_BLOB pHugeInteger,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
PkiAsn1GetHugeInteger(pOssHugeInteger->length, pOssHugeInteger->value, 0,
pHugeInteger, ppbExtra, plRemainExtra);
}
//+-------------------------------------------------------------------------
// Get an Attribute
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssAttribute(
IN Attribute *poatr,
OUT PCRYPT_ATTRIBUTE patr,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra)
{
BOOL fRet;
LONG lData;
DWORD i;
Any *pAny;
PCRYPT_ATTR_BLOB patrbl = NULL;
if (!ICM_GetOssObjId(&poatr->attributeType, &patr->pszObjId,
ppbExtra, plRemainExtra))
goto GetOssObjIdError;
lData = INFO_LEN_ALIGN( poatr->attributeValue.count * sizeof(CRYPT_ATTR_BLOB));
*plRemainExtra -= lData;
if (0 < *plRemainExtra) {
patr->cValue = poatr->attributeValue.count;
patr->rgValue = patrbl = (PCRYPT_ATTR_BLOB)*ppbExtra;
*ppbExtra += lData;
}
for (i=poatr->attributeValue.count, pAny=poatr->attributeValue.value;
i>0;
i--, pAny++, patrbl++) {
if (!ICM_GetOssAny(pAny, patrbl, ppbExtra, plRemainExtra))
goto GetOssAnyError;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssObjIdError) // error already set
TRACE_ERROR(GetOssAnyError) // error already set
}
//+-------------------------------------------------------------------------
// Get an CRYPT_ATTRIBUTE
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetATTRIBUTE(
IN Attribute *poatr,
OUT void *pvData,
IN OUT DWORD *pcbData)
{
BOOL fRet;
LONG lData;
LONG lRemainExtra;
PBYTE pbExtra;
PCRYPT_ATTRIBUTE patr = (PCRYPT_ATTRIBUTE)pvData;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CRYPT_ATTRIBUTE));
lRemainExtra = (LONG)*pcbData - lData;
if (0 > lRemainExtra) {
patr = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)patr + lData;
}
if (!ICM_GetOssAttribute( poatr, patr, &pbExtra, &lRemainExtra))
goto GetOssAttributeError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pvData, pcbData);
CommonReturn:
return fRet;
ErrorReturn:
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssAttributeError) // error already set
}
//+-------------------------------------------------------------------------
// Get an Attributes
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssAttributes(
IN Attributes *poatrs,
OUT PCRYPT_ATTRIBUTES patrs,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra)
{
BOOL fRet;
LONG lData;
DWORD i;
Attribute *poatr;
PCRYPT_ATTRIBUTE patr;
lData = INFO_LEN_ALIGN( poatrs->count * sizeof(CRYPT_ATTRIBUTE));
*plRemainExtra -= lData;
if (0 < *plRemainExtra) {
patrs->cAttr = poatrs->count;
patrs->rgAttr = patr = (PCRYPT_ATTRIBUTE)*ppbExtra;
*ppbExtra += lData;
} else {
patr = NULL;
}
for (i=poatrs->count, poatr=poatrs->value;
i>0;
i--, poatr++, patr++) {
if (!ICM_GetOssAttribute( poatr, patr, ppbExtra, plRemainExtra))
goto GetOssAttributeError;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssAttributeError) // error already set
}
//+-------------------------------------------------------------------------
// Get from an Attributes in CList form
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetCListAttributes(
IN CBlobList *pBlobList,
OUT PCRYPT_ATTRIBUTES patrs,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
LONG lData;
CBlobNode *pBlobNode;
AttributeNC2 *poatr = NULL;
PCRYPT_ATTRIBUTE patr;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
PCRYPT_DATA_BLOB pDataBlob;
lData = INFO_LEN_ALIGN( pBlobList->Length() * sizeof(CRYPT_ATTRIBUTE));
*plRemainExtra -= lData;
if (0 < *plRemainExtra) {
patrs->cAttr = pBlobList->Length();
patrs->rgAttr = patr = (PCRYPT_ATTRIBUTE)*ppbExtra;
*ppbExtra += lData;
} else {
patr = NULL;
}
for (pBlobNode=pBlobList->Head();
pBlobNode;
pBlobNode=pBlobNode->Next(), patr++) {
poatr = NULL;
pDataBlob = pBlobNode->Data();
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&poatr,
AttributeNC2_PDU,
pDataBlob->pbData,
pDataBlob->cbData)))
goto DecodeAttributeNC2Error;
if (!ICM_GetOssAttribute(
(Attribute *)poatr, // same, except for NOCOPY
patr,
ppbExtra,
plRemainExtra))
goto GetOssAttributeError;
PkiAsn1FreeDecoded(pDec, poatr, AttributeNC2_PDU);
poatr = NULL;
}
fRet = TRUE;
CommonReturn:
PkiAsn1FreeInfo(pDec, AttributeNC2_PDU, poatr);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(DecodeAttributeNC2Error, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(GetOssAttributeError) // error already set
}
//+-------------------------------------------------------------------------
// Get the data for an Attributes
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetAttributesData(
IN Attributes *poatrs,
OUT void *pvData,
IN OUT DWORD *pcbData)
{
BOOL fRet;
LONG lData;
LONG lRemainExtra;
PBYTE pbExtra;
PCRYPT_ATTRIBUTES patrs = (PCRYPT_ATTRIBUTES)pvData;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CRYPT_ATTRIBUTES));
lRemainExtra = (LONG)*pcbData - lData;
if (0 > lRemainExtra) {
patrs = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)patrs + lData;
}
if (!ICM_GetOssAttributes( poatrs, patrs, &pbExtra, &lRemainExtra))
goto GetOssAttributesError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pvData, pcbData);
CommonReturn:
return fRet;
ErrorReturn:
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssAttributesError) // error already set
}
//+-------------------------------------------------------------------------
// Get an OSS Algorithm
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssAlgorithm(
IN AlgorithmIdentifier *pai,
OUT PCRYPT_ALGORITHM_IDENTIFIER pInfo,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra)
{
if (!ICM_GetOssObjId(&pai->algorithm, &pInfo->pszObjId,
ppbExtra, plRemainExtra))
return FALSE;
if (pai->bit_mask & parameters_present) {
if (!ICM_GetOssAny(&pai->parameters, &pInfo->Parameters,
ppbExtra, plRemainExtra))
return FALSE;
} else if (*plRemainExtra >= 0) {
memset(&pInfo->Parameters, 0, sizeof(pInfo->Parameters));
}
return TRUE;
}
//+-------------------------------------------------------------------------
// Get a ContentInfo (internal)
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssContentInfo(
IN ContentInfo *poci,
OUT PCONTENT_INFO pInfo,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra)
{
if (!ICM_GetOssObjId(&poci->contentType, &pInfo->pszContentType,
ppbExtra, plRemainExtra))
return FALSE;
if (poci->bit_mask & content_present) {
if (!ICM_GetOssAny(&poci->content, &pInfo->content,
ppbExtra, plRemainExtra))
return FALSE;
} else {
if (pInfo) {
pInfo->content.cbData = 0;
pInfo->content.pbData = 0;
}
}
return TRUE;
}
//+-------------------------------------------------------------------------
// Get a ContentInfo
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssContentInfoData(
IN ContentInfo *poci,
OUT void *pvData,
IN OUT DWORD *pcbData)
{
BOOL fRet;
LONG lData;
LONG lRemainExtra;
PBYTE pbExtra;
PCONTENT_INFO pci = (PCONTENT_INFO)pvData;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CONTENT_INFO));
lRemainExtra = (LONG)*pcbData - lData;
if (0 > lRemainExtra) {
pci = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)pci + lData;
}
if (!ICM_GetOssContentInfo( poci, pci, &pbExtra, &lRemainExtra))
goto GetContentInfoError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pvData, pcbData);
CommonReturn:
return fRet;
ErrorReturn:
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetContentInfoError) // error already set
}
BOOL
WINAPI
ICM_GetOssIssuerAndSerialNumberFromCertId(
IN CertIdentifier *pOssCertId,
OUT PCERT_NAME_BLOB pIssuer,
OUT PCRYPT_INTEGER_BLOB pSerialNumber,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra);
//+-------------------------------------------------------------------------
// Get an Special Issuer and SerialNumber from a KeyId.
//
// Converts the KeyId to a special encoded Issuer name having a RDN with
// the szOID_KEYID_RDN OID and a CERT_RDN_OCTET_STRING value containing
// the KeyId. The SerialNumber is set to 0.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssIssuerAndSerialNumberFromKeyId(
IN SubjectKeyIdentifier *pOssKeyId,
OUT PCERT_NAME_BLOB pIssuer,
OUT PCRYPT_INTEGER_BLOB pSerialNumber,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra)
{
BOOL fRet;
CertIdentifier OssCertId;
ASN1octet_t SerialNumber;
CERT_RDN_ATTR KeyIdAttr;
CERT_RDN KeyIdRDN;
CERT_NAME_INFO IssuerInfo;
BYTE *pbEncodedIssuer = NULL;
DWORD cbEncodedIssuer;
KeyIdAttr.pszObjId = szOID_KEYID_RDN;
KeyIdAttr.dwValueType = CERT_RDN_OCTET_STRING;
KeyIdAttr.Value.pbData = pOssKeyId->value;
KeyIdAttr.Value.cbData = pOssKeyId->length;
KeyIdRDN.cRDNAttr = 1;
KeyIdRDN.rgRDNAttr = &KeyIdAttr;
IssuerInfo.cRDN = 1;
IssuerInfo.rgRDN = &KeyIdRDN;
// Encode the special Issuer Name containing the KeyId
if (!CryptEncodeObjectEx(
X509_ASN_ENCODING,
X509_NAME,
&IssuerInfo,
CRYPT_ENCODE_ALLOC_FLAG,
&PkiEncodePara,
(void *) &pbEncodedIssuer,
&cbEncodedIssuer
))
goto EncodeError;
OssCertId.choice = issuerAndSerialNumber_chosen;
OssCertId.u.issuerAndSerialNumber.serialNumber.length = 1;
OssCertId.u.issuerAndSerialNumber.serialNumber.value = &SerialNumber;
SerialNumber = 0;
OssCertId.u.issuerAndSerialNumber.issuer.length = cbEncodedIssuer;
OssCertId.u.issuerAndSerialNumber.issuer.value = pbEncodedIssuer;
fRet = ICM_GetOssIssuerAndSerialNumberFromCertId(
&OssCertId,
pIssuer,
pSerialNumber,
ppbExtra,
plRemainExtra
);
CommonReturn:
PkiFree(pbEncodedIssuer);
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(EncodeError)
}
//+-------------------------------------------------------------------------
// Get an Issuer and SerialNumber from a CertIdentifier.
//
// Converts a KEYID choice to a special encoded Issuer name having a RDN with
// the szOID_KEYID_RDN OID and a CERT_RDN_OCTET_STRING value containing
// the KeyId. The SerialNumber is set to 0.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssIssuerAndSerialNumberFromCertId(
IN CertIdentifier *pOssCertId,
OUT PCERT_NAME_BLOB pIssuer,
OUT PCRYPT_INTEGER_BLOB pSerialNumber,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra)
{
BOOL fRet;
switch (pOssCertId->choice) {
case issuerAndSerialNumber_chosen:
ICM_GetOssHugeInteger(
&pOssCertId->u.issuerAndSerialNumber.serialNumber,
pSerialNumber, ppbExtra, plRemainExtra);
if (!ICM_GetOssAny(&pOssCertId->u.issuerAndSerialNumber.issuer,
pIssuer, ppbExtra, plRemainExtra))
goto GetIssuerError;
break;
case subjectKeyIdentifier_chosen:
if (!ICM_GetOssIssuerAndSerialNumberFromKeyId(
&pOssCertId->u.subjectKeyIdentifier,
pIssuer, pSerialNumber, ppbExtra, plRemainExtra))
goto GetKeyIdError;
break;
default:
goto InvalidCertIdChoice;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetIssuerError)
TRACE_ERROR(GetKeyIdError)
SET_ERROR(InvalidCertIdChoice, CRYPT_E_BAD_ENCODE)
}
BOOL
WINAPI
ICM_GetOssIssuerAndSerialNumberForCertInfo(
IN CertIdentifier *pOssCertId,
OUT PCERT_INFO pCertInfo,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra)
{
return ICM_GetOssIssuerAndSerialNumberFromCertId(
pOssCertId,
&pCertInfo->Issuer,
&pCertInfo->SerialNumber,
ppbExtra,
plRemainExtra
);
}
//+-------------------------------------------------------------------------
// Get an CertInfo with an updated IssuerAndSerialNumber
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetCertInfoIssuerAndSerialNumber(
IN CertIdentifier *pOssCertIdentifier,
OUT void *pvData,
IN OUT DWORD *pcbData)
{
BOOL fRet;
LONG lData;
PCERT_INFO pci = (PCERT_INFO)pvData;
PBYTE pbExtra;
LONG lRemainExtra;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CERT_INFO));
lRemainExtra = (LONG)*pcbData - lData;
if (0 > lRemainExtra) {
pci = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)pci + lData;
}
if (!ICM_GetOssIssuerAndSerialNumberForCertInfo(pOssCertIdentifier,
pci, &pbExtra, &lRemainExtra))
goto GetOssIssuerAndSerialNumberError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pvData, pcbData);
CommonReturn:
return fRet;
ErrorReturn:
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssIssuerAndSerialNumberError) // error already set
}
BOOL
WINAPI
ICM_GetOssCertIdentifier(
IN CertIdentifier *pOssCertId,
OUT PCERT_ID pCertId,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
);
BOOL
WINAPI
ICM_GetCertId(
IN CertIdentifier *pOssCertIdentifier,
OUT void *pvData,
IN OUT DWORD *pcbData)
{
BOOL fRet;
LONG lData;
PCERT_ID pid = (PCERT_ID)pvData;
PBYTE pbExtra;
LONG lRemainExtra;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CERT_ID));
lRemainExtra = (LONG)*pcbData - lData;
if (0 > lRemainExtra) {
pid = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)pid + lData;
}
if (!ICM_GetOssCertIdentifier(pOssCertIdentifier,
pid, &pbExtra, &lRemainExtra))
goto GetOssCertIdentifierError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pvData, pcbData);
CommonReturn:
return fRet;
ErrorReturn:
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssCertIdentifierError) // error already set
}
//+-------------------------------------------------------------------------
// Copy out an CRYPT_ALGORITHM_IDENTIFIER
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetALGORITHM_IDENTIFIER(
IN AlgorithmIdentifier *paiOss,
OUT void *pvData,
IN OUT DWORD *pcbData)
{
BOOL fRet;
LONG lData;
PCRYPT_ALGORITHM_IDENTIFIER pai = (PCRYPT_ALGORITHM_IDENTIFIER)pvData;
PBYTE pbExtra;
LONG lRemainExtra;
if (NULL == pvData)
*pcbData = 0;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CRYPT_ALGORITHM_IDENTIFIER));
lRemainExtra = (LONG)*pcbData - lData;
if (0 > lRemainExtra) {
pai = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)pai + lData;
}
if (!ICM_GetOssAlgorithm( paiOss, pai, &pbExtra, &lRemainExtra))
goto GetOssAlgorithmError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pvData, pcbData);
CommonReturn:
return fRet;
ErrorReturn:
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssAlgorithmError) // error already set
}
//+-------------------------------------------------------------------------
// Get the digest in a DIGESTED message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetDigestDataParam(
IN PCRYPT_MSG_INFO pcmi,
OUT void *pvData,
IN OUT DWORD *pcbData)
{
BOOL fRet;
DigestedData *pdd;
if (CMSG_HASHED != pcmi->dwMsgType)
goto InvalidMsgType;
pdd = (DigestedData *)pcmi->pvMsg;
fRet = ICM_CopyOut(
(PBYTE)pdd->digest.value,
(DWORD)pdd->digest.length,
(PBYTE)pvData,
pcbData);
CommonReturn:
return fRet;
ErrorReturn:
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidMsgType,CRYPT_E_INVALID_MSG_TYPE)
}
#ifdef CMS_PKCS7
HCRYPTHASH
WINAPI
ICM_GetEncodedSignerHash(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwSignerIndex
)
{
HCRYPTHASH hHash = NULL;
SignerInfo *psi;
PSIGNER_ENCODE_DATA_INFO pSignerEncodeDataInfo;
CHashNode *pnHash;
PICM_HASH_INFO pHashInfo;
if (dwSignerIndex >= ((SignedData *)pcmi->pvMsg)->signerInfos.count)
goto IndexTooBig;
psi = ((SignedData *)pcmi->pvMsg)->signerInfos.value + dwSignerIndex;
pSignerEncodeDataInfo = pcmi->rgSignerEncodeDataInfo + dwSignerIndex;
pnHash = pSignerEncodeDataInfo->pHashNode;
pHashInfo = pnHash->Data();
if (psi->bit_mask & authenticatedAttributes_present) {
if (!ICM_GetAttrsHash(
pHashInfo->dwAlgoCAPI,
pSignerEncodeDataInfo->hCryptProv,
&psi->authenticatedAttributes,
&hHash))
goto GetAuthAttrsHashError;
} else {
if (!ICM_DupListHash( pnHash, pSignerEncodeDataInfo->hCryptProv,
&hHash))
goto DupListHashError;
}
CommonReturn:
return hHash;
ErrorReturn:
hHash = NULL;
goto CommonReturn;
SET_ERROR(IndexTooBig,CRYPT_E_INVALID_INDEX)
TRACE_ERROR(GetAuthAttrsHashError) // error already set
TRACE_ERROR(DupListHashError) // error already set
}
HCRYPTHASH
WINAPI
ICM_GetDecodedSignerHash(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwSignerIndex
)
{
HCRYPTHASH hHash = NULL;
DWORD dwError = ERROR_SUCCESS;
SignerInfoWithBlobs *psib = NULL;
CSignerNode *pSignerNode = NULL;
HCRYPTPROV hCryptProv; // doen't need to be released
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
CRYPT_DATA_BLOB DataBlob;
CHashNode *pnHash;
PICM_HASH_INFO pHashInfo;
if (!ICM_FindSignerInfo(pcmi, dwSignerIndex, (PVOID *)&pSignerNode))
goto FindSignerInfoError;
DataBlob = pSignerNode->Data()->blob;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&psib,
SignerInfoWithBlobs_PDU,
DataBlob.pbData,
DataBlob.cbData)))
goto DecodeSignerInfoWithBlobsError;
if (!ICM_FindHashNodeFromEncodedAlgo(
pcmi->pHashList,
(PCRYPT_DATA_BLOB)&psib->digestAlgorithm,
&pnHash))
goto GetHashNodeFromEncodedAlgoError;
pHashInfo = pnHash->Data();
if (pcmi->fDefaultCryptProv)
hCryptProv = 0;
else
hCryptProv = pcmi->hCryptProv;
if (0 == hCryptProv) {
hCryptProv = I_CryptGetDefaultCryptProv(0);
if (0 == hCryptProv)
goto GetDefaultCryptProvError;
}
if (psib->bit_mask & authAttributes_present) {
if (!ICM_GetAttrsHash(
pHashInfo->dwAlgoCAPI,
hCryptProv,
(Attributes *)&psib->authAttributes, // same, except for NOCOPY
&hHash))
goto GetAuthAttrsHashError;
} else {
if (!ICM_DupListHash( pnHash, hCryptProv, &hHash))
goto DupListHashError;
}
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, psib);
ICM_SetLastError(dwError);
return hHash;
ErrorReturn:
dwError = GetLastError();
hHash = NULL;
goto CommonReturn;
TRACE_ERROR(FindSignerInfoError) // error already set
SET_ERROR_VAR(DecodeSignerInfoWithBlobsError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(GetHashNodeFromEncodedAlgoError) // error already set
TRACE_ERROR(GetDefaultCryptProvError) // error already set
TRACE_ERROR(GetAuthAttrsHashError) // error already set
TRACE_ERROR(DupListHashError) // error already set
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Get the digest of the content in a DIGESTED message or for one of
// the signers in a SIGNED message
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetComputedDigestParam(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwIndex,
OUT void *pvData,
IN OUT DWORD *pcbData)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
HCRYPTHASH hHash = NULL;
PBYTE pbAllocHash = NULL;
DWORD cbHash;
PBYTE pbHash;
switch (pcmi->dwMsgType) {
case CMSG_HASHED:
if (!ICM_GetListHashValue(
pcmi->pHashList->Head(),
&cbHash,
&pbHash))
goto GetHashValueError;
break;
#ifdef CMS_PKCS7
case CMSG_SIGNED:
if (pcmi->fEncoding)
hHash = ICM_GetEncodedSignerHash(pcmi, dwIndex);
else
hHash = ICM_GetDecodedSignerHash(pcmi, dwIndex);
if (NULL == hHash)
goto GetSignerHashError;
if (!CryptGetHashParam(
hHash,
HP_HASHVAL,
NULL,
&cbHash,
0)) // dwFlags
goto GetHashParamSizeError;
if (NULL == (pbAllocHash = (PBYTE)ICM_AllocA(cbHash)))
goto AllocHashParamError;
pbHash = pbAllocHash;
if (!CryptGetHashParam(
hHash,
HP_HASHVAL,
pbHash,
&cbHash,
0)) // dwFlags
goto GetHashParamError;
break;
#endif // CMS_PKCS7
default:
goto InvalidMsgType;
}
fRet = ICM_CopyOut(
pbHash,
cbHash,
(PBYTE)pvData,
pcbData);
if (!fRet)
dwError = GetLastError();
CommonReturn:
if (hHash)
CryptDestroyHash(hHash);
ICM_FreeA(pbAllocHash);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidMsgType,CRYPT_E_INVALID_MSG_TYPE)
TRACE_ERROR(GetHashValueError)
TRACE_ERROR(GetSignerHashError)
TRACE_ERROR(GetHashParamSizeError)
TRACE_ERROR(AllocHashParamError)
TRACE_ERROR(GetHashParamError)
}
//+-------------------------------------------------------------------------
// Find the SignerInfo by index, if the message type permits and if the
// index value is in range.
//
// Returns: FALSE iff fails
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_FindSignerInfo(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwIndex,
OUT PVOID *ppv)
{
BOOL fRet;
PVOID pv;
SignerInfo *psi = NULL;
CSignerNode *pSignerNode = NULL;
DWORD i;
if (pcmi->fEncoding) {
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (dwIndex >= ((SignedData *)pcmi->pvMsg)->signerInfos.count)
goto IndexTooBig;
psi = ((SignedData *)pcmi->pvMsg)->signerInfos.value + dwIndex;
break;
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
pv = psi;
} else {
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (NULL == pcmi->psdi)
goto InvalidSignedMessageError;
for (i=dwIndex, pSignerNode=pcmi->psdi->pSignerList->Head();
(i>0) && pSignerNode;
i--, pSignerNode=pSignerNode->Next())
;
if (NULL == pSignerNode)
goto IndexTooBig;
break;
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
pv = pSignerNode;
}
fRet = TRUE;
CommonReturn:
*ppv = pv;
return fRet;
ErrorReturn:
pv = NULL;
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidSignedMessageError, ERROR_INVALID_DATA)
SET_ERROR(IndexTooBig,CRYPT_E_INVALID_INDEX)
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(InvalidMsgType,CRYPT_E_INVALID_MSG_TYPE)
}
//+-------------------------------------------------------------------------
// Countersign an already-existing signature, output an encoded attribute
//--------------------------------------------------------------------------
BOOL
WINAPI
#ifdef DEBUG_CRYPT_ASN1_MASTER
ICMTest_NewCryptMsgCountersignEncoded(
#else
CryptMsgCountersignEncoded(
#endif
IN DWORD dwEncodingType,
IN PBYTE pbSignerInfo,
IN DWORD cbSignerInfo,
IN DWORD cCountersigners,
IN PCMSG_SIGNER_ENCODE_INFO rgCountersigners,
OUT PBYTE pbCountersignatureAttribute,
IN OUT PDWORD pcbCountersignatureAttribute)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
HCRYPTMSG hCryptMsgCountersign = NULL;
CMSG_SIGNED_ENCODE_INFO EncodeInfo; ZEROSTRUCT(EncodeInfo);
EncodeInfo.cbSize = sizeof(EncodeInfo);
CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA UnauthAttrPara; ZEROSTRUCT(UnauthAttrPara);
UnauthAttrPara.cbSize = sizeof(UnauthAttrPara);
Attribute oatrCountersignature; ZEROSTRUCT(oatrCountersignature);
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
ASN1encoding_t pEnc = ICM_GetEncoder();
PBYTE pbEncoded = NULL;
DWORD cbEncoded;
SignerInfoWithBlobs *posib = NULL;
DWORD i;
Any *pAny;
DWORD dwFlags;
if (GET_CMSG_ENCODING_TYPE(dwEncodingType) != PKCS_7_ASN_ENCODING)
goto InvalidEncodingTypeError;
// crack the SignerInfo being countersigned
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posib,
SignerInfoWithBlobs_PDU,
pbSignerInfo,
cbSignerInfo)))
goto DecodeSignerInfoError;
// create a new message
EncodeInfo.cSigners = cCountersigners;
EncodeInfo.rgSigners = rgCountersigners;
dwFlags = CMSG_AUTHENTICATED_ATTRIBUTES_FLAG;
if (NULL == pbCountersignatureAttribute ||
0 == *pcbCountersignatureAttribute)
dwFlags |= CMSG_MAX_LENGTH_FLAG;
if (NULL == (hCryptMsgCountersign = CryptMsgOpenToEncode(
PKCS_7_ASN_ENCODING,
dwFlags,
CMSG_SIGNED,
&EncodeInfo,
NULL, // pszInnerContentObjID
NULL))) // pStreamInfo
goto OpenToEncodeError;
// feed encrypted digest into the new message
if (!CryptMsgUpdate(
hCryptMsgCountersign,
posib->encryptedDigest.value,
posib->encryptedDigest.length,
TRUE)) // fFinal
goto UpdateError;
oatrCountersignature.attributeType.count = SIZE_OSS_OID;
if (!PkiAsn1ToObjectIdentifier(
szOID_RSA_counterSign,
&oatrCountersignature.attributeType.count,
oatrCountersignature.attributeType.value))
goto PkiAsn1ToObjectIdentifierError;
oatrCountersignature.attributeValue.count = cCountersigners;
if (NULL == (oatrCountersignature.attributeValue.value = (Any *)ICM_AllocA(
cCountersigners * sizeof(Any))))
goto AllocCountersignersError;
// extract encoded SignerInfo's, and store
for (i=0, pAny=oatrCountersignature.attributeValue.value;
i<cCountersigners;
i++, pAny++) {
cbSignerInfo = 0;
CryptMsgGetParam(
hCryptMsgCountersign,
CMSG_ENCODED_SIGNER,
i,
NULL,
&cbSignerInfo);
if (cbSignerInfo == 0)
goto GetSignerInfoSizeError;
if (NULL == (pbSignerInfo = (PBYTE)ICM_AllocA( cbSignerInfo)))
goto AllocSignerInfoError;
if (!CryptMsgGetParam(
hCryptMsgCountersign,
CMSG_ENCODED_SIGNER,
i,
pbSignerInfo,
&cbSignerInfo))
goto GetSignerInfoError;
pAny->length = cbSignerInfo;
pAny->value = pbSignerInfo;
}
// encode the Countersignature attribute
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
&oatrCountersignature,
AttributeNC2_PDU,
&pbEncoded,
&cbEncoded)))
goto Asn1EncodeAttributeError;
// copy out the Countersignature attribute
fRet = ICM_CopyOut(
pbEncoded,
cbEncoded,
pbCountersignatureAttribute,
pcbCountersignatureAttribute);
if (!fRet)
dwError = GetLastError();
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, posib);
CryptMsgClose( hCryptMsgCountersign);
if (oatrCountersignature.attributeValue.value) {
for (i=cCountersigners, pAny=oatrCountersignature.attributeValue.value;
i>0;
i--, pAny++)
ICM_FreeA( pAny->value);
ICM_FreeA( oatrCountersignature.attributeValue.value);
}
PkiAsn1FreeEncoded(pEnc, pbEncoded);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidEncodingTypeError,E_INVALIDARG)
SET_ERROR_VAR(DecodeSignerInfoError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(PkiAsn1ToObjectIdentifierError,CRYPT_E_OID_FORMAT)
SET_ERROR_VAR(Asn1EncodeAttributeError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(OpenToEncodeError) // error already set
TRACE_ERROR(UpdateError) // error already set
TRACE_ERROR(AllocCountersignersError) // error already set
TRACE_ERROR(GetSignerInfoSizeError) // error already set
TRACE_ERROR(AllocSignerInfoError) // error already set
TRACE_ERROR(GetSignerInfoError) // error already set
}
//+-------------------------------------------------------------------------
// Countersign an already-existing signature in a message
//--------------------------------------------------------------------------
BOOL
WINAPI
#ifdef DEBUG_CRYPT_ASN1_MASTER
ICMTest_NewCryptMsgCountersign(
#else
CryptMsgCountersign(
#endif
IN OUT HCRYPTMSG hCryptMsg,
IN DWORD dwIndex,
IN DWORD cCountersigners,
IN PCMSG_SIGNER_ENCODE_INFO rgCountersigners)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PBYTE pbCountersignatureAttribute = NULL;
DWORD cbCountersignatureAttribute;
PBYTE pbSignerInfo = NULL;
DWORD cbSignerInfo;
CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA UnauthAttrPara; ZEROSTRUCT(UnauthAttrPara);
UnauthAttrPara.cbSize = sizeof(UnauthAttrPara);
if (((PCRYPT_MSG_INFO)hCryptMsg)->fEncoding)
goto EncodingCountersignNotSupportedError;
// extract encoded SignerInfo being countersigned from the message
cbSignerInfo = 0;
CryptMsgGetParam(
hCryptMsg,
CMSG_ENCODED_SIGNER,
dwIndex,
NULL,
&cbSignerInfo);
if (cbSignerInfo == 0)
goto GetEncodedSignerSizeError;
if (NULL == (pbSignerInfo = (PBYTE)ICM_AllocA( cbSignerInfo)))
goto AllocEncodedSignerError;
if (!CryptMsgGetParam(
hCryptMsg,
CMSG_ENCODED_SIGNER,
dwIndex,
pbSignerInfo,
&cbSignerInfo))
goto GetEncodedSignerError;
// create the countersignature blob
cbCountersignatureAttribute = 0;
CryptMsgCountersignEncoded(
PKCS_7_ASN_ENCODING,
pbSignerInfo,
cbSignerInfo,
cCountersigners,
rgCountersigners,
NULL,
&cbCountersignatureAttribute);
if (cbCountersignatureAttribute == 0)
goto GetCountersignatureAttributeSizeError;
if (NULL == (pbCountersignatureAttribute = (PBYTE)ICM_AllocA( cbCountersignatureAttribute)))
goto AllocCountersignatureAttributeError;
if (!CryptMsgCountersignEncoded(
PKCS_7_ASN_ENCODING,
pbSignerInfo,
cbSignerInfo,
cCountersigners,
rgCountersigners,
pbCountersignatureAttribute,
&cbCountersignatureAttribute))
goto GetCountersignatureAttributeError;
// add encoded Countersignature attribute to unauth attrs
UnauthAttrPara.dwSignerIndex = dwIndex;
UnauthAttrPara.blob.cbData = cbCountersignatureAttribute;
UnauthAttrPara.blob.pbData = pbCountersignatureAttribute;
if (!CryptMsgControl(
hCryptMsg,
0, // dwFlags
CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR,
&UnauthAttrPara))
goto AddUnauthAttrError;
fRet = TRUE;
CommonReturn:
ICM_FreeA( pbSignerInfo);
ICM_FreeA( pbCountersignatureAttribute);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(EncodingCountersignNotSupportedError) // error already set
TRACE_ERROR(GetEncodedSignerSizeError) // error already set
TRACE_ERROR(AllocEncodedSignerError) // error already set
TRACE_ERROR(GetEncodedSignerError) // error already set
TRACE_ERROR(GetCountersignatureAttributeSizeError) // error already set
TRACE_ERROR(AllocCountersignatureAttributeError) // error already set
TRACE_ERROR(GetCountersignatureAttributeError) // error already set
TRACE_ERROR(AddUnauthAttrError) // error already set
}
#ifdef CMS_PKCS7
//+-------------------------------------------------------------------------
// Verify a countersignature, at the SignerInfo level.
// ie. verify that pbSignerInfoCountersignature contains the encrypted
// hash of the encryptedDigest field of pbSignerInfo.
//
// hCryptProv is used to hash the encryptedDigest field of pbSignerInfo.
//
// The signer can be a CERT_PUBLIC_KEY_INFO, certificate context or a
// chain context.
//--------------------------------------------------------------------------
BOOL
WINAPI
#ifdef DEBUG_CRYPT_ASN1_MASTER
ICMTest_NewCryptMsgVerifyCountersignatureEncodedEx(
#else
CryptMsgVerifyCountersignatureEncodedEx(
#endif
IN HCRYPTPROV hCryptProv,
IN DWORD dwEncodingType,
IN PBYTE pbSignerInfo,
IN DWORD cbSignerInfo,
IN PBYTE pbSignerInfoCountersignature,
IN DWORD cbSignerInfoCountersignature,
IN DWORD dwSignerType,
IN void *pvSigner,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
SignerInfoWithBlobs *posib = NULL;
SignerInfoWithBlobs *posibCS = NULL;
Any anyValue;
DWORD cbMessageDigest;
PBYTE pbMessageDigest;
DWORD dwDigestAlgoCAPI;
DWORD dwPubKeyAlgId;
DWORD dwPubKeyFlags;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
HCRYPTKEY hPubKey = NULL;
HCRYPTHASH hHashRaw = NULL;
HCRYPTHASH hHashAttr = NULL;
PBYTE pbHash = NULL;
DWORD cbHash;
if (GET_CMSG_ENCODING_TYPE(dwEncodingType) != PKCS_7_ASN_ENCODING)
goto InvalidEncodingTypeError;
// crack the SignerInfo being countersigned
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posib,
SignerInfoWithBlobs_PDU,
pbSignerInfo,
cbSignerInfo)))
goto DecodeSignerInfoError;
// crack the SignerInfo doing the countersigning
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posibCS,
SignerInfoWithBlobs_PDU,
pbSignerInfoCountersignature,
cbSignerInfoCountersignature)))
goto DecodeSignerInfoCSError;
if (!ICM_GetVerifySignatureStuff(
dwSignerType,
pvSigner,
&hCryptProv,
&hPubKey,
&dwPubKeyAlgId,
&dwPubKeyFlags)) goto GetSignatureStuffError;
// hash the encrypted digest
if (!ICM_GetCapiFromAlgidBlob(
(PCRYPT_DATA_BLOB)&posibCS->digestAlgorithm,
&dwDigestAlgoCAPI))
goto GetCapiFromAlgidBlobError;
if (!CryptCreateHash(
hCryptProv,
dwDigestAlgoCAPI,
NULL, // hKey - optional for MAC
0, // dwFlags
&hHashRaw))
goto CreateHashError;
if (!ICM_UpdateDigest(
hHashRaw,
posib->encryptedDigest.value,
posib->encryptedDigest.length))
goto HashDataError;
if (0 == (posibCS->bit_mask & authAttributes_present))
goto CountersignerAuthAttributesMissingError;
// check that the message digest attr matches the hashed encrypted digest
if (!CryptGetHashParam(
hHashRaw,
HP_HASHVAL,
NULL,
&cbHash,
0)) // dwFlags
goto GetHashParamSizeError;
if (NULL == (pbHash = (PBYTE)ICM_AllocA( cbHash)))
goto AllocHashParamError;
if (!CryptGetHashParam(
hHashRaw,
HP_HASHVAL,
pbHash,
&cbHash,
0)) // dwFlags
goto GetHashParamError;
// find the message digest attr value
if (!ICM_GetAttrValue(
(Attributes *)&posibCS->authAttributes, // same, except for NOCOPY
&oidMessageDigest,
&anyValue))
goto FindAttrError;
// find the message digest octets
if (!Asn1UtilExtractContent(
#ifdef OSS_CRYPT_ASN1
anyValue.value,
#else
(const BYTE *) anyValue.value,
#endif // OSS_CRYPT_ASN1
anyValue.length,
&cbMessageDigest,
(const BYTE **)&pbMessageDigest))
goto ExtractContentError;
// hash sizes equal?
if (cbHash != cbMessageDigest)
goto HashCompareSizeError;
// hash octets equal?
if (memcmp( pbMessageDigest, pbHash, cbHash))
goto HashCompareValueError;
// Now that we have verified the message digest octets,
// get the hash of the authenticated attributes.
if (!ICM_GetAttrsHash(
dwDigestAlgoCAPI,
hCryptProv,
(Attributes *)&posibCS->authAttributes, // same, except for NOCOPY
&hHashAttr))
goto GetAuthAttrsHashError;
// verify the hash, signature, and public key are consistent
if (!ICM_VerifySignature(
hHashAttr,
hPubKey,
dwPubKeyAlgId,
dwPubKeyFlags,
posibCS->encryptedDigest.value,
posibCS->encryptedDigest.length))
goto VerifySignatureError;
fRet = TRUE;
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, posib);
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, posibCS);
if (hHashRaw)
CryptDestroyHash( hHashRaw);
if (hHashAttr)
CryptDestroyHash( hHashAttr);
if (hPubKey)
CryptDestroyKey( hPubKey);
ICM_FreeA( pbHash);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidEncodingTypeError,E_INVALIDARG)
SET_ERROR_VAR(DecodeSignerInfoError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(DecodeSignerInfoCSError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(CountersignerAuthAttributesMissingError,CRYPT_E_AUTH_ATTR_MISSING)
SET_ERROR(FindAttrError,CRYPT_E_AUTH_ATTR_MISSING)
SET_ERROR(ExtractContentError,CRYPT_E_UNEXPECTED_ENCODING)
SET_ERROR(HashCompareSizeError,CRYPT_E_HASH_VALUE)
SET_ERROR(HashCompareValueError,CRYPT_E_HASH_VALUE)
TRACE_ERROR(GetCapiFromAlgidBlobError) // error already set
TRACE_ERROR(CreateHashError) // error already set
TRACE_ERROR(HashDataError) // error already set
TRACE_ERROR(GetHashParamSizeError) // error already set
TRACE_ERROR(AllocHashParamError) // error already set
TRACE_ERROR(GetHashParamError) // error already set
TRACE_ERROR(GetAuthAttrsHashError) // error already set
TRACE_ERROR(GetSignatureStuffError) // error already set
TRACE_ERROR(VerifySignatureError) // error already set
}
//+-------------------------------------------------------------------------
// Verify a countersignature, at the SignerInfo level
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptMsgVerifyCountersignatureEncoded(
IN HCRYPTPROV hCryptProv,
IN DWORD dwEncodingType,
IN PBYTE pbSignerInfo,
IN DWORD cbSignerInfo,
IN PBYTE pbSignerInfoCountersignature,
IN DWORD cbSignerInfoCountersignature,
IN PCERT_INFO pciCountersigner)
{
return CryptMsgVerifyCountersignatureEncodedEx(
hCryptProv,
dwEncodingType,
pbSignerInfo,
cbSignerInfo,
pbSignerInfoCountersignature,
cbSignerInfoCountersignature,
CMSG_VERIFY_SIGNER_PUBKEY,
(void *) &pciCountersigner->SubjectPublicKeyInfo,
0, // dwFlags
NULL // pvReserved
);
}
#else
//+-------------------------------------------------------------------------
// Verify a countersignature, at the SignerInfo level
//--------------------------------------------------------------------------
BOOL
WINAPI
CryptMsgVerifyCountersignatureEncoded(
IN HCRYPTPROV hCryptProv,
IN DWORD dwEncodingType,
IN PBYTE pbSignerInfo,
IN DWORD cbSignerInfo,
IN PBYTE pbSignerInfoCountersignature,
IN DWORD cbSignerInfoCountersignature,
IN PCERT_INFO pciCountersigner)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
SignerInfoWithBlobs *posib = NULL;
SignerInfoWithBlobs *posibCS = NULL;
Any anyValue;
DWORD cbMessageDigest;
PBYTE pbMessageDigest;
DWORD dwDigestAlgoCAPI;
DWORD dwPubKeyAlgId;
DWORD dwPubKeyFlags;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
IssuerAndSerialNumber *pisn = NULL;
HCRYPTKEY hPubKey = NULL;
HCRYPTHASH hHashRaw = NULL;
HCRYPTHASH hHashAttr = NULL;
PBYTE pbHash = NULL;
DWORD cbHash;
if (GET_CMSG_ENCODING_TYPE(dwEncodingType) != PKCS_7_ASN_ENCODING)
goto InvalidEncodingTypeError;
// crack the SignerInfo being countersigned
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posib,
SignerInfoWithBlobs_PDU,
pbSignerInfo,
cbSignerInfo)))
goto DecodeSignerInfoError;
// crack the SignerInfo doing the countersigning
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posibCS,
SignerInfoWithBlobs_PDU,
pbSignerInfoCountersignature,
cbSignerInfoCountersignature)))
goto DecodeSignerInfoCSError;
// verify that the countersignature SignerInfo and the cert info are consistent
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&pisn,
IssuerAndSerialNumber_PDU,
(BYTE *) posibCS->issuerAndSerialNumber.value,
posibCS->issuerAndSerialNumber.length)))
goto DecodeIssuerAndSerialNumberError;
if (pisn->issuer.length != pciCountersigner->Issuer.cbData)
goto IssuerSizeMismatchError;
if (0 != memcmp(
pciCountersigner->Issuer.pbData,
pisn->issuer.value,
pciCountersigner->Issuer.cbData))
goto IssuerValueMismatchError;
if (pisn->serialNumber.length != pciCountersigner->SerialNumber.cbData)
goto SerialNumberSizeMismatchError;
if (ICM_ReverseCompare(
pisn->serialNumber.value,
pciCountersigner->SerialNumber.pbData,
pciCountersigner->SerialNumber.cbData))
goto SerialNumberValueMismatchError;
if (!ICM_GetVerifySignatureStuff(
pciCountersigner,
&hCryptProv,
&hPubKey,
&dwPubKeyAlgId,
&dwPubKeyFlags)) goto GetSignatureStuffError;
// hash the encrypted digest
if (!ICM_GetCapiFromAlgidBlob(
(PCRYPT_DATA_BLOB)&posibCS->digestAlgorithm,
&dwDigestAlgoCAPI))
goto GetCapiFromAlgidBlobError;
if (!CryptCreateHash(
hCryptProv,
dwDigestAlgoCAPI,
NULL, // hKey - optional for MAC
0, // dwFlags
&hHashRaw))
goto CreateHashError;
if (!ICM_UpdateDigest(
hHashRaw,
posib->encryptedDigest.value,
posib->encryptedDigest.length))
goto HashDataError;
if (0 == (posibCS->bit_mask & authAttributes_present))
goto CountersignerAuthAttributesMissingError;
// check that the message digest attr matches the hashed encrypted digest
if (!CryptGetHashParam(
hHashRaw,
HP_HASHVAL,
NULL,
&cbHash,
0)) // dwFlags
goto GetHashParamSizeError;
if (NULL == (pbHash = (PBYTE)ICM_AllocA( cbHash)))
goto AllocHashParamError;
if (!CryptGetHashParam(
hHashRaw,
HP_HASHVAL,
pbHash,
&cbHash,
0)) // dwFlags
goto GetHashParamError;
// find the message digest attr value
if (!ICM_GetAttrValue(
(Attributes *)&posibCS->authAttributes, // same, except for NOCOPY
&oidMessageDigest,
&anyValue))
goto FindAttrError;
// find the message digest octets
if (!Asn1UtilExtractContent(
(BYTE *) anyValue.value,
anyValue.length,
&cbMessageDigest,
(const BYTE **)&pbMessageDigest))
goto ExtractContentError;
// hash sizes equal?
if (cbHash != cbMessageDigest)
goto HashCompareSizeError;
// hash octets equal?
if (memcmp( pbMessageDigest, pbHash, cbHash))
goto HashCompareValueError;
// Now that we have verified the message digest octets,
// get the hash of the authenticated attributes.
if (!ICM_GetAttrsHash(
dwDigestAlgoCAPI,
hCryptProv,
(Attributes *)&posibCS->authAttributes, // same, except for NOCOPY
&hHashAttr))
goto GetAuthAttrsHashError;
// verify the hash, signature, and public key are consistent
if (!ICM_VerifySignature(
hHashAttr,
hPubKey,
dwPubKeyAlgId,
dwPubKeyFlags,
posibCS->encryptedDigest.value,
posibCS->encryptedDigest.length))
goto VerifySignatureError;
fRet = TRUE;
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, posib);
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, posibCS);
PkiAsn1FreeInfo(pDec, IssuerAndSerialNumber_PDU, pisn);
if (hHashRaw)
CryptDestroyHash( hHashRaw);
if (hHashAttr)
CryptDestroyHash( hHashAttr);
if (hPubKey)
CryptDestroyKey( hPubKey);
ICM_FreeA( pbHash);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidEncodingTypeError,E_INVALIDARG)
SET_ERROR_VAR(DecodeSignerInfoError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(DecodeSignerInfoCSError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(DecodeIssuerAndSerialNumberError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(IssuerSizeMismatchError,CRYPT_E_ISSUER_SERIALNUMBER)
SET_ERROR(IssuerValueMismatchError,CRYPT_E_ISSUER_SERIALNUMBER)
SET_ERROR(SerialNumberSizeMismatchError,CRYPT_E_ISSUER_SERIALNUMBER)
SET_ERROR(SerialNumberValueMismatchError,CRYPT_E_ISSUER_SERIALNUMBER)
SET_ERROR(CountersignerAuthAttributesMissingError,CRYPT_E_AUTH_ATTR_MISSING)
SET_ERROR(FindAttrError,CRYPT_E_AUTH_ATTR_MISSING)
SET_ERROR(ExtractContentError,CRYPT_E_UNEXPECTED_ENCODING)
SET_ERROR(HashCompareSizeError,CRYPT_E_HASH_VALUE)
SET_ERROR(HashCompareValueError,CRYPT_E_HASH_VALUE)
TRACE_ERROR(GetCapiFromAlgidBlobError) // error already set
TRACE_ERROR(CreateHashError) // error already set
TRACE_ERROR(HashDataError) // error already set
TRACE_ERROR(GetHashParamSizeError) // error already set
TRACE_ERROR(AllocHashParamError) // error already set
TRACE_ERROR(GetHashParamError) // error already set
TRACE_ERROR(GetAuthAttrsHashError) // error already set
TRACE_ERROR(GetSignatureStuffError) // error already set
TRACE_ERROR(VerifySignatureError) // error already set
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Set an OSS Any
//--------------------------------------------------------------------------
void
WINAPI
ICM_SetOssAny(
IN PCRYPT_OBJID_BLOB pInfo,
OUT OpenType *pOss
)
{
memset(pOss, 0, sizeof(*pOss));
pOss->encoded = pInfo->pbData;
pOss->length = pInfo->cbData;
}
//+-------------------------------------------------------------------------
// Encode a CMS SignerInfo
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
ICM_CmsSignerInfoEncode(
IN DWORD dwEncodingType,
IN LPCSTR lpszStructType,
IN PCMSG_CMS_SIGNER_INFO pInfo,
OUT PBYTE pbEncoded,
IN OUT PDWORD pcbEncoded)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
SignerInfo osi; ZEROSTRUCT(osi);
PCMSG_CMS_SIGNER_INFO psi = pInfo;
DWORD i;
Attribute *poatrAuth = NULL;
Attribute *poatrUnauth = NULL;
Attribute *poatr;
PCRYPT_ATTRIBUTE patr;
if (GET_CMSG_ENCODING_TYPE(dwEncodingType) != PKCS_7_ASN_ENCODING)
goto InvalidEncodingTypeError;
// version
osi.version = psi->dwVersion;
// sid
if (!ICM_SetOssCertIdentifier(
&psi->SignerId,
&osi.sid
))
goto SetOssCertIdentifierError;
// digestAlgorithm
if (!ICM_Asn1ToAlgorithmIdentifier(
&psi->HashAlgorithm,
&osi.digestAlgorithm))
goto DigestAsn1ToAlgorithmIdentifierError;
// authenticatedAttributes
if (psi->AuthAttrs.cAttr) {
osi.bit_mask |= authenticatedAttributes_present;
osi.authenticatedAttributes.count = psi->AuthAttrs.cAttr;
if (NULL == (poatrAuth = (Attribute *)ICM_AllocA(
psi->AuthAttrs.cAttr * sizeof(Attribute))))
goto AllocAuthAttrsError;
osi.authenticatedAttributes.value = poatrAuth;
for (i=psi->AuthAttrs.cAttr, patr=psi->AuthAttrs.rgAttr, poatr=poatrAuth;
i>0;
i--, patr++, poatr++) {
if (!ICM_Asn1ToAttribute( patr, poatr))
goto Asn1AuthenticatedAttributeError;
}
}
// digestEncryptionAlgorithm
if (!ICM_FillAsnDigestEncryptionAlgorithm(
NULL, // pcmi
&psi->HashEncryptionAlgorithm,
&osi.digestEncryptionAlgorithm))
goto FillAsnDigestEncryptionAlgorithmError;
// encryptedDigest
osi.encryptedDigest.length = psi->EncryptedHash.cbData;
osi.encryptedDigest.value = psi->EncryptedHash.pbData;
// unauthenticatedAttributes
if (psi->UnauthAttrs.cAttr) {
osi.bit_mask |= unauthAttributes_present;
osi.unauthAttributes.count = psi->UnauthAttrs.cAttr;
if (NULL == (poatrUnauth = (Attribute *)ICM_AllocA(
psi->UnauthAttrs.cAttr * sizeof(Attribute))))
goto AllocUnauthAttrsError;
osi.unauthAttributes.value = poatrUnauth;
for (i=psi->UnauthAttrs.cAttr, patr=psi->UnauthAttrs.rgAttr, poatr=poatrUnauth;
i>0;
i--, patr++, poatr++) {
if (!ICM_Asn1ToAttribute( patr, poatr))
goto Asn1UnauthenticatedAttributeError;
}
}
fRet = PkiAsn1EncodeInfo(
ICM_GetEncoder(),
SignerInfo_PDU,
&osi,
pbEncoded,
pcbEncoded);
if (!fRet)
dwError = GetLastError();
CommonReturn:
ICM_FreeOssCertIdentifier(&osi.sid);
if (poatrAuth) {
for (i=psi->AuthAttrs.cAttr, poatr=poatrAuth;
i>0;
i--, poatr++)
ICM_Free( poatr->attributeValue.value);
}
if (poatrUnauth) {
for (i=psi->UnauthAttrs.cAttr, poatr=poatrUnauth;
i>0;
i--, poatr++)
ICM_Free( poatr->attributeValue.value);
}
ICM_FreeA( poatrAuth);
ICM_FreeA( poatrUnauth);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
*pcbEncoded = 0;
goto CommonReturn;
SET_ERROR(InvalidEncodingTypeError,E_INVALIDARG)
TRACE_ERROR(SetOssCertIdentifierError) // error already set
TRACE_ERROR(DigestAsn1ToAlgorithmIdentifierError) // error already set
TRACE_ERROR(AllocAuthAttrsError) // error already set
TRACE_ERROR(Asn1AuthenticatedAttributeError) // error already set
TRACE_ERROR(FillAsnDigestEncryptionAlgorithmError) // error already set
TRACE_ERROR(AllocUnauthAttrsError) // error already set
TRACE_ERROR(Asn1UnauthenticatedAttributeError) // error already set
lpszStructType;
}
//+-------------------------------------------------------------------------
// Encode a Pkcs SignerInfo
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
ICM_PkcsSignerInfoEncode(
IN DWORD dwEncodingType,
IN LPCSTR lpszStructType,
IN PCMSG_SIGNER_INFO pInfo,
OUT PBYTE pbEncoded,
IN OUT PDWORD pcbEncoded)
{
CMSG_CMS_SIGNER_INFO csi;
CERT_INFO CertInfo;
csi.dwVersion = pInfo->dwVersion;
CertInfo.Issuer = pInfo->Issuer;
CertInfo.SerialNumber = pInfo->SerialNumber;
ICM_GetCertIdFromCertInfo(&CertInfo, &csi.SignerId);
csi.HashAlgorithm = pInfo->HashAlgorithm;
csi.HashEncryptionAlgorithm = pInfo->HashEncryptionAlgorithm;
csi.EncryptedHash = pInfo->EncryptedHash;
csi.AuthAttrs = pInfo->AuthAttrs;
csi.UnauthAttrs = pInfo->UnauthAttrs;
return ICM_CmsSignerInfoEncode(
dwEncodingType,
lpszStructType,
&csi,
pbEncoded,
pcbEncoded
);
}
//+-------------------------------------------------------------------------
// Get fields shared by PKCS and CMS SignerInfos
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssSharedSignerInfo(
IN SignerInfo *posi,
IN CBlobList *pUnauthAttrList,
OUT PCRYPT_ALGORITHM_IDENTIFIER pHashAlgorithm,
OUT PCRYPT_ALGORITHM_IDENTIFIER pHashEncryptionAlgorithm,
OUT PCRYPT_DATA_BLOB pEncryptedHash,
OUT PCRYPT_ATTRIBUTES pAuthAttrs,
OUT PCRYPT_ATTRIBUTES pUnauthAttrs,
IN OUT PBYTE *ppbExtra,
IN OUT LONG *plRemainExtra)
{
BOOL fRet;
if (!ICM_GetOssAlgorithm( &posi->digestAlgorithm,
pHashAlgorithm, ppbExtra, plRemainExtra))
goto GetOssHashAlgorithmError;
if (!ICM_GetOssAlgorithm( &posi->digestEncryptionAlgorithm,
pHashEncryptionAlgorithm, ppbExtra, plRemainExtra))
goto GetOssHashEncryptionAlgorithmError;
if (!ICM_GetOssAny( (Any *)&posi->encryptedDigest,
pEncryptedHash, ppbExtra, plRemainExtra))
goto GetOssEncryptedHashError;
if (posi->bit_mask & authenticatedAttributes_present) {
if (!ICM_GetOssAttributes( &posi->authenticatedAttributes,
pAuthAttrs, ppbExtra, plRemainExtra))
goto GetOssAuthAttrsError;
} else if (0 <= *plRemainExtra)
pAuthAttrs->cAttr = 0;
if (posi->bit_mask & unauthAttributes_present || pUnauthAttrList) {
if (pUnauthAttrList) {
if (!ICM_GetCListAttributes( pUnauthAttrList,
pUnauthAttrs, ppbExtra, plRemainExtra))
goto GetCListUnauthAttrsError;
} else {
if (!ICM_GetOssAttributes( &posi->unauthAttributes,
pUnauthAttrs, ppbExtra, plRemainExtra))
goto GetOssUnauthAttrsError;
}
} else if (0 <= *plRemainExtra)
pUnauthAttrs->cAttr = 0;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssHashAlgorithmError) // error already set
TRACE_ERROR(GetOssHashEncryptionAlgorithmError) // error already set
TRACE_ERROR(GetOssEncryptedHashError) // error already set
TRACE_ERROR(GetOssAuthAttrsError) // error already set
TRACE_ERROR(GetCListUnauthAttrsError) // error already set
TRACE_ERROR(GetOssUnauthAttrsError) // error already set
}
//+-------------------------------------------------------------------------
// Get a CMS SignerInfo
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssCmsSignerInfo(
IN SignerInfo *posi,
IN CBlobList *pUnauthAttrList,
OUT PCMSG_CMS_SIGNER_INFO psi,
IN OUT PBYTE *ppbExtra,
IN OUT LONG *plRemainExtra)
{
BOOL fRet;
if (0 <= *plRemainExtra)
psi->dwVersion = posi->version;
if (!ICM_GetOssCertIdentifier(&posi->sid, &psi->SignerId,
ppbExtra, plRemainExtra))
goto GetOssCertIdentifierError;
if (!ICM_GetOssSharedSignerInfo(
posi,
pUnauthAttrList,
&psi->HashAlgorithm,
&psi->HashEncryptionAlgorithm,
&psi->EncryptedHash,
&psi->AuthAttrs,
&psi->UnauthAttrs,
ppbExtra,
plRemainExtra))
goto GetOssSharedSignerInfoError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssCertIdentifierError) // error already set
TRACE_ERROR(GetOssSharedSignerInfoError) // error already set
}
//+-------------------------------------------------------------------------
// Get a PKCS SignerInfo
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssPkcsSignerInfo(
IN SignerInfo *posi,
IN CBlobList *pUnauthAttrList,
OUT PCMSG_SIGNER_INFO psi,
IN OUT PBYTE *ppbExtra,
IN OUT LONG *plRemainExtra)
{
BOOL fRet;
if (0 <= *plRemainExtra)
psi->dwVersion = posi->version;
if (!ICM_GetOssIssuerAndSerialNumberFromCertId(&posi->sid,
&psi->Issuer, &psi->SerialNumber, ppbExtra, plRemainExtra))
goto GetOssIssuerAndSerialNumberError;
if (!ICM_GetOssSharedSignerInfo(
posi,
pUnauthAttrList,
&psi->HashAlgorithm,
&psi->HashEncryptionAlgorithm,
&psi->EncryptedHash,
&psi->AuthAttrs,
&psi->UnauthAttrs,
ppbExtra,
plRemainExtra))
goto GetOssSharedSignerInfoError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssIssuerAndSerialNumberError) // error already set
TRACE_ERROR(GetOssSharedSignerInfoError) // error already set
}
//+-------------------------------------------------------------------------
// Decode a PKCS SignerInfo blob.
//
// Returns: FALSE iff fails
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
ICM_PkcsSignerInfoDecode(
IN DWORD dwEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PCMSG_SIGNER_INFO pInfo,
IN OUT DWORD *pcbInfo)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
LONG lData;
SignerInfo *posi = NULL;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
PCMSG_SIGNER_INFO psi = pInfo;
LONG lRemainExtra;
PBYTE pbExtra;
if (pInfo == NULL)
*pcbInfo = 0;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posi,
SignerInfo_PDU,
pbEncoded,
cbEncoded)))
goto Asn1DecodeSignerInfoError;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CMSG_SIGNER_INFO));
lRemainExtra = (LONG)*pcbInfo - lData;
if (0 > lRemainExtra) {
psi = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)psi + lData;
}
if (!ICM_GetOssPkcsSignerInfo(
posi,
NULL, // pUnauthAttrList
psi, &pbExtra, &lRemainExtra))
goto GetOssSignerInfoError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pInfo, pcbInfo);
if (!fRet)
dwError = GetLastError();
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfo_PDU, posi);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
*pcbInfo = 0;
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(Asn1DecodeSignerInfoError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(GetOssSignerInfoError) // error already set
dwFlags;
lpszStructType;
}
//+-------------------------------------------------------------------------
// Find the Pkcs SignerInfo by index, if the message type permits and if the
// index value is in range.
//
// Returns: FALSE iff fails
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetPkcsSignerInfo(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwIndex,
OUT PVOID pvData,
IN OUT PDWORD pcbData)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
LONG lData;
CSignerNode *pSignerNode;
SignerInfo *posi = NULL;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
CRYPT_DATA_BLOB DataBlob;
PCMSG_SIGNER_INFO psi = (PCMSG_SIGNER_INFO)pvData;
LONG lRemainExtra;
PBYTE pbExtra;
if (!ICM_FindSignerInfo( pcmi, dwIndex, (PVOID *)&pSignerNode))
goto FindSignerInfoError;
DataBlob = pSignerNode->Data()->blob;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posi,
SignerInfo_PDU,
DataBlob.pbData,
DataBlob.cbData)))
goto Asn1DecodeSignerInfoError;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CMSG_SIGNER_INFO));
lRemainExtra = (LONG)*pcbData - lData;
if (0 > lRemainExtra) {
psi = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)psi + lData;
}
if (!ICM_GetOssPkcsSignerInfo( posi, pSignerNode->Data()->pUnauthAttrList,
psi, &pbExtra, &lRemainExtra))
goto GetOssSignerInfoError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pvData, pcbData);
if (!fRet)
dwError = GetLastError();
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfo_PDU, posi);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(Asn1DecodeSignerInfoError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(FindSignerInfoError) // error already set
TRACE_ERROR(GetOssSignerInfoError) // error already set
}
//+-------------------------------------------------------------------------
// Decode a CMS SignerInfo blob.
//
// Returns: FALSE iff fails
//--------------------------------------------------------------------------
STATIC
BOOL
WINAPI
ICM_CmsSignerInfoDecode(
IN DWORD dwEncodingType,
IN LPCSTR lpszStructType,
IN const BYTE *pbEncoded,
IN DWORD cbEncoded,
IN DWORD dwFlags,
OUT PCMSG_CMS_SIGNER_INFO pInfo,
IN OUT DWORD *pcbInfo)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
LONG lData;
SignerInfo *posi = NULL;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
PCMSG_CMS_SIGNER_INFO psi = pInfo;
LONG lRemainExtra;
PBYTE pbExtra;
if (pInfo == NULL)
*pcbInfo = 0;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posi,
SignerInfo_PDU,
pbEncoded,
cbEncoded)))
goto Asn1DecodeSignerInfoError;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CMSG_CMS_SIGNER_INFO));
lRemainExtra = (LONG)*pcbInfo - lData;
if (0 > lRemainExtra) {
psi = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)psi + lData;
}
if (!ICM_GetOssCmsSignerInfo(
posi,
NULL, // pUnauthAttrList
psi, &pbExtra, &lRemainExtra))
goto GetOssSignerInfoError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pInfo, pcbInfo);
if (!fRet)
dwError = GetLastError();
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfo_PDU, posi);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
*pcbInfo = 0;
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(Asn1DecodeSignerInfoError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(GetOssSignerInfoError) // error already set
dwFlags;
lpszStructType;
}
//+-------------------------------------------------------------------------
// Find the CMS SignerInfo by index, if the message type permits and if the
// index value is in range.
//
// Returns: FALSE iff fails
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetCmsSignerInfo(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwIndex,
OUT PVOID pvData,
IN OUT PDWORD pcbData)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
LONG lData;
CSignerNode *pSignerNode;
SignerInfo *posi = NULL;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
CRYPT_DATA_BLOB DataBlob;
PCMSG_CMS_SIGNER_INFO psi = (PCMSG_CMS_SIGNER_INFO)pvData;
LONG lRemainExtra;
PBYTE pbExtra;
if (!ICM_FindSignerInfo( pcmi, dwIndex, (PVOID *)&pSignerNode))
goto FindSignerInfoError;
DataBlob = pSignerNode->Data()->blob;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posi,
SignerInfo_PDU,
DataBlob.pbData,
DataBlob.cbData)))
goto Asn1DecodeSignerInfoError;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CMSG_CMS_SIGNER_INFO));
lRemainExtra = (LONG)*pcbData - lData;
if (0 > lRemainExtra) {
psi = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)psi + lData;
}
if (!ICM_GetOssCmsSignerInfo( posi, pSignerNode->Data()->pUnauthAttrList,
psi, &pbExtra, &lRemainExtra))
goto GetOssSignerInfoError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pvData, pcbData);
if (!fRet)
dwError = GetLastError();
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfo_PDU, posi);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(Asn1DecodeSignerInfoError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(FindSignerInfoError) // error already set
TRACE_ERROR(GetOssSignerInfoError) // error already set
}
//+-------------------------------------------------------------------------
// Get the data for a field in a Signer, while encoding a message
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetSignerParamEncoding(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwIndex,
IN DWORD dwParamType,
OUT PVOID pvData,
IN OUT PDWORD pcbData)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
ASN1error_e Asn1Err;
ASN1encoding_t pEnc = ICM_GetEncoder();
PBYTE pbEncoded = NULL;
DWORD cbEncoded;
SignerInfo *posi = NULL;
if (!ICM_FindSignerInfo( pcmi, dwIndex, (PVOID *)&posi))
goto FindSignerInfoError;
switch (dwParamType) {
case CMSG_ENCODED_SIGNER:
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
posi,
SignerInfo_PDU,
&pbEncoded,
&cbEncoded)))
goto EncodeSignerInfoError;
break;
default:
goto InvalidParamError;
}
fRet = ICM_CopyOut(
pbEncoded,
cbEncoded,
(PBYTE)pvData,
pcbData);
if (!fRet)
dwError = GetLastError();
CommonReturn:
PkiAsn1FreeEncoded(pEnc, pbEncoded);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(FindSignerInfoError) // error already set
SET_ERROR_VAR(EncodeSignerInfoError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(InvalidParamError,E_INVALIDARG)
}
//+-------------------------------------------------------------------------
// Get the data for a field in a Signer
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetSignerParam(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD dwIndex,
IN DWORD dwParamType,
OUT PVOID pvData,
IN OUT PDWORD pcbData)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
CRYPT_DATA_BLOB DataBlob;
ASN1uint32_t pdunumRef = 0; // invalid
SignerInfoWithBlobs *posib = NULL;
PVOID pv = NULL;
CSignerNode *pSignerNode;
if (!ICM_FindSignerInfo( pcmi, dwIndex, (PVOID *)&pSignerNode))
goto FindSignerInfoError;
DataBlob = pSignerNode->Data()->blob;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posib,
SignerInfoWithBlobs_PDU,
DataBlob.pbData,
DataBlob.cbData)))
goto DecodeSignerInfoError;
switch (dwParamType) {
case CMSG_SIGNER_INFO_PARAM:
fRet = ICM_GetPkcsSignerInfo( pcmi, dwIndex, pvData, pcbData);
break;
case CMSG_CMS_SIGNER_INFO_PARAM:
fRet = ICM_GetCmsSignerInfo( pcmi, dwIndex, pvData, pcbData);
break;
case CMSG_ENCRYPTED_DIGEST:
fRet = ICM_CopyOut(
(PBYTE)posib->encryptedDigest.value,
(DWORD)posib->encryptedDigest.length,
(PBYTE)pvData,
pcbData);
break;
case CMSG_ENCODED_SIGNER:
if (pSignerNode->Data()->pUnauthAttrList) {
// Need to re-encode with new unauth attrs
goto ReEncodedSignerNotImplementedError;
} else {
fRet = ICM_CopyOut(
pSignerNode->Data()->blob.pbData,
pSignerNode->Data()->blob.cbData,
(PBYTE)pvData,
pcbData);
}
break;
case CMSG_SIGNER_CERT_INFO_PARAM:
case CMSG_SIGNER_CERT_ID_PARAM:
pdunumRef = CertIdentifier_PDU;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
&pv,
pdunumRef,
(BYTE *) posib->sid.value,
posib->sid.length)))
goto DecodeCertIdentifierError;
if (CMSG_SIGNER_CERT_INFO_PARAM == dwParamType)
fRet = ICM_GetCertInfoIssuerAndSerialNumber(
(CertIdentifier *)pv,
pvData,
pcbData);
else
fRet = ICM_GetCertId(
(CertIdentifier *)pv,
pvData,
pcbData);
break;
case CMSG_SIGNER_HASH_ALGORITHM_PARAM:
pdunumRef = AlgorithmIdentifierNC2_PDU;
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
&pv,
pdunumRef,
(BYTE *) posib->digestAlgorithm.value,
posib->digestAlgorithm.length)))
goto DecodeAlgorithmIdentifierNC2Error;
fRet = ICM_GetALGORITHM_IDENTIFIER(
(AlgorithmIdentifier *)pv,
pvData,
pcbData);
break;
case CMSG_SIGNER_AUTH_ATTR_PARAM:
if (posib->bit_mask & authAttributes_present)
fRet = ICM_GetAttributesData(
(Attributes *)&posib->authAttributes,
pvData,
pcbData);
else
goto AuthAttrMissingError;
break;
case CMSG_SIGNER_UNAUTH_ATTR_PARAM:
if (posib->bit_mask & unauthAttributes_present)
fRet = ICM_GetAttributesData(
(Attributes *)&posib->unauthAttributes,
pvData,
pcbData);
else
goto UnauthAttrMissingError;
break;
default:
goto InvalidParamError;
}
if (!fRet)
dwError = GetLastError();
CommonReturn:
PkiAsn1FreeInfo(pDec, SignerInfoWithBlobs_PDU, posib);
PkiAsn1FreeInfo(pDec, pdunumRef, pv);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(DecodeSignerInfoError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(DecodeCertIdentifierError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(DecodeAlgorithmIdentifierNC2Error, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(AuthAttrMissingError,CRYPT_E_ATTRIBUTES_MISSING)
SET_ERROR(UnauthAttrMissingError,CRYPT_E_ATTRIBUTES_MISSING)
SET_ERROR(ReEncodedSignerNotImplementedError,E_INVALIDARG)
SET_ERROR(InvalidParamError,E_INVALIDARG)
TRACE_ERROR(FindSignerInfoError) // error already set
}
//+-------------------------------------------------------------------------
// Get the encoded blob for a SignerInfo
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetEncodedSignerInfo(
IN DWORD dwEncodingType,
IN PSIGNER_DATA_INFO pSignerInfo,
OUT PBYTE pbSignerInfo,
IN OUT PDWORD pcbSignerInfo)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
SignerInfoWithAttrBlobs *posiab = NULL;
Any *pAnyAttr = NULL;
Any *pAny;
DWORD cAnyAttr;
AttributesNC unauthAttributesSave;
ZEROSTRUCT(unauthAttributesSave);
#ifdef OSS_CRYPT_ASN1
BYTE bit_maskSave = 0;
#else
ASN1uint16_t bit_maskSave = 0;
#endif // OSS_CRYPT_ASN1
ASN1error_e Asn1Err;
ASN1decoding_t pDec = ICM_GetDecoder();
ASN1encoding_t pEnc = ICM_GetEncoder();
PBYTE pbEncoded = NULL;
DWORD cbEncoded;
CBlobNode *pnBlob;
DWORD cbOut;
PBYTE pbOut;
if (GET_CMSG_ENCODING_TYPE(dwEncodingType) != PKCS_7_ASN_ENCODING)
goto InvalidEncodingTypeError;
if (pSignerInfo->pUnauthAttrList) {
if (0 != (Asn1Err = PkiAsn1Decode(
pDec,
(void **)&posiab,
SignerInfoWithAttrBlobs_PDU,
pSignerInfo->blob.pbData,
pSignerInfo->blob.cbData)))
goto DecodeSignerInfoWithAttrBlobsError;
// We have to take into account both the case where we have added
// unauth attrs, and the case where we have removed them. There might
// have been unauth attrs in the original message, and we removed
// them all. Or, there might have been none originally, and we added
// some.
bit_maskSave = posiab->bit_mask;
unauthAttributesSave = posiab->unauthAttributes;
cAnyAttr = pSignerInfo->pUnauthAttrList->Length();
posiab->bit_mask &= ~unauthAttributes_present;
posiab->bit_mask |= (cAnyAttr > 0) ? unauthAttributes_present : 0;
if (NULL == (pAnyAttr = (Any *)ICM_AllocA( cAnyAttr * sizeof(Any))))
goto AllocAnyAttrError;
posiab->unauthAttributes.count = cAnyAttr;
posiab->unauthAttributes.value = pAnyAttr;
for (pnBlob=pSignerInfo->pUnauthAttrList->Head(), pAny=pAnyAttr;
pnBlob;
pnBlob=pnBlob->Next(), pAny++)
*pAny = *(Any *)pnBlob->Data();
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
posiab,
SignerInfoWithAttrBlobs_PDU,
&pbEncoded,
&cbEncoded)))
goto EncodeSignerInfoWithAttrBlobsError;
cbOut = cbEncoded;
pbOut = pbEncoded;
} else {
cbOut = pSignerInfo->blob.cbData;
pbOut = pSignerInfo->blob.pbData;
}
fRet = ICM_CopyOut(
pbOut,
cbOut,
pbSignerInfo,
pcbSignerInfo);
if (!fRet)
dwError = GetLastError();
CommonReturn:
ICM_FreeA( pAnyAttr);
if (posiab) {
posiab->bit_mask = bit_maskSave;
posiab->unauthAttributes = unauthAttributesSave;
PkiAsn1FreeDecoded(pDec, posiab, SignerInfoWithAttrBlobs_PDU);
}
PkiAsn1FreeEncoded(pEnc, pbEncoded);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(InvalidEncodingTypeError,E_INVALIDARG)
SET_ERROR_VAR(DecodeSignerInfoWithAttrBlobsError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(EncodeSignerInfoWithAttrBlobsError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(AllocAnyAttrError) // error already set
}
//+-------------------------------------------------------------------------
// Get the data for a field in a Signer
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetEncodedMessageParam(
IN PCRYPT_MSG_INFO pcmi,
OUT PBYTE pbEncodedMessage,
IN OUT PDWORD pcbEncodedMessage)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
SignedDataWithBlobs *posdb = NULL;
PSIGNED_DATA_INFO psdi = pcmi->psdi;
Any *pAny;
PSIGNER_DATA_INFO pSignerInfo;
ASN1error_e Asn1Err;
ASN1encoding_t pEnc = ICM_GetEncoder();
PBYTE pbEncodedSignedData = NULL;
DWORD cbEncodedSignedData;
PBYTE pbEncodedContentInfo = NULL;
DWORD cbEncodedContentInfo;
CSignerNode *pnSigner;
CBlobNode *pnBlob;
DWORD cb;
PBYTE pb;
DWORD i;
ContentInfo ci;
if (NULL == (posdb = (SignedDataWithBlobs *)ICM_AllocZeroA(
sizeof(SignedDataWithBlobs) +
sizeof(Any) *
(psdi->pAlgidList->Length() +
psdi->pCertificateList->Length() +
psdi->pCrlList->Length() +
psdi->pSignerList->Length()))))
goto AllocSignedDataWithBlobsError;
pAny = (Any *)(posdb + 1);
// version
posdb->version = psdi->version;
// digest algorithms
posdb->digestAlgorithms.count = psdi->pAlgidList->Length();
posdb->digestAlgorithms.value = pAny;
for (pnBlob=psdi->pAlgidList->Head();
pnBlob;
pnBlob=pnBlob->Next())
*pAny++ = *(Any *)pnBlob->Data();
// contentInfo
posdb->contentInfo.contentType.count = SIZE_OSS_OID;
if (!PkiAsn1ToObjectIdentifier(
psdi->pci->pszContentType,
&posdb->contentInfo.contentType.count,
posdb->contentInfo.contentType.value))
goto PkiAsn1ToObjectIdentifierError;
if (psdi->pci->content.cbData) {
posdb->contentInfo.bit_mask |= content_present;
posdb->contentInfo.content.length = psdi->pci->content.cbData;
posdb->contentInfo.content.value = psdi->pci->content.pbData;
}
// certificates
posdb->certificates.count = psdi->pCertificateList->Length();
#ifdef OSS_CRYPT_ASN1
posdb->certificates.certificates = pAny;
#else
posdb->certificates.value = pAny;
#endif // OSS_CRYPT_ASN1
for (pnBlob=psdi->pCertificateList->Head();
pnBlob;
pnBlob=pnBlob->Next()) {
posdb->bit_mask |= certificates_present;
*pAny++ = *(Any *)pnBlob->Data();
}
// crls
posdb->crls.count = psdi->pCrlList->Length();
#ifdef OSS_CRYPT_ASN1
posdb->crls.crls = pAny;
#else
posdb->crls.value = pAny;
#endif // OSS_CRYPT_ASN1
for (pnBlob=psdi->pCrlList->Head();
pnBlob;
pnBlob=pnBlob->Next()) {
posdb->bit_mask |= crls_present;
*pAny++ = *(Any *)pnBlob->Data();
}
// signerInfos
posdb->signerInfos.count = psdi->pSignerList->Length();
posdb->signerInfos.value = pAny;
for (pnSigner=psdi->pSignerList->Head();
pnSigner;
pnSigner=pnSigner->Next()) {
pSignerInfo = pnSigner->Data();
if (!ICM_GetEncodedSignerInfo(
PKCS_7_ASN_ENCODING,
pnSigner->Data(),
NULL,
&cb))
goto GetEncodedSignerInfoSizeError;
if (NULL == (pb = (PBYTE)ICM_AllocA( cb)))
goto AllocEncodedSignerInfoError;
if (!ICM_GetEncodedSignerInfo(
PKCS_7_ASN_ENCODING,
pnSigner->Data(),
pb,
&cb))
goto GetEncodedSignerInfoError;
pAny->length = cb;
pAny->value = pb;
pAny++;
}
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
posdb,
SignedDataWithBlobs_PDU,
&pbEncodedSignedData,
&cbEncodedSignedData)))
goto EncodeSignedDataWithBlobsError;
ci.contentType.count = SIZE_OSS_OID;
if (!PkiAsn1ToObjectIdentifier(
szOID_RSA_signedData,
&ci.contentType.count,
ci.contentType.value))
goto ConvSignedDataToOidError;
ci.bit_mask = content_present;
ci.content.length = cbEncodedSignedData;
ci.content.value = pbEncodedSignedData;
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
&ci,
ContentInfo_PDU,
&pbEncodedContentInfo,
&cbEncodedContentInfo)))
goto EncodeContentInfoError;
fRet = ICM_CopyOut(
pbEncodedContentInfo,
cbEncodedContentInfo,
pbEncodedMessage,
pcbEncodedMessage);
if (!fRet)
dwError = GetLastError();
CommonReturn:
PkiAsn1FreeEncoded(pEnc, pbEncodedSignedData);
PkiAsn1FreeEncoded(pEnc, pbEncodedContentInfo);
if (NULL != posdb) {
for (i=posdb->signerInfos.count, pAny=posdb->signerInfos.value;
i>0;
i--, pAny++)
ICM_FreeA( pAny->value);
ICM_FreeA(posdb);
}
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(PkiAsn1ToObjectIdentifierError,CRYPT_E_OID_FORMAT)
SET_ERROR_VAR(EncodeSignedDataWithBlobsError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(ConvSignedDataToOidError,CRYPT_E_OID_FORMAT)
SET_ERROR_VAR(EncodeContentInfoError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(AllocSignedDataWithBlobsError) // error already set
TRACE_ERROR(GetEncodedSignerInfoSizeError) // error already set
TRACE_ERROR(AllocEncodedSignerInfoError) // error already set
TRACE_ERROR(GetEncodedSignerInfoError) // error already set
}
#ifdef CMS_PKCS7
//+-------------------------------------------------------------------------
// Get Oss OctetString
//--------------------------------------------------------------------------
void
inline
WINAPI
ICM_GetOssOctetString(
IN OctetStringType *pOssOctetString,
OUT PCRYPT_DATA_BLOB pOctetString,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
PkiAsn1GetOctetString(pOssOctetString->length, pOssOctetString->value, 0,
pOctetString, ppbExtra, plRemainExtra);
}
//+-------------------------------------------------------------------------
// Get Oss BitString
//--------------------------------------------------------------------------
void
inline
WINAPI
ICM_GetOssBitString(
IN BitStringType *pOssBitString,
OUT PCRYPT_BIT_BLOB pBitString,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
PkiAsn1GetBitString(pOssBitString->length, pOssBitString->value, 0,
pBitString, ppbExtra, plRemainExtra);
}
//+-------------------------------------------------------------------------
// Get an Oss IssuerAndSerialNumber
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssIssuerAndSerialNumber(
IN IssuerAndSerialNumber *pOssIssuerAndSerialNumber,
OUT PCERT_ISSUER_SERIAL_NUMBER pIssuerAndSerialNumber,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra)
{
ICM_GetOssHugeInteger(&pOssIssuerAndSerialNumber->serialNumber,
&pIssuerAndSerialNumber->SerialNumber, ppbExtra, plRemainExtra);
return ICM_GetOssAny(&pOssIssuerAndSerialNumber->issuer,
&pIssuerAndSerialNumber->Issuer, ppbExtra, plRemainExtra);
}
//+-------------------------------------------------------------------------
// Get Oss CertIdentifier
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssCertIdentifier(
IN CertIdentifier *pOssCertId,
OUT PCERT_ID pCertId,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
BOOL fRet;
if (0 <= *plRemainExtra) {
assert(CERT_ID_ISSUER_SERIAL_NUMBER == issuerAndSerialNumber_chosen);
assert(CERT_ID_KEY_IDENTIFIER == subjectKeyIdentifier_chosen);
pCertId->dwIdChoice = pOssCertId->choice;
}
switch (pOssCertId->choice) {
case issuerAndSerialNumber_chosen:
if (!ICM_GetOssIssuerAndSerialNumber(
&pOssCertId->u.issuerAndSerialNumber,
&pCertId->IssuerSerialNumber, ppbExtra, plRemainExtra))
goto GetOssIssuerAndSerialNumberError;
break;
case subjectKeyIdentifier_chosen:
ICM_GetOssOctetString( &pOssCertId->u.subjectKeyIdentifier,
&pCertId->KeyId, ppbExtra, plRemainExtra);
break;
default:
goto InvalidCertIdChoice;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssIssuerAndSerialNumberError)
SET_ERROR(InvalidCertIdChoice, CRYPT_E_BAD_ENCODE)
}
//+-------------------------------------------------------------------------
// Get Oss OtherKeyAttribute
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssOtherKeyAttribute(
IN OtherKeyAttribute *pOssOtherAttr,
OUT PCRYPT_ATTRIBUTE_TYPE_VALUE *ppOtherAttr,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
BOOL fRet;
LONG lData;
PCRYPT_ATTRIBUTE_TYPE_VALUE pOtherAttr;
lData = INFO_LEN_ALIGN(sizeof(CRYPT_ATTRIBUTE_TYPE_VALUE));
*plRemainExtra -= lData;
if (0 <= *plRemainExtra) {
pOtherAttr = (PCRYPT_ATTRIBUTE_TYPE_VALUE) *ppbExtra;
memset(pOtherAttr, 0, sizeof(*pOtherAttr));
*ppOtherAttr = pOtherAttr;
*ppbExtra += lData;
} else
pOtherAttr = NULL;
if (!ICM_GetOssObjId(&pOssOtherAttr->keyAttrId, &pOtherAttr->pszObjId,
ppbExtra, plRemainExtra))
goto GetOssObjIdError;
if (pOssOtherAttr->bit_mask & keyAttr_present) {
if (!ICM_GetOssAny(&pOssOtherAttr->keyAttr,
&pOtherAttr->Value, ppbExtra, plRemainExtra))
goto GetOssAnyError;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssObjIdError)
TRACE_ERROR(GetOssAnyError)
}
//+-------------------------------------------------------------------------
// Get Oss KeyTransRecipientInfo
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssKeyTransRecipientInfo(
IN KeyTransRecipientInfo *pori,
OUT PCMSG_KEY_TRANS_RECIPIENT_INFO *ppri,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
BOOL fRet;
LONG lData;
PCMSG_KEY_TRANS_RECIPIENT_INFO pri;
lData = INFO_LEN_ALIGN(sizeof(CMSG_KEY_TRANS_RECIPIENT_INFO));
*plRemainExtra -= lData;
if (0 <= *plRemainExtra) {
pri = (PCMSG_KEY_TRANS_RECIPIENT_INFO) *ppbExtra;
*ppri = pri;
*ppbExtra += lData;
pri->dwVersion = pori->version;
} else {
pri = NULL;
}
if (!ICM_GetOssCertIdentifier(&pori->rid, &pri->RecipientId,
ppbExtra, plRemainExtra))
goto GetOssCertIdentifierError;
if (!ICM_GetOssAlgorithm(&pori->keyEncryptionAlgorithm,
&pri->KeyEncryptionAlgorithm,
ppbExtra, plRemainExtra))
goto GetOssKeyEncryptionAlgorithmError;
ICM_GetOssOctetString(&pori->encryptedKey, &pri->EncryptedKey,
ppbExtra, plRemainExtra);
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssCertIdentifierError)
TRACE_ERROR(GetOssKeyEncryptionAlgorithmError)
}
//+-------------------------------------------------------------------------
// Get Oss KeyAgreeRecipientInfo
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssKeyAgreeRecipientInfo(
IN KeyAgreeRecipientInfo *pori,
OUT PCMSG_KEY_AGREE_RECIPIENT_INFO *ppri,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
BOOL fRet;
LONG lData;
PCMSG_KEY_AGREE_RECIPIENT_INFO pri;
DWORD count;
OriginatorIdentifierOrKey *pooriginator;
OriginatorPublicKey *pooriginatorKey;
lData = INFO_LEN_ALIGN(sizeof(CMSG_KEY_AGREE_RECIPIENT_INFO));
*plRemainExtra -= lData;
if (0 <= *plRemainExtra) {
pri = (PCMSG_KEY_AGREE_RECIPIENT_INFO) *ppbExtra;
memset(pri, 0, sizeof(*pri));
*ppri = pri;
*ppbExtra += lData;
pri->dwVersion = pori->version;
} else {
pri = NULL;
}
pooriginator = &pori->originator;
switch (pooriginator->choice) {
case issuerAndSerialNumber_chosen:
if (!ICM_GetOssIssuerAndSerialNumber(
&pooriginator->u.issuerAndSerialNumber,
&pri->OriginatorCertId.IssuerSerialNumber,
ppbExtra, plRemainExtra))
goto GetOssOriginatorIssuerAndSerialNumberError;
if (0 <= *plRemainExtra) {
pri->OriginatorCertId.dwIdChoice =
CERT_ID_ISSUER_SERIAL_NUMBER;
pri->dwOriginatorChoice = CMSG_KEY_AGREE_ORIGINATOR_CERT;
}
break;
case subjectKeyIdentifier_chosen:
ICM_GetOssOctetString(
&pooriginator->u.subjectKeyIdentifier,
&pri->OriginatorCertId.KeyId,
ppbExtra, plRemainExtra);
if (0 <= *plRemainExtra) {
pri->OriginatorCertId.dwIdChoice =
CERT_ID_KEY_IDENTIFIER;
pri->dwOriginatorChoice = CMSG_KEY_AGREE_ORIGINATOR_CERT;
}
break;
case originatorKey_chosen:
pooriginatorKey = &pooriginator->u.originatorKey;
if (!ICM_GetOssAlgorithm(&pooriginatorKey->algorithm,
&pri->OriginatorPublicKeyInfo.Algorithm,
ppbExtra, plRemainExtra
))
goto GetOssOriginatorPublicKeyAlgorithmError;
ICM_GetOssBitString(&pooriginatorKey->publicKey,
&pri->OriginatorPublicKeyInfo.PublicKey,
ppbExtra, plRemainExtra);
if (0 <= *plRemainExtra)
pri->dwOriginatorChoice = CMSG_KEY_AGREE_ORIGINATOR_PUBLIC_KEY;
break;
default:
goto InvalidOriginatorChoice;
}
if (pori->bit_mask & ukm_present)
ICM_GetOssOctetString(&pori->ukm, &pri->UserKeyingMaterial,
ppbExtra, plRemainExtra);
if (!ICM_GetOssAlgorithm(&pori->keyEncryptionAlgorithm,
&pri->KeyEncryptionAlgorithm,
ppbExtra, plRemainExtra))
goto GetOssKeyEncryptionAlgorithmError;
count = pori->recipientEncryptedKeys.count;
if (0 < count) {
RecipientEncryptedKey *porek;
PCMSG_RECIPIENT_ENCRYPTED_KEY_INFO prek;
PCMSG_RECIPIENT_ENCRYPTED_KEY_INFO *pprek;
lData = INFO_LEN_ALIGN(
count * sizeof(PCMSG_RECIPIENT_ENCRYPTED_KEY_INFO) +
count * sizeof(CMSG_RECIPIENT_ENCRYPTED_KEY_INFO));
*plRemainExtra -= lData;
if (0 <= *plRemainExtra) {
pprek = (PCMSG_RECIPIENT_ENCRYPTED_KEY_INFO *) *ppbExtra;
prek = (PCMSG_RECIPIENT_ENCRYPTED_KEY_INFO) (((PBYTE) pprek) +
(count * sizeof(PCMSG_RECIPIENT_ENCRYPTED_KEY_INFO)));
*ppbExtra += lData;
pri->cRecipientEncryptedKeys = count;
pri->rgpRecipientEncryptedKeys = pprek;
} else {
pprek = NULL;
prek = NULL;
}
porek = pori->recipientEncryptedKeys.value;
for ( ; 0 < count; count--, porek++, prek++, pprek++) {
RecipientIdentifier *porid = &porek->rid;
if (0 <= *plRemainExtra) {
memset(prek, 0, sizeof(*prek));
*pprek = prek;
assert(issuerAndSerialNumber_chosen ==
CERT_ID_ISSUER_SERIAL_NUMBER);
assert(rKeyId_chosen ==
CERT_ID_KEY_IDENTIFIER);
prek->RecipientId.dwIdChoice = porid->choice;
}
ICM_GetOssOctetString(&porek->encryptedKey, &prek->EncryptedKey,
ppbExtra, plRemainExtra);
switch (porid->choice) {
case issuerAndSerialNumber_chosen:
if (!ICM_GetOssIssuerAndSerialNumber(
&porid->u.issuerAndSerialNumber,
&prek->RecipientId.IssuerSerialNumber,
ppbExtra, plRemainExtra))
goto GetOssIssuerAndSerialNumberError;
break;
case rKeyId_chosen:
ICM_GetOssOctetString(
&porid->u.rKeyId.subjectKeyIdentifier,
&prek->RecipientId.KeyId, ppbExtra, plRemainExtra);
if (porid->u.rKeyId.bit_mask & date_present) {
if (0 <= *plRemainExtra) {
if (!PkiAsn1FromGeneralizedTime(
&porid->u.rKeyId.date, &prek->Date))
goto ConvFromGeneralizedTimeError;
}
}
if (porid->u.rKeyId.bit_mask & other_present) {
if (!ICM_GetOssOtherKeyAttribute(
&porid->u.rKeyId.other,
&prek->pOtherAttr,
ppbExtra, plRemainExtra))
goto GetOssOtherKeyAttributeError;
}
break;
default:
goto InvalidRecipientChoice;
}
}
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssOriginatorIssuerAndSerialNumberError)
TRACE_ERROR(GetOssOriginatorPublicKeyAlgorithmError)
TRACE_ERROR(GetOssKeyEncryptionAlgorithmError)
TRACE_ERROR(GetOssIssuerAndSerialNumberError)
TRACE_ERROR(ConvFromGeneralizedTimeError)
TRACE_ERROR(GetOssOtherKeyAttributeError)
SET_ERROR(InvalidOriginatorChoice, CRYPT_E_BAD_ENCODE)
SET_ERROR(InvalidRecipientChoice, CRYPT_E_BAD_ENCODE)
}
//+-------------------------------------------------------------------------
// Get Oss MailListRecipientInfo
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetOssMailListRecipientInfo(
IN MailListRecipientInfo *pori,
OUT PCMSG_MAIL_LIST_RECIPIENT_INFO *ppri,
IN OUT BYTE **ppbExtra,
IN OUT LONG *plRemainExtra
)
{
BOOL fRet;
LONG lData;
PCMSG_MAIL_LIST_RECIPIENT_INFO pri;
MailListKeyIdentifier *pomlid;
lData = INFO_LEN_ALIGN(sizeof(CMSG_MAIL_LIST_RECIPIENT_INFO));
*plRemainExtra -= lData;
if (0 <= *plRemainExtra) {
pri = (PCMSG_MAIL_LIST_RECIPIENT_INFO) *ppbExtra;
memset(pri, 0, sizeof(*pri));
*ppri = pri;
*ppbExtra += lData;
pri->dwVersion = pori->version;
} else {
pri = NULL;
}
pomlid = &pori->mlid;
ICM_GetOssOctetString(&pomlid->kekIdentifier, &pri->KeyId,
ppbExtra, plRemainExtra);
if (!ICM_GetOssAlgorithm(&pori->keyEncryptionAlgorithm,
&pri->KeyEncryptionAlgorithm,
ppbExtra, plRemainExtra))
goto GetOssKeyEncryptionAlgorithmError;
ICM_GetOssOctetString(&pori->encryptedKey, &pri->EncryptedKey,
ppbExtra, plRemainExtra);
if (pomlid->bit_mask & date_present) {
if (0 <= *plRemainExtra) {
if (!PkiAsn1FromGeneralizedTime(
&pomlid->date, &pri->Date))
goto ConvFromGeneralizedTimeError;
}
}
if (pomlid->bit_mask & other_present) {
if (!ICM_GetOssOtherKeyAttribute(
&pomlid->other,
&pri->pOtherAttr,
ppbExtra, plRemainExtra))
goto GetOssOtherKeyAttributeError;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssKeyEncryptionAlgorithmError)
TRACE_ERROR(ConvFromGeneralizedTimeError)
TRACE_ERROR(GetOssOtherKeyAttributeError)
}
//+-------------------------------------------------------------------------
// Copy out a CMSG_CMS_RECIPIENT_INFO
//--------------------------------------------------------------------------
BOOL
WINAPI
ICM_GetCmsRecipientInfo(
IN CmsRecipientInfo *pori,
OUT void *pvData,
IN OUT DWORD *pcbData
)
{
BOOL fRet;
LONG lData;
PCMSG_CMS_RECIPIENT_INFO pri = (PCMSG_CMS_RECIPIENT_INFO) pvData;
PBYTE pbExtra;
LONG lRemainExtra;
if (NULL == pvData)
*pcbData = 0;
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN(sizeof(CMSG_CMS_RECIPIENT_INFO));
lRemainExtra = (LONG)*pcbData - lData;
if (0 > lRemainExtra) {
pri = NULL;
pbExtra = NULL;
} else {
assert(CMSG_KEY_TRANS_RECIPIENT == keyTransRecipientInfo_chosen);
assert(CMSG_KEY_AGREE_RECIPIENT == keyAgreeRecipientInfo_chosen);
assert(CMSG_MAIL_LIST_RECIPIENT == mailListRecipientInfo_chosen);
pri->dwRecipientChoice = pori->choice;
pbExtra = (PBYTE) pri + lData;
}
switch (pori->choice) {
case keyTransRecipientInfo_chosen:
if (!ICM_GetOssKeyTransRecipientInfo(
&pori->u.keyTransRecipientInfo,
&pri->pKeyTrans,
&pbExtra, &lRemainExtra
))
goto GetOssKeyTransRecipientInfoError;
break;
case keyAgreeRecipientInfo_chosen:
if (!ICM_GetOssKeyAgreeRecipientInfo(
&pori->u.keyAgreeRecipientInfo,
&pri->pKeyAgree,
&pbExtra, &lRemainExtra
))
goto GetOssKeyAgreeRecipientInfoError;
break;
case mailListRecipientInfo_chosen:
if (!ICM_GetOssMailListRecipientInfo(
&pori->u.mailListRecipientInfo,
&pri->pMailList,
&pbExtra, &lRemainExtra
))
goto GetOssMailListRecipientInfoError;
break;
default:
goto InvalidRecipientChoice;
}
fRet = ICM_GetSizeFromExtra(lRemainExtra, pvData, pcbData);
CommonReturn:
return fRet;
ErrorReturn:
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetOssKeyTransRecipientInfoError)
TRACE_ERROR(GetOssKeyAgreeRecipientInfoError)
TRACE_ERROR(GetOssMailListRecipientInfoError)
SET_ERROR(InvalidRecipientChoice, CRYPT_E_BAD_ENCODE)
}
#endif // CMS_PKCS7
//+-------------------------------------------------------------------------
// Get a parameter after encoding/decoding a cryptographic message. Called
// after the final CryptMsgUpdate. Only the CMSG_CONTENT_PARAM and
// CMSG_COMPUTED_HASH_PARAM are valid for an encoded message.
//
// For an encoded HASHED message, the CMSG_COMPUTED_HASH_PARAM can be got
// before any CryptMsgUpdates to get its length.
//
// The pvData type definition depends on the dwParamType value.
//
// Elements pointed to by fields in the pvData structure follow the
// structure. Therefore, *pcbData may exceed the size of the structure.
//
// Upon input, if *pcbData == 0, then, *pcbData is updated with the length
// of the data and the pvData parameter is ignored.
//
// Upon return, *pcbData is updated with the length of the data.
//
// The OBJID BLOBs returned in the pvData structures point to
// their still encoded representation. The appropriate functions
// must be called to decode the information.
//
// See wincrypt.h for a list of the parameters to get.
//--------------------------------------------------------------------------
BOOL
WINAPI
#ifdef DEBUG_CRYPT_ASN1_MASTER
ICMTest_NewCryptMsgGetParam(
#else
CryptMsgGetParam(
#endif
IN HCRYPTMSG hCryptMsg,
IN DWORD dwParamType,
IN DWORD dwIndex,
OUT void *pvData,
IN OUT DWORD *pcbData)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PCRYPT_MSG_INFO pcmi = (PCRYPT_MSG_INFO)hCryptMsg;
ASN1error_e Asn1Err;
PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
BOOL fBER = FALSE;
DWORD dwExceptionCode;
ICM_Lock( pcmi); // Single thread access to HCRYPTMSG
// Handle MappedFile Exceptions
__try {
if (NULL == pvData)
*pcbData = 0;
#ifdef CMS_PKCS7
if (CMSG_VERSION_PARAM == dwParamType) {
int version = 0;
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (pcmi->fEncoding) {
if (NULL == pcmi->pvMsg)
goto InvalidMessageDataError;
version = ((SignedData *)pcmi->pvMsg)->version;
} else {
if (NULL == pcmi->psdi)
goto MessageNotDecodedError;
version = pcmi->psdi->version;
}
break;
case CMSG_ENVELOPED:
if (NULL == pcmi->pvMsg)
goto MessageNotDecodedError;
version = ((CmsEnvelopedData *)pcmi->pvMsg)->version;
break;
case CMSG_HASHED:
if (NULL == pcmi->pvMsg)
goto MessageNotDecodedError;
version = ((DigestedData *)pcmi->pvMsg)->version;
break;
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
case CMSG_ENCRYPTED:
case CMSG_DATA:
default:
goto InvalidMsgType;
}
fRet = ICM_GetDWORD(version, pvData, pcbData);
goto PreserveLengthReturn;
}
#endif // CMS_PKCS7
if (pcmi->fEncoding) {
switch (dwParamType) {
case CMSG_CONTENT_PARAM:
case CMSG_BARE_CONTENT_PARAM:
{
ContentInfo ci;
ASN1encoding_t pEnc = ICM_GetEncoder();
PBYTE pbEncoded = NULL;
DWORD cbEncoded;
PBYTE pbContent = NULL;
if (pcsi)
goto GetContentParamNotValidForStreaming;
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (0 == ((SignedData *) pcmi->pvMsg)->signerInfos.count)
// For a bag of certs, don't DER order
fBER = TRUE;
break;
case CMSG_DATA:
case CMSG_ENVELOPED:
case CMSG_HASHED:
break;
case CMSG_SIGNED_AND_ENVELOPED:
case CMSG_ENCRYPTED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
if (fBER)
PkiAsn1SetEncodingRule(ICM_GetEncoder(), ASN1_BER_RULE_BER);
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
pcmi->pvMsg,
aiPduNum[ pcmi->dwMsgType - 1],
&pbEncoded,
&cbEncoded))) {
goto CONTENT_PARAMAsn1EncodeError;
}
if (CMSG_CONTENT_PARAM == dwParamType) {
if (!ICM_CopyOssObjectIdentifier(
&ci.contentType,
&aoidMessages[ pcmi->dwMsgType - 1]))
goto CopyOssObjectIdentifierContentTypeError;
ci.bit_mask = content_present;
ci.content.length = cbEncoded;
ci.content.value = pbEncoded;
pbContent = pbEncoded;
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
&ci,
ContentInfo_PDU,
&pbEncoded,
&cbEncoded))) {
PkiAsn1FreeEncoded(pEnc, pbContent);
goto Asn1EncodeSignedDataError;
}
}
fRet = ICM_CopyOut(
pbEncoded,
cbEncoded,
(PBYTE)pvData,
pcbData);
if (!fRet)
dwError = GetLastError();
if (pbContent)
PkiAsn1FreeEncoded(pEnc, pbContent);
PkiAsn1FreeEncoded(pEnc, pbEncoded);
if (!fRet)
SetLastError(dwError);
break;
}
case CMSG_COMPUTED_HASH_PARAM:
fRet = ICM_GetComputedDigestParam( pcmi, dwIndex, pvData, pcbData);
break;
case CMSG_ENCODED_SIGNER:
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
break;
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
fRet = ICM_GetSignerParamEncoding(
pcmi,
dwIndex,
dwParamType,
pvData,
pcbData);
break;
default:
goto InvalidMsgType;
}
} else {
//
// Decode
//
switch (dwParamType) {
case CMSG_TYPE_PARAM:
if (pcsi && (0 == pcmi->dwMsgType))
goto StreamMsgNotReadyError;
fRet = ICM_GetDWORD( pcmi->dwMsgType, pvData, pcbData);
break;
case CMSG_CONTENT_PARAM:
{
ContentInfo *pci;
PCONTENT_INFO pci2;
PBYTE pbDER = NULL;
DWORD cbDER;
PBYTE pb;
DWORD cb;
if (pcsi)
goto GetContentParamNotValidForStreaming;
switch (pcmi->dwMsgType) {
case CMSG_DATA:
{
OctetStringType *poos = (OctetStringType *)pcmi->pvMsg;
pb = (PBYTE)poos->value;
cb = poos->length;
fRet = ICM_CopyOut( pb, cb, (PBYTE)pvData, pcbData);
break;
}
case CMSG_SIGNED:
if (NULL == pcmi->psdi)
goto InvalidSignedMessageError;
pci2 = pcmi->psdi->pci;
if (pci2->content.cbData) {
cb = pci2->content.cbData;
pb = pci2->content.pbData;
if (0 == strcmp(pszObjIdDataType,
pci2->pszContentType)
#ifdef CMS_PKCS7
|| pcmi->psdi->version >= CMSG_SIGNED_DATA_CMS_VERSION
#endif // CMS_PKCS7
) {
if (!ICM_ReEncodeAsOctetDER(
pb,
cb,
&pbDER,
&cbDER
))
goto ReEncodeAsOctetDERError;
if (pbDER) {
if (0 > Asn1UtilExtractContent( pbDER, cbDER,
&cb, (const BYTE **)&pb)) {
PkiAsn1FreeEncoded( ICM_GetEncoder(), pbDER);
goto ExtractContentError;
}
}
}
fRet = ICM_CopyOut( pb, cb, (PBYTE)pvData, pcbData);
if (!fRet)
dwError = GetLastError();
if (pbDER)
PkiAsn1FreeEncoded( ICM_GetEncoder(), pbDER);
if (!fRet)
SetLastError(dwError);
} else {
*pcbData = 0;
fRet = TRUE;
}
break;
case CMSG_ENVELOPED:
if (NULL == pcmi->Plaintext.pbData) {
// Hasn't been decrypted yet
EncryptedContentInfo *peci;
PBYTE pbCiphertext;
DWORD cbCiphertext;
#ifdef CMS_PKCS7
peci = &((CmsEnvelopedData *)pcmi->pvMsg)->encryptedContentInfo;
#else
peci = &((EnvelopedData *)pcmi->pvMsg)->encryptedContentInfo;
#endif // CMS_PKCS7
if (peci->bit_mask & encryptedContent_present) {
pbCiphertext = peci->encryptedContent.value;
cbCiphertext = peci->encryptedContent.length;
} else {
pbCiphertext = NULL;
cbCiphertext = 0;
}
if (NULL == pvData) {
// Assume (sizeof plaintext) <=
// (sizeof ciphertext)
//
// not decrypted yet; return ciphertext size
fRet = TRUE;
// + 6 => to allow for identifier and length octets
*pcbData = cbCiphertext + 6;
} else
// Return ciphertext
fRet = ICM_CopyOut(
pbCiphertext,
cbCiphertext,
(PBYTE)pvData,
pcbData);
goto ContentCopiedOut;
}
if (!ICM_EqualObjectIDs(
#ifdef CMS_PKCS7
&((CmsEnvelopedData *)pcmi->pvMsg)->encryptedContentInfo.contentType,
&aoidMessages[ CMSG_DATA - 1])
&&
CMSG_ENVELOPED_DATA_CMS_VERSION >
((CmsEnvelopedData *)pcmi->pvMsg)->version) {
#else
&((EnvelopedData *)pcmi->pvMsg)->encryptedContentInfo.contentType,
&aoidMessages[ CMSG_DATA - 1])) {
#endif // CMS_PKCS7
// Not DATA or encapsulated, so must prepend
// identifier and length octets
fRet = ICM_CopyOutAddDERPrefix(
pcmi->Plaintext.pbData,
pcmi->Plaintext.cbData,
ICM_TAG_SEQ,
(PBYTE)pvData,
pcbData);
} else {
fRet = ICM_CopyOut(
pcmi->Plaintext.pbData,
pcmi->Plaintext.cbData,
(PBYTE)pvData,
pcbData);
}
goto ContentCopiedOut;
case CMSG_HASHED:
pci = &((DigestedData *)pcmi->pvMsg)->contentInfo;
if (pci->bit_mask & content_present) {
cb = (DWORD)pci->content.length;
pb = (PBYTE)pci->content.value;
if (ICM_EqualObjectIDs(
&pci->contentType,
&aoidMessages[ CMSG_DATA - 1])
#ifdef CMS_PKCS7
|| ((DigestedData *)pcmi->pvMsg)->version >=
CMSG_HASHED_DATA_V2
#endif // CMS_PKCS7
) {
if (!ICM_ReEncodeAsOctetDER(
pb,
cb,
&pbDER,
&cbDER
))
goto ReEncodeAsOctetDERError;
if (pbDER) {
if (0 > Asn1UtilExtractContent( pbDER, cbDER,
&cb, (const BYTE **)&pb)) {
PkiAsn1FreeEncoded( ICM_GetEncoder(), pbDER);
goto ExtractContentError;
}
}
}
fRet = ICM_CopyOut( pb, cb, (PBYTE)pvData, pcbData);
if (!fRet)
dwError = GetLastError();
if (pbDER)
PkiAsn1FreeEncoded( ICM_GetEncoder(), pbDER);
if (!fRet)
SetLastError(dwError);
} else {
*pcbData = 0;
fRet = TRUE;
}
break;
case CMSG_SIGNED_AND_ENVELOPED:
case CMSG_ENCRYPTED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
ContentCopiedOut:
break;
}
case CMSG_INNER_CONTENT_TYPE_PARAM:
{
ContentType *pct;
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (NULL == pcmi->psdi)
goto InvalidSignedMessageError;
fRet = ICM_CopyOut(
(PBYTE)pcmi->psdi->pci->pszContentType,
strlen( pcmi->psdi->pci->pszContentType) + 1,
(PBYTE)pvData,
pcbData);
goto ContentTypeCopiedOut;
break;
case CMSG_ENVELOPED:
#ifdef CMS_PKCS7
pct = &((CmsEnvelopedData *)pcmi->pvMsg)->encryptedContentInfo.contentType;
#else
pct = &((EnvelopedData *)pcmi->pvMsg)->encryptedContentInfo.contentType;
#endif // CMS_PKCS7
break;
case CMSG_HASHED:
pct = &((DigestedData *)pcmi->pvMsg)->contentInfo.contentType;
break;
case CMSG_SIGNED_AND_ENVELOPED:
case CMSG_ENCRYPTED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
fRet = PkiAsn1FromObjectIdentifier(
pct->count,
pct->value,
(LPSTR)pvData,
pcbData);
ContentTypeCopiedOut:
break;
}
case CMSG_ENCODED_MESSAGE:
fRet = ICM_GetEncodedMessageParam(
pcmi,
(PBYTE)pvData,
pcbData);
break;
case CMSG_SIGNER_COUNT_PARAM:
{
DWORD cSigner;
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (NULL == pcmi->psdi)
goto InvalidSignedMessageError;
cSigner = pcmi->psdi->pSignerList->Length();
break;
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
fRet = ICM_GetDWORD( cSigner, pvData, pcbData);
break;
}
case CMSG_ENCRYPTED_DIGEST:
case CMSG_ENCODED_SIGNER:
case CMSG_SIGNER_INFO_PARAM:
case CMSG_SIGNER_CERT_INFO_PARAM:
case CMSG_SIGNER_HASH_ALGORITHM_PARAM:
case CMSG_SIGNER_AUTH_ATTR_PARAM:
case CMSG_SIGNER_UNAUTH_ATTR_PARAM:
case CMSG_CMS_SIGNER_INFO_PARAM:
case CMSG_SIGNER_CERT_ID_PARAM:
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
break;
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
fRet = ICM_GetSignerParam(
pcmi,
dwIndex,
dwParamType,
pvData,
pcbData);
break;
case CMSG_CERT_COUNT_PARAM:
{
CBlobList *pBlobList;
DWORD dwCount;
#ifdef CMS_PKCS7
BOOL fPossibleAttrCert = FALSE;
#endif // CMS_PKCS7
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (NULL == pcmi->psdi)
goto InvalidSignedMessageError;
pBlobList = pcmi->psdi->pCertificateList;
#ifdef CMS_PKCS7
if (pcmi->psdi->version >= CMSG_SIGNED_DATA_CMS_VERSION)
fPossibleAttrCert = TRUE;
#endif // CMS_PKCS7
break;
#ifdef CMS_PKCS7
case CMSG_ENVELOPED:
pBlobList = pcmi->pCertificateList;
fPossibleAttrCert = TRUE;
break;
#endif // CMS_PKCS7
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
dwCount = pBlobList->Length();
#ifdef CMS_PKCS7
if (dwCount && fPossibleAttrCert)
dwCount = ICM_GetTaggedBlobCount(
pBlobList,
ICM_TAG_SEQ
);
#endif // CMS_PKCS7
fRet = ICM_GetDWORD( dwCount, pvData, pcbData);
break;
}
case CMSG_CERT_PARAM:
{
CBlobList *pBlobList;
CBlobNode *pBlobNode;
#ifdef CMS_PKCS7
BOOL fPossibleAttrCert = FALSE;
#endif // CMS_PKCS7
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (NULL == pcmi->psdi)
goto InvalidSignedMessageError;
pBlobList = pcmi->psdi->pCertificateList;
#ifdef CMS_PKCS7
if (pcmi->psdi->version >= CMSG_SIGNED_DATA_CMS_VERSION)
fPossibleAttrCert = TRUE;
#endif // CMS_PKCS7
break;
#ifdef CMS_PKCS7
case CMSG_ENVELOPED:
pBlobList = pcmi->pCertificateList;
fPossibleAttrCert = TRUE;
break;
#endif // CMS_PKCS7
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
// Get blob at specified cert index. Index
// is advanced to the appropriate blob.
pBlobNode = ICM_GetTaggedBlobAndAdvanceIndex(
pBlobList,
#ifdef CMS_PKCS7
(BYTE)( fPossibleAttrCert ? ICM_TAG_SEQ : 0),
#else
0, // bTag
#endif // CMS_PKCS7
&dwIndex
);
if (pBlobNode)
fRet = ICM_CopyOut(
pBlobNode->Data()->pbData,
pBlobNode->Data()->cbData,
(PBYTE)pvData,
pcbData);
else
fRet = FALSE;
break;
}
#ifdef CMS_PKCS7
case CMSG_ATTR_CERT_COUNT_PARAM:
{
CBlobList *pBlobList;
BOOL fPossibleAttrCert = FALSE;
DWORD dwCount;
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (NULL == pcmi->psdi)
goto InvalidSignedMessageError;
pBlobList = pcmi->psdi->pCertificateList;
if (pcmi->psdi->version >= CMSG_SIGNED_DATA_CMS_VERSION)
fPossibleAttrCert = TRUE;
break;
case CMSG_ENVELOPED:
pBlobList = pcmi->pCertificateList;
fPossibleAttrCert = TRUE;
break;
default:
goto InvalidMsgType;
}
if (fPossibleAttrCert)
dwCount = ICM_GetTaggedBlobCount(
pBlobList,
ICM_TAG_CONSTRUCTED_CONTEXT_1
);
else
dwCount = 0;
fRet = ICM_GetDWORD( dwCount, pvData, pcbData);
break;
}
case CMSG_ATTR_CERT_PARAM:
{
CBlobList *pBlobList;
CBlobNode *pBlobNode;
BOOL fPossibleAttrCert = FALSE;
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (NULL == pcmi->psdi)
goto InvalidSignedMessageError;
pBlobList = pcmi->psdi->pCertificateList;
if (pcmi->psdi->version >= CMSG_SIGNED_DATA_CMS_VERSION)
fPossibleAttrCert = TRUE;
break;
case CMSG_ENVELOPED:
pBlobList = pcmi->pCertificateList;
fPossibleAttrCert = TRUE;
break;
default:
goto InvalidMsgType;
}
if (!fPossibleAttrCert)
pBlobNode = NULL;
else
// Get blob at specified attribute cert index. Index
// is advanced to the appropriate blob
pBlobNode = ICM_GetTaggedBlobAndAdvanceIndex(
pBlobList,
ICM_TAG_CONSTRUCTED_CONTEXT_1,
&dwIndex
);
if (pBlobNode) {
fRet = ICM_CopyOut(
pBlobNode->Data()->pbData,
pBlobNode->Data()->cbData,
(PBYTE)pvData,
pcbData);
if (fRet && pvData)
*((PBYTE)pvData) = ICM_TAG_SEQ;
} else
fRet = FALSE;
break;
}
#endif // CMS_PKCS7
case CMSG_CRL_COUNT_PARAM:
{
CBlobList *pBlobList;
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (NULL == pcmi->psdi)
goto InvalidSignedMessageError;
pBlobList = pcmi->psdi->pCrlList;
break;
#ifdef CMS_PKCS7
case CMSG_ENVELOPED:
pBlobList = pcmi->pCrlList;
break;
#endif // CMS_PKCS7
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
fRet = ICM_GetDWORD( pBlobList->Length(), pvData, pcbData);
break;
}
case CMSG_CRL_PARAM:
{
CBlobList *pBlobList;
CBlobNode *pBlobNode;
DWORD i;
switch (pcmi->dwMsgType) {
case CMSG_SIGNED:
if (NULL == pcmi->psdi)
goto InvalidSignedMessageError;
pBlobList = pcmi->psdi->pCrlList;
break;
#ifdef CMS_PKCS7
case CMSG_ENVELOPED:
pBlobList = pcmi->pCrlList;
break;
#endif // CMS_PKCS7
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
// This list-walking should be a class method
for (i=dwIndex, pBlobNode=pBlobList->Head();
(i>0) && pBlobNode;
i--, pBlobNode=pBlobNode->Next())
;
if (pBlobNode)
fRet = ICM_CopyOut(
pBlobNode->Data()->pbData,
pBlobNode->Data()->cbData,
(PBYTE)pvData,
pcbData);
else
fRet = FALSE;
break;
}
case CMSG_ENVELOPE_ALGORITHM_PARAM:
{
ContentEncryptionAlgId *pceai;
if (pcsi &&
(0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECIALGID)))
goto StreamMsgNotReadyError;
switch (pcmi->dwMsgType) {
case CMSG_ENVELOPED:
#ifdef CMS_PKCS7
pceai = &((CmsEnvelopedData *)pcmi->pvMsg)->encryptedContentInfo.contentEncryptionAlgorithm;
#else
pceai = &((EnvelopedData *)pcmi->pvMsg)->encryptedContentInfo.contentEncryptionAlgorithm;
#endif // CMS_PKCS7
break;
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
fRet = ICM_GetALGORITHM_IDENTIFIER( pceai, pvData, pcbData);
break;
}
#ifdef CMS_PKCS7
case CMSG_UNPROTECTED_ATTR_PARAM:
{
CmsEnvelopedData *ped;
ped = (CmsEnvelopedData *)pcmi->pvMsg;
if (ped && (ped->bit_mask & unprotectedAttrs_present))
fRet = ICM_GetAttributesData(
&ped->unprotectedAttrs,
pvData,
pcbData);
else
goto UnprotectedAttrMissingError;
}
break;
case CMSG_RECIPIENT_COUNT_PARAM:
{
DWORD dwPkcsCount;
if (!ICM_GetPkcsRecipientCount(pcmi, &dwPkcsCount))
goto GetPkcsRecipientCountError;
fRet = ICM_GetDWORD(dwPkcsCount, pvData, pcbData);
}
break;
case CMSG_RECIPIENT_INDEX_PARAM:
{
DWORD dwPkcsIndex;
DWORD dwCmsIndex;
DWORD cbData = sizeof(dwCmsIndex);
if (!CryptMsgGetParam(
hCryptMsg,
CMSG_CMS_RECIPIENT_INDEX_PARAM,
0, // dwIndex
&dwCmsIndex,
&cbData))
goto GetCmsRecipientIndexError;
if (!ICM_ConvertCmsToPkcsRecipientIndex(
pcmi, dwCmsIndex, &dwPkcsIndex))
goto ConvertCmsToPkcsRecipientIndexError;
fRet = ICM_GetDWORD(
dwPkcsIndex,
pvData,
pcbData);
}
break;
case CMSG_RECIPIENT_INFO_PARAM:
{
CmsRecipientInfos *pris;
KeyTransRecipientInfo *pri;
DWORD dwCmsIndex;
if (NULL == (pris = ICM_GetDecodedCmsRecipientInfos(pcmi)))
goto GetDecodedCmsRecipientsError;
if (!ICM_ConvertPkcsToCmsRecipientIndex(
pcmi, dwIndex, &dwCmsIndex))
goto ConvertPkcsToCmsRecipientIndexError;
pri = &pris->value[dwCmsIndex].u.keyTransRecipientInfo;
fRet = ICM_GetCertInfoIssuerAndSerialNumber(
&pri->rid, pvData, pcbData);
break;
}
case CMSG_CMS_RECIPIENT_COUNT_PARAM:
{
CmsRecipientInfos *pris;
if (NULL == (pris = ICM_GetDecodedCmsRecipientInfos(pcmi)))
goto GetDecodedCmsRecipientsError;
fRet = ICM_GetDWORD(pris->count, pvData, pcbData);
}
break;
case CMSG_CMS_RECIPIENT_INDEX_PARAM:
{
CmsRecipientInfos *pris;
if (NULL == (pris = ICM_GetDecodedCmsRecipientInfos(pcmi)))
goto GetDecodedCmsRecipientsError;
fRet = ICM_GetDWORD(
pcmi->dwDecryptedRecipientIndex,
pvData,
pcbData);
}
break;
case CMSG_CMS_RECIPIENT_ENCRYPTED_KEY_INDEX_PARAM:
{
CmsRecipientInfos *pris;
CmsRecipientInfo *pri;
if (NULL == (pris = ICM_GetDecodedCmsRecipientInfos(pcmi)))
goto GetDecodedCmsRecipientsError;
pri = pris->value + pcmi->dwDecryptedRecipientIndex;
if (keyAgreeRecipientInfo_chosen != pri->choice)
goto NotKeyAgreeRecipientIndex;
fRet = ICM_GetDWORD(
pcmi->dwDecryptedRecipientEncryptedKeyIndex,
pvData,
pcbData);
}
break;
case CMSG_CMS_RECIPIENT_INFO_PARAM:
{
CmsRecipientInfos *pris;
if (NULL == (pris = ICM_GetDecodedCmsRecipientInfos(pcmi)))
goto GetDecodedCmsRecipientsError;
if (dwIndex >= pris->count)
goto IndexTooBig;
fRet = ICM_GetCmsRecipientInfo(pris->value + dwIndex,
pvData, pcbData);
}
break;
#else
case CMSG_RECIPIENT_COUNT_PARAM:
{
RecipientInfos *pris;
if (pcsi &&
(0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_RECIPINFOS)))
goto StreamMsgNotReadyError;
switch (pcmi->dwMsgType) {
case CMSG_ENVELOPED:
pris = &((EnvelopedData *)pcmi->pvMsg)->recipientInfos;
break;
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
fRet = ICM_GetDWORD( pris->count, pvData, pcbData);
break;
}
case CMSG_RECIPIENT_INDEX_PARAM:
{
if (pcsi &&
(0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_RECIPINFOS)))
goto StreamMsgNotReadyError;
switch (pcmi->dwMsgType) {
case CMSG_ENVELOPED:
case CMSG_SIGNED_AND_ENVELOPED:
break;
default:
goto InvalidMsgType;
}
fRet = ICM_GetDWORD(
pcmi->dwDecryptedRecipientIndex,
pvData,
pcbData);
break;
}
case CMSG_RECIPIENT_INFO_PARAM:
{
RecipientInfos *pris;
RecipientInfo *pri;
PCERT_INFO pci = (PCERT_INFO)pvData;
if (pcsi &&
(0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_RECIPINFOS)))
goto StreamMsgNotReadyError;
switch (pcmi->dwMsgType) {
case CMSG_ENVELOPED:
pris = &((EnvelopedData *)pcmi->pvMsg)->recipientInfos;
if (dwIndex >= pris->count)
goto IndexTooBig;
pri = pris->value + dwIndex;
break;
case CMSG_SIGNED_AND_ENVELOPED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
// for lRemainExtra < 0, LENGTH_ONLY calculation
lData = INFO_LEN_ALIGN( sizeof(CERT_INFO));
lRemainExtra = (LONG)*pcbData - lData;
if (0 > lRemainExtra) {
pci = NULL;
pbExtra = NULL;
} else {
pbExtra = (PBYTE)pci + lData;
}
if (!ICM_GetOssIssuerAndSerialNumber(
&pri->issuerAndSerialNumber,
pci, &pbExtra, &lRemainExtra))
goto GetOssIssuerAndSerialNumberError;
fRet = ICM_GetSizeFromExtra( lRemainExtra, pvData, pcbData);
break;
}
#endif // CMS_PKCS7
case CMSG_HASH_ALGORITHM_PARAM:
fRet = ICM_GetALGORITHM_IDENTIFIER(
&((DigestedData *)pcmi->pvMsg)->digestAlgorithm,
pvData,
pcbData);
break;
case CMSG_HASH_DATA_PARAM:
fRet = ICM_GetDigestDataParam( pcmi, pvData, pcbData);
break;
case CMSG_COMPUTED_HASH_PARAM:
fRet = ICM_GetComputedDigestParam( pcmi, dwIndex, pvData, pcbData);
break;
case CMSG_ENCRYPT_PARAM:
#if 0
{
goto ParamTypeNotSupportedYet;
}
#endif
default:
goto InvalidMsgType;
}
}
#ifdef CMS_PKCS7
PreserveLengthReturn:
#endif // CMS_PKCS7
if (!fRet)
dwError = GetLastError();
} __except(EXCEPTION_EXECUTE_HANDLER) {
dwExceptionCode = GetExceptionCode();
goto ExceptionError;
}
CommonReturn:
if (fBER)
PkiAsn1SetEncodingRule(ICM_GetEncoder(), ASN1_BER_RULE_DER);
ICM_Unlock( pcmi);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
*pcbData = 0;
fRet = FALSE;
goto CommonReturn;
StreamMsgNotReadyError:
dwError = (DWORD)CRYPT_E_STREAM_MSG_NOT_READY;
goto ErrorReturn;
SET_ERROR(GetContentParamNotValidForStreaming, E_INVALIDARG)
SET_ERROR(IndexTooBig,CRYPT_E_INVALID_INDEX)
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(InvalidMsgType,CRYPT_E_INVALID_MSG_TYPE)
SET_ERROR(ExtractContentError,CRYPT_E_UNEXPECTED_ENCODING)
SET_ERROR_VAR(CONTENT_PARAMAsn1EncodeError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(Asn1EncodeSignedDataError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(CopyOssObjectIdentifierContentTypeError) // error already set
TRACE_ERROR(ReEncodeAsOctetDERError) // error already set
SET_ERROR(InvalidSignedMessageError, ERROR_INVALID_DATA)
#ifdef CMS_PKCS7
SET_ERROR(MessageNotDecodedError, ERROR_INVALID_DATA)
SET_ERROR(InvalidMessageDataError, ERROR_INVALID_DATA)
TRACE_ERROR(GetDecodedCmsRecipientsError)
TRACE_ERROR(GetPkcsRecipientCountError)
TRACE_ERROR(ConvertCmsToPkcsRecipientIndexError)
TRACE_ERROR(ConvertPkcsToCmsRecipientIndexError)
TRACE_ERROR(GetCmsRecipientIndexError)
SET_ERROR(NotKeyAgreeRecipientIndex, CRYPT_E_INVALID_INDEX)
SET_ERROR(UnprotectedAttrMissingError,CRYPT_E_ATTRIBUTES_MISSING)
#else
TRACE_ERROR(GetOssIssuerAndSerialNumberError) // error already set
#endif // CMS_PKCS7
SET_ERROR_VAR(ExceptionError, dwExceptionCode)
}
//+=========================================================================
// Data structures and functions to test and compare the NEW Net Meeting
// ASN1 compiler and RTS with the OSS compiler and RTS.
//-=========================================================================
#ifdef DEBUG_CRYPT_ASN1
//#define DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG 0x010
//#define DEBUG_OSS_CRYPT_ASN1_CMSG_COMPARE_FLAG 0x020
//#define DEBUG_OSS_CRYPT_ASN1_SAME_ENCRYPT_FLAG 0x100
//static BOOL fGotDebugCryptAsn1Flags = FALSE;
//static int iDebugCryptAsn1Flags = 0;
#ifdef DEBUG_CRYPT_ASN1_MASTER
typedef HCRYPTMSG (WINAPI *PFN_CRYPT_MSG_OPEN_TO_ENCODE)(
IN DWORD dwMsgEncodingType,
IN DWORD dwFlags,
IN DWORD dwMsgType,
IN void const *pvMsgEncodeInfo,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo
);
static PFN_CRYPT_MSG_OPEN_TO_ENCODE pfnOssCryptMsgOpenToEncode = NULL;
typedef HCRYPTMSG (WINAPI *PFN_CRYPT_MSG_OPEN_TO_DECODE)(
IN DWORD dwMsgEncodingType,
IN DWORD dwFlags,
IN DWORD dwMsgType,
IN HCRYPTPROV hCryptProv,
IN OPTIONAL PCERT_INFO pRecipientInfo,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo
);
static PFN_CRYPT_MSG_OPEN_TO_DECODE pfnOssCryptMsgOpenToDecode = NULL;
typedef HCRYPTMSG (WINAPI *PFN_CRYPT_MSG_DUPLICATE)(
IN HCRYPTMSG hCryptMsg
);
static PFN_CRYPT_MSG_DUPLICATE pfnOssCryptMsgDuplicate = NULL;
typedef BOOL (WINAPI *PFN_CRYPT_MSG_CLOSE)(
IN HCRYPTMSG hCryptMsg
);
static PFN_CRYPT_MSG_CLOSE pfnOssCryptMsgClose = NULL;
typedef BOOL (WINAPI *PFN_CRYPT_MSG_UPDATE)(
IN HCRYPTMSG hCryptMsg,
IN const BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal
);
static PFN_CRYPT_MSG_UPDATE pfnOssCryptMsgUpdate = NULL;
typedef BOOL (WINAPI *PFN_CRYPT_MSG_GET_PARAM)(
IN HCRYPTMSG hCryptMsg,
IN DWORD dwParamType,
IN DWORD dwIndex,
OUT void *pvData,
IN OUT DWORD *pcbData
);
static PFN_CRYPT_MSG_GET_PARAM pfnOssCryptMsgGetParam = NULL;
typedef BOOL (WINAPI *PFN_CRYPT_MSG_CONTROL)(
IN HCRYPTMSG hCryptMsg,
IN DWORD dwFlags,
IN DWORD dwCtrlType,
IN void const *pvCtrlPara
);
static PFN_CRYPT_MSG_CONTROL pfnOssCryptMsgControl = NULL;
#ifdef CMS_PKCS7
typedef BOOL (WINAPI *PFN_CRYPT_MSG_VERIFY_COUNTERSIGNATURE_ENCODED_EX)(
IN HCRYPTPROV hCryptProv,
IN DWORD dwEncodingType,
IN PBYTE pbSignerInfo,
IN DWORD cbSignerInfo,
IN PBYTE pbSignerInfoCountersignature,
IN DWORD cbSignerInfoCountersignature,
IN DWORD dwSignerType,
IN void *pvSigner,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
);
static PFN_CRYPT_MSG_VERIFY_COUNTERSIGNATURE_ENCODED_EX
pfnOssCryptMsgVerifyCountersignatureEncodedEx = NULL;
#endif // CMS_PKCS7
typedef BOOL (WINAPI *PFN_CRYPT_MSG_COUNTERSIGN)(
IN OUT HCRYPTMSG hCryptMsg,
IN DWORD dwIndex,
IN DWORD cCountersigners,
IN PCMSG_SIGNER_ENCODE_INFO rgCountersigners
);
static PFN_CRYPT_MSG_COUNTERSIGN pfnOssCryptMsgCountersign = NULL;
typedef BOOL (WINAPI *PFN_CRYPT_MSG_COUNTERSIGN_ENCODED)(
IN DWORD dwEncodingType,
IN PBYTE pbSignerInfo,
IN DWORD cbSignerInfo,
IN DWORD cCountersigners,
IN PCMSG_SIGNER_ENCODE_INFO rgCountersigners,
OUT PBYTE pbCountersignature,
IN OUT PDWORD pcbCountersignature
);
static PFN_CRYPT_MSG_COUNTERSIGN_ENCODED
pfnOssCryptMsgCountersignEncoded = NULL;
#endif // DEBUG_CRYPT_ASN1_MASTER
int
WINAPI
ICMTest_GetDebugCryptAsn1Flags()
{
if (!fGotDebugCryptAsn1Flags) {
char *pszEnvVar;
char *p;
int iFlags;
if (pszEnvVar = getenv("DEBUG_CRYPT_ASN1_FLAGS")) {
iFlags = strtol(pszEnvVar, &p, 16);
#ifdef DEBUG_CRYPT_ASN1_MASTER
if (iFlags) {
if (NULL == (hOssCryptDll = LoadLibraryA("osscrypt.dll"))) {
iFlags = 0;
MessageBoxA(
NULL, // hwndOwner
"LoadLibrary(osscrypt.dll) failed",
"CheckCryptMessageAsn1",
MB_TOPMOST | MB_OK | MB_ICONWARNING |
MB_SERVICE_NOTIFICATION
);
} else if (NULL == (pfnOssCryptMsgOpenToEncode =
(PFN_CRYPT_MSG_OPEN_TO_ENCODE)
GetProcAddress(hOssCryptDll,
"CryptMsgOpenToEncode")) ||
NULL == (pfnOssCryptMsgOpenToDecode =
(PFN_CRYPT_MSG_OPEN_TO_DECODE)
GetProcAddress(hOssCryptDll,
"CryptMsgOpenToDecode")) ||
NULL == (pfnOssCryptMsgDuplicate =
(PFN_CRYPT_MSG_DUPLICATE)
GetProcAddress(hOssCryptDll,
"CryptMsgDuplicate")) ||
NULL == (pfnOssCryptMsgClose =
(PFN_CRYPT_MSG_CLOSE)
GetProcAddress(hOssCryptDll,
"CryptMsgClose")) ||
NULL == (pfnOssCryptMsgUpdate =
(PFN_CRYPT_MSG_UPDATE)
GetProcAddress(hOssCryptDll,
"CryptMsgUpdate")) ||
NULL == (pfnOssCryptMsgControl =
(PFN_CRYPT_MSG_CONTROL)
GetProcAddress(hOssCryptDll,
"CryptMsgControl")) ||
NULL == (pfnOssCryptMsgGetParam =
(PFN_CRYPT_MSG_GET_PARAM)
GetProcAddress(hOssCryptDll,
"CryptMsgGetParam")) ||
#ifdef CMS_PKCS7
NULL == (pfnOssCryptMsgVerifyCountersignatureEncodedEx =
(PFN_CRYPT_MSG_VERIFY_COUNTERSIGNATURE_ENCODED_EX)
GetProcAddress(hOssCryptDll,
"CryptMsgVerifyCountersignatureEncodedEx"))
||
#endif // CMS_PKCS7
NULL == (pfnOssCryptMsgCountersign =
(PFN_CRYPT_MSG_COUNTERSIGN)
GetProcAddress(hOssCryptDll,
"CryptMsgCountersign")) ||
NULL == (pfnOssCryptMsgCountersignEncoded =
(PFN_CRYPT_MSG_COUNTERSIGN_ENCODED)
GetProcAddress(hOssCryptDll,
"CryptMsgCountersignEncoded"))) {
iFlags = 0;
MessageBoxA(
NULL, // hwndOwner
"GetProcAddress(osscrypt.dll) failed",
"CheckCryptMessageAsn1",
MB_TOPMOST | MB_OK | MB_ICONWARNING |
MB_SERVICE_NOTIFICATION
);
}
}
#endif // DEBUG_CRYPT_ASN1_MASTER
} else
iFlags = 0;
if (iFlags & DEBUG_OSS_CRYPT_ASN1_CMSG_COMPARE_FLAG)
iFlags &= ~DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG;
iDebugCryptAsn1Flags = iFlags;
fGotDebugCryptAsn1Flags = TRUE;
}
return iDebugCryptAsn1Flags;
}
HCRYPTKEY
ICMTest_GetSameEncryptKey()
{
DWORD dwError = 0;
HCRYPTPROV hCryptProv; // doesn't need to be freed
HCRYPTHASH hHash = 0;
HCRYPTKEY hDeriveKey = 0;
BYTE rgbBaseData[] = {1,2,3,4,5,6,7,8};
hCryptProv = I_CryptGetDefaultCryptProvForEncrypt(
0, // aiPubKey
CALG_RC2,
0 // dwBitLen
);
if (0 == hCryptProv)
goto GetDefaultCryptProvError;
if (!CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash))
goto CreateHashError;
if (!CryptHashData(hHash, rgbBaseData, sizeof(rgbBaseData), 0))
goto HashDataError;
if (!CryptDeriveKey(hCryptProv, CALG_RC2, hHash, 0, &hDeriveKey))
goto DeriveKeyError;
CommonReturn:
if (hHash)
CryptDestroyHash(hHash);
ICM_SetLastError(dwError);
return hDeriveKey;
ErrorReturn:
dwError = GetLastError();
if (hDeriveKey) {
CryptDestroyKey(hDeriveKey);
hDeriveKey = 0;
}
goto CommonReturn;
TRACE_ERROR(GetDefaultCryptProvError)
TRACE_ERROR(CreateHashError)
TRACE_ERROR(HashDataError)
TRACE_ERROR(DeriveKeyError)
}
#ifdef CMS_PKCS7
BOOL
WINAPI
ICM_DefaultGenContentEncryptKey(
IN OUT PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
)
{
int iOssAsn1Flags = ICMTest_GetDebugCryptAsn1Flags();
if (0 == (iOssAsn1Flags & DEBUG_OSS_CRYPT_ASN1_SAME_ENCRYPT_FLAG))
return ICMTest_DefaultGenContentEncryptKey(
pContentEncryptInfo,
dwFlags,
pvReserved
);
pContentEncryptInfo->hContentEncryptKey = ICMTest_GetSameEncryptKey();
if (pContentEncryptInfo->hContentEncryptKey)
return TRUE;
else
return FALSE;
}
BOOL
WINAPI
ICM_DefaultExportKeyTrans(
IN PCMSG_CONTENT_ENCRYPT_INFO pContentEncryptInfo,
IN PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTransEncodeInfo,
IN OUT PCMSG_KEY_TRANS_ENCRYPT_INFO pKeyTransEncryptInfo,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
)
{
int iOssAsn1Flags = ICMTest_GetDebugCryptAsn1Flags();
PCRYPT_DATA_BLOB pEncryptedKey;
BYTE rgbEncryptedKey[] = {1,1,2,2,3,3,4,4,5,5};
if (0 == (iOssAsn1Flags & DEBUG_OSS_CRYPT_ASN1_SAME_ENCRYPT_FLAG))
return ICMTest_DefaultExportKeyTrans(
pContentEncryptInfo,
pKeyTransEncodeInfo,
pKeyTransEncryptInfo,
dwFlags,
pvReserved
);
pEncryptedKey = &pKeyTransEncryptInfo->EncryptedKey;
if (NULL == (pEncryptedKey->pbData = (PBYTE) ICM_Alloc(
sizeof(rgbEncryptedKey))))
return FALSE;
pEncryptedKey->cbData = sizeof(rgbEncryptedKey);
memcpy(pEncryptedKey->pbData, rgbEncryptedKey, sizeof(rgbEncryptedKey));
return TRUE;
}
BOOL
WINAPI
ICM_DefaultImportKeyTrans(
IN PCRYPT_ALGORITHM_IDENTIFIER pContentEncryptionAlgorithm,
IN PCMSG_CTRL_KEY_TRANS_DECRYPT_PARA pKeyTransDecryptPara,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved,
OUT HCRYPTKEY *phContentEncryptKey
)
{
int iOssAsn1Flags = ICMTest_GetDebugCryptAsn1Flags();
if (0 == (iOssAsn1Flags & DEBUG_OSS_CRYPT_ASN1_SAME_ENCRYPT_FLAG))
return ICMTest_DefaultImportKeyTrans(
pContentEncryptionAlgorithm,
pKeyTransDecryptPara,
dwFlags,
pvReserved,
phContentEncryptKey
);
*phContentEncryptKey = ICMTest_GetSameEncryptKey();
if (*phContentEncryptKey)
return TRUE;
else
return FALSE;
}
#endif // CMS_PKCS7
#ifdef DEBUG_CRYPT_ASN1_MASTER
void
ICMTest_MessageBox(
IN LPSTR pszText
)
{
int id;
LPSTR pszAlloc = NULL;
DWORD cchAlloc;
static LPCSTR pszSelect =
" Select Cancel to stop future OssCryptAsn1 Cryptographic Messages.";
cchAlloc = strlen(pszText) + strlen(pszSelect) + 1;
if (pszAlloc = (LPSTR) ICM_Alloc(cchAlloc)) {
strcpy(pszAlloc, pszText);
strcat(pszAlloc, pszSelect);
pszText = pszAlloc;
}
id = MessageBoxA(
NULL, // hwndOwner
pszText,
"CheckCryptMessageAsn1",
MB_TOPMOST | MB_OKCANCEL | MB_ICONQUESTION |
MB_SERVICE_NOTIFICATION
);
if (IDCANCEL == id)
iDebugCryptAsn1Flags = 0;
ICM_Free(pszAlloc);
}
void
ICMTest_MessageBoxLastError(
IN LPSTR pszText,
IN DWORD dwOssErr,
IN DWORD dwNewErr
)
{
char szText[512];
if (dwNewErr == (DWORD) PkiAsn1ErrToHr(ASN1_ERR_BADTAG) &&
(OSS_DATA_ERROR == dwOssErr || OSS_PDU_MISMATCH == dwOssErr))
return;
if (dwNewErr == (DWORD) PkiAsn1ErrToHr(ASN1_ERR_EOD) &&
OSS_MORE_INPUT == dwOssErr)
return;
wsprintfA(szText,
"%s:: failed with different LastError Oss: %d 0x%x New: %d 0x%x.",
pszText, dwOssErr, dwOssErr, dwNewErr, dwNewErr
);
ICMTest_MessageBox(szText);
}
//+-------------------------------------------------------------------------
// Write an encoded DER blob to a file
//--------------------------------------------------------------------------
BOOL
ICMTest_WriteDERToFile(
LPCSTR pszFileName,
PBYTE pbDER,
DWORD cbDER
)
{
BOOL fResult;
// Write the Encoded Blob to the file
HANDLE hFile;
hFile = CreateFile(pszFileName,
GENERIC_WRITE,
0, // fdwShareMode
NULL, // lpsa
CREATE_ALWAYS,
0, // fdwAttrsAndFlags
0); // TemplateFile
if (INVALID_HANDLE_VALUE == hFile) {
fResult = FALSE;
} else {
DWORD dwBytesWritten;
fResult = WriteFile(
hFile,
pbDER,
cbDER,
&dwBytesWritten,
NULL // lpOverlapped
);
CloseHandle(hFile);
}
return fResult;
}
#define TEST_MAGIC -12348765
// Note, in the following data structure lMagic is at the same offest as
// lRefCnt in CRYPT_MSG_INFO. lRefCnt should never be negative.
typedef struct _OSS_CRYPT_ASN1_MSG_INFO {
// The following must be ordered the same as CRYPT_MSG_INFO through
// dwEncodingType. msghlpr.cpp does a (PCRYPT_MSG_INFO) cast to
// access dwEncodingType.
CRITICAL_SECTION CriticalSection;
LONG lMagic; // lRefCnt in CRYPT_MSG_INFO
HCRYPTPROV hCryptProv; // decode
BOOL fDefaultCryptProv; // decode
DWORD dwKeySpec; // key to use in CryptSignHash
DWORD dwEncodingType; // encode
LONG lRefCnt;
union {
HCRYPTMSG hNewCryptMsg;
PCRYPT_MSG_INFO pNewcmi;
};
union {
HCRYPTMSG hOssCryptMsg;
PCRYPT_MSG_INFO pOsscmi;
};
PFN_CMSG_STREAM_OUTPUT pfnStreamOutput;
void *pvArg;
BYTE *pbOssOutput;
DWORD cbOssOutput;
BOOL fOssFinal;
BYTE *pbNewOutput;
DWORD cbNewOutput;
BOOL fNewFinal;
BOOL fDidCompare;
} OSS_CRYPT_ASN1_MSG_INFO, *POSS_CRYPT_ASN1_MSG_INFO;
BOOL
WINAPI
ICMTest_OssStreamOutput(
IN const void *pvArg,
IN BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal
)
{
POSS_CRYPT_ASN1_MSG_INFO pInfo = (POSS_CRYPT_ASN1_MSG_INFO) pvArg;
assert(TEST_MAGIC == pInfo->lMagic);
assert(!pInfo->fOssFinal);
pInfo->fOssFinal = fFinal;
if (cbData) {
BYTE *pbOssOutput;
if (pbOssOutput = (BYTE *) ICM_ReAlloc(pInfo->pbOssOutput,
pInfo->cbOssOutput + cbData)) {
memcpy(pbOssOutput + pInfo->cbOssOutput, pbData, cbData);
pInfo->pbOssOutput = pbOssOutput;
pInfo->cbOssOutput += cbData;
}
}
return TRUE;
}
BOOL
WINAPI
ICMTest_NewStreamOutput(
IN const void *pvArg,
IN BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal
)
{
POSS_CRYPT_ASN1_MSG_INFO pInfo = (POSS_CRYPT_ASN1_MSG_INFO) pvArg;
assert(TEST_MAGIC == pInfo->lMagic);
assert(!pInfo->fNewFinal);
pInfo->fNewFinal = fFinal;
if (cbData) {
BYTE *pbNewOutput;
if (pbNewOutput = (BYTE *) ICM_ReAlloc(pInfo->pbNewOutput,
pInfo->cbNewOutput + cbData)) {
memcpy(pbNewOutput + pInfo->cbNewOutput, pbData, cbData);
pInfo->pbNewOutput = pbNewOutput;
pInfo->cbNewOutput += cbData;
}
}
return pInfo->pfnStreamOutput(
pInfo->pvArg,
pbData,
cbData,
fFinal
);
}
void
ICMTest_CompareMessageBox(
IN LPSTR pszText,
IN BYTE *pbOss,
IN DWORD cbOss,
IN BYTE *pbNew,
IN DWORD cbNew
)
{
if (NULL == pbOss || NULL == pbNew)
return;
if (cbOss != cbNew || 0 != memcmp(pbOss, pbNew, cbNew)) {
ICMTest_WriteDERToFile("ossasn1.der", pbOss, cbOss);
ICMTest_WriteDERToFile("newasn1.der", pbNew, cbNew);
ICMTest_MessageBox(pszText);
}
}
void
ICMTest_CompareStreamOutput(
IN POSS_CRYPT_ASN1_MSG_INFO pInfo,
IN BOOL fForceCompare = FALSE
)
{
BOOL fDoCompare;
if (NULL == pInfo->pfnStreamOutput || pInfo->fDidCompare)
return;
fDoCompare = fForceCompare;
if (pInfo->fOssFinal || pInfo->fNewFinal)
fDoCompare = TRUE;
if (fDoCompare) {
if (pInfo->fOssFinal != pInfo->fNewFinal) {
if (pInfo->fOssFinal)
ICMTest_MessageBox("No fFinal on NewStreamOutput.");
else
ICMTest_MessageBox("No fFinal on OssStreamOutput.");
}
ICMTest_CompareMessageBox(
"StreamOutput compare failed. Check ossasn1.der and newasn1.der.",
pInfo->pbOssOutput,
pInfo->cbOssOutput,
pInfo->pbNewOutput,
pInfo->cbNewOutput
);
pInfo->fDidCompare = TRUE;
}
}
void
ICMTest_CompareGetParam(
IN POSS_CRYPT_ASN1_MSG_INFO pInfo,
IN DWORD dwParamType,
IN DWORD dwIndex,
IN void *pvOssData,
IN DWORD cbOssData,
IN void *pvNewData,
IN DWORD cbNewData
)
{
char szText[512];
switch (dwParamType) {
case CMSG_TYPE_PARAM:
case CMSG_CONTENT_PARAM:
case CMSG_BARE_CONTENT_PARAM:
case CMSG_INNER_CONTENT_TYPE_PARAM:
case CMSG_SIGNER_COUNT_PARAM:
case CMSG_CERT_COUNT_PARAM:
case CMSG_CERT_PARAM:
case CMSG_CRL_COUNT_PARAM:
case CMSG_CRL_PARAM:
case CMSG_RECIPIENT_COUNT_PARAM:
case CMSG_HASH_DATA_PARAM:
case CMSG_COMPUTED_HASH_PARAM:
case CMSG_ENCRYPTED_DIGEST:
case CMSG_ENCODED_SIGNER:
case CMSG_ENCODED_MESSAGE:
#ifdef CMS_PKCS7
case CMSG_VERSION_PARAM:
case CMSG_ATTR_CERT_COUNT_PARAM:
case CMSG_ATTR_CERT_PARAM:
case CMSG_CMS_RECIPIENT_COUNT_PARAM:
#endif // CMS_PKCS7
break;
default:
return;
}
if (NULL == pvOssData || NULL == pvNewData)
return;
wsprintfA(szText,
"ParamType: %d compare failed. Check ossasn1.der and newasn1.der.",
dwParamType
);
ICMTest_CompareMessageBox(
szText,
(BYTE *) pvOssData,
cbOssData,
(BYTE *) pvNewData,
cbNewData
);
}
inline
void
ICMTest_Lock(
IN POSS_CRYPT_ASN1_MSG_INFO pInfo
)
{
EnterCriticalSection( &pInfo->CriticalSection);
}
inline
void
ICMTest_Unlock(
IN POSS_CRYPT_ASN1_MSG_INFO pInfo
)
{
LeaveCriticalSection( &pInfo->CriticalSection);
}
HCRYPTMSG
WINAPI
CryptMsgOpenToEncode(
IN DWORD dwMsgEncodingType,
IN DWORD dwFlags,
IN DWORD dwMsgType,
IN void const *pvMsgEncodeInfo,
IN OPTIONAL LPSTR pszInnerContentObjID,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo
)
{
int iOssAsn1Flags = ICMTest_GetDebugCryptAsn1Flags();
if (iOssAsn1Flags & DEBUG_OSS_CRYPT_ASN1_CMSG_COMPARE_FLAG) {
POSS_CRYPT_ASN1_MSG_INFO pInfo;
CMSG_STREAM_INFO StreamInfo;
DWORD dwOssErr;
DWORD dwNewErr;
if (NULL == (pInfo = (POSS_CRYPT_ASN1_MSG_INFO) ICM_AllocZero(
sizeof(OSS_CRYPT_ASN1_MSG_INFO))))
return NULL;
pInfo->lMagic = TEST_MAGIC;
if (pStreamInfo) {
pInfo->pfnStreamOutput = pStreamInfo->pfnStreamOutput;
pInfo->pvArg = pStreamInfo->pvArg;
StreamInfo.cbContent = pStreamInfo->cbContent;
// StreamInfo.pfnStreamOutput =
StreamInfo.pvArg = pInfo;
pStreamInfo = &StreamInfo;
}
StreamInfo.pfnStreamOutput = ICMTest_NewStreamOutput;
pInfo->hNewCryptMsg = ICMTest_NewCryptMsgOpenToEncode(
dwMsgEncodingType,
dwFlags,
dwMsgType,
pvMsgEncodeInfo,
pszInnerContentObjID,
pStreamInfo
);
dwNewErr = GetLastError();
StreamInfo.pfnStreamOutput = ICMTest_OssStreamOutput;
pInfo->hOssCryptMsg = pfnOssCryptMsgOpenToEncode(
dwMsgEncodingType,
dwFlags & ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG,
dwMsgType,
pvMsgEncodeInfo,
pszInnerContentObjID,
pStreamInfo
);
dwOssErr = GetLastError();
if (pInfo->hNewCryptMsg) {
if (pInfo->hOssCryptMsg) {
pInfo->dwEncodingType = pInfo->pNewcmi->dwEncodingType;
InitializeCriticalSection(&pInfo->CriticalSection);
pInfo->lRefCnt = 1;
return (HCRYPTMSG) pInfo;
} else {
HCRYPTMSG hRet;
ICMTest_MessageBox("OssCryptMsgOpenToEncode failed.");
hRet = pInfo->hNewCryptMsg;
ICM_Free(pInfo);
return hRet;
}
} else {
if (pInfo->hOssCryptMsg) {
ICMTest_MessageBox("OssCryptMsgOpenToEncode succeeded while NewCryptMsgOpenToEncoded failed.");
pfnOssCryptMsgClose(pInfo->hOssCryptMsg);
} else if (dwOssErr != dwNewErr)
ICMTest_MessageBoxLastError("CryptMsgOpenToEncode",
dwOssErr, dwNewErr);
ICM_Free(pInfo);
SetLastError(dwNewErr);
return NULL;
}
} else if (iOssAsn1Flags & DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG)
return pfnOssCryptMsgOpenToEncode(
dwMsgEncodingType,
dwFlags,
dwMsgType,
pvMsgEncodeInfo,
pszInnerContentObjID,
pStreamInfo
);
else
return ICMTest_NewCryptMsgOpenToEncode(
dwMsgEncodingType,
dwFlags,
dwMsgType,
pvMsgEncodeInfo,
pszInnerContentObjID,
pStreamInfo
);
}
HCRYPTMSG
WINAPI
CryptMsgOpenToDecode(
IN DWORD dwMsgEncodingType,
IN DWORD dwFlags,
IN DWORD dwMsgType,
IN HCRYPTPROV hCryptProv,
IN OPTIONAL PCERT_INFO pRecipientInfo,
IN OPTIONAL PCMSG_STREAM_INFO pStreamInfo
)
{
int iOssAsn1Flags = ICMTest_GetDebugCryptAsn1Flags();
if (iOssAsn1Flags & DEBUG_OSS_CRYPT_ASN1_CMSG_COMPARE_FLAG) {
POSS_CRYPT_ASN1_MSG_INFO pInfo;
CMSG_STREAM_INFO StreamInfo;
DWORD dwOssErr;
DWORD dwNewErr;
if (NULL == (pInfo = (POSS_CRYPT_ASN1_MSG_INFO) ICM_AllocZero(
sizeof(OSS_CRYPT_ASN1_MSG_INFO))))
return NULL;
pInfo->lMagic = TEST_MAGIC;
if (pStreamInfo) {
pInfo->pfnStreamOutput = pStreamInfo->pfnStreamOutput;
pInfo->pvArg = pStreamInfo->pvArg;
StreamInfo.cbContent = pStreamInfo->cbContent;
// StreamInfo.pfnStreamOutput =
StreamInfo.pvArg = pInfo;
pStreamInfo = &StreamInfo;
}
StreamInfo.pfnStreamOutput = ICMTest_NewStreamOutput;
pInfo->hNewCryptMsg = ICMTest_NewCryptMsgOpenToDecode(
dwMsgEncodingType,
dwFlags,
dwMsgType,
hCryptProv,
pRecipientInfo,
pStreamInfo
);
dwNewErr = GetLastError();
StreamInfo.pfnStreamOutput = ICMTest_OssStreamOutput;
pInfo->hOssCryptMsg = pfnOssCryptMsgOpenToDecode(
dwMsgEncodingType,
dwFlags & ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG,
dwMsgType,
hCryptProv,
pRecipientInfo,
pStreamInfo
);
dwOssErr = GetLastError();
if (pInfo->hNewCryptMsg) {
if (pInfo->hOssCryptMsg) {
pInfo->dwEncodingType = pInfo->pNewcmi->dwEncodingType;
InitializeCriticalSection(&pInfo->CriticalSection);
pInfo->lRefCnt = 1;
return (HCRYPTMSG) pInfo;
} else {
HCRYPTMSG hRet;
ICMTest_MessageBox("OssCryptMsgOpenToDecode failed.");
hRet = pInfo->hNewCryptMsg;
ICM_Free(pInfo);
return hRet;
}
} else {
if (pInfo->hOssCryptMsg) {
ICMTest_MessageBox("OssCryptMsgOpenToDecode succeeded while NewCryptMsgOpenToDecode failed.");
pfnOssCryptMsgClose(pInfo->hOssCryptMsg);
} else if (dwOssErr != dwNewErr)
ICMTest_MessageBoxLastError("CryptMsgOpenToDecode",
dwOssErr, dwNewErr);
ICM_Free(pInfo);
SetLastError(dwNewErr);
return NULL;
}
} else if (iOssAsn1Flags & DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG)
return pfnOssCryptMsgOpenToDecode(
dwMsgEncodingType,
dwFlags,
dwMsgType,
hCryptProv,
pRecipientInfo,
pStreamInfo
);
else
return ICMTest_NewCryptMsgOpenToDecode(
dwMsgEncodingType,
dwFlags,
dwMsgType,
hCryptProv,
pRecipientInfo,
pStreamInfo
);
}
HCRYPTMSG
WINAPI
CryptMsgDuplicate(
IN HCRYPTMSG hCryptMsg
)
{
POSS_CRYPT_ASN1_MSG_INFO pInfo = (POSS_CRYPT_ASN1_MSG_INFO) hCryptMsg;
if (pInfo && TEST_MAGIC == pInfo->lMagic) {
InterlockedIncrement(&pInfo->lRefCnt);
return hCryptMsg;
} else if (ICMTest_GetDebugCryptAsn1Flags() &
DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG)
return pfnOssCryptMsgDuplicate(hCryptMsg);
else
return ICMTest_NewCryptMsgDuplicate(hCryptMsg);
}
BOOL
WINAPI
CryptMsgClose(
IN HCRYPTMSG hCryptMsg
)
{
BOOL fRet;
DWORD dwError;
POSS_CRYPT_ASN1_MSG_INFO pInfo = (POSS_CRYPT_ASN1_MSG_INFO) hCryptMsg;
if (NULL == pInfo)
return TRUE;
if (TEST_MAGIC != pInfo->lMagic) {
if (iDebugCryptAsn1Flags &
DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG)
return pfnOssCryptMsgClose(hCryptMsg);
else
return ICMTest_NewCryptMsgClose(hCryptMsg);
}
if (0 != InterlockedDecrement(&pInfo->lRefCnt))
return TRUE;
// Preserve LastError
dwError = GetLastError();
assert(pInfo->hOssCryptMsg);
assert(1 == ((PCRYPT_MSG_INFO) pInfo->hOssCryptMsg)->lRefCnt);
assert(pInfo->hNewCryptMsg);
assert(1 == ((PCRYPT_MSG_INFO) pInfo->hNewCryptMsg)->lRefCnt);
ICMTest_CompareStreamOutput(pInfo, TRUE);
pfnOssCryptMsgClose(pInfo->hOssCryptMsg);
fRet = ICMTest_NewCryptMsgClose(pInfo->hNewCryptMsg);
ICM_Free(pInfo->pbOssOutput);
ICM_Free(pInfo->pbNewOutput);
DeleteCriticalSection(&pInfo->CriticalSection);
ICM_Free(pInfo);
SetLastError(dwError); // Preserve LastError
return fRet;
}
BOOL
WINAPI
CryptMsgUpdate(
IN HCRYPTMSG hCryptMsg,
IN const BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal
)
{
BOOL fNew;
DWORD dwNewErr;
BOOL fOss;
DWORD dwOssErr;
POSS_CRYPT_ASN1_MSG_INFO pInfo = (POSS_CRYPT_ASN1_MSG_INFO) hCryptMsg;
if (NULL == pInfo || TEST_MAGIC != pInfo->lMagic) {
if (ICMTest_GetDebugCryptAsn1Flags() &
DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG)
return pfnOssCryptMsgUpdate(
hCryptMsg,
pbData,
cbData,
fFinal
);
else
return ICMTest_NewCryptMsgUpdate(
hCryptMsg,
pbData,
cbData,
fFinal
);
}
ICMTest_Lock(pInfo);
fOss = pfnOssCryptMsgUpdate(
pInfo->hOssCryptMsg,
pbData,
cbData,
fFinal
);
dwOssErr = GetLastError();
fNew = ICMTest_NewCryptMsgUpdate(
pInfo->hNewCryptMsg,
pbData,
cbData,
fFinal
);
dwNewErr = GetLastError();
if (fNew) {
if (fOss)
ICMTest_CompareStreamOutput(pInfo);
else
ICMTest_MessageBox("OssCryptMsgUpdate failed.");
} else {
if (fOss)
ICMTest_MessageBox("OssCryptMsgUpdate succeeded while NewCryptMsgUpdate failed.");
else if (dwOssErr != dwNewErr)
ICMTest_MessageBoxLastError("CryptMsgUpdate",
dwOssErr, dwNewErr);
}
ICMTest_Unlock(pInfo);
SetLastError(dwNewErr);
return fNew;
}
BOOL
WINAPI
CryptMsgGetParam(
IN HCRYPTMSG hCryptMsg,
IN DWORD dwParamType,
IN DWORD dwIndex,
OUT void *pvData,
IN OUT DWORD *pcbData
)
{
BOOL fOss;
DWORD dwOssErr;
void *pvOssData = NULL;
DWORD cbOssData;
BOOL fNew;
DWORD dwNewErr;
POSS_CRYPT_ASN1_MSG_INFO pInfo = (POSS_CRYPT_ASN1_MSG_INFO) hCryptMsg;
if (NULL == pInfo || TEST_MAGIC != pInfo->lMagic) {
if (ICMTest_GetDebugCryptAsn1Flags() &
DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG)
return pfnOssCryptMsgGetParam(
hCryptMsg,
dwParamType,
dwIndex,
pvData,
pcbData
);
else
return ICMTest_NewCryptMsgGetParam(
hCryptMsg,
dwParamType,
dwIndex,
pvData,
pcbData
);
}
ICMTest_Lock(pInfo);
cbOssData = *pcbData;
if (pvData)
pvOssData = ICM_Alloc(cbOssData);
fOss = pfnOssCryptMsgGetParam(
pInfo->hOssCryptMsg,
dwParamType,
dwIndex,
pvOssData,
&cbOssData
);
dwOssErr = GetLastError();
fNew = ICMTest_NewCryptMsgGetParam(
pInfo->hNewCryptMsg,
dwParamType,
dwIndex,
pvData,
pcbData
);
dwNewErr = GetLastError();
if (fNew) {
if (fOss)
ICMTest_CompareGetParam(
pInfo,
dwParamType,
dwIndex,
pvOssData,
cbOssData,
pvData,
*pcbData
);
else
ICMTest_MessageBox("OssCryptMsgGetParam failed.");
} else {
if (fOss)
ICMTest_MessageBox("OssCryptMsgGetParam succeeded while NewCryptMsgGetParam failed.");
else if (dwOssErr != dwNewErr)
ICMTest_MessageBoxLastError("CryptMsgGetParam",
dwOssErr, dwNewErr);
}
ICMTest_Unlock(pInfo);
ICM_Free(pvOssData);
SetLastError(dwNewErr);
return fNew;
}
BOOL
WINAPI
CryptMsgControl(
IN HCRYPTMSG hCryptMsg,
IN DWORD dwFlags,
IN DWORD dwCtrlType,
IN void const *pvCtrlPara
)
{
BOOL fNew;
DWORD dwNewErr;
BOOL fOss;
DWORD dwOssErr;
POSS_CRYPT_ASN1_MSG_INFO pInfo = (POSS_CRYPT_ASN1_MSG_INFO) hCryptMsg;
if (NULL == pInfo || TEST_MAGIC != pInfo->lMagic) {
if (ICMTest_GetDebugCryptAsn1Flags() &
DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG)
return pfnOssCryptMsgControl(
hCryptMsg,
dwFlags,
dwCtrlType,
pvCtrlPara
);
else
return ICMTest_NewCryptMsgControl(
hCryptMsg,
dwFlags,
dwCtrlType,
pvCtrlPara
);
}
ICMTest_Lock(pInfo);
fOss = pfnOssCryptMsgControl(
pInfo->hOssCryptMsg,
dwFlags & ~CMSG_CRYPT_RELEASE_CONTEXT_FLAG,
dwCtrlType,
pvCtrlPara
);
dwOssErr = GetLastError();
fNew = ICMTest_NewCryptMsgControl(
pInfo->hNewCryptMsg,
dwFlags,
dwCtrlType,
pvCtrlPara
);
dwNewErr = GetLastError();
if (fNew) {
if (fOss)
ICMTest_CompareStreamOutput(pInfo);
else
ICMTest_MessageBox("OssCryptMsgControl failed.");
} else {
if (fOss)
ICMTest_MessageBox("OssCryptMsgControl succeeded while NewCryptMsgControl failed.");
else if (dwOssErr != dwNewErr)
ICMTest_MessageBoxLastError("CryptMsgControl",
dwOssErr, dwNewErr);
}
ICMTest_Unlock(pInfo);
SetLastError(dwNewErr);
return fNew;
}
#ifdef CMS_PKCS7
BOOL
WINAPI
CryptMsgVerifyCountersignatureEncodedEx(
IN HCRYPTPROV hCryptProv,
IN DWORD dwEncodingType,
IN PBYTE pbSignerInfo,
IN DWORD cbSignerInfo,
IN PBYTE pbSignerInfoCountersignature,
IN DWORD cbSignerInfoCountersignature,
IN DWORD dwSignerType,
IN void *pvSigner,
IN DWORD dwFlags,
IN OPTIONAL void *pvReserved
)
{
BOOL fOss;
int iOssAsn1Flags = ICMTest_GetDebugCryptAsn1Flags();
if (0 == (iOssAsn1Flags &
(DEBUG_OSS_CRYPT_ASN1_CMSG_COMPARE_FLAG |
DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG)))
return ICMTest_NewCryptMsgVerifyCountersignatureEncodedEx(
hCryptProv,
dwEncodingType,
pbSignerInfo,
cbSignerInfo,
pbSignerInfoCountersignature,
cbSignerInfoCountersignature,
dwSignerType,
pvSigner,
dwFlags,
pvReserved
);
fOss = pfnOssCryptMsgVerifyCountersignatureEncodedEx(
hCryptProv,
dwEncodingType,
pbSignerInfo,
cbSignerInfo,
pbSignerInfoCountersignature,
cbSignerInfoCountersignature,
dwSignerType,
pvSigner,
dwFlags,
pvReserved
);
if (iOssAsn1Flags & DEBUG_OSS_CRYPT_ASN1_CMSG_COMPARE_FLAG) {
DWORD dwOssErr = GetLastError();
BOOL fNew;
DWORD dwNewErr;
fNew = ICMTest_NewCryptMsgVerifyCountersignatureEncodedEx(
hCryptProv,
dwEncodingType,
pbSignerInfo,
cbSignerInfo,
pbSignerInfoCountersignature,
cbSignerInfoCountersignature,
dwSignerType,
pvSigner,
dwFlags,
pvReserved
);
dwNewErr = GetLastError();
if (fNew) {
if (!fOss)
ICMTest_MessageBox("OssCryptMsgVerifyCountersignatureEncodedEx failed.");
} else {
if (fOss)
ICMTest_MessageBox("OssCryptMsgVerifyCountersignatureEncodedEx succeeded while NewCryptMsgVerifyCountersignatureEncodedEx failed.");
else if (dwOssErr != dwNewErr)
ICMTest_MessageBoxLastError("CryptMsgVerifyCountersignatureEncodedEx",
dwOssErr, dwNewErr);
}
SetLastError(dwOssErr);
}
return fOss;
}
#endif // CMS_PKCS7
BOOL
WINAPI
CryptMsgCountersign(
IN OUT HCRYPTMSG hCryptMsg,
IN DWORD dwIndex,
IN DWORD cCountersigners,
IN PCMSG_SIGNER_ENCODE_INFO rgCountersigners
)
{
BOOL fNew;
DWORD dwNewErr;
BOOL fOss;
DWORD dwOssErr;
POSS_CRYPT_ASN1_MSG_INFO pInfo = (POSS_CRYPT_ASN1_MSG_INFO) hCryptMsg;
if (NULL == pInfo || TEST_MAGIC != pInfo->lMagic) {
if (ICMTest_GetDebugCryptAsn1Flags() &
DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG)
return pfnOssCryptMsgCountersign(
hCryptMsg,
dwIndex,
cCountersigners,
rgCountersigners
);
else
return ICMTest_NewCryptMsgCountersign(
hCryptMsg,
dwIndex,
cCountersigners,
rgCountersigners
);
}
ICMTest_Lock(pInfo);
fOss = pfnOssCryptMsgCountersign(
pInfo->hOssCryptMsg,
dwIndex,
cCountersigners,
rgCountersigners
);
dwOssErr = GetLastError();
fNew = ICMTest_NewCryptMsgCountersign(
pInfo->hNewCryptMsg,
dwIndex,
cCountersigners,
rgCountersigners
);
dwNewErr = GetLastError();
if (fNew) {
if (!fOss)
ICMTest_MessageBox("OssCryptMsgCountersign failed.");
} else {
if (fOss)
ICMTest_MessageBox("OssCryptMsgCountersign succeeded while NewCryptMsgCountersign failed.");
else if (dwOssErr != dwNewErr)
ICMTest_MessageBoxLastError("CryptMsgCountersign",
dwOssErr, dwNewErr);
}
ICMTest_Unlock(pInfo);
SetLastError(dwNewErr);
return fNew;
}
BOOL
WINAPI
CryptMsgCountersignEncoded(
IN DWORD dwEncodingType,
IN PBYTE pbSignerInfo,
IN DWORD cbSignerInfo,
IN DWORD cCountersigners,
IN PCMSG_SIGNER_ENCODE_INFO rgCountersigners,
OUT PBYTE pbCountersignature,
IN OUT PDWORD pcbCountersignature
)
{
BOOL fOss;
int iOssAsn1Flags = ICMTest_GetDebugCryptAsn1Flags();
BYTE *pbNew = NULL;
DWORD cbNew;
if (0 == (iOssAsn1Flags &
(DEBUG_OSS_CRYPT_ASN1_CMSG_COMPARE_FLAG |
DEBUG_OSS_CRYPT_ASN1_CMSG_FLAG)))
return ICMTest_NewCryptMsgCountersignEncoded(
dwEncodingType,
pbSignerInfo,
cbSignerInfo,
cCountersigners,
rgCountersigners,
pbCountersignature,
pcbCountersignature
);
if (iOssAsn1Flags & DEBUG_OSS_CRYPT_ASN1_CMSG_COMPARE_FLAG) {
cbNew = *pcbCountersignature;
if (pbCountersignature)
pbNew = (BYTE *) ICM_Alloc(cbNew);
}
fOss = pfnOssCryptMsgCountersignEncoded(
dwEncodingType,
pbSignerInfo,
cbSignerInfo,
cCountersigners,
rgCountersigners,
pbCountersignature,
pcbCountersignature
);
if (iOssAsn1Flags & DEBUG_OSS_CRYPT_ASN1_CMSG_COMPARE_FLAG) {
DWORD dwOssErr = GetLastError();
BOOL fNew;
DWORD dwNewErr;
fNew = ICMTest_NewCryptMsgCountersignEncoded(
dwEncodingType,
pbSignerInfo,
cbSignerInfo,
cCountersigners,
rgCountersigners,
pbNew,
&cbNew
);
dwNewErr = GetLastError();
if (fNew) {
if (fOss)
ICMTest_CompareMessageBox(
"CountersignEncoded compare failed. Check ossasn1.der and newasn1.der.",
pbCountersignature,
*pcbCountersignature,
pbNew,
cbNew
);
else
ICMTest_MessageBox("NewCryptMsgCountersignEncoded failed.");
} else {
if (fOss)
ICMTest_MessageBox("OssCryptMsgCountersignEncoded succeeded while NewCryptMsgCountersignEncoded failed.");
else if (dwOssErr != dwNewErr)
ICMTest_MessageBoxLastError("CryptMsgCountersignEncoded",
dwOssErr, dwNewErr);
}
SetLastError(dwOssErr);
}
ICM_Free(pbNew);
return fOss;
}
#endif // DEBUG_CRYPT_ASN1_MASTER
#endif // DEBUG_CRYPT_ASN1