|
|
//+-------------------------------------------------------------------------
//
// 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
|