19414 lines
597 KiB
C++
19414 lines
597 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// 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)) {
|
|
CryptMsgClose(hcrmsg);
|
|
hcrmsg = NULL;
|
|
}
|
|
}
|
|
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->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);
|
|
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->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);
|
|
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);
|
|
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
|
|
|