You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6638 lines
219 KiB
6638 lines
219 KiB
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1997
|
|
//
|
|
// File: tcrmsg.cpp
|
|
//
|
|
// Contents: Cryptographic Message API Tests
|
|
//
|
|
// See Usage() for list of test options.
|
|
//
|
|
//
|
|
// Functions: main
|
|
//
|
|
// History: 26-Feb-96 philh created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "global.hxx"
|
|
|
|
#define SAVE_STREAM_FILES 1
|
|
|
|
#define MAX_HASH_LEN 20
|
|
|
|
#define ZEROSTRUCT(arg) (memset( &arg, 0, sizeof(arg)))
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Parameters, data used to encode the messages.
|
|
//--------------------------------------------------------------------------
|
|
HCRYPTPROV hCryptProv = 0;
|
|
DWORD dwProvType = PROV_RSA_FULL;
|
|
|
|
#ifdef CMS_PKCS7
|
|
HCRYPTPROV hMultiSignerCryptProv = 0;
|
|
DWORD dwMultiSignerProvType = PROV_RSA_FULL;
|
|
BOOL fMultiSigner = FALSE;
|
|
BOOL fHashEncryptionAlgorithm = FALSE;
|
|
BOOL fAlgorithmParameters = FALSE;
|
|
BOOL fNoSignature = FALSE;
|
|
|
|
BYTE rgbOctets[] = {4, 8, 1,2,3,4,5,6,7,8};
|
|
BYTE rgbInvalidAsn[] = {0xFF, 0xFF};
|
|
#endif // CMS_PKCS7
|
|
|
|
LPSTR pszCertNameFindStr = NULL;
|
|
HCERTSTORE hSignerStore = NULL;
|
|
PCCERT_CONTEXT pNamedSigner = NULL;
|
|
HCRYPTPROV hNamedSignerCryptProv = 0;
|
|
|
|
LPSTR pszFilename = NULL;
|
|
BOOL fVerbose = FALSE;
|
|
BOOL fNoSigners = FALSE;
|
|
BOOL fAddSigner = FALSE;
|
|
BOOL fDetached = FALSE;
|
|
BOOL fAuthAttr = FALSE;
|
|
BOOL fInnerContent = FALSE;
|
|
BOOL fCountersign = FALSE;
|
|
BOOL fStream = FALSE;
|
|
BOOL fIndefinite = FALSE;
|
|
BOOL fBare = FALSE;
|
|
BOOL fMD5 = FALSE;
|
|
BOOL fNoRecipients = FALSE;
|
|
DWORD dwMsgEncodingType = PKCS_7_ASN_ENCODING;
|
|
DWORD dwCertEncodingType = X509_ASN_ENCODING;
|
|
|
|
|
|
LPCSTR pszContainer = NULL;
|
|
LPCSTR pszProvider = NULL;
|
|
BOOL fDefaultVerifyProv = FALSE;
|
|
HCRYPTPROV hDefaultVerifyProv = 0;
|
|
BOOL fEnhanced = FALSE;
|
|
LPCSTR pszEncryptName = "rc2";
|
|
LPCSTR pszEncryptOID = NULL;
|
|
DWORD dwEncryptBitLen = 0;
|
|
BOOL fEncryptIV = FALSE;
|
|
|
|
#ifdef CMS_PKCS7
|
|
BOOL fOriginatorInfo = FALSE;
|
|
#endif // CMS_PKCS7
|
|
|
|
typedef struct _PUBLIC_KEY_DATA {
|
|
BYTE Data[1024];
|
|
} PUBLIC_KEY_DATA;
|
|
|
|
#define DEFAULT_MSG_CONTENT_SIZE 49
|
|
DWORD cbMsgContent = DEFAULT_MSG_CONTENT_SIZE;
|
|
BYTE rgbMsgContentFill[7] = {'C','o','n','t','e','n','t'};
|
|
#define cbMsgContentFill sizeof(rgbMsgContentFill)
|
|
DWORD iMsgContentOffset = 0;
|
|
PBYTE pbInnerContent = NULL;
|
|
DWORD cbInnerContent;
|
|
|
|
// rsaEncryption
|
|
CRYPT_ALGORITHM_IDENTIFIER PublicKeyAlgorithm =
|
|
{szOID_RSA_RSA, {0,0}};
|
|
|
|
// DES or RC4
|
|
CRYPT_ALGORITHM_IDENTIFIER ContentEncryptionAlgorithm[] = {
|
|
{szOID_OIWSEC_desCBC, {0,0}},
|
|
{szOID_RSA_RC4, {0,0}},
|
|
{szOID_RSA_RC2CBC, {0,0}},
|
|
};
|
|
#define CONTENT_ALG_DES 0
|
|
#define CONTENT_ALG_RC4 1
|
|
#define CONTENT_ALG_RC2 2
|
|
|
|
// MD5 or SHA1
|
|
CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithms[] = {
|
|
{szOID_RSA_MD5, {0,0}},
|
|
{szOID_OIWSEC_sha1, {0,0}},
|
|
};
|
|
#define DIGEST_ALG_MD5 0
|
|
#define DIGEST_ALG_SHA 1
|
|
|
|
// MD5 or SHA
|
|
CRYPT_ALGORITHM_IDENTIFIER SignDigestAlgorithms[] = {
|
|
{szOID_RSA_MD5, {0,0}},
|
|
{szOID_OIWSEC_sha1, {0,0}},
|
|
};
|
|
#define SIGNDIGEST_ALG_MD5 0
|
|
#define SIGNDIGEST_ALG_SHA 1
|
|
|
|
LPSTR pszSignerSerialNumberFileName = "name.der";
|
|
DWORD dwSignerSerialNumber = 0x01010101;
|
|
DWORD dwSignerSerialNumber1 = 0x02020202;
|
|
DWORD dwSignerSerialNumber2 = 0x03030303;
|
|
PUBLIC_KEY_DATA SignerPublicKeyData;
|
|
|
|
#define SIGNED_CERT_COUNT 3
|
|
DWORD cSignedCert = 1;
|
|
LPCSTR rgpszSignedCertFileName[SIGNED_CERT_COUNT] = {
|
|
"cert1.der",
|
|
"cert2.der",
|
|
"cert3.der"
|
|
};
|
|
CERT_BLOB rgSignedCertBlob[3];
|
|
|
|
#ifdef CMS_PKCS7
|
|
#define ATTR_CERT_COUNT 2
|
|
DWORD cAttrCert = 0;
|
|
BOOL fEncapsulatedContent = FALSE;
|
|
|
|
LPCSTR rgpszAttrCertFileName[ATTR_CERT_COUNT] = {
|
|
"cert2.der",
|
|
"cert3.der"
|
|
};
|
|
CERT_BLOB rgAttrCertBlob[ATTR_CERT_COUNT];
|
|
#endif // CMS_PKCS7
|
|
|
|
#ifdef CMS_PKCS7
|
|
#define SIGNED_CRL_COUNT 1
|
|
DWORD cSignedCrl = 0;
|
|
LPCSTR rgpszSignedCrlFileName[SIGNED_CRL_COUNT] = {
|
|
"crl1.der"
|
|
};
|
|
CRL_BLOB rgSignedCrlBlob[SIGNED_CRL_COUNT];
|
|
#else
|
|
#define SIGNED_CRL_COUNT 0
|
|
#endif
|
|
|
|
#define RECIPIENT_COUNT 2
|
|
DWORD PkcsRecipientCount = RECIPIENT_COUNT;
|
|
LPCSTR rgpszRecipientIssuerFileName[RECIPIENT_COUNT] = {
|
|
"recip1.der",
|
|
"recip2.der"
|
|
};
|
|
DWORD rgdwRecipientSerialNumber[RECIPIENT_COUNT] = {
|
|
0x02020202,
|
|
0x03030303
|
|
};
|
|
PUBLIC_KEY_DATA RecipientPublicKeyData;
|
|
CERT_INFO rgRecipientCertInfo[RECIPIENT_COUNT];
|
|
PCERT_INFO rgpRecipientCertInfo[RECIPIENT_COUNT];
|
|
|
|
#ifdef CMS_PKCS7
|
|
BOOL fRecipientProv = FALSE;
|
|
BOOL fKeyTrans = FALSE;
|
|
BOOL fKeyAgree = FALSE;
|
|
BOOL fMailList = FALSE;
|
|
BOOL fCmsRecipient = FALSE;
|
|
BOOL fRecipientKeyId = FALSE;
|
|
BOOL fCertInfoKeyId = FALSE;
|
|
BOOL fSignerId = FALSE;
|
|
|
|
BOOL fNoSalt = FALSE;
|
|
#define MAX_SALT_LEN 11
|
|
BYTE rgbSalt[MAX_SALT_LEN];
|
|
CMSG_RC4_AUX_INFO RC4AuxInfo;
|
|
|
|
CMSG_RECIPIENT_ENCODE_INFO rgCmsRecipient[RECIPIENT_COUNT * 4];
|
|
CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO rgKeyTrans[RECIPIENT_COUNT * 4];
|
|
|
|
HCRYPTPROV hKeyAgreeProv = 0;
|
|
PUBLIC_KEY_DATA KeyAgreePublicKeyData;
|
|
CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO rgKeyAgree[RECIPIENT_COUNT * 4];
|
|
CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO rgEncryptedKey[RECIPIENT_COUNT];
|
|
PCMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO rgpEncryptedKey[RECIPIENT_COUNT];
|
|
CMSG_RC2_AUX_INFO KeyAgreeRC2AuxInfo;
|
|
|
|
BYTE rgbKeyAgreeOtherAttr[] = {0x04, 3, 3, 2, 1};
|
|
CRYPT_ATTRIBUTE_TYPE_VALUE KeyAgreeOtherAttr = {
|
|
"1.2.10.11.12",
|
|
sizeof(rgbKeyAgreeOtherAttr), rgbKeyAgreeOtherAttr
|
|
};
|
|
|
|
LPCSTR pszUserKeyingMaterial = "UserKeyingMaterial";
|
|
|
|
|
|
CMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO rgMailList[RECIPIENT_COUNT * 4];
|
|
CMSG_RC2_AUX_INFO MailListRC2AuxInfo;
|
|
|
|
BYTE rgbMailListOtherAttr[] = {0x04, 2, 1, 2};
|
|
CRYPT_ATTRIBUTE_TYPE_VALUE MailListOtherAttr = {
|
|
"1.2.3.4.5.6.7.8.9",
|
|
sizeof(rgbMailListOtherAttr), rgbMailListOtherAttr
|
|
};
|
|
|
|
DWORD cCmsRecipients = 0;
|
|
#endif // CMS_PKCS7
|
|
|
|
#define AUTH_ATTR_COUNT 2
|
|
BYTE attr1[] = {0x04, 0x0c, 'A','t','t','r','i','b','u','t','e',' ','1',0};
|
|
BYTE attr2[] = {0x04, 0x0c, 'A','t','t','r','i','b','u','t','e',' ','2',0};
|
|
BYTE attr3[] = {0x04, 0x0c, 'A','t','t','r','i','b','u','t','e',' ','3',0};
|
|
CRYPT_ATTR_BLOB rgatrblob1[] = {
|
|
{ sizeof( attr1), attr1}
|
|
};
|
|
CRYPT_ATTR_BLOB rgatrblob2[] = {
|
|
{ sizeof( attr2), attr2},
|
|
{ sizeof( attr3), attr3}
|
|
};
|
|
CRYPT_ATTRIBUTE rgAuthAttr[AUTH_ATTR_COUNT] = {
|
|
{"1.2.3.5.7", 1, rgatrblob1},
|
|
{"1.2.3.5.11", 2, rgatrblob2}
|
|
};
|
|
|
|
#define UNAUTH_ATTR_COUNT 1
|
|
BYTE unattr1[] = {0x04, 0x0c, 'A','T','T','R','I','B','U','T','E',' ','1',0};
|
|
CRYPT_ATTR_BLOB rgunatrblob1[] = {
|
|
{ sizeof( unattr1), unattr1}
|
|
};
|
|
CRYPT_ATTRIBUTE rgUnauthAttr[UNAUTH_ATTR_COUNT] = {
|
|
{"1.2.3.5.13.23", 1, rgunatrblob1},
|
|
};
|
|
|
|
LPSTR pszInnerContentObjId = szOID_RSA_digestedData;
|
|
LPCSTR pszInnerContentFileName = "content.der";
|
|
//CRYPT_DER_BLOB derInnerContent = {NULL,0};
|
|
|
|
CERT_INFO rgSignerCertInfo[2];
|
|
#ifdef CMS_PKCS7
|
|
CERT_ID rgSignerId[2];
|
|
#endif // CMS_PKCS7
|
|
CMSG_SIGNER_ENCODE_INFO rgSignerEncodeInfo[2];
|
|
CMSG_SIGNED_ENCODE_INFO SignedMsgEncodeInfo;
|
|
CMSG_ENVELOPED_ENCODE_INFO EnvelopedMsgEncodeInfo;
|
|
CMSG_SIGNED_AND_ENVELOPED_ENCODE_INFO SignedAndEnvelopedMsgEncodeInfo;
|
|
CMSG_HASHED_ENCODE_INFO HashedMsgEncodeInfo;
|
|
|
|
#ifdef CMS_PKCS7
|
|
PUBLIC_KEY_DATA MultiSignerPublicKeyData;
|
|
|
|
BYTE rgbEncodedSignerHash[2][MAX_HASH_LEN];
|
|
DWORD rgcbEncodedSignerHash[2];
|
|
|
|
#endif // CMS_PKCS7
|
|
|
|
static inline IsDSSProv(
|
|
IN DWORD dwProvType
|
|
)
|
|
{
|
|
return (PROV_DSS == dwProvType || PROV_DSS_DH == dwProvType);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Error output routines
|
|
//--------------------------------------------------------------------------
|
|
#define PRINT_ERROR(function,label) \
|
|
label##: \
|
|
PrintError( #function "::" #label); \
|
|
goto ErrorReturn;
|
|
|
|
void PrintError(LPCSTR pszMsg)
|
|
{
|
|
printf("failed => %s\n", pszMsg);
|
|
}
|
|
void PrintLastError(LPCSTR pszMsg)
|
|
{
|
|
DWORD dwErr = GetLastError();
|
|
printf("%s failed => 0x%x (%d) \n", pszMsg, dwErr, dwErr);
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Test allocation and free routines
|
|
//--------------------------------------------------------------------------
|
|
void *TestAlloc(
|
|
IN size_t cb
|
|
)
|
|
{
|
|
void *pv;
|
|
// pv = LocalAlloc(LMEM_FIXED, cb);
|
|
pv = malloc(cb);
|
|
if (pv == NULL) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
PrintLastError("TestAlloc");
|
|
}
|
|
return pv;
|
|
}
|
|
|
|
void *TestAllocZero(
|
|
IN size_t cb
|
|
)
|
|
{
|
|
void *pv;
|
|
// pv = LocalAlloc(LMEM_FIXED, cb);
|
|
pv = malloc(cb);
|
|
if (pv == NULL) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
PrintLastError("TestAlloc");
|
|
} else {
|
|
memset( pv, 0, cb);
|
|
}
|
|
return pv;
|
|
}
|
|
|
|
void TestFree(
|
|
IN void *pv
|
|
)
|
|
{
|
|
// LocalFree((HLOCAL) pv);
|
|
if (pv)
|
|
free(pv);
|
|
}
|
|
|
|
|
|
static BOOL AllocAndEncodeObject(
|
|
IN LPCSTR lpszStructType,
|
|
IN const void *pvStructInfo,
|
|
OUT BYTE **ppbEncoded,
|
|
OUT DWORD *pcbEncoded
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbEncoded = NULL;
|
|
DWORD cbEncoded;
|
|
|
|
fResult = CryptEncodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
lpszStructType,
|
|
pvStructInfo,
|
|
NULL, // pbEncoded
|
|
&cbEncoded);
|
|
if (!fResult || cbEncoded == 0) {
|
|
if ((DWORD_PTR) lpszStructType <= 0xFFFF)
|
|
printf("CryptEncodeObject(StructType: %d, cbEncoded == 0)",
|
|
(DWORD)(DWORD_PTR) lpszStructType);
|
|
else
|
|
printf("CryptEncodeObject(StructType: %s, cbEncoded == 0)",
|
|
lpszStructType);
|
|
PrintLastError("");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (NULL == (pbEncoded = (BYTE *) TestAlloc(cbEncoded)))
|
|
goto ErrorReturn;
|
|
if (!CryptEncodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
lpszStructType,
|
|
pvStructInfo,
|
|
pbEncoded,
|
|
&cbEncoded
|
|
)) {
|
|
if ((DWORD_PTR) lpszStructType <= 0xFFFF)
|
|
printf("CryptEncodeObject(StructType: %d)",
|
|
(DWORD)(DWORD_PTR) lpszStructType);
|
|
else
|
|
printf("CryptEncodeObject(StructType: %s)",
|
|
lpszStructType);
|
|
PrintLastError("");
|
|
goto ErrorReturn;
|
|
}
|
|
fResult = TRUE;
|
|
|
|
CommonReturn:
|
|
*ppbEncoded = pbEncoded;
|
|
*pcbEncoded = cbEncoded;
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
if (pbEncoded) {
|
|
TestFree(pbEncoded);
|
|
pbEncoded = NULL;
|
|
}
|
|
cbEncoded = 0;
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
static BOOL AllocAndDecodeObject(
|
|
IN LPCSTR lpszStructType,
|
|
IN const BYTE *pbEncoded,
|
|
IN DWORD cbEncoded,
|
|
OUT void **ppvStructInfo,
|
|
IN OUT DWORD *pcbStructInfo
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
void *pvStructInfo = NULL;
|
|
DWORD cbStructInfo = 0;
|
|
|
|
if (!CryptDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
lpszStructType,
|
|
pbEncoded,
|
|
cbEncoded,
|
|
0, // dwFlags
|
|
NULL,
|
|
&cbStructInfo
|
|
)) {
|
|
if ((DWORD_PTR) lpszStructType <= 0xFFFF)
|
|
printf("CryptDecodeObject(StructType: %d, cbStructInfo == 0)",
|
|
(DWORD)(DWORD_PTR) lpszStructType);
|
|
else
|
|
printf("CryptDecodeObject(StructType: %s, cbStructInfo == 0)",
|
|
lpszStructType);
|
|
PrintLastError("");
|
|
goto ErrorReturn;
|
|
}
|
|
if (NULL == (pvStructInfo = TestAlloc(cbStructInfo)))
|
|
goto ErrorReturn;
|
|
if (!CryptDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
lpszStructType,
|
|
pbEncoded,
|
|
cbEncoded,
|
|
0, // dwFlags
|
|
pvStructInfo,
|
|
&cbStructInfo
|
|
)) {
|
|
if ((DWORD_PTR) lpszStructType <= 0xFFFF)
|
|
printf("CryptDecodeObject(StructType: %d)",
|
|
(DWORD)(DWORD_PTR) lpszStructType);
|
|
else
|
|
printf("CryptDecodeObject(StructType: %s)",
|
|
lpszStructType);
|
|
PrintLastError("");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fResult = TRUE;
|
|
|
|
CommonReturn:
|
|
*ppvStructInfo = pvStructInfo;
|
|
*pcbStructInfo = cbStructInfo;
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
TestFree(pvStructInfo);
|
|
pvStructInfo = NULL;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Stream support
|
|
//--------------------------------------------------------------------------
|
|
typedef struct _TEST_STREAM_DATA {
|
|
DWORD dwEncodingType;
|
|
DWORD dwEncodeFlags;
|
|
DWORD dwDecodeFlags;
|
|
DWORD dwMsgTypeEncoding;
|
|
DWORD dwMsgTypeDecoding;
|
|
PVOID pvMsgEncodeInfo;
|
|
LPSTR pszInnerContentType;
|
|
PCMSG_STREAM_INFO pStreamInfo;
|
|
HCRYPTMSG hMsg;
|
|
BOOL fEncoding;
|
|
BOOL fReady;
|
|
#ifdef CMS_PKCS7
|
|
DWORD rgcbComputedHash[2];
|
|
BYTE rgbComputedHash[2][MAX_HASH_LEN];
|
|
#endif // CMS_PKCS7
|
|
} TEST_STREAM_DATA, *PTEST_STREAM_DATA;
|
|
|
|
DEFINE_LIST_AND_NODE_CLASS( CStreamList, CStreamNode, TEST_STREAM_DATA);
|
|
CStreamNode::~CStreamNode()
|
|
{
|
|
TestFree( m_data.pStreamInfo);
|
|
};
|
|
|
|
CStreamList *plistStream = NULL;
|
|
|
|
|
|
DEFINE_LIST_AND_NODE_CLASS( CBlobList, CBlobNode, CRYPT_DATA_BLOB);
|
|
CBlobNode::~CBlobNode()
|
|
{
|
|
TestFree( m_data.pbData);
|
|
};
|
|
|
|
|
|
LPSTR pszStreamMsgTypes = "S";
|
|
#define pszStreamFileName "stream.msg"
|
|
#define pszFilenameDecode "decode.dat"
|
|
HANDLE hFileStream = INVALID_HANDLE_VALUE;
|
|
HANDLE hFileStreamDecode = INVALID_HANDLE_VALUE;
|
|
DWORD cbFileDecode;
|
|
#if DBG
|
|
#define cbStreamDataDeltaEncode 17
|
|
#else
|
|
#define cbStreamDataDeltaEncode 1024
|
|
#endif
|
|
BYTE abStreamDataDeltaEncode[cbStreamDataDeltaEncode];
|
|
#if DBG
|
|
DWORD cbStreamDataDeltaDecode = 1;
|
|
//DWORD cbStreamDataDeltaDecode = 19;
|
|
#else
|
|
DWORD cbStreamDataDeltaDecode = 1024;
|
|
#endif
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Check that a CryptMsgGetParam to a buffer fails with the right error
|
|
// because the buffer is too small.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
TCM_CheckGetParam(
|
|
IN HCRYPTMSG hCryptMsg,
|
|
IN DWORD dwParamType,
|
|
IN DWORD dwIndex,
|
|
IN PVOID pv,
|
|
IN DWORD cbData)
|
|
{
|
|
BOOL fRet;
|
|
DWORD cbSmall;
|
|
|
|
if (cbData < 1)
|
|
goto SuccessReturn;
|
|
|
|
cbSmall = cbData - 1;
|
|
if (CryptMsgGetParam(
|
|
hCryptMsg,
|
|
dwParamType,
|
|
dwIndex,
|
|
pv,
|
|
&cbSmall))
|
|
goto GetSmallBufferRetError;
|
|
|
|
if (ERROR_MORE_DATA != GetLastError())
|
|
goto GetSmallBufferLastErrorError;
|
|
|
|
SuccessReturn:
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(TCM_CheckGetParam,GetSmallBufferRetError)
|
|
PRINT_ERROR(TCM_CheckGetParam,GetSmallBufferLastErrorError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Do a CryptMsgGetParam to a buffer alloc'd by TestAlloc
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
TCM_AllocGetParam(
|
|
IN HCRYPTMSG hCryptMsg,
|
|
IN DWORD dwParamType,
|
|
IN DWORD dwIndex,
|
|
OUT PBYTE *ppbData,
|
|
OUT DWORD *pcbData)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
BOOL fRet;
|
|
DWORD cb;
|
|
PBYTE pb = NULL;
|
|
|
|
cb = 0;
|
|
CryptMsgGetParam(
|
|
hCryptMsg,
|
|
dwParamType,
|
|
dwIndex,
|
|
NULL,
|
|
&cb);
|
|
if (cb == 0)
|
|
goto GetEncodedSizeError;
|
|
if (NULL == (pb = (PBYTE)TestAlloc(cb)))
|
|
goto AllocEncodedError;
|
|
if (!TCM_CheckGetParam(
|
|
hCryptMsg,
|
|
dwParamType,
|
|
dwIndex,
|
|
pb,
|
|
cb))
|
|
goto CheckGetEncodedError;
|
|
if (!CryptMsgGetParam(
|
|
hCryptMsg,
|
|
dwParamType,
|
|
dwIndex,
|
|
pb,
|
|
&cb))
|
|
goto GetEncodedError;
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
*ppbData = pb;
|
|
*pcbData = cb;
|
|
if (dwError != ERROR_SUCCESS)
|
|
SetLastError(dwError);
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
dwError = GetLastError();
|
|
TestFree(pb);
|
|
pb = NULL;
|
|
cb = 0;
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(TCM_AllocGetParam,GetEncodedSizeError)
|
|
PRINT_ERROR(TCM_AllocGetParam,AllocEncodedError)
|
|
PRINT_ERROR(TCM_AllocGetParam,CheckGetEncodedError)
|
|
PRINT_ERROR(TCM_AllocGetParam,GetEncodedError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Compare 2 CRYPT_ALGORITHM_IDENTIFIER structs.
|
|
//
|
|
// Returns: FALSE iff differ
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
EqualAlgorithm(
|
|
IN PCRYPT_ALGORITHM_IDENTIFIER pai1,
|
|
IN PCRYPT_ALGORITHM_IDENTIFIER pai2)
|
|
{
|
|
BOOL fRet;
|
|
|
|
fRet = (0 == strcmp( pai1->pszObjId, pai2->pszObjId));
|
|
fRet &= (pai1->Parameters.cbData == pai2->Parameters.cbData);
|
|
if (fRet) {
|
|
fRet &= (0 == memcmp( pai1->Parameters.pbData,
|
|
pai2->Parameters.pbData,
|
|
pai1->Parameters.cbData));
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Compare 2 CRYPT_ATTRIBUTE structs.
|
|
//
|
|
// Returns: FALSE iff differ
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
EqualAttribute(
|
|
IN PCRYPT_ATTRIBUTE patr1,
|
|
IN PCRYPT_ATTRIBUTE patr2)
|
|
{
|
|
BOOL fRet;
|
|
DWORD i;
|
|
PCRYPT_ATTR_BLOB pabl1;
|
|
PCRYPT_ATTR_BLOB pabl2;
|
|
|
|
fRet = (0 == strcmp( patr1->pszObjId, patr2->pszObjId));
|
|
fRet &= (patr1->cValue == patr2->cValue);
|
|
if (fRet) {
|
|
for (i=patr1->cValue, pabl1=patr1->rgValue, pabl2=patr2->rgValue;
|
|
i>0;
|
|
i--, pabl1++, pabl2++) {
|
|
fRet &= (pabl1->cbData == pabl2->cbData);
|
|
if (fRet) {
|
|
fRet &= (0 == memcmp( pabl1->pbData,
|
|
pabl2->pbData,
|
|
pabl1->cbData));
|
|
}
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
void XORAttributeBytes()
|
|
{
|
|
DWORD cb;
|
|
BYTE *pb;
|
|
|
|
cb = sizeof(attr1) / sizeof(attr1[0]);
|
|
pb = attr1;
|
|
while(cb--)
|
|
*pb++ ^= 0xFF;
|
|
|
|
cb = sizeof(attr2) / sizeof(attr2[0]);
|
|
pb = attr2;
|
|
while(cb--)
|
|
*pb++ ^= 0xFF;
|
|
|
|
cb = sizeof(attr3) / sizeof(attr3[0]);
|
|
pb = attr3;
|
|
while(cb--)
|
|
*pb++ ^= 0xFF;
|
|
|
|
cb = sizeof(unattr1) / sizeof(unattr1[0]);
|
|
pb = unattr1;
|
|
while(cb--)
|
|
*pb++ ^= 0xFF;
|
|
}
|
|
|
|
void XORBlob(
|
|
IN PCRYPT_DATA_BLOB pBlob
|
|
)
|
|
{
|
|
DWORD cb;
|
|
BYTE *pb;
|
|
|
|
cb = pBlob->cbData;
|
|
pb = pBlob->pbData;
|
|
while(cb--)
|
|
*pb++ ^= 0xFF;
|
|
}
|
|
|
|
void XORBitBlob(
|
|
IN PCRYPT_BIT_BLOB pBlob
|
|
)
|
|
{
|
|
CRYPT_DATA_BLOB Blob;
|
|
Blob.pbData = pBlob->pbData;
|
|
Blob.cbData = pBlob->cbData;
|
|
|
|
XORBlob(&Blob);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Read an encoded DER blob from a file
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
GetDERFromFile(
|
|
LPCSTR pszFileName,
|
|
PBYTE *ppbDER,
|
|
PDWORD pcbDER
|
|
)
|
|
{
|
|
BOOL fRet;
|
|
HANDLE hFile;
|
|
PBYTE pbDER;
|
|
DWORD cbDER;
|
|
DWORD cbRead;
|
|
|
|
if( INVALID_HANDLE_VALUE == (hFile = CreateFile( pszFileName, GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING, 0, NULL))) {
|
|
printf( "can't open %s\n", pszFileName);
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
cbDER = GetFileSize( hFile, NULL);
|
|
if (NULL == (pbDER = (PBYTE)TestAlloc( cbDER))) {
|
|
printf( "can't alloc %d bytes\n", cbDER);
|
|
goto ErrorReturn;
|
|
}
|
|
if (!ReadFile( hFile, pbDER, cbDER, &cbRead, NULL) ||
|
|
(cbRead != cbDER)) {
|
|
printf( "can't read %s\n", pszFileName);
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
CloseHandle( hFile);
|
|
*ppbDER = pbDER;
|
|
*pcbDER = cbDER;
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
return fRet;
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Write a buffer to a file
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
TCM_WriteBufToFile(
|
|
LPCSTR pszFile,
|
|
PBYTE pbData,
|
|
DWORD cbData)
|
|
{
|
|
BOOL fRet;
|
|
HANDLE hFile;
|
|
DWORD cbWritten;
|
|
|
|
if( INVALID_HANDLE_VALUE == (hFile = CreateFile( pszFile, 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;
|
|
PRINT_ERROR(TCM_WriteBufToFile,CreateFileError)
|
|
PRINT_ERROR(TCM_WriteBufToFile,WriteFileError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get the number of contents octets in a DER encoding.
|
|
//
|
|
// Parameters:
|
|
// pcbContent - receives the number of contents octets
|
|
// pbLength - points to the first length octet
|
|
// cbDER - number of bytes remaining in the DER encoding
|
|
//
|
|
// Returns:
|
|
// success - the number of bytes in the length field, >=0
|
|
// failure - <0
|
|
//--------------------------------------------------------------------------
|
|
LONG
|
|
WINAPI
|
|
TCM_DecodeLength(
|
|
OUT DWORD *pcbContent,
|
|
IN PBYTE pbLength,
|
|
IN DWORD cbDER)
|
|
{
|
|
long i;
|
|
BYTE cbLength;
|
|
PBYTE pb;
|
|
|
|
if (cbDER < 1)
|
|
goto EncodeOverflowError;
|
|
|
|
if (0x80 == *pbLength)
|
|
goto IsBERError;
|
|
|
|
// determine the number of length octets and contents octets
|
|
if ((cbLength = *pbLength) & 0x80) {
|
|
cbLength &= ~0x80; // low 7 bits have number of bytes
|
|
if (cbLength > 4)
|
|
goto LengthTooLargeError;
|
|
if (cbLength >= cbDER)
|
|
goto EncodeOverflowError2;
|
|
*pcbContent = 0;
|
|
for (i=cbLength, pb=pbLength+1; i>0; i--, pb++)
|
|
*pcbContent = (*pcbContent << 8) + (DWORD)*pb;
|
|
i = cbLength + 1;
|
|
} else {
|
|
*pcbContent = (DWORD)cbLength;
|
|
i = 1;
|
|
}
|
|
|
|
CommonReturn:
|
|
return i; // how many bytes there were in the length field
|
|
|
|
EncodeOverflowError:
|
|
IsBERError:
|
|
LengthTooLargeError:
|
|
EncodeOverflowError2:
|
|
i = -1;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Point to the content octets in a DER-encoded blob.
|
|
//
|
|
// Returns:
|
|
// success - the number of bytes skipped, >=0
|
|
// failure - <0
|
|
//
|
|
// Assume pbData points to a definite-length BER-encoded blob.
|
|
//--------------------------------------------------------------------------
|
|
LONG
|
|
WINAPI
|
|
TCM_ExtractContent(
|
|
IN PBYTE pbDER,
|
|
IN DWORD cbDER,
|
|
OUT DWORD *pcbContent,
|
|
OUT OPTIONAL PBYTE *ppbContent)
|
|
{
|
|
#define TAG_MASK 0x1f
|
|
DWORD cbIdentifier;
|
|
DWORD cbContent;
|
|
LONG cbLength;
|
|
PBYTE pb = pbDER;
|
|
|
|
// Skip over the identifier octet(s)
|
|
if (TAG_MASK == (*pb++ & TAG_MASK)) {
|
|
// high-tag-number form
|
|
for (cbIdentifier=2; *pb++ & 0x80; cbIdentifier++)
|
|
;
|
|
} else {
|
|
// low-tag-number form
|
|
cbIdentifier = 1;
|
|
}
|
|
|
|
if (0 > (cbLength = TCM_DecodeLength( &cbContent, pb, cbDER-cbIdentifier)))
|
|
goto DecodeLengthError;
|
|
|
|
pb += cbLength;
|
|
|
|
*pcbContent = cbContent;
|
|
if (ppbContent)
|
|
*ppbContent = pb;
|
|
|
|
return cbLength + cbIdentifier;
|
|
|
|
DecodeLengthError:
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Functions for initializing message encode information
|
|
//--------------------------------------------------------------------------
|
|
void InitSignedMsgEncodeInfo(
|
|
OUT PCMSG_SIGNED_ENCODE_INFO pSignedMsgEncodeInfo
|
|
);
|
|
void InitEnvelopedMsgEncodeInfo(
|
|
OUT PCMSG_ENVELOPED_ENCODE_INFO pEnvelopedMsgEncodeInfo
|
|
);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Functions for cleaning up message encode information
|
|
//--------------------------------------------------------------------------
|
|
void CleanupSignedMsgEncodeInfo(
|
|
OUT PCMSG_SIGNED_ENCODE_INFO pSignedMsgEncodeInfo
|
|
);
|
|
void CleanupEnvelopedMsgEncodeInfo(
|
|
OUT PCMSG_ENVELOPED_ENCODE_INFO pEnvelopedMsgEncodeInfo
|
|
);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Message encode and decode routines
|
|
//--------------------------------------------------------------------------
|
|
BOOL EncodeAndDecodeMsg(
|
|
IN DWORD dwMsgType,
|
|
IN void *pvMsgEncodeInfo
|
|
);
|
|
BOOL EncodeMsg(
|
|
IN DWORD dwMsgType,
|
|
IN void *pvMsgEncodeInfo,
|
|
OUT BYTE **ppbEncodedBlob,
|
|
OUT DWORD *pcbEncodedBlob
|
|
);
|
|
BOOL DecodeMsg(
|
|
IN DWORD dwExpectedMsgType,
|
|
IN const BYTE *pbEncodedBlob,
|
|
IN DWORD cbEncodedBlob
|
|
);
|
|
BOOL StreamEncodeAndDecodeMsg();
|
|
BOOL StreamEncodeMsg();
|
|
BOOL StreamDecodeMsg();
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get signer info and verify the signed message
|
|
//--------------------------------------------------------------------------
|
|
BOOL GetSignerInfoAndVerify(IN HCRYPTMSG hMsg, IN BOOL fInnerNonData);
|
|
|
|
BOOL GetSignerInfoAndVerify(
|
|
IN HCRYPTMSG hMsg,
|
|
IN BOOL fInnerNonData,
|
|
IN DWORD dwSignerIndex,
|
|
OUT DWORD *pdwSrcIndex
|
|
);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get recipient info and decrypt the message.
|
|
//--------------------------------------------------------------------------
|
|
BOOL GetRecipientInfoAndDecrypt(IN HCRYPTMSG hMsg);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Allocate and get the CMSG_SIGNER_CERT_INFO_PARAM or CMSG_RECIPIENT_INFO_PARAM
|
|
// from the message
|
|
//--------------------------------------------------------------------------
|
|
PCERT_INFO GetCertIdFromMsg(
|
|
IN HCRYPTMSG hMsg,
|
|
IN DWORD dwParamType,
|
|
IN DWORD dwIndex
|
|
);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Allocate and get the CMSG_SIGNER_INFO_PARAM from the message
|
|
//--------------------------------------------------------------------------
|
|
PCMSG_SIGNER_INFO GetSignerInfoFromMsg(
|
|
IN HCRYPTMSG hMsg,
|
|
IN DWORD dwIndex
|
|
);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get computed digest and digest data from a decoded CMSG_HASHED
|
|
//--------------------------------------------------------------------------
|
|
BOOL Undigest(IN HCRYPTMSG hMsg);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Countersign test functions
|
|
//--------------------------------------------------------------------------
|
|
BOOL CountersignAndVerify(IN HCRYPTMSG hCryptMsg);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Add signer test functions
|
|
//--------------------------------------------------------------------------
|
|
BOOL AddSignerAndVerify(IN HCRYPTMSG hCryptMsg);
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Top Level Test Functions
|
|
//--------------------------------------------------------------------------
|
|
BOOL TestSign()
|
|
{
|
|
BOOL fRet;
|
|
|
|
InitSignedMsgEncodeInfo(&SignedMsgEncodeInfo);
|
|
fRet = EncodeAndDecodeMsg(CMSG_SIGNED, &SignedMsgEncodeInfo);
|
|
CleanupSignedMsgEncodeInfo(&SignedMsgEncodeInfo);
|
|
return fRet;
|
|
}
|
|
|
|
BOOL TestEnvelope()
|
|
{
|
|
BOOL fRet;
|
|
|
|
InitEnvelopedMsgEncodeInfo(&EnvelopedMsgEncodeInfo);
|
|
fRet = EncodeAndDecodeMsg(CMSG_ENVELOPED, &EnvelopedMsgEncodeInfo);
|
|
CleanupEnvelopedMsgEncodeInfo(&EnvelopedMsgEncodeInfo);
|
|
return fRet;
|
|
}
|
|
|
|
BOOL TestSignAndEnvelope()
|
|
{
|
|
BOOL fRet;
|
|
|
|
return FALSE;
|
|
SignedAndEnvelopedMsgEncodeInfo.cbSize =
|
|
sizeof(CMSG_SIGNED_AND_ENVELOPED_ENCODE_INFO);
|
|
InitSignedMsgEncodeInfo(&SignedAndEnvelopedMsgEncodeInfo.SignedInfo);
|
|
InitEnvelopedMsgEncodeInfo(&SignedAndEnvelopedMsgEncodeInfo.EnvelopedInfo);
|
|
fRet = EncodeAndDecodeMsg(CMSG_SIGNED_AND_ENVELOPED,
|
|
&SignedAndEnvelopedMsgEncodeInfo);
|
|
CleanupSignedMsgEncodeInfo(&SignedAndEnvelopedMsgEncodeInfo.SignedInfo);
|
|
CleanupEnvelopedMsgEncodeInfo(&SignedAndEnvelopedMsgEncodeInfo.EnvelopedInfo);
|
|
return fRet;
|
|
}
|
|
|
|
BOOL TestDigest()
|
|
{
|
|
HashedMsgEncodeInfo.cbSize = sizeof(CMSG_HASHED_ENCODE_INFO);
|
|
HashedMsgEncodeInfo.hCryptProv = hDefaultVerifyProv;
|
|
HashedMsgEncodeInfo.HashAlgorithm =
|
|
DigestAlgorithms[ fMD5 ? DIGEST_ALG_MD5 : DIGEST_ALG_SHA];
|
|
HashedMsgEncodeInfo.pvHashAuxInfo = NULL;
|
|
|
|
return EncodeAndDecodeMsg(CMSG_HASHED, &HashedMsgEncodeInfo);
|
|
}
|
|
|
|
BOOL TestCountersign()
|
|
{
|
|
BOOL fRet;
|
|
|
|
fCountersign = TRUE;
|
|
InitSignedMsgEncodeInfo(&SignedMsgEncodeInfo);
|
|
fRet = EncodeAndDecodeMsg(CMSG_SIGNED, &SignedMsgEncodeInfo);
|
|
CleanupSignedMsgEncodeInfo(&SignedMsgEncodeInfo);
|
|
return fRet;
|
|
}
|
|
|
|
BOOL TestStream()
|
|
{
|
|
BOOL fRet;
|
|
|
|
if (NULL == (plistStream = new CStreamList))
|
|
return FALSE;
|
|
fStream = TRUE;
|
|
|
|
InitSignedMsgEncodeInfo(&SignedMsgEncodeInfo);
|
|
InitEnvelopedMsgEncodeInfo(&EnvelopedMsgEncodeInfo);
|
|
fRet = StreamEncodeAndDecodeMsg();
|
|
CleanupEnvelopedMsgEncodeInfo(&EnvelopedMsgEncodeInfo);
|
|
CleanupSignedMsgEncodeInfo(&SignedMsgEncodeInfo);
|
|
|
|
delete plistStream;
|
|
plistStream = NULL;
|
|
return fRet;
|
|
}
|
|
|
|
|
|
typedef BOOL (*PFN_TEST)(void);
|
|
struct
|
|
{
|
|
LPCSTR pszName;
|
|
PFN_TEST pfn;
|
|
} Tests[] = {
|
|
"Sign", TestSign,
|
|
"Envelope", TestEnvelope,
|
|
"SignAndEnvelope", TestSignAndEnvelope,
|
|
"Digest", TestDigest,
|
|
"Countersign", TestCountersign,
|
|
"Stream", TestStream
|
|
};
|
|
#define NTESTS (sizeof(Tests)/sizeof(Tests[0]))
|
|
|
|
void Usage(void)
|
|
{
|
|
int i;
|
|
|
|
printf("Usage: tcrmsg [options] [<TestName>] [<StoreFilename>][<CertNameString>]\n");
|
|
printf("Options are:\n");
|
|
#ifdef CMS_PKCS7
|
|
printf(" -AttrCert - Add CMS attribute certificates\n");
|
|
printf(" -Crl - Add CRLs\n");
|
|
printf(" -EncapsulatedContent - CMS encapsulated content\n");
|
|
printf(" -OriginatorInfo - CMS EnvelopedData OriginatorInfo\n");
|
|
printf(" -KeyTrans - CMS KeyTrans recipients\n");
|
|
printf(" -KeyAgree - CMS KeyAgree recipients\n");
|
|
printf(" -MailList - CMS MailList recipients\n");
|
|
printf(" -RecipientKeyId - Use KeyId for recipients\n");
|
|
printf(" -CertInfoKeyId - Use KeyId for encode CertInfo\n");
|
|
printf(" -SignerId - Use SignerId instead of CertInfo\n");
|
|
printf(" -HashEncryptionAlgorithm - Use for first signer info\n");
|
|
printf(" -NoSignature - Use NO_SIGNATURE OID \n");
|
|
printf(" -NoRecipients - No Envelope Recipients\n");
|
|
printf(" -AlgorithmParameters - Algorithms have dummy parameters\n");
|
|
printf(" -NoSalt - NoSalt for RC4\n");
|
|
#endif // CMS_PKCS7
|
|
printf(" -h - This message\n");
|
|
printf(" -A - Authenticated Attributes\n");
|
|
printf(" -B - Bare content (no outer ContentInfo)\n");
|
|
printf(" -c - no Certs\n");
|
|
printf(" -C - non-data inner Content\n");
|
|
printf(" -D - Detached Signature/Digest\n");
|
|
printf(" -i - indefinite-length encoding\n");
|
|
printf(" -l - print command Line\n");
|
|
printf(" -M - MD5 hash algorithm\n");
|
|
printf(" -n<size> - Number of bytes in content\n");
|
|
printf(" -N - No signers\n");
|
|
#ifdef CMS_PKCS7
|
|
printf(" -NMultiple - Multiple signers\n");
|
|
#endif // CMS_PKCS7
|
|
printf(" -p<provider#> - Crypto Provider\n");
|
|
printf(" -PEnhanced - Use enhanced crypto provider\n");
|
|
printf(" -PDefault - Use default crypto provider\n");
|
|
#ifdef CMS_PKCS7
|
|
printf(" -PRecipient - Each recipient has a crypto provider\n");
|
|
printf(" -PDSS - Use DSS provider for second signer\n");
|
|
printf(" -PDSS_DH - Use DSS_DH provider for second signer\n");
|
|
#endif // CMS_PKCS7
|
|
printf(" -P<ProviderName> - Crypto provider Name\n");
|
|
printf(" -K<ContainerName> - Provider key container Name\n");
|
|
printf(" -E<name> - Encrypt algorithm, default of \"rc2\"\n");
|
|
printf(" -e<EncryptBitLen> - Encrypt key bit length\n");
|
|
printf(" -I - Include IV in encrypt parameters\n");
|
|
printf(" -s[ES]+ - list of stream message types\n");
|
|
printf(" -S - add signer\n");
|
|
printf(" -t - tiny streaming decode buffer\n");
|
|
printf(" -v - verbose\n");
|
|
printf(" -f<filename> - Write encoded message to file\n");
|
|
printf("\n");
|
|
printf("Tests are (case insensitive name):\n");
|
|
for (i = 0; i < NTESTS; i++)
|
|
printf(" %s\n", Tests[i].pszName);
|
|
printf("\n");
|
|
printf("Default: ALL Tests\n");
|
|
}
|
|
|
|
HCRYPTPROV GetCryptProv(
|
|
DWORD dwMyProvType = dwProvType,
|
|
LPCSTR pszMyProvider = pszProvider
|
|
)
|
|
{
|
|
HCRYPTPROV hProv = 0;
|
|
BOOL fResult;
|
|
|
|
if (NULL == pszMyProvider) {
|
|
if (fEnhanced) {
|
|
if (PROV_RSA_FULL == dwMyProvType)
|
|
pszMyProvider = MS_ENHANCED_PROV_A;
|
|
}
|
|
}
|
|
|
|
fResult = CryptAcquireContextA(
|
|
&hProv,
|
|
pszContainer,
|
|
pszMyProvider,
|
|
dwMyProvType,
|
|
fNoSignature ? CRYPT_VERIFYCONTEXT : 0 // dwFlags
|
|
);
|
|
if (fResult) {
|
|
printf("Using default sign and xchg keys for provider type: %d",
|
|
dwMyProvType);
|
|
if (pszMyProvider && *pszMyProvider)
|
|
printf(" provider: %s", pszMyProvider);
|
|
if (pszContainer && *pszContainer)
|
|
printf(" container: %s", pszContainer);
|
|
printf("\n");
|
|
} else {
|
|
DWORD dwErr = GetLastError();
|
|
if (dwErr == NTE_BAD_KEYSET) {
|
|
|
|
// Need to create the keys
|
|
printf("Generating SIGNATURE and EXCHANGE private keys\n");
|
|
|
|
hProv = 0;
|
|
fResult = CryptAcquireContextA(
|
|
&hProv,
|
|
pszContainer,
|
|
pszMyProvider,
|
|
dwMyProvType,
|
|
CRYPT_NEWKEYSET
|
|
);
|
|
if (!fResult || hProv == 0) {
|
|
PrintLastError("CryptAcquireContext");
|
|
return 0;
|
|
}
|
|
|
|
HCRYPTKEY hKey = 0;
|
|
fResult = CryptGenKey(
|
|
hProv,
|
|
AT_SIGNATURE,
|
|
CRYPT_EXPORTABLE,
|
|
&hKey
|
|
);
|
|
if (!fResult || hKey == 0)
|
|
PrintLastError("CryptGenKey(AT_SIGNATURE)");
|
|
else
|
|
CryptDestroyKey(hKey);
|
|
|
|
hKey = 0;
|
|
fResult = CryptGenKey(
|
|
hProv,
|
|
AT_KEYEXCHANGE,
|
|
CRYPT_EXPORTABLE,
|
|
&hKey
|
|
);
|
|
if (!fResult || hKey == 0)
|
|
PrintLastError("CryptGenKey(AT_KEYEXCHANGE)");
|
|
else
|
|
CryptDestroyKey(hKey);
|
|
|
|
} else {
|
|
PrintLastError("CryptAcquireContext");
|
|
return 0;
|
|
}
|
|
}
|
|
return hProv;
|
|
}
|
|
|
|
|
|
BOOL
|
|
GetNonStreamedMsgContent(
|
|
IN DWORD cbContent,
|
|
OUT PBYTE *ppbContent,
|
|
OUT DWORD *pcbContent)
|
|
{
|
|
BOOL fRet;
|
|
PBYTE pbContent;
|
|
PBYTE pb;
|
|
DWORD cb;
|
|
|
|
if (fInnerContent) {
|
|
if (!GetDERFromFile(
|
|
pszInnerContentFileName,
|
|
ppbContent,
|
|
pcbContent))
|
|
goto GetDERFromFileError;
|
|
} else {
|
|
if (NULL == (pbContent = (PBYTE)TestAlloc( cbContent)))
|
|
goto AllocContentError;
|
|
|
|
for (pb=pbContent, cb=0; cb < cbContent; pb++, cb++)
|
|
*pb = rgbMsgContentFill[ cb%cbMsgContentFill];
|
|
*ppbContent = pbContent;
|
|
*pcbContent = cbContent;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
*ppbContent = NULL;
|
|
*pcbContent = 0;
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(GetNonStreamedMsgContent,GetDERFromFileError)
|
|
PRINT_ERROR(GetNonStreamedMsgContent,AllocContentError)
|
|
}
|
|
|
|
PCCRYPT_OID_INFO GetOIDInfo(LPCSTR pszName, DWORD dwGroupId = 0)
|
|
{
|
|
WCHAR wszName[256];
|
|
PCCRYPT_OID_INFO pInfo;
|
|
|
|
MultiByteToWideChar(
|
|
CP_ACP,
|
|
0, // dwFlags
|
|
pszName,
|
|
-1, // null terminated
|
|
wszName,
|
|
sizeof(wszName) / sizeof(wszName[0]));
|
|
|
|
return CryptFindOIDInfo(
|
|
CRYPT_OID_INFO_NAME_KEY,
|
|
(void *) wszName,
|
|
dwGroupId
|
|
);
|
|
}
|
|
|
|
LPCSTR GetOID(LPCSTR pszName, DWORD dwGroupId = 0)
|
|
{
|
|
PCCRYPT_OID_INFO pInfo;
|
|
|
|
if (pInfo = GetOIDInfo(pszName, dwGroupId))
|
|
return pInfo->pszOID;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
ALG_ID GetAlgid(LPCSTR pszName, DWORD dwGroupId = 0)
|
|
{
|
|
PCCRYPT_OID_INFO pInfo;
|
|
|
|
if (pInfo = GetOIDInfo(pszName, dwGroupId))
|
|
return pInfo->Algid;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static HCERTSTORE OpenStore(LPCSTR pszStoreFilename)
|
|
{
|
|
HCERTSTORE hStore;
|
|
HANDLE hFile = 0;
|
|
|
|
if( INVALID_HANDLE_VALUE == (hFile = CreateFile(pszStoreFilename,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING, 0, NULL))) {
|
|
printf( "can't open %s\n", pszStoreFilename);
|
|
|
|
hStore = NULL;
|
|
} else {
|
|
hStore = CertOpenStore(
|
|
CERT_STORE_PROV_FILE,
|
|
dwCertEncodingType,
|
|
0, // hProv
|
|
0, // dwFlags
|
|
hFile
|
|
);
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
if (hStore == NULL)
|
|
PrintLastError("CertOpenStore");
|
|
return hStore;
|
|
}
|
|
|
|
int _cdecl main(int argc, char * argv[])
|
|
{
|
|
BOOL fResult;
|
|
LPSTR pszTestName = NULL;
|
|
int TestIdx = 0;
|
|
LPSTR pszStoreFilename = NULL;
|
|
|
|
while (--argc>0)
|
|
{
|
|
if (**++argv == '-')
|
|
{
|
|
#ifdef CMS_PKCS7
|
|
if (0 == _stricmp(argv[0]+1, "AttrCert")) {
|
|
cAttrCert = ATTR_CERT_COUNT;
|
|
} else if (0 == _stricmp(argv[0]+1, "Crl")) {
|
|
cSignedCrl = SIGNED_CRL_COUNT;
|
|
} else if (0 == _stricmp(argv[0]+1, "EncapsulatedContent")) {
|
|
fEncapsulatedContent = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "OriginatorInfo")) {
|
|
fOriginatorInfo = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "KeyTrans")) {
|
|
fKeyTrans = TRUE;
|
|
fCmsRecipient = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "KeyAgree")) {
|
|
fKeyAgree = TRUE;
|
|
fCmsRecipient = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "MailList")) {
|
|
fMailList = TRUE;
|
|
fCmsRecipient = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "RecipientKeyId")) {
|
|
fRecipientKeyId = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "CertInfoKeyId")) {
|
|
fCertInfoKeyId = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "SignerId")) {
|
|
fSignerId = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "HashEncryptionAlgorithm")) {
|
|
fHashEncryptionAlgorithm = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "NoSignature")) {
|
|
fNoSignature = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "NoRecipients")) {
|
|
fNoRecipients = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "AlgorithmParameters")) {
|
|
fAlgorithmParameters = TRUE;
|
|
} else if (0 == _stricmp(argv[0]+1, "NoSalt")) {
|
|
fNoSalt = TRUE;
|
|
} else {
|
|
#endif // CMS_PKCS7
|
|
switch(argv[0][1])
|
|
{
|
|
case 'A':
|
|
fAuthAttr = TRUE;
|
|
break;
|
|
case 'B':
|
|
fBare = TRUE;
|
|
break;
|
|
case 'c':
|
|
cSignedCert = 0;
|
|
break;
|
|
case 'C':
|
|
fInnerContent = TRUE;
|
|
break;
|
|
case 'D':
|
|
fDetached = TRUE;
|
|
break;
|
|
case 'i':
|
|
fIndefinite = TRUE;
|
|
break;
|
|
case 'l':
|
|
printf("command line: %s\n", GetCommandLine());
|
|
break;
|
|
case 'M':
|
|
fMD5 = TRUE;
|
|
break;
|
|
case 'n':
|
|
cbMsgContent = strtoul( argv[0]+2, NULL, 0);
|
|
break;
|
|
case 'N':
|
|
#ifdef CMS_PKCS7
|
|
if (0 == _stricmp(argv[0]+2, "Multiple"))
|
|
fMultiSigner = TRUE;
|
|
else
|
|
#endif // CMS_PKCS7
|
|
fNoSigners = TRUE;
|
|
break;
|
|
case 'p':
|
|
dwProvType = strtoul( argv[0]+2, NULL, 0);
|
|
break;
|
|
case 'P':
|
|
if (0 == _stricmp(argv[0]+2, "Enhanced"))
|
|
fEnhanced = TRUE;
|
|
else if (0 == _stricmp(argv[0]+2, "Default"))
|
|
fDefaultVerifyProv = TRUE;
|
|
#ifdef CMS_PKCS7
|
|
else if (0 == _stricmp(argv[0]+2, "Recipient"))
|
|
fRecipientProv = TRUE;
|
|
else if (0 == _stricmp(argv[0]+2, "DSS"))
|
|
dwMultiSignerProvType = PROV_DSS;
|
|
else if (0 == _stricmp(argv[0]+2, "DSS_DH"))
|
|
dwMultiSignerProvType = PROV_DSS_DH;
|
|
#endif // CMS_PKCS7
|
|
else
|
|
pszProvider = argv[0]+2;
|
|
break;
|
|
case 'K':
|
|
pszContainer = argv[0]+2;
|
|
break;
|
|
case 'E':
|
|
pszEncryptName = argv[0]+2;
|
|
break;
|
|
case 'e':
|
|
dwEncryptBitLen = strtoul( argv[0]+2, NULL, 0);
|
|
break;
|
|
case 'I':
|
|
fEncryptIV = TRUE;
|
|
break;
|
|
case 'R':
|
|
pszEncryptName = "rc4";
|
|
break;
|
|
case 's':
|
|
pszStreamMsgTypes = argv[0]+2;
|
|
break;
|
|
case 'S':
|
|
fAddSigner = TRUE;
|
|
break;
|
|
case 't':
|
|
cbStreamDataDeltaDecode = 1;
|
|
break;
|
|
case 'v':
|
|
fVerbose = TRUE;
|
|
break;
|
|
case 'f':
|
|
pszFilename = argv[0]+2;
|
|
if (*pszFilename == '\0') {
|
|
printf("Need to specify filename\n");
|
|
Usage();
|
|
return -1;
|
|
}
|
|
break;
|
|
case 'h':
|
|
default:
|
|
Usage();
|
|
return -1;
|
|
}
|
|
#ifdef CMS_PKCS7
|
|
}
|
|
#endif // CMS_PKCS7
|
|
} else {
|
|
if(pszTestName == NULL)
|
|
pszTestName = argv[0];
|
|
else if (pszStoreFilename == NULL)
|
|
pszStoreFilename = argv[0];
|
|
else if (pszCertNameFindStr == NULL)
|
|
pszCertNameFindStr = argv[0];
|
|
else {
|
|
printf("Too many arguments\n");
|
|
Usage();
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fInnerContent && (cbMsgContent != DEFAULT_MSG_CONTENT_SIZE)) {
|
|
printf( "-n and -C not compatible\n");
|
|
return -1;
|
|
}
|
|
|
|
if (pszTestName) {
|
|
for (TestIdx = 0; TestIdx < NTESTS; TestIdx++) {
|
|
if (_stricmp(pszTestName, Tests[TestIdx].pszName) == 0)
|
|
break;
|
|
}
|
|
if (TestIdx >= NTESTS) {
|
|
printf("Bad TestName: %s\n", pszTestName);
|
|
Usage();
|
|
return -1;
|
|
}
|
|
|
|
} else
|
|
TestIdx = 0;
|
|
|
|
if (NULL == (pszEncryptOID = (LPSTR) GetOID(
|
|
pszEncryptName, CRYPT_ENCRYPT_ALG_OID_GROUP_ID))) {
|
|
printf("Failed => unknown encrypt name (%s)\n", pszEncryptName);
|
|
return -1;
|
|
}
|
|
|
|
if (fDetached) printf("Enabled: DetachedDigest/Signature\n");
|
|
if (fNoSigners) printf("Enabled: NoSigners\n");
|
|
if (fAuthAttr) printf("Enabled: Authenticated attributes\n");
|
|
if (fInnerContent) printf("Enabled: non-data Content\n");
|
|
if (0 != _stricmp("rc2", pszEncryptName))
|
|
printf("Enabled: %s\n", pszEncryptName);
|
|
if (0 != dwEncryptBitLen)
|
|
printf("Enabled: Encrypt bit length: %d\n", dwEncryptBitLen);
|
|
if (fEncryptIV) printf("Enabled: IV\n");
|
|
if (fMD5) printf("Enabled: MD5\n");
|
|
if (pszFilename) printf("Enabled: Writing encoded to file: %s\n", pszFilename);
|
|
|
|
// Get crypto provider having both signature and exchange private keys
|
|
hCryptProv = GetCryptProv();
|
|
if (hCryptProv == 0)
|
|
return -1;
|
|
|
|
// Attempt to open the store
|
|
if (pszStoreFilename) {
|
|
hSignerStore = OpenStore(pszStoreFilename);
|
|
if (NULL == hSignerStore)
|
|
return -1;
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fKeyAgree) {
|
|
hKeyAgreeProv = GetCryptProv(PROV_DSS_DH, NULL);
|
|
|
|
if (hKeyAgreeProv == 0)
|
|
return -1;
|
|
}
|
|
|
|
if (fMultiSigner) {
|
|
hMultiSignerCryptProv = GetCryptProv(dwMultiSignerProvType, NULL);
|
|
if (hMultiSignerCryptProv == 0)
|
|
return -1;
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
if (fDefaultVerifyProv) {
|
|
printf("Using default hCryptProv for encrypting and verifying\n");
|
|
hDefaultVerifyProv = 0;
|
|
} else
|
|
hDefaultVerifyProv = hCryptProv;
|
|
|
|
for ( ; TestIdx < NTESTS; TestIdx++) {
|
|
printf("Starting %s Test\n", Tests[TestIdx].pszName);
|
|
fResult = Tests[TestIdx].pfn();
|
|
if (fResult)
|
|
printf("Passed\n");
|
|
else
|
|
printf("Failed\n");
|
|
printf("\n");
|
|
if (pszTestName)
|
|
break;
|
|
}
|
|
|
|
TestFree( pbInnerContent);
|
|
if (pNamedSigner)
|
|
CertFreeCertificateContext(pNamedSigner);
|
|
if (hSignerStore)
|
|
CertCloseStore(hSignerStore, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Functions for initializing message encode information
|
|
//--------------------------------------------------------------------------
|
|
|
|
static PCCERT_CONTEXT FindCertWithKey(
|
|
IN HCERTSTORE hCertStore,
|
|
IN DWORD dwKeySpec
|
|
)
|
|
{
|
|
PCCERT_CONTEXT pCert;
|
|
void *pvFindPara;
|
|
DWORD dwFindType;
|
|
|
|
if (pszCertNameFindStr) {
|
|
dwFindType = CERT_FIND_SUBJECT_STR_A;
|
|
pvFindPara = (void *) pszCertNameFindStr;
|
|
} else {
|
|
dwFindType = CERT_FIND_ANY;
|
|
pvFindPara = NULL;
|
|
}
|
|
|
|
// Find the first certificate in the store with a CRYPT_KEY_PROV_INFO
|
|
// property matching the specified dwSignKeySpec, dwCryptProvType and
|
|
// dwPubKeyBitLen
|
|
pCert = NULL;
|
|
while (TRUE) {
|
|
pCert = CertFindCertificateInStore(
|
|
hCertStore,
|
|
dwCertEncodingType,
|
|
0, // dwFindFlags,
|
|
dwFindType,
|
|
pvFindPara,
|
|
pCert
|
|
);
|
|
if (pCert == NULL)
|
|
break;
|
|
|
|
PCRYPT_KEY_PROV_INFO pInfo = NULL;
|
|
DWORD cbInfo = 0;
|
|
CertGetCertificateContextProperty(
|
|
pCert,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
NULL,
|
|
&cbInfo
|
|
);
|
|
if (cbInfo >= sizeof(CRYPT_KEY_PROV_INFO) &&
|
|
(pInfo = (PCRYPT_KEY_PROV_INFO) TestAlloc(cbInfo))) {
|
|
BOOL fMatch = FALSE;
|
|
if (CertGetCertificateContextProperty(
|
|
pCert,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
pInfo,
|
|
&cbInfo) &&
|
|
dwKeySpec == pInfo->dwKeySpec)
|
|
fMatch = TRUE;
|
|
TestFree(pInfo);
|
|
if (fMatch)
|
|
break;
|
|
}
|
|
}
|
|
return pCert;
|
|
}
|
|
|
|
|
|
#ifdef CMS_PKCS7
|
|
|
|
static BYTE bZeroSerialNumber = 0;
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Create a Special Issuer and SerialNumber from a KeyId.
|
|
//--------------------------------------------------------------------------
|
|
void CreateIssuerAndSerialNumberFromKeyId(
|
|
IN const BYTE *pbKeyId,
|
|
IN DWORD cbKeyId,
|
|
IN OUT PCERT_INFO pCertInfo
|
|
)
|
|
{
|
|
CERT_RDN_ATTR KeyIdAttr;
|
|
CERT_RDN KeyIdRDN;
|
|
CERT_NAME_INFO IssuerInfo;
|
|
|
|
KeyIdAttr.pszObjId = szOID_KEYID_RDN;
|
|
KeyIdAttr.dwValueType = CERT_RDN_OCTET_STRING;
|
|
KeyIdAttr.Value.pbData = (BYTE *) pbKeyId;
|
|
KeyIdAttr.Value.cbData = cbKeyId;
|
|
KeyIdRDN.cRDNAttr = 1;
|
|
KeyIdRDN.rgRDNAttr = &KeyIdAttr;
|
|
IssuerInfo.cRDN = 1;
|
|
IssuerInfo.rgRDN = &KeyIdRDN;
|
|
|
|
// Encode the special Issuer Name containing the KeyId
|
|
AllocAndEncodeObject(
|
|
X509_NAME,
|
|
&IssuerInfo,
|
|
&pCertInfo->Issuer.pbData,
|
|
&pCertInfo->Issuer.cbData
|
|
);
|
|
|
|
pCertInfo->SerialNumber.cbData = 1;
|
|
pCertInfo->SerialNumber.pbData = &bZeroSerialNumber;
|
|
}
|
|
#endif
|
|
|
|
|
|
void InitSignerEncodeInfo()
|
|
{
|
|
DWORD cbSignerPublicKeyData;
|
|
|
|
// Update the Issuer, SerialNumber and PublicKeyAlgorithm in
|
|
// the signer's CERT_INFO
|
|
memset(&rgSignerCertInfo[0], 0, sizeof(CERT_INFO));
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fCertInfoKeyId) {
|
|
CreateIssuerAndSerialNumberFromKeyId(
|
|
(const BYTE *)"Signer 0",
|
|
strlen("Signer 0"),
|
|
&rgSignerCertInfo[0]
|
|
);
|
|
|
|
rgSignerId[0].dwIdChoice = CERT_ID_KEY_IDENTIFIER;
|
|
rgSignerId[0].KeyId.pbData = (BYTE *)"Signer 0";
|
|
rgSignerId[0].KeyId.cbData = strlen("Signer 0");
|
|
} else {
|
|
#endif
|
|
|
|
GetDERFromFile(
|
|
pszSignerSerialNumberFileName,
|
|
&rgSignerCertInfo[0].Issuer.pbData,
|
|
&rgSignerCertInfo[0].Issuer.cbData);
|
|
rgSignerCertInfo[0].SerialNumber.cbData = sizeof(DWORD);
|
|
rgSignerCertInfo[0].SerialNumber.pbData = (BYTE *) &dwSignerSerialNumber;
|
|
#ifdef CMS_PKCS7
|
|
rgSignerId[0].dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
|
|
rgSignerId[0].IssuerSerialNumber.Issuer = rgSignerCertInfo[0].Issuer;
|
|
rgSignerId[0].IssuerSerialNumber.SerialNumber =
|
|
rgSignerCertInfo[0].SerialNumber;
|
|
}
|
|
#endif
|
|
|
|
if (!fNoSignature) {
|
|
// Get crypt provider's public signature key. It will be used as the
|
|
// signer's public key algorithm
|
|
cbSignerPublicKeyData = sizeof(SignerPublicKeyData.Data);
|
|
memset(SignerPublicKeyData.Data, 0, cbSignerPublicKeyData);
|
|
CryptExportPublicKeyInfo(
|
|
hCryptProv,
|
|
AT_SIGNATURE,
|
|
X509_ASN_ENCODING,
|
|
(PCERT_PUBLIC_KEY_INFO) SignerPublicKeyData.Data,
|
|
&cbSignerPublicKeyData);
|
|
rgSignerCertInfo[0].SubjectPublicKeyInfo.Algorithm =
|
|
((PCERT_PUBLIC_KEY_INFO) SignerPublicKeyData.Data)->Algorithm;
|
|
}
|
|
|
|
// Update the rgSignerEncodeInfo[0]
|
|
memset(&rgSignerEncodeInfo[0], 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
|
|
rgSignerEncodeInfo[0].cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
|
|
rgSignerEncodeInfo[0].pCertInfo = &rgSignerCertInfo[0];
|
|
rgSignerEncodeInfo[0].hCryptProv = hCryptProv;
|
|
rgSignerEncodeInfo[0].HashAlgorithm =
|
|
SignDigestAlgorithms[ fMD5 ? SIGNDIGEST_ALG_MD5 : SIGNDIGEST_ALG_SHA];
|
|
rgSignerEncodeInfo[0].pvHashAuxInfo = NULL;
|
|
#ifdef CMS_PKCS7
|
|
if (fAlgorithmParameters) {
|
|
rgSignerEncodeInfo[0].HashAlgorithm.Parameters.pbData = rgbOctets;
|
|
rgSignerEncodeInfo[0].HashAlgorithm.Parameters.cbData =
|
|
sizeof(rgbOctets);
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
if (fAuthAttr) {
|
|
rgSignerEncodeInfo[0].cAuthAttr = AUTH_ATTR_COUNT;
|
|
rgSignerEncodeInfo[0].rgAuthAttr = rgAuthAttr;
|
|
|
|
if (!fCountersign) {
|
|
rgSignerEncodeInfo[0].cUnauthAttr = UNAUTH_ATTR_COUNT;
|
|
rgSignerEncodeInfo[0].rgUnauthAttr = rgUnauthAttr;
|
|
}
|
|
}
|
|
|
|
if (hSignerStore) {
|
|
pNamedSigner = FindCertWithKey(hSignerStore, AT_SIGNATURE);
|
|
if (NULL == pNamedSigner) {
|
|
PrintLastError("FindCertWithKey(AT_SIGNATURE)");
|
|
} else {
|
|
if (!CryptAcquireCertificatePrivateKey(
|
|
pNamedSigner,
|
|
0, // dwFlags
|
|
NULL, // pvReserved
|
|
&hNamedSignerCryptProv,
|
|
NULL, // pdwKeySpec,
|
|
NULL // pfCallerFreeProv
|
|
)) {
|
|
PrintLastError("CryptAcquireCertificatePrivateKey");
|
|
CertFreeCertificateContext(pNamedSigner);
|
|
pNamedSigner = NULL;
|
|
} else {
|
|
rgSignerEncodeInfo[0].pCertInfo = pNamedSigner->pCertInfo;
|
|
rgSignerEncodeInfo[0].hCryptProv = hNamedSignerCryptProv;
|
|
#ifdef CMS_PKCS7
|
|
rgSignerId[0].dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
|
|
rgSignerId[0].IssuerSerialNumber.Issuer =
|
|
rgSignerEncodeInfo[0].pCertInfo->Issuer;
|
|
rgSignerId[0].IssuerSerialNumber.SerialNumber =
|
|
rgSignerEncodeInfo[0].pCertInfo->SerialNumber;
|
|
#endif // CMS_PKCS7
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fNoSignature) {
|
|
rgSignerEncodeInfo[0].HashEncryptionAlgorithm.pszObjId =
|
|
szOID_PKIX_NO_SIGNATURE;
|
|
} else if (fHashEncryptionAlgorithm) {
|
|
if (pNamedSigner)
|
|
rgSignerEncodeInfo[0].HashEncryptionAlgorithm =
|
|
pNamedSigner->pCertInfo->SignatureAlgorithm;
|
|
else
|
|
rgSignerEncodeInfo[0].HashEncryptionAlgorithm =
|
|
rgSignerCertInfo[0].SubjectPublicKeyInfo.Algorithm;
|
|
|
|
if (fAlgorithmParameters &&
|
|
0 == rgSignerEncodeInfo[0].HashEncryptionAlgorithm.Parameters.cbData)
|
|
{
|
|
rgSignerEncodeInfo[0].HashEncryptionAlgorithm.Parameters.pbData =
|
|
rgbOctets;
|
|
rgSignerEncodeInfo[0].HashEncryptionAlgorithm.Parameters.cbData =
|
|
sizeof(rgbOctets);
|
|
}
|
|
}
|
|
|
|
if (fMultiSigner) {
|
|
// Update the Issuer, SerialNumber and PublicKeyAlgorithm in
|
|
// the signer's CERT_INFO
|
|
memset(&rgSignerCertInfo[1], 0, sizeof(CERT_INFO));
|
|
|
|
if (fCertInfoKeyId) {
|
|
CreateIssuerAndSerialNumberFromKeyId(
|
|
(const BYTE *)"Signer 1",
|
|
strlen("Signer 1"),
|
|
&rgSignerCertInfo[1]
|
|
);
|
|
|
|
rgSignerId[1].dwIdChoice = CERT_ID_KEY_IDENTIFIER;
|
|
rgSignerId[1].KeyId.pbData = (BYTE *)"Signer 1";
|
|
rgSignerId[1].KeyId.cbData = strlen("Signer 1");
|
|
} else {
|
|
GetDERFromFile(
|
|
pszSignerSerialNumberFileName,
|
|
&rgSignerCertInfo[1].Issuer.pbData,
|
|
&rgSignerCertInfo[1].Issuer.cbData);
|
|
rgSignerCertInfo[1].SerialNumber.cbData = sizeof(DWORD);
|
|
rgSignerCertInfo[1].SerialNumber.pbData =
|
|
(BYTE *) &dwSignerSerialNumber1;
|
|
|
|
rgSignerId[1].dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
|
|
rgSignerId[1].IssuerSerialNumber.Issuer =
|
|
rgSignerCertInfo[1].Issuer;
|
|
rgSignerId[1].IssuerSerialNumber.SerialNumber =
|
|
rgSignerCertInfo[1].SerialNumber;
|
|
}
|
|
|
|
|
|
if (!fNoSignature) {
|
|
// Get crypt provider's public signature key. It will be used as the
|
|
// signer's public key algorithm
|
|
cbSignerPublicKeyData = sizeof(MultiSignerPublicKeyData.Data);
|
|
memset(MultiSignerPublicKeyData.Data, 0, cbSignerPublicKeyData);
|
|
CryptExportPublicKeyInfo(
|
|
hMultiSignerCryptProv,
|
|
AT_SIGNATURE,
|
|
X509_ASN_ENCODING,
|
|
(PCERT_PUBLIC_KEY_INFO) MultiSignerPublicKeyData.Data,
|
|
&cbSignerPublicKeyData);
|
|
rgSignerCertInfo[1].SubjectPublicKeyInfo.Algorithm =
|
|
((PCERT_PUBLIC_KEY_INFO) MultiSignerPublicKeyData.Data)->Algorithm;
|
|
}
|
|
|
|
// Update the rgSignerEncodeInfo[1]
|
|
memset(&rgSignerEncodeInfo[1], 0, sizeof(CMSG_SIGNER_ENCODE_INFO));
|
|
rgSignerEncodeInfo[1].cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO);
|
|
rgSignerEncodeInfo[1].pCertInfo = &rgSignerCertInfo[1];
|
|
rgSignerEncodeInfo[1].hCryptProv = hMultiSignerCryptProv;
|
|
rgSignerEncodeInfo[1].HashAlgorithm =
|
|
SignDigestAlgorithms[SIGNDIGEST_ALG_SHA];
|
|
rgSignerEncodeInfo[1].pvHashAuxInfo = NULL;
|
|
|
|
if (fNoSignature) {
|
|
rgSignerEncodeInfo[1].HashEncryptionAlgorithm.pszObjId =
|
|
szOID_PKIX_NO_SIGNATURE;
|
|
}
|
|
|
|
if (fAuthAttr) {
|
|
rgSignerEncodeInfo[1].cAuthAttr = AUTH_ATTR_COUNT;
|
|
rgSignerEncodeInfo[1].rgAuthAttr = rgAuthAttr;
|
|
|
|
if (!fCountersign) {
|
|
rgSignerEncodeInfo[1].cUnauthAttr = UNAUTH_ATTR_COUNT;
|
|
rgSignerEncodeInfo[1].rgUnauthAttr = rgUnauthAttr;
|
|
}
|
|
}
|
|
|
|
if (fSignerId)
|
|
rgSignerEncodeInfo[1].SignerId = rgSignerId[1];
|
|
}
|
|
|
|
if (fSignerId) {
|
|
rgSignerEncodeInfo[0].SignerId = rgSignerId[0];
|
|
if (fHashEncryptionAlgorithm)
|
|
rgSignerEncodeInfo[0].pCertInfo = NULL;
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
}
|
|
|
|
void CleanupSignerEncodeInfo()
|
|
{
|
|
free( rgSignerCertInfo[0].Issuer.pbData);
|
|
#ifdef CMS_PKCS7
|
|
if (fMultiSigner)
|
|
free( rgSignerCertInfo[1].Issuer.pbData);
|
|
#endif // CMS_PKCS7
|
|
}
|
|
|
|
void InitSignedCertAndCrl()
|
|
{
|
|
DWORD i;
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (rgSignedCertBlob[0].pbData)
|
|
return;
|
|
#endif // CMS_PKCS7
|
|
|
|
for (i = 0; i < SIGNED_CERT_COUNT; i++) {
|
|
GetDERFromFile(
|
|
rgpszSignedCertFileName[i],
|
|
&rgSignedCertBlob[i].pbData,
|
|
&rgSignedCertBlob[i].cbData);
|
|
}
|
|
#ifdef CMS_PKCS7
|
|
for (i = 0; i < SIGNED_CRL_COUNT; i++) {
|
|
GetDERFromFile(
|
|
rgpszSignedCrlFileName[i],
|
|
&rgSignedCrlBlob[i].pbData,
|
|
&rgSignedCrlBlob[i].cbData);
|
|
}
|
|
|
|
for (i = 0; i < ATTR_CERT_COUNT; i++) {
|
|
GetDERFromFile(
|
|
rgpszAttrCertFileName[i],
|
|
&rgAttrCertBlob[i].pbData,
|
|
&rgAttrCertBlob[i].cbData);
|
|
}
|
|
#endif // CMS_PKCS7
|
|
}
|
|
|
|
void CleanupSignedCertAndCrl()
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < SIGNED_CERT_COUNT; i++) {
|
|
if (rgSignedCertBlob[i].pbData) {
|
|
free( rgSignedCertBlob[i].pbData);
|
|
rgSignedCertBlob[i].pbData = NULL;
|
|
}
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
for (i = 0; i < SIGNED_CRL_COUNT; i++) {
|
|
if (rgSignedCrlBlob[i].pbData) {
|
|
free( rgSignedCrlBlob[i].pbData);
|
|
rgSignedCrlBlob[i].pbData = NULL;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ATTR_CERT_COUNT; i++) {
|
|
if (rgAttrCertBlob[i].pbData) {
|
|
free( rgAttrCertBlob[i].pbData);
|
|
rgAttrCertBlob[i].pbData = NULL;
|
|
}
|
|
}
|
|
#endif // CMS_PKCS7
|
|
}
|
|
|
|
void InitSignedMsgEncodeInfo(
|
|
OUT PCMSG_SIGNED_ENCODE_INFO pSignedMsgEncodeInfo
|
|
)
|
|
{
|
|
InitSignerEncodeInfo();
|
|
pSignedMsgEncodeInfo->cbSize = sizeof(CMSG_SIGNED_ENCODE_INFO);
|
|
pSignedMsgEncodeInfo->cSigners = fNoSigners ? 0 : 1;
|
|
#ifdef CMS_PKCS7
|
|
if (fMultiSigner)
|
|
pSignedMsgEncodeInfo->cSigners = 2;
|
|
#endif // CMS_PKCS7
|
|
pSignedMsgEncodeInfo->rgSigners = &rgSignerEncodeInfo[0];
|
|
InitSignedCertAndCrl();
|
|
pSignedMsgEncodeInfo->cCertEncoded = cSignedCert;
|
|
pSignedMsgEncodeInfo->rgCertEncoded = rgSignedCertBlob;
|
|
#ifdef CMS_PKCS7
|
|
pSignedMsgEncodeInfo->cCrlEncoded = cSignedCrl;
|
|
pSignedMsgEncodeInfo->rgCrlEncoded = rgSignedCrlBlob;
|
|
#else
|
|
pSignedMsgEncodeInfo->cCrlEncoded = 0;
|
|
pSignedMsgEncodeInfo->rgCrlEncoded = NULL;
|
|
#endif
|
|
#ifdef CMS_PKCS7
|
|
pSignedMsgEncodeInfo->cAttrCertEncoded = cAttrCert;
|
|
pSignedMsgEncodeInfo->rgAttrCertEncoded = rgAttrCertBlob;
|
|
#endif // CMS_PKCS7
|
|
}
|
|
|
|
void CleanupSignedMsgEncodeInfo(
|
|
IN PCMSG_SIGNED_ENCODE_INFO pSignedMsgEncodeInfo
|
|
)
|
|
{
|
|
CleanupSignerEncodeInfo();
|
|
CleanupSignedCertAndCrl();
|
|
}
|
|
|
|
void InitRecipientEncodeInfo()
|
|
{
|
|
DWORD cbRecipientPublicKeyData;
|
|
int i;
|
|
|
|
// Get crypt provider's public exchange key. It will be used as the
|
|
// recipient's public key
|
|
cbRecipientPublicKeyData = sizeof(RecipientPublicKeyData.Data);
|
|
memset(RecipientPublicKeyData.Data, 0, cbRecipientPublicKeyData);
|
|
CryptExportPublicKeyInfo(
|
|
hCryptProv,
|
|
AT_KEYEXCHANGE,
|
|
X509_ASN_ENCODING,
|
|
(PCERT_PUBLIC_KEY_INFO) RecipientPublicKeyData.Data,
|
|
&cbRecipientPublicKeyData);
|
|
|
|
// Update the Issuer, SerialNumber, PublicKey and PublicKeyAlgorithm
|
|
// for each recipient. Update the rgpRecipientCertInfo[].
|
|
for (i = 0; i < RECIPIENT_COUNT; i++) {
|
|
memset(&rgRecipientCertInfo[i], 0, sizeof(CERT_INFO));
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fCertInfoKeyId) {
|
|
CreateIssuerAndSerialNumberFromKeyId(
|
|
(const BYTE *)rgpszRecipientIssuerFileName[i],
|
|
strlen(rgpszRecipientIssuerFileName[i]),
|
|
&rgRecipientCertInfo[i]
|
|
);
|
|
} else {
|
|
#endif
|
|
GetDERFromFile(
|
|
rgpszRecipientIssuerFileName[i],
|
|
&rgRecipientCertInfo[i].Issuer.pbData,
|
|
&rgRecipientCertInfo[i].Issuer.cbData);
|
|
rgRecipientCertInfo[i].SerialNumber.cbData = sizeof(DWORD);
|
|
rgRecipientCertInfo[i].SerialNumber.pbData =
|
|
(BYTE *) &rgdwRecipientSerialNumber[i];
|
|
|
|
#ifdef CMS_PKCS7
|
|
}
|
|
#endif
|
|
|
|
rgRecipientCertInfo[i].SubjectPublicKeyInfo =
|
|
*((PCERT_PUBLIC_KEY_INFO) RecipientPublicKeyData.Data);
|
|
|
|
if (0 == i)
|
|
rgRecipientCertInfo[i].SubjectPublicKeyInfo.Algorithm.pszObjId =
|
|
szOID_OIWSEC_rsaXchg;
|
|
|
|
rgpRecipientCertInfo[i] = &rgRecipientCertInfo[i];
|
|
}
|
|
}
|
|
|
|
void CleanupRecipientEncodeInfo()
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < RECIPIENT_COUNT; i++)
|
|
free( rgRecipientCertInfo[i].Issuer.pbData);
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
|
|
HCRYPTKEY
|
|
WINAPI
|
|
GenerateMailListKey(
|
|
IN HCRYPTPROV hProv,
|
|
IN PCRYPT_DATA_BLOB pKeyId
|
|
)
|
|
{
|
|
HCRYPTHASH hHash = 0;
|
|
HCRYPTKEY hDeriveKey = 0;
|
|
ALG_ID AlgId;
|
|
|
|
// Generate derive key to use to encrypt and export the content encrypt key
|
|
if (!CryptCreateHash(hProv, CALG_SHA1, 0, 0, &hHash)) {
|
|
PrintLastError("CryptCreateHash");
|
|
goto ErrorReturn;
|
|
}
|
|
if (!CryptHashData(hHash, pKeyId->pbData, pKeyId->cbData, 0)) {
|
|
PrintLastError("CryptHashData");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (0 == _stricmp(pszEncryptName, "rc2"))
|
|
AlgId = CALG_RC2;
|
|
else
|
|
AlgId = CALG_3DES;
|
|
if (!CryptDeriveKey(hProv, AlgId, hHash, 0, &hDeriveKey)) {
|
|
PrintLastError("CryptDeriveKey");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
CommonReturn:
|
|
if (hHash)
|
|
CryptDestroyHash(hHash);
|
|
return hDeriveKey;
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
}
|
|
|
|
void InitCmsRecipientEncodeInfo(
|
|
OUT PCMSG_ENVELOPED_ENCODE_INFO pEnvelopedMsgEncodeInfo
|
|
)
|
|
{
|
|
PCERT_PUBLIC_KEY_INFO pPublicKeyInfo;
|
|
DWORD cbRecipientPublicKeyData;
|
|
DWORD i;
|
|
DWORD cRecipients = 0;
|
|
|
|
// Get crypt provider's public exchange key. It will be used as the
|
|
// recipient's public key
|
|
cbRecipientPublicKeyData = sizeof(RecipientPublicKeyData.Data);
|
|
memset(RecipientPublicKeyData.Data, 0, cbRecipientPublicKeyData);
|
|
CryptExportPublicKeyInfo(
|
|
hCryptProv,
|
|
AT_KEYEXCHANGE,
|
|
X509_ASN_ENCODING,
|
|
(PCERT_PUBLIC_KEY_INFO) RecipientPublicKeyData.Data,
|
|
&cbRecipientPublicKeyData);
|
|
pPublicKeyInfo = (PCERT_PUBLIC_KEY_INFO) RecipientPublicKeyData.Data;
|
|
|
|
if (fKeyTrans && fRecipientKeyId) {
|
|
PkcsRecipientCount = RECIPIENT_COUNT * 2;
|
|
|
|
for (i = 0; i < RECIPIENT_COUNT; i++) {
|
|
PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTrans =
|
|
&rgKeyTrans[cRecipients];
|
|
|
|
rgCmsRecipient[cRecipients].dwRecipientChoice =
|
|
CMSG_KEY_TRANS_RECIPIENT;
|
|
rgCmsRecipient[cRecipients].pKeyTrans = pKeyTrans;
|
|
|
|
memset(pKeyTrans, 0, sizeof(*pKeyTrans));
|
|
pKeyTrans->cbSize = sizeof(*pKeyTrans);
|
|
pKeyTrans->KeyEncryptionAlgorithm = pPublicKeyInfo->Algorithm;
|
|
// pKeyTrans->pvKeyEncryptionAuxInfo =
|
|
// pKeyTrans->hCryptProv =
|
|
pKeyTrans->RecipientPublicKey = pPublicKeyInfo->PublicKey;
|
|
pKeyTrans->RecipientId.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
|
|
pKeyTrans->RecipientId.KeyId.pbData =
|
|
(PBYTE) rgpszRecipientIssuerFileName[i];
|
|
pKeyTrans->RecipientId.KeyId.cbData =
|
|
strlen(rgpszRecipientIssuerFileName[i]);
|
|
|
|
cRecipients++;
|
|
}
|
|
}
|
|
|
|
if (fKeyTrans) {
|
|
for (i = 0; i < RECIPIENT_COUNT; i++) {
|
|
PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTrans =
|
|
&rgKeyTrans[cRecipients];
|
|
|
|
rgCmsRecipient[cRecipients].dwRecipientChoice =
|
|
CMSG_KEY_TRANS_RECIPIENT;
|
|
rgCmsRecipient[cRecipients].pKeyTrans = pKeyTrans;
|
|
|
|
memset(pKeyTrans, 0, sizeof(*pKeyTrans));
|
|
pKeyTrans->cbSize = sizeof(*pKeyTrans);
|
|
pKeyTrans->KeyEncryptionAlgorithm = pPublicKeyInfo->Algorithm;
|
|
// pKeyTrans->pvKeyEncryptionAuxInfo =
|
|
// pKeyTrans->hCryptProv =
|
|
pKeyTrans->RecipientPublicKey = pPublicKeyInfo->PublicKey;
|
|
pKeyTrans->RecipientId.dwIdChoice = CERT_ID_ISSUER_SERIAL_NUMBER;
|
|
GetDERFromFile(
|
|
rgpszRecipientIssuerFileName[i],
|
|
&pKeyTrans->RecipientId.IssuerSerialNumber.Issuer.pbData,
|
|
&pKeyTrans->RecipientId.IssuerSerialNumber.Issuer.cbData
|
|
);
|
|
pKeyTrans->RecipientId.IssuerSerialNumber.SerialNumber.cbData =
|
|
sizeof(DWORD);
|
|
pKeyTrans->RecipientId.IssuerSerialNumber.SerialNumber.pbData =
|
|
(BYTE *) &rgdwRecipientSerialNumber[i];
|
|
|
|
if (fRecipientProv)
|
|
pKeyTrans->hCryptProv = GetCryptProv();
|
|
|
|
cRecipients++;
|
|
}
|
|
}
|
|
|
|
if (fKeyAgree) {
|
|
void *pvStructInfo;
|
|
DWORD cbStructInfo;
|
|
|
|
cbRecipientPublicKeyData = sizeof(KeyAgreePublicKeyData.Data);
|
|
memset(KeyAgreePublicKeyData.Data, 0, cbRecipientPublicKeyData);
|
|
CryptExportPublicKeyInfo(
|
|
hKeyAgreeProv,
|
|
AT_KEYEXCHANGE,
|
|
X509_ASN_ENCODING,
|
|
(PCERT_PUBLIC_KEY_INFO) KeyAgreePublicKeyData.Data,
|
|
&cbRecipientPublicKeyData);
|
|
pPublicKeyInfo = (PCERT_PUBLIC_KEY_INFO) KeyAgreePublicKeyData.Data;
|
|
|
|
// Check that we can decode both as X509_DH_PARAMETERS and
|
|
// X942_DH_PARAMETERS
|
|
AllocAndDecodeObject(
|
|
X509_DH_PARAMETERS,
|
|
pPublicKeyInfo->Algorithm.Parameters.pbData,
|
|
pPublicKeyInfo->Algorithm.Parameters.cbData,
|
|
&pvStructInfo,
|
|
&cbStructInfo
|
|
);
|
|
TestFree(pvStructInfo);
|
|
AllocAndDecodeObject(
|
|
X942_DH_PARAMETERS,
|
|
pPublicKeyInfo->Algorithm.Parameters.pbData,
|
|
pPublicKeyInfo->Algorithm.Parameters.cbData,
|
|
&pvStructInfo,
|
|
&cbStructInfo
|
|
);
|
|
TestFree(pvStructInfo);
|
|
|
|
for (i = 0; i < RECIPIENT_COUNT; i++) {
|
|
PCMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO pKeyAgree =
|
|
&rgKeyAgree[cRecipients];
|
|
PCMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO pEncryptedKey =
|
|
&rgEncryptedKey[i];
|
|
|
|
rgCmsRecipient[cRecipients].dwRecipientChoice =
|
|
CMSG_KEY_AGREE_RECIPIENT;
|
|
rgCmsRecipient[cRecipients].pKeyAgree = pKeyAgree;
|
|
|
|
memset(pKeyAgree, 0, sizeof(*pKeyAgree));
|
|
pKeyAgree->cbSize = sizeof(*pKeyAgree);
|
|
|
|
pKeyAgree->KeyEncryptionAlgorithm.pszObjId =
|
|
szOID_RSA_SMIMEalgESDH;
|
|
|
|
if (0 == _stricmp(pszEncryptName, "rc2")) {
|
|
pKeyAgree->KeyWrapAlgorithm.pszObjId =
|
|
szOID_RSA_SMIMEalgCMSRC2wrap;
|
|
|
|
// Update pvKeyWrapAuxInfo or KeyWrapAlgorithm
|
|
// Parameters
|
|
if (0 != dwEncryptBitLen) {
|
|
if (0 == i) {
|
|
int iVersion;
|
|
|
|
switch (dwEncryptBitLen) {
|
|
case 40:
|
|
iVersion = CRYPT_RC2_40BIT_VERSION;
|
|
break;
|
|
case 56:
|
|
iVersion = CRYPT_RC2_56BIT_VERSION;
|
|
break;
|
|
case 64:
|
|
iVersion = CRYPT_RC2_64BIT_VERSION;
|
|
break;
|
|
case 128:
|
|
iVersion = CRYPT_RC2_128BIT_VERSION;
|
|
break;
|
|
default:
|
|
printf("Failed => unknown RC2 length (%d)\n", dwEncryptBitLen);
|
|
iVersion = 0;
|
|
}
|
|
|
|
AllocAndEncodeObject(
|
|
X509_INTEGER,
|
|
&iVersion,
|
|
&pKeyAgree->KeyWrapAlgorithm.Parameters.pbData,
|
|
&pKeyAgree->KeyWrapAlgorithm.Parameters.cbData);
|
|
} else {
|
|
KeyAgreeRC2AuxInfo.cbSize = sizeof(KeyAgreeRC2AuxInfo);
|
|
KeyAgreeRC2AuxInfo.dwBitLen = dwEncryptBitLen;
|
|
pKeyAgree->pvKeyWrapAuxInfo =
|
|
&KeyAgreeRC2AuxInfo;
|
|
}
|
|
}
|
|
} else {
|
|
pKeyAgree->KeyWrapAlgorithm.pszObjId =
|
|
szOID_RSA_SMIMEalgCMS3DESwrap;
|
|
}
|
|
|
|
if (fRecipientProv)
|
|
pKeyAgree->hCryptProv = GetCryptProv(PROV_DSS_DH, NULL);
|
|
|
|
|
|
pKeyAgree->dwKeyChoice = CMSG_KEY_AGREE_EPHEMERAL_KEY_CHOICE;
|
|
pKeyAgree->pEphemeralAlgorithm = &pPublicKeyInfo->Algorithm;
|
|
|
|
if (1 == i) {
|
|
pKeyAgree->UserKeyingMaterial.cbData =
|
|
strlen(pszUserKeyingMaterial);
|
|
pKeyAgree->UserKeyingMaterial.pbData =
|
|
(BYTE *) pszUserKeyingMaterial;
|
|
}
|
|
|
|
pKeyAgree->cRecipientEncryptedKeys = i + 1;
|
|
pKeyAgree->rgpRecipientEncryptedKeys = rgpEncryptedKey;
|
|
|
|
rgpEncryptedKey[i] = pEncryptedKey;
|
|
memset(pEncryptedKey, 0, sizeof(*pEncryptedKey));
|
|
pEncryptedKey->cbSize = sizeof(*pEncryptedKey);
|
|
pEncryptedKey->RecipientPublicKey = pPublicKeyInfo->PublicKey;
|
|
|
|
if (fRecipientKeyId) {
|
|
pEncryptedKey->RecipientId.dwIdChoice = CERT_ID_KEY_IDENTIFIER;
|
|
pEncryptedKey->RecipientId.KeyId.pbData =
|
|
(PBYTE) rgpszRecipientIssuerFileName[i];
|
|
pEncryptedKey->RecipientId.KeyId.cbData =
|
|
strlen(rgpszRecipientIssuerFileName[i]);
|
|
|
|
if (1 == i) {
|
|
SYSTEMTIME st;
|
|
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &pEncryptedKey->Date);
|
|
pEncryptedKey->pOtherAttr = &KeyAgreeOtherAttr;
|
|
}
|
|
} else {
|
|
pEncryptedKey->RecipientId.dwIdChoice =
|
|
CERT_ID_ISSUER_SERIAL_NUMBER;
|
|
GetDERFromFile(
|
|
rgpszRecipientIssuerFileName[i],
|
|
&pEncryptedKey->RecipientId.IssuerSerialNumber.Issuer.pbData,
|
|
&pEncryptedKey->RecipientId.IssuerSerialNumber.Issuer.cbData
|
|
);
|
|
pEncryptedKey->RecipientId.IssuerSerialNumber.SerialNumber.cbData =
|
|
sizeof(DWORD);
|
|
pEncryptedKey->RecipientId.IssuerSerialNumber.SerialNumber.pbData =
|
|
(BYTE *) &rgdwRecipientSerialNumber[i];
|
|
}
|
|
|
|
cRecipients++;
|
|
}
|
|
}
|
|
|
|
if (fMailList) {
|
|
for (i = 0; i < RECIPIENT_COUNT; i++) {
|
|
PCMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO pMailList =
|
|
&rgMailList[cRecipients];
|
|
|
|
rgCmsRecipient[cRecipients].dwRecipientChoice =
|
|
CMSG_MAIL_LIST_RECIPIENT;
|
|
rgCmsRecipient[cRecipients].pMailList = pMailList;
|
|
|
|
memset(pMailList, 0, sizeof(*pMailList));
|
|
pMailList->cbSize = sizeof(*pMailList);
|
|
|
|
if (0 == _stricmp(pszEncryptName, "rc2")) {
|
|
pMailList->KeyEncryptionAlgorithm.pszObjId =
|
|
szOID_RSA_SMIMEalgCMSRC2wrap;
|
|
|
|
// Update pvKeyEncryptionAuxInfo or KeyEncryptionAlgorithm
|
|
// Parameters
|
|
if (0 != dwEncryptBitLen) {
|
|
if (0 == i) {
|
|
int iVersion;
|
|
|
|
switch (dwEncryptBitLen) {
|
|
case 40:
|
|
iVersion = CRYPT_RC2_40BIT_VERSION;
|
|
break;
|
|
case 56:
|
|
iVersion = CRYPT_RC2_56BIT_VERSION;
|
|
break;
|
|
case 64:
|
|
iVersion = CRYPT_RC2_64BIT_VERSION;
|
|
break;
|
|
case 128:
|
|
iVersion = CRYPT_RC2_128BIT_VERSION;
|
|
break;
|
|
default:
|
|
printf("Failed => unknown RC2 length (%d)\n", dwEncryptBitLen);
|
|
iVersion = 0;
|
|
}
|
|
|
|
AllocAndEncodeObject(
|
|
X509_INTEGER,
|
|
&iVersion,
|
|
&pMailList->KeyEncryptionAlgorithm.Parameters.pbData,
|
|
&pMailList->KeyEncryptionAlgorithm.Parameters.cbData);
|
|
} else {
|
|
MailListRC2AuxInfo.cbSize = sizeof(MailListRC2AuxInfo);
|
|
MailListRC2AuxInfo.dwBitLen = dwEncryptBitLen;
|
|
pMailList->pvKeyEncryptionAuxInfo =
|
|
&MailListRC2AuxInfo;
|
|
}
|
|
}
|
|
} else {
|
|
pMailList->KeyEncryptionAlgorithm.pszObjId =
|
|
szOID_RSA_SMIMEalgCMS3DESwrap;
|
|
}
|
|
|
|
pMailList->KeyId.pbData =
|
|
(PBYTE) rgpszRecipientIssuerFileName[i];
|
|
pMailList->KeyId.cbData =
|
|
strlen(rgpszRecipientIssuerFileName[i]);
|
|
|
|
if (fRecipientProv)
|
|
pMailList->hCryptProv = GetCryptProv();
|
|
else
|
|
pMailList->hCryptProv = hCryptProv;
|
|
pMailList->dwKeyChoice = CMSG_MAIL_LIST_HANDLE_KEY_CHOICE;
|
|
pMailList->hKeyEncryptionKey = GenerateMailListKey(
|
|
pMailList->hCryptProv,
|
|
&pMailList->KeyId
|
|
);
|
|
|
|
if (0 != i) {
|
|
SYSTEMTIME st;
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &pMailList->Date);
|
|
|
|
pMailList->pOtherAttr = &MailListOtherAttr;
|
|
}
|
|
|
|
cRecipients++;
|
|
}
|
|
}
|
|
|
|
pEnvelopedMsgEncodeInfo->cRecipients = cRecipients;
|
|
cCmsRecipients = cRecipients;
|
|
pEnvelopedMsgEncodeInfo->rgpRecipients = NULL;
|
|
pEnvelopedMsgEncodeInfo->rgCmsRecipients = rgCmsRecipient;
|
|
fNoRecipients = FALSE;
|
|
}
|
|
|
|
void CleanupCmsRecipientEncodeInfo()
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < cCmsRecipients; i++) {
|
|
switch (rgCmsRecipient[i].dwRecipientChoice) {
|
|
case CMSG_KEY_TRANS_RECIPIENT:
|
|
{
|
|
PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pKeyTrans =
|
|
&rgKeyTrans[i];
|
|
if (CERT_ID_ISSUER_SERIAL_NUMBER ==
|
|
pKeyTrans->RecipientId.dwIdChoice)
|
|
free(pKeyTrans->RecipientId.IssuerSerialNumber.Issuer.pbData);
|
|
if (pKeyTrans->hCryptProv)
|
|
CryptReleaseContext(pKeyTrans->hCryptProv, 0);
|
|
}
|
|
break;
|
|
case CMSG_KEY_AGREE_RECIPIENT:
|
|
{
|
|
PCMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO pKeyAgree =
|
|
&rgKeyAgree[i];
|
|
|
|
TestFree(
|
|
pKeyAgree->KeyEncryptionAlgorithm.Parameters.pbData);
|
|
TestFree(pKeyAgree->KeyWrapAlgorithm.Parameters.pbData);
|
|
|
|
if (pKeyAgree->hCryptProv)
|
|
CryptReleaseContext(pKeyAgree->hCryptProv, 0);
|
|
}
|
|
break;
|
|
case CMSG_MAIL_LIST_RECIPIENT:
|
|
{
|
|
PCMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO pMailList =
|
|
&rgMailList[i];
|
|
TestFree(
|
|
pMailList->KeyEncryptionAlgorithm.Parameters.pbData);
|
|
if (pMailList->hCryptProv &&
|
|
pMailList->hCryptProv != hCryptProv)
|
|
CryptReleaseContext(pMailList->hCryptProv, 0);
|
|
if (pMailList->hKeyEncryptionKey)
|
|
CryptDestroyKey(pMailList->hKeyEncryptionKey);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (fKeyAgree) {
|
|
for (i = 0; i < RECIPIENT_COUNT; i++) {
|
|
PCMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO pEncryptedKey =
|
|
&rgEncryptedKey[i];
|
|
|
|
if (CERT_ID_ISSUER_SERIAL_NUMBER ==
|
|
pEncryptedKey->RecipientId.dwIdChoice)
|
|
free(pEncryptedKey->RecipientId.IssuerSerialNumber.Issuer.pbData);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // CMS_PKCS7
|
|
|
|
#define IV_LENGTH 8
|
|
static BOOL GetIV(BYTE rgbIV[IV_LENGTH])
|
|
{
|
|
|
|
SYSTEMTIME st;
|
|
GetSystemTime(&st);
|
|
assert(IV_LENGTH == sizeof(FILETIME));
|
|
SystemTimeToFileTime(&st, (LPFILETIME) rgbIV);
|
|
return TRUE;
|
|
}
|
|
|
|
void InitEnvelopedMsgEncodeInfo(
|
|
OUT PCMSG_ENVELOPED_ENCODE_INFO pEnvelopedMsgEncodeInfo
|
|
)
|
|
{
|
|
PCRYPT_OBJID_BLOB pAlgPara;
|
|
|
|
InitRecipientEncodeInfo();
|
|
|
|
pEnvelopedMsgEncodeInfo->cbSize = sizeof(CMSG_ENVELOPED_ENCODE_INFO);
|
|
pEnvelopedMsgEncodeInfo->hCryptProv = hDefaultVerifyProv;
|
|
pEnvelopedMsgEncodeInfo->pvEncryptionAuxInfo = NULL;
|
|
pEnvelopedMsgEncodeInfo->cRecipients = fNoRecipients ? 0 : RECIPIENT_COUNT;
|
|
pEnvelopedMsgEncodeInfo->rgpRecipients = rgpRecipientCertInfo;
|
|
#ifdef CMS_PKCS7
|
|
if (fCmsRecipient)
|
|
InitCmsRecipientEncodeInfo(pEnvelopedMsgEncodeInfo);
|
|
|
|
if (fOriginatorInfo) {
|
|
InitSignedCertAndCrl();
|
|
pEnvelopedMsgEncodeInfo->cCertEncoded = cSignedCert;
|
|
pEnvelopedMsgEncodeInfo->rgCertEncoded = rgSignedCertBlob;
|
|
pEnvelopedMsgEncodeInfo->cCrlEncoded = cSignedCrl;
|
|
pEnvelopedMsgEncodeInfo->rgCrlEncoded = rgSignedCrlBlob;
|
|
pEnvelopedMsgEncodeInfo->cAttrCertEncoded = cAttrCert;
|
|
pEnvelopedMsgEncodeInfo->rgAttrCertEncoded = rgAttrCertBlob;
|
|
}
|
|
|
|
if (fAuthAttr) {
|
|
pEnvelopedMsgEncodeInfo->cUnprotectedAttr = AUTH_ATTR_COUNT;
|
|
pEnvelopedMsgEncodeInfo->rgUnprotectedAttr = rgAuthAttr;
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
pEnvelopedMsgEncodeInfo->ContentEncryptionAlgorithm.pszObjId =
|
|
(LPSTR) pszEncryptOID;
|
|
pAlgPara = &pEnvelopedMsgEncodeInfo->ContentEncryptionAlgorithm.Parameters;
|
|
memset(pAlgPara, 0, sizeof(*pAlgPara));
|
|
|
|
if (0 != dwEncryptBitLen && 0 == _stricmp(pszEncryptName, "rc2")) {
|
|
CRYPT_RC2_CBC_PARAMETERS RC2Parameters;
|
|
|
|
switch (dwEncryptBitLen) {
|
|
case 40:
|
|
RC2Parameters.dwVersion = CRYPT_RC2_40BIT_VERSION;
|
|
break;
|
|
case 56:
|
|
RC2Parameters.dwVersion = CRYPT_RC2_56BIT_VERSION;
|
|
break;
|
|
case 64:
|
|
RC2Parameters.dwVersion = CRYPT_RC2_64BIT_VERSION;
|
|
break;
|
|
case 128:
|
|
RC2Parameters.dwVersion = CRYPT_RC2_128BIT_VERSION;
|
|
break;
|
|
default:
|
|
printf("Failed => unknown RC2 length (%d)\n", dwEncryptBitLen);
|
|
return;
|
|
}
|
|
RC2Parameters.fIV = fEncryptIV;
|
|
if (fEncryptIV) {
|
|
if (!GetIV(RC2Parameters.rgbIV))
|
|
return;
|
|
}
|
|
|
|
if (!AllocAndEncodeObject(
|
|
PKCS_RC2_CBC_PARAMETERS,
|
|
&RC2Parameters,
|
|
&pAlgPara->pbData,
|
|
&pAlgPara->cbData))
|
|
return;
|
|
} else if (0 == _stricmp(pszEncryptName, "rc4")) {
|
|
if (fEncryptIV) {
|
|
CRYPT_DATA_BLOB Salt;
|
|
DWORD i;
|
|
|
|
for (i = 0; i < MAX_SALT_LEN; i++)
|
|
rgbSalt[i] = (BYTE) i;
|
|
|
|
Salt.cbData = MAX_SALT_LEN;
|
|
Salt.pbData = rgbSalt;
|
|
|
|
AllocAndEncodeObject(
|
|
X509_OCTET_STRING,
|
|
&Salt,
|
|
&pAlgPara->pbData,
|
|
&pAlgPara->cbData
|
|
);
|
|
} else if (0 != dwEncryptBitLen) {
|
|
memset(&RC4AuxInfo, 0, sizeof(RC4AuxInfo));
|
|
RC4AuxInfo.cbSize = sizeof(RC4AuxInfo);
|
|
RC4AuxInfo.dwBitLen = dwEncryptBitLen;
|
|
if (fNoSalt)
|
|
RC4AuxInfo.dwBitLen |= CMSG_RC4_NO_SALT_FLAG;
|
|
pEnvelopedMsgEncodeInfo->pvEncryptionAuxInfo = &RC4AuxInfo;
|
|
}
|
|
} else if (fEncryptIV) {
|
|
BYTE rgbIV[IV_LENGTH];
|
|
CRYPT_DATA_BLOB Data;
|
|
|
|
Data.pbData = rgbIV;
|
|
Data.cbData = sizeof(rgbIV);
|
|
|
|
if (!GetIV(rgbIV))
|
|
return;
|
|
if (!AllocAndEncodeObject(
|
|
X509_OCTET_STRING,
|
|
&Data,
|
|
&pAlgPara->pbData,
|
|
&pAlgPara->cbData))
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void CleanupEnvelopedMsgEncodeInfo(
|
|
IN PCMSG_ENVELOPED_ENCODE_INFO pEnvelopedMsgEncodeInfo
|
|
)
|
|
{
|
|
TestFree(
|
|
pEnvelopedMsgEncodeInfo->ContentEncryptionAlgorithm.Parameters.pbData);
|
|
CleanupRecipientEncodeInfo();
|
|
#ifdef CMS_PKCS7
|
|
if (fCmsRecipient)
|
|
CleanupCmsRecipientEncodeInfo();
|
|
if (fOriginatorInfo)
|
|
CleanupSignedCertAndCrl();
|
|
#endif // CMS_PKCS7
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Add and delete items
|
|
//--------------------------------------------------------------------------
|
|
BOOL AddDelItems(
|
|
IN HCRYPTMSG hCryptMsg,
|
|
IN DWORD dwCountType,
|
|
IN DWORD dwAddAction,
|
|
IN DWORD dwDelAction,
|
|
IN void const *pvCtrlPara)
|
|
{
|
|
BOOL fRet;
|
|
DWORD cb;
|
|
DWORD cOrg;
|
|
DWORD cCurr;
|
|
|
|
// Get the original count of items
|
|
cb = sizeof(cOrg);
|
|
if (!CryptMsgGetParam(
|
|
hCryptMsg,
|
|
dwCountType,
|
|
0, // dwIndex
|
|
&cOrg,
|
|
&cb))
|
|
goto GetItemCountError;
|
|
// Add an item
|
|
if (!CryptMsgControl(
|
|
hCryptMsg,
|
|
0, // dwFlags
|
|
dwAddAction,
|
|
pvCtrlPara))
|
|
goto AddItemError;
|
|
// Check that the count of items has increased by 1
|
|
if (!CryptMsgGetParam(
|
|
hCryptMsg,
|
|
dwCountType,
|
|
0, // dwIndex
|
|
&cCurr,
|
|
&cb))
|
|
goto GetItemCountAddError;
|
|
if (cCurr != (cOrg + 1))
|
|
goto AddCountError;
|
|
|
|
// Delete the item we just added.
|
|
// Since new items get added to the tail, we use the count of items
|
|
// prior to the add as the index of the new item.
|
|
if (!CryptMsgControl(
|
|
hCryptMsg,
|
|
0, // dwFlags
|
|
dwDelAction,
|
|
&cOrg))
|
|
goto DelItemError;
|
|
// Check that the count of items is back to what it was
|
|
if (!CryptMsgGetParam(
|
|
hCryptMsg,
|
|
dwCountType,
|
|
0, // dwIndex
|
|
&cCurr,
|
|
&cb))
|
|
goto GetItemCountDelError;
|
|
if (cCurr != cOrg)
|
|
goto DelCountError;
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(AddDelItems,GetItemCountError)
|
|
PRINT_ERROR(AddDelItems,AddItemError)
|
|
PRINT_ERROR(AddDelItems,GetItemCountAddError)
|
|
PRINT_ERROR(AddDelItems,AddCountError)
|
|
PRINT_ERROR(AddDelItems,DelItemError)
|
|
PRINT_ERROR(AddDelItems,GetItemCountDelError)
|
|
PRINT_ERROR(AddDelItems,DelCountError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Insert blob at the tail of a blob list
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
TCM_InsertTailBlob(
|
|
IN OUT CBlobList *pBlobList,
|
|
IN PBYTE pbIn,
|
|
IN DWORD cbIn)
|
|
{
|
|
BOOL fRet;
|
|
CBlobNode *pnBlob = NULL;
|
|
PBYTE pb = NULL;
|
|
CRYPT_DATA_BLOB blob;
|
|
|
|
if (NULL == (pnBlob = new CBlobNode))
|
|
goto NewCBlobNodeError;
|
|
if (NULL == (pb = (PBYTE)TestAlloc( cbIn)))
|
|
goto AllocError;
|
|
memcpy( pb, pbIn, cbIn);
|
|
blob.cbData = cbIn;
|
|
blob.pbData = pb;
|
|
pnBlob->SetData( &blob);
|
|
pBlobList->InsertTail( pnBlob);
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
TestFree( pb);
|
|
goto CommonReturn;
|
|
PRINT_ERROR(TCM_InsertTailBlob,NewCBlobNodeError)
|
|
PRINT_ERROR(TCM_InsertTailBlob,AllocError)
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
BOOL VerifyCerts(IN HCRYPTMSG hMsg);
|
|
BOOL VerifyUnprotectedAttr(IN HCRYPTMSG hMsg);
|
|
BOOL GetCmsRecipientInfoAndDecrypt(IN HCRYPTMSG hMsg);
|
|
#endif // CMS_PKCS7
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get message type, recipient info, and set the hProv needed to decrypt
|
|
// the message.
|
|
//--------------------------------------------------------------------------
|
|
BOOL StreamGetRecipientInfoAndSetHProv(
|
|
IN HCRYPTMSG hMsg,
|
|
OUT PDWORD pdwMsgType,
|
|
OUT BOOL *pfReady)
|
|
{
|
|
BOOL fRet;
|
|
PCERT_INFO pRecipientInfo = NULL;
|
|
DWORD cRecipient;
|
|
DWORD cbData;
|
|
DWORD dwIndex;
|
|
CMSG_CTRL_DECRYPT_PARA DecryptPara; ZEROSTRUCT(DecryptPara);
|
|
DWORD cbEnvelopeAlgorithm;
|
|
DWORD cKeyIdRecipient;
|
|
|
|
// Get the message type.
|
|
cbData = sizeof(DWORD);
|
|
if (!CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_TYPE_PARAM,
|
|
0, // dwIndex
|
|
pdwMsgType,
|
|
&cbData)) {
|
|
if (GetLastError() != CRYPT_E_STREAM_MSG_NOT_READY)
|
|
goto GetMessageTypeError;
|
|
*pfReady = FALSE;
|
|
goto SuccessReturn;
|
|
}
|
|
if (CMSG_ENVELOPED != *pdwMsgType) {
|
|
*pfReady = TRUE;
|
|
goto SuccessReturn;
|
|
}
|
|
|
|
// Get content encryption algorithm.
|
|
if (!CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_ENVELOPE_ALGORITHM_PARAM,
|
|
0, // dwIndex
|
|
NULL,
|
|
&cbEnvelopeAlgorithm)) {
|
|
if (GetLastError() != CRYPT_E_STREAM_MSG_NOT_READY)
|
|
goto GetEnvelopeAlgorithmError;
|
|
*pfReady = FALSE;
|
|
goto SuccessReturn;
|
|
}
|
|
*pfReady = TRUE;
|
|
|
|
// Get # of recipients in the message.
|
|
cbData = sizeof(cRecipient);
|
|
cRecipient = 0;
|
|
if (!CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_RECIPIENT_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cRecipient,
|
|
&cbData))
|
|
goto GetRecipientCountError;
|
|
if (!TCM_CheckGetParam(
|
|
hMsg,
|
|
CMSG_RECIPIENT_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cRecipient,
|
|
cbData))
|
|
goto CheckGetRecipientCountError;
|
|
if (fNoRecipients) {
|
|
if (cRecipient != 0)
|
|
goto WrongRecipientCountError;
|
|
} else {
|
|
if (cRecipient != PkcsRecipientCount)
|
|
goto WrongRecipientCountError;
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fKeyTrans && fRecipientKeyId && !fNoRecipients) {
|
|
// The first RECIPIENT_COUNT recipients should be KeyId recipients
|
|
cKeyIdRecipient = RECIPIENT_COUNT;
|
|
|
|
// Get all the KeyId recipients and verify
|
|
for (dwIndex = 0; dwIndex < RECIPIENT_COUNT; dwIndex++) {
|
|
// Allocate and get the CERT_INFO containing the Special
|
|
// KeyId RecipientId
|
|
PCERT_NAME_INFO pKeyIdName = NULL;
|
|
DWORD cbKeyIdName;
|
|
|
|
pRecipientInfo = GetCertIdFromMsg(
|
|
hMsg,
|
|
CMSG_RECIPIENT_INFO_PARAM,
|
|
dwIndex
|
|
);
|
|
|
|
if (pRecipientInfo == NULL)
|
|
goto GetRecipientInfoError;
|
|
|
|
if (pRecipientInfo->SerialNumber.cbData != 1 ||
|
|
*pRecipientInfo->SerialNumber.pbData != 0)
|
|
PrintError("StreamGetRecipientInfoAndSetHProv::Bad KeyId SerialNumber");
|
|
|
|
// Decode the Issuer Name. It should contain the special KeyId
|
|
// RDN
|
|
|
|
if (AllocAndDecodeObject(
|
|
X509_NAME,
|
|
pRecipientInfo->Issuer.pbData,
|
|
pRecipientInfo->Issuer.cbData,
|
|
(void **) &pKeyIdName,
|
|
&cbKeyIdName
|
|
)) {
|
|
|
|
if (pKeyIdName->cRDN != 1 ||
|
|
pKeyIdName->rgRDN[0].cRDNAttr != 1)
|
|
PrintError("StreamGetRecipientInfoAndSetHProv::Bad KeyId Issuer");
|
|
else {
|
|
PCERT_RDN_ATTR pAttr = pKeyIdName->rgRDN[0].rgRDNAttr;
|
|
|
|
if (0 != strcmp(pAttr->pszObjId, szOID_KEYID_RDN) ||
|
|
pAttr->dwValueType != CERT_RDN_OCTET_STRING ||
|
|
pAttr->Value.cbData !=
|
|
strlen(rgpszRecipientIssuerFileName[dwIndex]) ||
|
|
0 != memcmp(pAttr->Value.pbData,
|
|
rgpszRecipientIssuerFileName[dwIndex],
|
|
pAttr->Value.cbData))
|
|
PrintError("StreamGetRecipientInfoAndSetHProv::Bad KeyId Issuer");
|
|
}
|
|
|
|
TestFree(pKeyIdName);
|
|
}
|
|
|
|
TestFree(pRecipientInfo);
|
|
pRecipientInfo = NULL;
|
|
}
|
|
} else
|
|
#endif // CMS_PKCS7
|
|
cKeyIdRecipient = 0;
|
|
|
|
// Get all the non KeyId recipients and verify
|
|
for (dwIndex = 0; dwIndex < cRecipient - cKeyIdRecipient; dwIndex++) {
|
|
// Allocate and get the CERT_INFO containing the RecipientId
|
|
// (Issuer and SerialNumber)
|
|
if (NULL == (pRecipientInfo = GetCertIdFromMsg(
|
|
hMsg,
|
|
CMSG_RECIPIENT_INFO_PARAM,
|
|
cKeyIdRecipient + dwIndex)))
|
|
goto GetRecipientInfoError;
|
|
if (pRecipientInfo->Issuer.cbData !=
|
|
rgRecipientCertInfo[dwIndex].Issuer.cbData ||
|
|
memcmp(pRecipientInfo->Issuer.pbData,
|
|
rgRecipientCertInfo[dwIndex].Issuer.pbData,
|
|
pRecipientInfo->Issuer.cbData) != 0 ||
|
|
pRecipientInfo->SerialNumber.cbData !=
|
|
rgRecipientCertInfo[dwIndex].SerialNumber.cbData ||
|
|
memcmp(pRecipientInfo->SerialNumber.pbData,
|
|
rgRecipientCertInfo[dwIndex].SerialNumber.pbData,
|
|
pRecipientInfo->SerialNumber.cbData) != 0)
|
|
goto BadRecipientInfoError;
|
|
TestFree(pRecipientInfo);
|
|
pRecipientInfo = NULL;
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fOriginatorInfo)
|
|
VerifyCerts(hMsg);
|
|
if (fCmsRecipient) {
|
|
fRet = GetCmsRecipientInfoAndDecrypt(hMsg);
|
|
goto CommonReturn;
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
if (fNoRecipients)
|
|
goto SuccessReturn;
|
|
|
|
DecryptPara.cbSize = sizeof(DecryptPara);
|
|
DecryptPara.hCryptProv = hCryptProv;
|
|
DecryptPara.dwKeySpec = 0;
|
|
DecryptPara.dwRecipientIndex = RECIPIENT_COUNT - 1;
|
|
if (!CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_DECRYPT,
|
|
&DecryptPara))
|
|
goto SetDecryptParamError;
|
|
|
|
SuccessReturn:
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
TestFree(pRecipientInfo);
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(StreamGetRecipientInfoAndSetHProv,GetEnvelopeAlgorithmError)
|
|
PRINT_ERROR(StreamGetRecipientInfoAndSetHProv,GetRecipientCountError)
|
|
PRINT_ERROR(StreamGetRecipientInfoAndSetHProv,CheckGetRecipientCountError)
|
|
PRINT_ERROR(StreamGetRecipientInfoAndSetHProv,WrongRecipientCountError)
|
|
PRINT_ERROR(StreamGetRecipientInfoAndSetHProv,GetRecipientInfoError)
|
|
PRINT_ERROR(StreamGetRecipientInfoAndSetHProv,BadRecipientInfoError)
|
|
PRINT_ERROR(StreamGetRecipientInfoAndSetHProv,SetDecryptParamError)
|
|
PRINT_ERROR(StreamGetRecipientInfoAndSetHProv,GetMessageTypeError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Fill a buffer with content.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
FillBufferWithContent(
|
|
OUT PBYTE pbData,
|
|
IN DWORD cbData)
|
|
{
|
|
BOOL fRet;
|
|
PBYTE pb;
|
|
DWORD cb;
|
|
DWORD i;
|
|
|
|
if (fInnerContent) {
|
|
if (!pbInnerContent) {
|
|
if (!GetDERFromFile(
|
|
pszInnerContentFileName,
|
|
&pbInnerContent,
|
|
&cbInnerContent))
|
|
goto GetDERFromFileError;
|
|
}
|
|
if (iMsgContentOffset + cbData > cbInnerContent)
|
|
goto RequestForTooMuchDataError;
|
|
for (pb=pbData, cb=iMsgContentOffset, i=cbData; i>0; pb++, cb++, i--)
|
|
*pb = pbInnerContent[ cb];
|
|
iMsgContentOffset = cb;
|
|
} else {
|
|
for (pb=pbData, cb=iMsgContentOffset, i=cbData; i>0; pb++, cb++, i--)
|
|
*pb = rgbMsgContentFill[ cb%cbMsgContentFill];
|
|
iMsgContentOffset = cb%cbMsgContentFill;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(FillBufferWithContent,GetDERFromFileError)
|
|
PRINT_ERROR(FillBufferWithContent,RequestForTooMuchDataError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Compare a buffer with content.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
BufferEqualsContent(
|
|
IN PBYTE pbData,
|
|
IN DWORD cbData)
|
|
{
|
|
BOOL fRet;
|
|
PBYTE pb;
|
|
DWORD cb;
|
|
DWORD i;
|
|
|
|
if (fInnerContent) {
|
|
if (iMsgContentOffset + cbData > cbInnerContent)
|
|
goto RequestForTooMuchDataError;
|
|
for (pb=pbData, cb=iMsgContentOffset, i=cbData; i>0; pb++, cb++, i--)
|
|
if (*pb != pbInnerContent[ cb])
|
|
goto InnerContentNotEqualError;
|
|
iMsgContentOffset = cb;
|
|
} else {
|
|
for (pb=pbData, cb=iMsgContentOffset, i=cbData; i>0; pb++, cb++, i--)
|
|
if (*pb != rgbMsgContentFill[ cb%cbMsgContentFill])
|
|
goto ContentNotEqualError;
|
|
iMsgContentOffset = cb%cbMsgContentFill;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(BufferEqualsContent,RequestForTooMuchDataError)
|
|
PRINT_ERROR(BufferEqualsContent,InnerContentNotEqualError)
|
|
PRINT_ERROR(BufferEqualsContent,ContentNotEqualError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Callback for streaming messages.
|
|
//--------------------------------------------------------------------------
|
|
BOOL
|
|
WINAPI
|
|
StreamCallback(
|
|
IN const void *pvArg,
|
|
IN BYTE *pbData,
|
|
IN DWORD cbData,
|
|
IN BOOL fFinal)
|
|
{
|
|
BOOL fRet;
|
|
CStreamNode *pnStream = (CStreamNode *)pvArg;
|
|
BOOL fEncoding = pnStream->Data()->fEncoding;
|
|
CStreamNode *pnStreamNbr;
|
|
DWORD cbWritten;
|
|
|
|
pnStreamNbr = fEncoding ? pnStream->Prev() : pnStream->Next();
|
|
if (pnStreamNbr) {
|
|
if (!CryptMsgUpdate(
|
|
pnStreamNbr->Data()->hMsg,
|
|
pbData,
|
|
cbData,
|
|
fFinal))
|
|
goto MsgUpdateError;
|
|
} else {
|
|
if (fEncoding) {
|
|
if (!WriteFile(
|
|
hFileStream,
|
|
pbData,
|
|
cbData,
|
|
&cbWritten,
|
|
NULL) ||
|
|
(cbWritten != cbData))
|
|
goto WriteFileError;
|
|
} else {
|
|
if (!WriteFile(
|
|
hFileStreamDecode,
|
|
pbData,
|
|
cbData,
|
|
&cbWritten,
|
|
NULL) ||
|
|
(cbWritten != cbData))
|
|
goto WriteFileDecodeError;
|
|
}
|
|
}
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(StreamCallback,MsgUpdateError)
|
|
PRINT_ERROR(StreamCallback,WriteFileError)
|
|
PRINT_ERROR(StreamCallback,WriteFileDecodeError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Encodes and decodes the streamed message.
|
|
//--------------------------------------------------------------------------
|
|
BOOL StreamEncodeAndDecodeMsg()
|
|
{
|
|
BOOL fRet;
|
|
CStreamNode *pnStream = NULL;
|
|
TEST_STREAM_DATA tsd; ZEROSTRUCT(tsd);
|
|
PCMSG_STREAM_INFO pstrmi = NULL;
|
|
PBYTE pb;
|
|
DWORD cb;
|
|
LPSTR psz;
|
|
CHAR ch;
|
|
DWORD dwMsgTypeEncodingPrev;
|
|
LPSTR pszFilenameEncoded = pszFilename ? pszFilename : pszStreamFileName;
|
|
|
|
if (INVALID_HANDLE_VALUE == (hFileStream = CreateFile(
|
|
pszFilenameEncoded,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
0,
|
|
NULL)))
|
|
goto CreateFileError;
|
|
|
|
for (psz=pszStreamMsgTypes, dwMsgTypeEncodingPrev=0; ch=*psz; psz++) {
|
|
switch (ch) {
|
|
case 'd':
|
|
case 'D':
|
|
tsd.dwMsgTypeEncoding = CMSG_DATA;
|
|
tsd.pvMsgEncodeInfo = NULL;
|
|
break;
|
|
case 'e':
|
|
case 'E':
|
|
tsd.dwMsgTypeEncoding = CMSG_ENVELOPED;
|
|
tsd.pvMsgEncodeInfo = &EnvelopedMsgEncodeInfo;
|
|
break;
|
|
case 's':
|
|
case 'S':
|
|
tsd.dwMsgTypeEncoding = CMSG_SIGNED;
|
|
tsd.pvMsgEncodeInfo = &SignedMsgEncodeInfo;
|
|
break;
|
|
default:
|
|
goto InvalidMsgTypeError;
|
|
}
|
|
tsd.dwEncodingType = dwMsgEncodingType;
|
|
|
|
tsd.dwEncodeFlags = 0;
|
|
if ((psz != pszStreamMsgTypes) && (dwMsgTypeEncodingPrev != CMSG_DATA))
|
|
tsd.dwEncodeFlags |= CMSG_BARE_CONTENT_FLAG;
|
|
if (dwMsgTypeEncodingPrev == CMSG_ENVELOPED)
|
|
tsd.dwEncodeFlags |= CMSG_CONTENTS_OCTETS_FLAG;
|
|
if (fBare && (psz == pszStreamMsgTypes))
|
|
tsd.dwEncodeFlags |= CMSG_BARE_CONTENT_FLAG;
|
|
#ifdef CMS_PKCS7
|
|
if (fEncapsulatedContent)
|
|
tsd.dwEncodeFlags |= CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
|
|
#endif // CMS_PKCS7
|
|
|
|
tsd.dwDecodeFlags = 0;
|
|
if (fBare && (psz == pszStreamMsgTypes))
|
|
tsd.dwDecodeFlags |= CMSG_BARE_CONTENT_FLAG;
|
|
|
|
if (NULL == (pstrmi = (PCMSG_STREAM_INFO)TestAllocZero(
|
|
sizeof(CMSG_STREAM_INFO))))
|
|
goto AllocTestStreamInfoError;
|
|
tsd.pStreamInfo = pstrmi;
|
|
if (NULL == (pnStream = new CStreamNode))
|
|
goto NewNodeError;
|
|
pstrmi->cbContent = CMSG_INDEFINITE_LENGTH;
|
|
pstrmi->pfnStreamOutput = StreamCallback;
|
|
pstrmi->pvArg = pnStream;
|
|
pnStream->SetData( &tsd);
|
|
plistStream->InsertTail( pnStream);
|
|
dwMsgTypeEncodingPrev = tsd.dwMsgTypeEncoding;
|
|
}
|
|
pstrmi = NULL;
|
|
|
|
if (!StreamEncodeMsg())
|
|
goto EncodeError;
|
|
|
|
if (hFileStream != INVALID_HANDLE_VALUE) {
|
|
CloseHandle( hFileStream);
|
|
hFileStream = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (!StreamDecodeMsg())
|
|
goto DecodeError;
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
if (hFileStream != INVALID_HANDLE_VALUE)
|
|
CloseHandle( hFileStream);
|
|
#ifndef SAVE_STREAM_FILES
|
|
if (!pszFilename)
|
|
DeleteFile( pszStreamFileName);
|
|
#endif // SAVE_STREAM_FILES
|
|
TestFree( pstrmi);
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(StreamEncodeAndDecodeMsg,CreateFileError)
|
|
PRINT_ERROR(StreamEncodeAndDecodeMsg,NewNodeError)
|
|
PRINT_ERROR(StreamEncodeAndDecodeMsg,EncodeError)
|
|
PRINT_ERROR(StreamEncodeAndDecodeMsg,DecodeError)
|
|
PRINT_ERROR(StreamEncodeAndDecodeMsg,InvalidMsgTypeError)
|
|
PRINT_ERROR(StreamEncodeAndDecodeMsg,AllocTestStreamInfoError)
|
|
}
|
|
|
|
|
|
#ifdef CMS_PKCS7
|
|
|
|
BOOL VerifyEncodedSignerComputedHash(
|
|
IN LPCSTR pszHdr,
|
|
IN HCRYPTMSG hMsg,
|
|
IN DWORD dwSignerIndex,
|
|
IN PBYTE pbExpectedHash,
|
|
IN DWORD cbExpectedHash
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
DWORD cbHash;
|
|
BYTE rgbHash[MAX_HASH_LEN];
|
|
DWORD dwSrcIndex;
|
|
|
|
if (fVerbose)
|
|
printf("%s VerifyEncodedSignerComputedHash(Signer[%d])\n",
|
|
pszHdr, dwSignerIndex);
|
|
|
|
cbHash = sizeof(rgbHash);
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_COMPUTED_HASH_PARAM,
|
|
dwSignerIndex,
|
|
rgbHash,
|
|
&cbHash
|
|
);
|
|
if (!fResult) {
|
|
printf("%s VerifyEncodedSignerComputedHash::CryptMsgGetParam(Signer[%d])",
|
|
pszHdr, dwSignerIndex);
|
|
PrintLastError("");
|
|
} else if (cbHash != cbExpectedHash ||
|
|
0 != memcmp(rgbHash, pbExpectedHash, cbHash)) {
|
|
fResult = FALSE;
|
|
printf("%s VerifyEncodedSignerComputedHash:: failed => bad hash for Signer[%d]\n",
|
|
pszHdr, dwSignerIndex);
|
|
} else {
|
|
TCM_CheckGetParam(
|
|
hMsg,
|
|
CMSG_COMPUTED_HASH_PARAM,
|
|
dwSignerIndex,
|
|
rgbHash,
|
|
cbHash
|
|
);
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
BOOL VerifyDecodedSignerComputedHash(
|
|
IN LPCSTR pszHdr,
|
|
IN HCRYPTMSG hMsg,
|
|
IN BOOL fInnerNonData,
|
|
IN DWORD dwSignerIndex,
|
|
IN BYTE rgbExpectedHash[2][MAX_HASH_LEN],
|
|
IN DWORD rgcbExpectedHash[2]
|
|
)
|
|
{
|
|
DWORD cbHash;
|
|
BYTE rgbHash[MAX_HASH_LEN];
|
|
DWORD dwSrcIndex;
|
|
|
|
if (fVerbose)
|
|
printf("%s VerifyDecodedSignerComputedHash(Signer[%d])\n",
|
|
pszHdr, dwSignerIndex);
|
|
|
|
cbHash = sizeof(rgbHash);
|
|
if (!CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_COMPUTED_HASH_PARAM,
|
|
dwSignerIndex,
|
|
rgbHash,
|
|
&cbHash
|
|
)) {
|
|
printf("%s VerifyDecodedSignerComputedHash(before verify signature)::CryptMsgGetParam(Signer[%d])",
|
|
pszHdr, dwSignerIndex);
|
|
PrintLastError("");
|
|
return FALSE;
|
|
}
|
|
|
|
if (pNamedSigner)
|
|
dwSrcIndex = dwSignerIndex;
|
|
else if (!GetSignerInfoAndVerify(
|
|
hMsg,
|
|
fInnerNonData,
|
|
dwSignerIndex,
|
|
&dwSrcIndex
|
|
)) {
|
|
printf("%s VerifyDecodedSignerComputedHash GetSignerInfoAndVerify(Signer[%d]):: failed\n",
|
|
pszHdr, dwSignerIndex);
|
|
return FALSE;
|
|
}
|
|
|
|
if (cbHash != rgcbExpectedHash[dwSrcIndex] ||
|
|
0 != memcmp(rgbHash, rgbExpectedHash[dwSrcIndex], cbHash)) {
|
|
printf("%s VerifyDecodedSignerComputedHash(before verify signature):: failed => unexpected hash for Signer[%d]\n",
|
|
pszHdr, dwSignerIndex);
|
|
return FALSE;
|
|
}
|
|
|
|
cbHash = sizeof(rgbHash);
|
|
if (!CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_COMPUTED_HASH_PARAM,
|
|
dwSignerIndex,
|
|
rgbHash,
|
|
&cbHash
|
|
)) {
|
|
printf("%s VerifyDecodedSignerComputedHash(after verify signature)::CryptMsgGetParam(Signer[%d])",
|
|
pszHdr, dwSignerIndex);
|
|
PrintLastError("");
|
|
return FALSE;
|
|
}
|
|
|
|
if (cbHash != rgcbExpectedHash[dwSrcIndex] ||
|
|
0 != memcmp(rgbHash, rgbExpectedHash[dwSrcIndex], cbHash)) {
|
|
printf("%s VerifyDecodedSignerComputedHash(after verify signature):: failed => unexpected hash for Signer[%d]\n",
|
|
pszHdr, dwSignerIndex);
|
|
return FALSE;
|
|
} else {
|
|
TCM_CheckGetParam(
|
|
hMsg,
|
|
CMSG_COMPUTED_HASH_PARAM,
|
|
dwSignerIndex,
|
|
rgbHash,
|
|
cbHash
|
|
);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#endif // CMS_PKCS7
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Encodes the streamed message.
|
|
//--------------------------------------------------------------------------
|
|
BOOL StreamEncodeMsg()
|
|
{
|
|
BOOL fRet;
|
|
CStreamNode *pnStream;
|
|
PTEST_STREAM_DATA ptsd;
|
|
HCRYPTMSG hMsg;
|
|
PBYTE pb;
|
|
DWORD cb;
|
|
DWORD cbRemain;
|
|
BOOL fFinal;
|
|
DWORD cbData;
|
|
DWORD cbDataInner;
|
|
LPSTR pszInnerContentType;
|
|
|
|
if (fVerbose)
|
|
printf( "Beginning stream encode\n");
|
|
|
|
if (fInnerContent && !FillBufferWithContent( NULL, 0)) // load inner content
|
|
goto NullFillBufferWithContentError;
|
|
|
|
cbDataInner = fInnerContent ? cbInnerContent : cbMsgContent;
|
|
|
|
if (fInnerContent &&
|
|
#ifdef CMS_PKCS7
|
|
!fEncapsulatedContent &&
|
|
#endif // CMS_PKCS7
|
|
(plistStream->Tail()->Data()->dwMsgTypeEncoding == CMSG_ENVELOPED)) {
|
|
if (!TCM_ExtractContent(
|
|
pbInnerContent,
|
|
cbInnerContent,
|
|
&cbDataInner,
|
|
NULL)) // ppbContent
|
|
goto ExtractContentError;
|
|
}
|
|
|
|
for (pnStream = plistStream->Tail(),
|
|
cbData=cbDataInner,
|
|
pszInnerContentType =
|
|
fInnerContent ? pszInnerContentObjId : NULL;
|
|
pnStream;
|
|
pnStream = pnStream->Prev()) {
|
|
ptsd = pnStream->Data();
|
|
ptsd->fEncoding = TRUE;
|
|
ptsd->pStreamInfo->cbContent = fIndefinite ? CMSG_INDEFINITE_LENGTH : cbData;
|
|
ptsd->pszInnerContentType = pszInnerContentType;
|
|
if (NULL == (ptsd->hMsg = CryptMsgOpenToEncode(
|
|
ptsd->dwEncodingType,
|
|
ptsd->dwEncodeFlags,
|
|
ptsd->dwMsgTypeEncoding,
|
|
ptsd->pvMsgEncodeInfo,
|
|
pszInnerContentType,
|
|
ptsd->pStreamInfo)))
|
|
goto OpenToEncodeError;
|
|
// NB- from PKCS#7, sec.10.3:
|
|
// An enveloped message encrypts only "the contents octets of a
|
|
// definite-length BER encoding of the content field of the ContentInfo"
|
|
// ie. The identifier and length octets are not included.
|
|
// Ergo, we must ask for the size of the contents octets if the outer
|
|
// message is enveloped.
|
|
if (0 == (cbData = CryptMsgCalculateEncodedLength(
|
|
ptsd->dwEncodingType,
|
|
ptsd->dwEncodeFlags,
|
|
ptsd->dwMsgTypeEncoding,
|
|
ptsd->pvMsgEncodeInfo,
|
|
pszInnerContentType,
|
|
cbData)))
|
|
goto CalculateEncodedLengthError;
|
|
switch(ptsd->dwMsgTypeEncoding) {
|
|
case CMSG_DATA:
|
|
pszInnerContentType = szOID_RSA_data;
|
|
break;
|
|
case CMSG_ENVELOPED:
|
|
pszInnerContentType = szOID_RSA_envelopedData;
|
|
break;
|
|
case CMSG_SIGNED:
|
|
pszInnerContentType = szOID_RSA_signedData;
|
|
break;
|
|
default:
|
|
goto InvalidMsgTypeError;
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (ptsd->dwMsgTypeEncoding != CMSG_DATA &&
|
|
(fVerbose || fEncapsulatedContent || cAttrCert ||
|
|
fOriginatorInfo || fCmsRecipient)) {
|
|
BOOL fResult;
|
|
DWORD dwVersion;
|
|
DWORD cbData = sizeof(dwVersion);
|
|
fResult = CryptMsgGetParam(
|
|
ptsd->hMsg,
|
|
CMSG_VERSION_PARAM,
|
|
0, // dwIndex
|
|
(PBYTE) &dwVersion,
|
|
&cbData
|
|
);
|
|
if (!fResult)
|
|
PrintLastError("StreamEncodeMsg::CryptMsgGetParam(CMSG_VERSION_PARAM)");
|
|
else
|
|
printf("StreamEncodeMsg(%d - %s) Version:: %d\n",
|
|
ptsd->dwMsgTypeEncoding, pszInnerContentType, dwVersion);
|
|
}
|
|
#endif // CMS_PKCS7
|
|
}
|
|
|
|
hMsg = plistStream->Tail()->Data()->hMsg;
|
|
iMsgContentOffset = 0;
|
|
cbRemain = fInnerContent ? cbInnerContent : cbMsgContent;
|
|
if (0 == cbRemain) {
|
|
if (!CryptMsgUpdate(
|
|
hMsg,
|
|
NULL,
|
|
0,
|
|
TRUE))
|
|
goto UpdateError;
|
|
} else {
|
|
for ( ; cbRemain; cbRemain -= cb) {
|
|
fFinal = (cbRemain <= cbStreamDataDeltaEncode);
|
|
cb = fFinal ? cbRemain : cbStreamDataDeltaEncode;
|
|
FillBufferWithContent( abStreamDataDeltaEncode, cb);
|
|
if (!CryptMsgUpdate(
|
|
hMsg,
|
|
(PBYTE)abStreamDataDeltaEncode,
|
|
cb,
|
|
fFinal))
|
|
goto UpdateError;
|
|
}
|
|
}
|
|
|
|
for (pnStream = plistStream->Head();
|
|
pnStream;
|
|
pnStream = pnStream->Next()) {
|
|
ptsd = pnStream->Data();
|
|
|
|
cbData = 0;
|
|
if (CryptMsgGetParam(
|
|
ptsd->hMsg,
|
|
CMSG_CONTENT_PARAM,
|
|
0, // dwIndex
|
|
NULL, // pvData
|
|
&cbData
|
|
))
|
|
PrintError("CryptMsgGetParam(CMSG_CONTENT_PARAM) succeeded for streaming");
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (CMSG_SIGNED == ptsd->dwMsgTypeEncoding && !fNoSigners) {
|
|
DWORD i;
|
|
DWORD c;
|
|
|
|
if (fMultiSigner)
|
|
c = 2;
|
|
else
|
|
c = 1;
|
|
|
|
for (i = 0; i < c; i++) {
|
|
ptsd->rgcbComputedHash[i] = sizeof(ptsd->rgbComputedHash[i]);
|
|
if (!CryptMsgGetParam(
|
|
ptsd->hMsg,
|
|
CMSG_COMPUTED_HASH_PARAM,
|
|
i, // dwSignerIndex
|
|
ptsd->rgbComputedHash[i],
|
|
&ptsd->rgcbComputedHash[i]
|
|
)) {
|
|
printf("StreamEncodeMsg::CryptMsgGetParam(Signer[%d] CMSG_COMPUTED_HASH_PARAM)",
|
|
i);
|
|
PrintLastError("");
|
|
} else
|
|
VerifyEncodedSignerComputedHash(
|
|
"StreamEncodeMsg", ptsd->hMsg, i,
|
|
ptsd->rgbComputedHash[i], ptsd->rgcbComputedHash[i]);
|
|
}
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
if (!CryptMsgClose(ptsd->hMsg))
|
|
goto CloseError;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(StreamEncodeMsg,NullFillBufferWithContentError)
|
|
PRINT_ERROR(StreamEncodeMsg,ExtractContentError)
|
|
PRINT_ERROR(StreamEncodeMsg,InvalidMsgTypeError)
|
|
PRINT_ERROR(StreamEncodeMsg,OpenToEncodeError)
|
|
PRINT_ERROR(StreamEncodeMsg,CalculateEncodedLengthError)
|
|
PRINT_ERROR(StreamEncodeMsg,UpdateError)
|
|
PRINT_ERROR(StreamEncodeMsg,CloseError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Decodes the streamed message.
|
|
//--------------------------------------------------------------------------
|
|
BOOL StreamDecodeMsg()
|
|
{
|
|
BOOL fRet;
|
|
CStreamNode *pnStream;
|
|
PTEST_STREAM_DATA ptsd;
|
|
HCRYPTMSG hMsg;
|
|
PBYTE pb;
|
|
DWORD cb;
|
|
PBYTE pbRemain;
|
|
DWORD cbRemain;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
PBYTE pbRead = NULL;
|
|
DWORD cbRead;
|
|
BOOL fFinal;
|
|
BOOL fFirst;
|
|
DWORD cbFile;
|
|
CBlobNode *pnBlob;
|
|
PCRYPT_DATA_BLOB pblob;
|
|
BOOL fInnerNonData;
|
|
DWORD dwMsgTypeInner;
|
|
LPSTR pszFilenameEncoded = pszFilename ? pszFilename : pszStreamFileName;
|
|
|
|
if (fVerbose)
|
|
printf( "Beginning stream decode\n");
|
|
|
|
if (NULL == (pbRead = (PBYTE)TestAlloc(cbStreamDataDeltaDecode)))
|
|
goto AllocDecodeBufferError;
|
|
|
|
// Open the messages
|
|
for (pnStream = plistStream->Head();
|
|
pnStream;
|
|
pnStream = pnStream->Next()) {
|
|
ptsd = pnStream->Data();
|
|
ptsd->fEncoding = FALSE;
|
|
fFirst = (NULL == pnStream->Prev());
|
|
if (NULL == (ptsd->hMsg = CryptMsgOpenToDecode(
|
|
ptsd->dwEncodingType,
|
|
ptsd->dwDecodeFlags,
|
|
((fFirst && fBare) ||
|
|
(!fFirst && (CMSG_DATA != pnStream->Prev()->Data()->dwMsgTypeEncoding)))
|
|
? ptsd->dwMsgTypeEncoding : 0,
|
|
hDefaultVerifyProv,
|
|
NULL, // pRecipientInfo
|
|
ptsd->pStreamInfo)))
|
|
goto OpenToDecodeError;
|
|
}
|
|
|
|
// Open the file containing the nested messages to decode
|
|
if (INVALID_HANDLE_VALUE == (hFile = CreateFile(
|
|
pszFilenameEncoded,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL)))
|
|
goto CreateFileError;
|
|
if (INVALID_FILE_SIZE == (cbFile = GetFileSize( hFile, NULL)))
|
|
goto GetFileSizeError;
|
|
|
|
// Create the file to hold the decoded data
|
|
if (INVALID_HANDLE_VALUE == (hFileStreamDecode = CreateFile(
|
|
pszFilenameDecode,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
0,
|
|
NULL)))
|
|
goto CreateFileDecodeError;
|
|
|
|
// Feed in the encoded nested messages in chunks
|
|
hMsg = plistStream->Head()->Data()->hMsg;
|
|
for (cbRemain=cbFile; cbRemain; cbRemain-=cbRead) {
|
|
if (!ReadFile(
|
|
hFile,
|
|
pbRead,
|
|
cbStreamDataDeltaDecode,
|
|
&cbRead,
|
|
NULL)) // lpOverlapped
|
|
goto ReadFileError;
|
|
fFinal = (cbRead == cbRemain);
|
|
if (!CryptMsgUpdate(
|
|
hMsg,
|
|
pbRead,
|
|
cbRead,
|
|
fFinal))
|
|
goto UpdateError;
|
|
for (pnStream = plistStream->Head();
|
|
pnStream;
|
|
pnStream = pnStream->Next()) {
|
|
ptsd = pnStream->Data();
|
|
if (((0 == ptsd->dwMsgTypeDecoding) ||
|
|
(CMSG_ENVELOPED == ptsd->dwMsgTypeDecoding)) &&
|
|
!ptsd->fReady) {
|
|
if (!StreamGetRecipientInfoAndSetHProv(
|
|
ptsd->hMsg,
|
|
&ptsd->dwMsgTypeDecoding,
|
|
&ptsd->fReady))
|
|
goto StreamGetRecipientInfoAndSetHProvError;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Validate the message types
|
|
for (pnStream = plistStream->Head();
|
|
pnStream;
|
|
pnStream = pnStream->Next()) {
|
|
ptsd = pnStream->Data();
|
|
if (ptsd->dwMsgTypeEncoding != ptsd->dwMsgTypeDecoding)
|
|
goto MsgTypeMismatchError;
|
|
}
|
|
|
|
// Check signatures
|
|
if (fVerbose)
|
|
printf( "Verify signatures\n");
|
|
for (pnStream = plistStream->Tail(), dwMsgTypeInner=CMSG_DATA;
|
|
pnStream;
|
|
pnStream = pnStream->Prev()) {
|
|
ptsd = pnStream->Data();
|
|
fInnerNonData = ((pnStream == plistStream->Tail()) && fInnerContent) ||
|
|
(dwMsgTypeInner != CMSG_DATA);
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (ptsd->dwMsgTypeDecoding != CMSG_DATA &&
|
|
(fVerbose || fEncapsulatedContent || cAttrCert ||
|
|
fOriginatorInfo || fCmsRecipient)) {
|
|
BOOL fResult;
|
|
DWORD dwVersion;
|
|
DWORD cbData = sizeof(dwVersion);
|
|
fResult = CryptMsgGetParam(
|
|
ptsd->hMsg,
|
|
CMSG_VERSION_PARAM,
|
|
0, // dwIndex
|
|
(PBYTE) &dwVersion,
|
|
&cbData
|
|
);
|
|
if (!fResult)
|
|
PrintLastError("StreamDecodeMsg::CryptMsgGetParam(CMSG_VERSION_PARAM)");
|
|
else
|
|
printf("StreamDecodeMsg(%d) Version:: %d\n",
|
|
ptsd->dwMsgTypeDecoding, dwVersion);
|
|
}
|
|
|
|
if (fAuthAttr && CMSG_ENVELOPED == ptsd->dwMsgTypeDecoding)
|
|
VerifyUnprotectedAttr(hMsg);
|
|
|
|
if (CMSG_SIGNED == ptsd->dwMsgTypeDecoding && !fNoSigners) {
|
|
DWORD i;
|
|
DWORD c;
|
|
|
|
if (fMultiSigner)
|
|
c = 2;
|
|
else
|
|
c = 1;
|
|
|
|
for (i = 0; i < c; i++) {
|
|
VerifyDecodedSignerComputedHash(
|
|
"StreamDecodeMsg",
|
|
ptsd->hMsg,
|
|
fInnerNonData,
|
|
i,
|
|
ptsd->rgbComputedHash,
|
|
ptsd->rgcbComputedHash
|
|
);
|
|
}
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
if ((CMSG_SIGNED == ptsd->dwMsgTypeDecoding) &&
|
|
!GetSignerInfoAndVerify( ptsd->hMsg, fInnerNonData))
|
|
goto GetSignerInfoAndVerifyError;
|
|
dwMsgTypeInner = ptsd->dwMsgTypeEncoding;
|
|
}
|
|
|
|
// Verify the data
|
|
if (fVerbose)
|
|
printf( "Verify data\n");
|
|
if (INVALID_FILE_SIZE ==
|
|
(cbFileDecode = GetFileSize( hFileStreamDecode, NULL)))
|
|
goto GetFileSizeDecodeError;
|
|
if (cbFileDecode != (fInnerContent ? cbInnerContent : cbMsgContent)) {
|
|
if (fNoRecipients && 0 == cbFileDecode)
|
|
;
|
|
else
|
|
goto WrongDataSizeError;
|
|
}
|
|
CloseHandle( hFileStreamDecode);
|
|
if (INVALID_HANDLE_VALUE == (hFileStreamDecode = CreateFile(
|
|
pszFilenameDecode,
|
|
GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL)))
|
|
goto CreateFileDecodeReadError;
|
|
iMsgContentOffset = 0;
|
|
for (cbRemain=cbFileDecode; cbRemain; cbRemain-=cbRead) {
|
|
if (!ReadFile(
|
|
hFileStreamDecode,
|
|
pbRead,
|
|
cbStreamDataDeltaDecode,
|
|
&cbRead,
|
|
NULL)) // lpOverlapped
|
|
goto ReadFileDecodeError;
|
|
if (!BufferEqualsContent( pbRead, cbRead))
|
|
goto WrongDataError;
|
|
}
|
|
|
|
// Close the messages
|
|
if (fVerbose)
|
|
printf( "Close messages\n");
|
|
for (pnStream = plistStream->Head();
|
|
pnStream;
|
|
pnStream = pnStream->Next()) {
|
|
|
|
DWORD cbData = 0;
|
|
if (CryptMsgGetParam(
|
|
pnStream->Data()->hMsg,
|
|
CMSG_CONTENT_PARAM,
|
|
0, // dwIndex
|
|
NULL, // pvData
|
|
&cbData
|
|
))
|
|
PrintError("CryptMsgGetParam(CMSG_CONTENT_PARAM) succeeded for streaming");
|
|
|
|
if (!CryptMsgClose( pnStream->Data()->hMsg))
|
|
goto CloseError;
|
|
}
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
TestFree( pbRead);
|
|
if (hFile != INVALID_HANDLE_VALUE)
|
|
CloseHandle( hFile);
|
|
if (hFileStreamDecode != INVALID_HANDLE_VALUE)
|
|
CloseHandle( hFileStreamDecode);
|
|
#ifndef SAVE_STREAM_FILES
|
|
DeleteFile( pszFilenameDecode);
|
|
#endif // SAVE_STREAM_FILES
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(StreamDecodeMsg,AllocDecodeBufferError)
|
|
PRINT_ERROR(StreamDecodeMsg,UpdateError)
|
|
PRINT_ERROR(StreamDecodeMsg,GetFileSizeError)
|
|
PRINT_ERROR(StreamDecodeMsg,CreateFileError)
|
|
PRINT_ERROR(StreamDecodeMsg,ReadFileError)
|
|
PRINT_ERROR(StreamDecodeMsg,ReadFileDecodeError)
|
|
PRINT_ERROR(StreamDecodeMsg,OpenToDecodeError)
|
|
PRINT_ERROR(StreamDecodeMsg,StreamGetRecipientInfoAndSetHProvError)
|
|
PRINT_ERROR(StreamDecodeMsg,MsgTypeMismatchError)
|
|
PRINT_ERROR(StreamDecodeMsg,GetSignerInfoAndVerifyError)
|
|
PRINT_ERROR(StreamDecodeMsg,WrongDataSizeError)
|
|
PRINT_ERROR(StreamDecodeMsg,WrongDataError)
|
|
PRINT_ERROR(StreamDecodeMsg,CloseError)
|
|
PRINT_ERROR(StreamDecodeMsg,CreateFileDecodeError)
|
|
PRINT_ERROR(StreamDecodeMsg,GetFileSizeDecodeError)
|
|
PRINT_ERROR(StreamDecodeMsg,CreateFileDecodeReadError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Encodes and decodes the message.
|
|
//--------------------------------------------------------------------------
|
|
BOOL EncodeAndDecodeMsg(
|
|
IN DWORD dwMsgType,
|
|
IN void *pvMsgEncodeInfo
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
|
|
BYTE *pbEncodedBlob;
|
|
DWORD cbEncodedBlob;
|
|
|
|
fResult = EncodeMsg(
|
|
dwMsgType,
|
|
pvMsgEncodeInfo,
|
|
&pbEncodedBlob,
|
|
&cbEncodedBlob
|
|
);
|
|
|
|
if (fResult) {
|
|
if (pszFilename)
|
|
TCM_WriteBufToFile( pszFilename, pbEncodedBlob, cbEncodedBlob);
|
|
|
|
fResult = DecodeMsg(
|
|
dwMsgType,
|
|
pbEncodedBlob,
|
|
cbEncodedBlob
|
|
);
|
|
|
|
TestFree(pbEncodedBlob);
|
|
}
|
|
return fResult;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Allocates and encodes the message.
|
|
//--------------------------------------------------------------------------
|
|
BOOL EncodeMsg(
|
|
IN DWORD dwMsgType,
|
|
IN void *pvMsgEncodeInfo,
|
|
OUT BYTE **ppbEncodedBlob,
|
|
OUT DWORD *pcbEncodedBlob
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
PBYTE pbToBeEncoded;
|
|
DWORD cbToBeEncoded;
|
|
PBYTE pbInnerEncoded;
|
|
DWORD cbInnerEncoded;
|
|
HCRYPTMSG hMsg = NULL;
|
|
BYTE *pbEncodedBlob = NULL;
|
|
DWORD cbEncodedBlobOrg;
|
|
DWORD cbEncodedBlob;
|
|
DWORD dwFlags = fBare ? CMSG_BARE_CONTENT_FLAG : 0;
|
|
|
|
if (!GetNonStreamedMsgContent(
|
|
cbMsgContent,
|
|
&pbToBeEncoded,
|
|
&cbToBeEncoded))
|
|
goto GetNonStreamedMsgContentError;
|
|
|
|
if (fInnerContent) {
|
|
if (dwMsgType == CMSG_ENVELOPED
|
|
#ifdef CMS_PKCS7
|
|
&& !fEncapsulatedContent
|
|
#endif // CMS_PKCS7
|
|
) {
|
|
if (0 > TCM_ExtractContent(
|
|
pbToBeEncoded,
|
|
cbToBeEncoded,
|
|
&cbInnerEncoded,
|
|
&pbInnerEncoded))
|
|
goto ExtractContentError;
|
|
} else {
|
|
pbInnerEncoded = pbToBeEncoded;
|
|
cbInnerEncoded = cbToBeEncoded;
|
|
}
|
|
}
|
|
|
|
switch (dwMsgType) {
|
|
case CMSG_HASHED:
|
|
case CMSG_SIGNED:
|
|
dwFlags |= fDetached ? CMSG_DETACHED_FLAG : 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fEncapsulatedContent)
|
|
dwFlags |= CMSG_CMS_ENCAPSULATED_CONTENT_FLAG;
|
|
#endif // CMS_PKCS7
|
|
|
|
if (0 == (cbEncodedBlobOrg = CryptMsgCalculateEncodedLength(
|
|
dwMsgEncodingType,
|
|
dwFlags,
|
|
dwMsgType,
|
|
pvMsgEncodeInfo,
|
|
fInnerContent ? pszInnerContentObjId : NULL,
|
|
fInnerContent ? cbInnerEncoded : cbToBeEncoded))) {
|
|
PrintLastError("EncodeMsg::CryptMsgCalculateEncodedLength == 0");
|
|
goto ErrorReturn;
|
|
}
|
|
cbEncodedBlob = cbEncodedBlobOrg + 1024; // A wee bit of padding
|
|
pbEncodedBlob = (BYTE *) TestAlloc( cbEncodedBlob);
|
|
if (pbEncodedBlob == NULL) goto ErrorReturn;
|
|
|
|
hMsg = CryptMsgOpenToEncode(
|
|
dwMsgEncodingType,
|
|
dwFlags,
|
|
dwMsgType,
|
|
pvMsgEncodeInfo,
|
|
fInnerContent ? pszInnerContentObjId : NULL,
|
|
NULL // pStreamInfo
|
|
);
|
|
if (hMsg == NULL) {
|
|
PrintLastError("EncodeMsg::CryptMsgOpenToEncode");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fAlgorithmParameters) {
|
|
rgSignerEncodeInfo[0].HashEncryptionAlgorithm.Parameters.pbData =
|
|
rgbInvalidAsn;
|
|
rgSignerEncodeInfo[0].HashEncryptionAlgorithm.Parameters.cbData =
|
|
sizeof(rgbInvalidAsn);
|
|
|
|
rgSignerEncodeInfo[0].HashAlgorithm.Parameters.pbData =
|
|
rgbInvalidAsn;
|
|
rgSignerEncodeInfo[0].HashAlgorithm.Parameters.cbData =
|
|
sizeof(rgbInvalidAsn);
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
fResult = CryptMsgUpdate(
|
|
hMsg,
|
|
pbToBeEncoded,
|
|
cbToBeEncoded,
|
|
TRUE // fFinal
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError("EncodeMsg::CryptMsgUpdate");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fAuthAttr)
|
|
XORAttributeBytes();
|
|
|
|
if (fVerbose || fEncapsulatedContent || cAttrCert ||
|
|
fOriginatorInfo || fCmsRecipient) {
|
|
DWORD dwVersion;
|
|
DWORD cbData = sizeof(dwVersion);
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_VERSION_PARAM,
|
|
0, // dwIndex
|
|
(PBYTE) &dwVersion,
|
|
&cbData
|
|
);
|
|
if (!fResult)
|
|
PrintLastError("EncodeMsg::CryptMsgGetParam(CMSG_VERSION_PARAM)");
|
|
else
|
|
printf("EncodeMsg Version:: %d\n", dwVersion);
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
fBare ? CMSG_BARE_CONTENT_PARAM : CMSG_CONTENT_PARAM,
|
|
0, // dwIndex
|
|
pbEncodedBlob,
|
|
&cbEncodedBlob
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError("EncodeMsg::CryptMsgGetParam(MSG_(BARE_)CONTENT_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
#ifdef CMS_PKCS7
|
|
if (IsDSSProv(dwProvType) || fKeyAgree ||
|
|
(fMultiSigner && PROV_RSA_FULL != dwMultiSignerProvType)
|
|
#else
|
|
if (IsDSSProv(dwProvType)
|
|
#endif // CMS_PKCS7
|
|
|| hNamedSignerCryptProv) {
|
|
// For DSS the length of the encoded output may be less than
|
|
// the length returned by CryptMsgCalculateEncodedLength
|
|
|
|
// Also Key Agreement recipients containing generated ephemeral
|
|
// public keys may have an encoded length less than
|
|
// the length returned by CryptMsgCalculateEncodedLength
|
|
if (cbEncodedBlobOrg < cbEncodedBlob)
|
|
printf( "Fail: encoding size mismatch: expect=%x >= actual=%x\n",
|
|
cbEncodedBlobOrg,
|
|
cbEncodedBlob);
|
|
} else {
|
|
if (cbEncodedBlobOrg != cbEncodedBlob)
|
|
printf( "Fail: encoding size mismatch: expect=%x actual=%x\n",
|
|
cbEncodedBlobOrg,
|
|
cbEncodedBlob);
|
|
}
|
|
// NB- We depart from the usual practice here since cbEncodedBlob can be
|
|
// somewhat larger than required. A buffer size of 1 will always be too
|
|
// small.
|
|
if (!TCM_CheckGetParam(
|
|
hMsg,
|
|
fBare ? CMSG_BARE_CONTENT_PARAM : CMSG_CONTENT_PARAM,
|
|
0, // dwIndex
|
|
pbEncodedBlob,
|
|
2))
|
|
goto CheckGetEncodedError;
|
|
|
|
if (dwMsgType == CMSG_HASHED) {
|
|
BYTE *pbComputedDigest = NULL;
|
|
DWORD cbComputedDigest = 0;
|
|
|
|
if (!TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_COMPUTED_HASH_PARAM,
|
|
0, // dwIndex
|
|
&pbComputedDigest,
|
|
&cbComputedDigest))
|
|
goto GetComputedHashError;
|
|
|
|
TCM_CheckGetParam(
|
|
hMsg,
|
|
CMSG_COMPUTED_HASH_PARAM,
|
|
0, // dwIndex
|
|
pbComputedDigest,
|
|
cbComputedDigest
|
|
);
|
|
|
|
TestFree(pbComputedDigest);
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (dwMsgType == CMSG_SIGNED && !fNoSigners) {
|
|
DWORD i;
|
|
DWORD c;
|
|
|
|
if (fMultiSigner)
|
|
c = 2;
|
|
else
|
|
c = 1;
|
|
|
|
for (i = 0; i < c; i++) {
|
|
rgcbEncodedSignerHash[i] = sizeof(rgbEncodedSignerHash[i]);
|
|
if (!CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_COMPUTED_HASH_PARAM,
|
|
i, // dwSignerIndex
|
|
rgbEncodedSignerHash[i],
|
|
&rgcbEncodedSignerHash[i]
|
|
)) {
|
|
printf("EncodeMsg::CryptMsgGetParam(Signer[%d] CMSG_COMPUTED_HASH_PARAM)",
|
|
i);
|
|
PrintLastError("");
|
|
} else
|
|
VerifyEncodedSignerComputedHash(
|
|
"EncodeMsg", hMsg, i,
|
|
rgbEncodedSignerHash[i],
|
|
rgcbEncodedSignerHash[i]);
|
|
}
|
|
}
|
|
|
|
if (fAuthAttr)
|
|
XORAttributeBytes();
|
|
#endif // CMS_PKCS7
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
TestFree(pbEncodedBlob);
|
|
pbEncodedBlob = NULL;
|
|
cbEncodedBlob = 0;
|
|
CommonReturn:
|
|
if (hMsg)
|
|
CryptMsgClose(hMsg);
|
|
TestFree(pbToBeEncoded);
|
|
*ppbEncodedBlob = pbEncodedBlob;
|
|
*pcbEncodedBlob = cbEncodedBlob;
|
|
|
|
return fResult;
|
|
//PRINT_ERROR(EncodeMsg,CalculateEncodedLengthWrongSizeError)
|
|
PRINT_ERROR(EncodeMsg,GetNonStreamedMsgContentError)
|
|
PRINT_ERROR(EncodeMsg,ExtractContentError)
|
|
PRINT_ERROR(EncodeMsg,CheckGetEncodedError)
|
|
PRINT_ERROR(EncodeMsg,GetComputedHashError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Decodes the message types:
|
|
// CMSG_SIGNED
|
|
// CMSG_ENVELOPED
|
|
// CMSG_SIGNED_AND_ENVELOPED
|
|
// CMSG_HASHED
|
|
//--------------------------------------------------------------------------
|
|
BOOL DecodeMsg(
|
|
IN DWORD dwExpectedMsgType,
|
|
IN const BYTE *pbEncodedBlob,
|
|
IN DWORD cbEncodedBlob
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
HCRYPTMSG hMsg = NULL;
|
|
PBYTE pbContent;
|
|
DWORD cbContent;
|
|
PBYTE pbDecoded = NULL;
|
|
DWORD cbDecoded;
|
|
DWORD cbData;
|
|
DWORD dwMsgType;
|
|
DWORD dwFlags = CMSG_LENGTH_ONLY_FLAG;
|
|
|
|
if (!GetNonStreamedMsgContent(
|
|
cbMsgContent,
|
|
&pbContent,
|
|
&cbContent))
|
|
goto GetNonStreamedMsgContentError;
|
|
|
|
switch (dwExpectedMsgType) {
|
|
case CMSG_HASHED:
|
|
case CMSG_SIGNED:
|
|
dwFlags |= fDetached ? CMSG_DETACHED_FLAG : 0;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Open to decode to get the message type and content length
|
|
hMsg = CryptMsgOpenToDecode(
|
|
dwMsgEncodingType,
|
|
dwFlags,
|
|
fBare ? dwExpectedMsgType : 0,
|
|
hDefaultVerifyProv,
|
|
NULL, // pRecipientInfo
|
|
NULL // pStreamInfo
|
|
);
|
|
if (hMsg == NULL) {
|
|
PrintLastError("DecodeMsg::CryptMsgOpenToDecode(CMSG_LENGTH_ONLY_FLAG)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
fResult = CryptMsgUpdate(
|
|
hMsg,
|
|
pbEncodedBlob,
|
|
cbEncodedBlob,
|
|
TRUE // fFinal
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError("DecodeMsg::CryptMsgUpdate");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fVerbose || fEncapsulatedContent || cAttrCert ||
|
|
fOriginatorInfo || fCmsRecipient) {
|
|
DWORD dwVersion;
|
|
DWORD cbData = sizeof(dwVersion);
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_VERSION_PARAM,
|
|
0, // dwIndex
|
|
(PBYTE) &dwVersion,
|
|
&cbData
|
|
);
|
|
if (!fResult)
|
|
PrintLastError("DecodeMsg::CryptMsgGetParam(CMSG_VERSION_PARAM)");
|
|
else
|
|
printf("DecodeMsg Version:: %d\n", dwVersion);
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
if (fDetached) {
|
|
fResult = CryptMsgUpdate(
|
|
hMsg,
|
|
pbContent,
|
|
cbContent,
|
|
TRUE // fFinal
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError("DecodeMsg::CryptMsgUpdate");
|
|
goto ErrorReturn;
|
|
}
|
|
} else if (!fNoSigners) {
|
|
cbData = sizeof(dwMsgType);
|
|
dwMsgType = 0;
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_TYPE_PARAM,
|
|
0, // dwIndex
|
|
&dwMsgType,
|
|
&cbData
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError("DecodeMsg::CryptMsgGetParam(CMSG_TYPE_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
if ((dwMsgType != dwExpectedMsgType) &&
|
|
(CMSG_SIGNED != dwExpectedMsgType)) {
|
|
PrintError("DecodeMsg::Unexpected message type");
|
|
}
|
|
if (!TCM_CheckGetParam(
|
|
hMsg,
|
|
CMSG_TYPE_PARAM,
|
|
0, // dwIndex
|
|
&dwMsgType,
|
|
cbData))
|
|
goto CheckGetTypeError;
|
|
|
|
cbDecoded = 0;
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CONTENT_PARAM,
|
|
0, // dwIndex
|
|
NULL, // pvData
|
|
&cbDecoded
|
|
);
|
|
if (cbDecoded == 0) {
|
|
PrintError("DecodeMsg::message content length == 0");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if ((cbDecoded < cbContent) && !fInnerContent)
|
|
PrintError(
|
|
"DecodeMsg::Ciphertext Length Less Than Plaintext Length");
|
|
|
|
pbDecoded = (BYTE *) TestAlloc(cbDecoded);
|
|
if (pbDecoded == NULL) goto ErrorReturn;
|
|
}
|
|
CryptMsgClose(hMsg);
|
|
hMsg = NULL;
|
|
|
|
// Re-open message to get its decoded content.
|
|
hMsg = CryptMsgOpenToDecode(
|
|
dwMsgEncodingType,
|
|
dwFlags,
|
|
fBare ? dwExpectedMsgType : 0,
|
|
hDefaultVerifyProv,
|
|
NULL, // pRecipientInfo
|
|
NULL // pStreamInfo
|
|
);
|
|
if (hMsg == NULL) {
|
|
PrintLastError("DecodeMsg::CryptMsgOpenToDecode");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
// Check that duplicate works
|
|
hMsg = CryptMsgDuplicate(hMsg);
|
|
CryptMsgClose(hMsg);
|
|
|
|
fResult = CryptMsgUpdate(
|
|
hMsg,
|
|
pbEncodedBlob,
|
|
cbEncodedBlob,
|
|
TRUE // fFinal
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError("DecodeMsg::CryptMsgUpdate");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (fDetached) {
|
|
fResult = CryptMsgUpdate(
|
|
hMsg,
|
|
pbContent,
|
|
cbContent,
|
|
TRUE // fFinal
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError("DecodeMsg::CryptMsgUpdate");
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
|
|
if (fInnerContent) {
|
|
DWORD cbInnerContentObjId;
|
|
PBYTE pbInnerContentObjId;
|
|
|
|
if (!TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_INNER_CONTENT_TYPE_PARAM,
|
|
0, // dwIndex
|
|
&pbInnerContentObjId,
|
|
&cbInnerContentObjId))
|
|
goto GetInnerContentTypeError;
|
|
|
|
if ((cbInnerContentObjId != (strlen(pszInnerContentObjId) + 1)) ||
|
|
(0 != memcmp(
|
|
pszInnerContentObjId,
|
|
pbInnerContentObjId,
|
|
cbInnerContentObjId))) {
|
|
PrintError(
|
|
"DecodeMsg::Decoded Content Object ID incorrect");
|
|
}
|
|
TestFree(pbInnerContentObjId);
|
|
}
|
|
|
|
if (dwExpectedMsgType == CMSG_ENVELOPED ||
|
|
dwExpectedMsgType == CMSG_SIGNED_AND_ENVELOPED) {
|
|
fResult = GetRecipientInfoAndDecrypt(hMsg);
|
|
if (!fResult) goto ErrorReturn;
|
|
}
|
|
|
|
if (!fNoSigners &&
|
|
(dwExpectedMsgType == CMSG_SIGNED ||
|
|
dwExpectedMsgType == CMSG_SIGNED_AND_ENVELOPED)) {
|
|
if (fAuthAttr) {
|
|
DWORD cbAuthAttrs;
|
|
PBYTE pbAuthAttrs;
|
|
|
|
if (!TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_SIGNER_AUTH_ATTR_PARAM,
|
|
0, // dwIndex
|
|
&pbAuthAttrs,
|
|
&cbAuthAttrs)) {
|
|
TestFree(pbAuthAttrs);
|
|
goto GetAuthAttrError;
|
|
}
|
|
TestFree(pbAuthAttrs);
|
|
|
|
if (!fCountersign) {
|
|
if (!TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_SIGNER_UNAUTH_ATTR_PARAM,
|
|
0, // dwIndex
|
|
&pbAuthAttrs,
|
|
&cbAuthAttrs)) {
|
|
TestFree(pbAuthAttrs);
|
|
goto GetAuthAttrError;
|
|
}
|
|
TestFree(pbAuthAttrs);
|
|
}
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
VerifyDecodedSignerComputedHash(
|
|
"DecodeMsg", hMsg, fInnerContent, 0,
|
|
rgbEncodedSignerHash,
|
|
rgcbEncodedSignerHash);
|
|
if (fMultiSigner) {
|
|
VerifyDecodedSignerComputedHash(
|
|
"DecodeMsg", hMsg, fInnerContent, 1,
|
|
rgbEncodedSignerHash,
|
|
rgcbEncodedSignerHash);
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
fResult = GetSignerInfoAndVerify(hMsg, fInnerContent);
|
|
if (!fResult) goto ErrorReturn;
|
|
|
|
if (fCountersign && !CountersignAndVerify( hMsg)) {
|
|
PrintError( "DecodeMsg::CountersignAndVerify");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (fAddSigner && !AddSignerAndVerify( hMsg)) {
|
|
PrintError( "DecodeMsg::AddSignerAndVerify");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (!AddDelItems(
|
|
hMsg,
|
|
CMSG_CERT_COUNT_PARAM,
|
|
CMSG_CTRL_ADD_CERT,
|
|
CMSG_CTRL_DEL_CERT,
|
|
rgSignedCertBlob))
|
|
goto AddDelCertsError;
|
|
|
|
if (!AddDelItems(
|
|
hMsg,
|
|
CMSG_CRL_COUNT_PARAM,
|
|
CMSG_CTRL_ADD_CRL,
|
|
CMSG_CTRL_DEL_CRL,
|
|
rgSignedCertBlob)) // This is not a cert
|
|
goto AddDelCrlsError;
|
|
#ifdef CMS_PKCS7
|
|
if (cAttrCert || (fEncapsulatedContent && fInnerContent)) {
|
|
if (!AddDelItems(
|
|
hMsg,
|
|
CMSG_ATTR_CERT_COUNT_PARAM,
|
|
CMSG_CTRL_ADD_ATTR_CERT,
|
|
CMSG_CTRL_DEL_ATTR_CERT,
|
|
rgSignedCertBlob))
|
|
goto AddDelAttrCertsError;
|
|
}
|
|
#endif // CMS_PKCS7
|
|
}
|
|
|
|
if (!fDetached && !fNoSigners
|
|
#ifdef CMS_PKCS7
|
|
&& !fNoRecipients
|
|
#endif // CMS_PKCS7
|
|
) {
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CONTENT_PARAM,
|
|
0, // dwIndex
|
|
pbDecoded,
|
|
&cbDecoded
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError("DecodeMsg::CryptMsgGetParam(CMSG_CONTENT_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
if (!TCM_CheckGetParam(
|
|
hMsg,
|
|
CMSG_CONTENT_PARAM,
|
|
0, // dwIndex
|
|
pbDecoded,
|
|
cbDecoded))
|
|
goto CheckGetContentError;
|
|
|
|
if (cbDecoded != cbContent ||
|
|
memcmp(pbContent, pbDecoded, cbContent) != 0) {
|
|
PrintError(
|
|
"DecodeMsg::Decoded Content doesn't match ToBeEncoded Content");
|
|
}
|
|
}
|
|
|
|
if (dwExpectedMsgType == CMSG_HASHED) {
|
|
fResult = Undigest(hMsg);
|
|
if (!fResult) goto ErrorReturn;
|
|
}
|
|
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
CommonReturn:
|
|
if (hMsg)
|
|
CryptMsgClose(hMsg);
|
|
TestFree(pbDecoded);
|
|
TestFree(pbContent);
|
|
return fResult;
|
|
PRINT_ERROR(DecodeMsg,GetNonStreamedMsgContentError)
|
|
PRINT_ERROR(DecodeMsg,CheckGetTypeError)
|
|
PRINT_ERROR(DecodeMsg,GetInnerContentTypeError)
|
|
PRINT_ERROR(DecodeMsg,GetAuthAttrError)
|
|
PRINT_ERROR(DecodeMsg,CheckGetContentError)
|
|
PRINT_ERROR(DecodeMsg,AddDelCrlsError)
|
|
PRINT_ERROR(DecodeMsg,AddDelCertsError)
|
|
#ifdef CMS_PKCS7
|
|
PRINT_ERROR(DecodeMsg,AddDelAttrCertsError)
|
|
#endif // CMS_PKCS7
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Decode and encode a SignerInfo, and check that the input matches the output
|
|
//--------------------------------------------------------------------------
|
|
BOOL VerifyEncodedSigner(
|
|
IN PBYTE pbEncodedSigner,
|
|
IN DWORD cbEncodedSigner)
|
|
{
|
|
BOOL fRet;
|
|
PCMSG_SIGNER_INFO psi = NULL;
|
|
#ifdef CMS_PKCS7
|
|
PCMSG_CMS_SIGNER_INFO pCMSsi = NULL;
|
|
#endif // CMS_PKCS7
|
|
DWORD cbsi;
|
|
PBYTE pbEncodedSignerNew = NULL;
|
|
DWORD cbEncodedSignerNew;
|
|
|
|
cbsi = 0;
|
|
if (!CryptDecodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
PKCS7_SIGNER_INFO,
|
|
pbEncodedSigner,
|
|
cbEncodedSigner,
|
|
0, // dwFlags
|
|
NULL,
|
|
&cbsi))
|
|
goto DecodeSizeError;
|
|
if (NULL == (psi = (PCMSG_SIGNER_INFO)TestAlloc( cbsi)))
|
|
goto AllocDecodeError;
|
|
if (!CryptDecodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
PKCS7_SIGNER_INFO,
|
|
pbEncodedSigner,
|
|
cbEncodedSigner,
|
|
0, // dwFlags
|
|
psi,
|
|
&cbsi))
|
|
goto DecodeError;
|
|
|
|
cbEncodedSignerNew = 0;
|
|
if (!CryptEncodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
PKCS7_SIGNER_INFO,
|
|
psi,
|
|
NULL,
|
|
&cbEncodedSignerNew))
|
|
goto EncodeSizeError;
|
|
if (NULL == (pbEncodedSignerNew = (PBYTE)TestAlloc( cbEncodedSignerNew)))
|
|
goto AllocEncodeError;
|
|
if (!CryptEncodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
PKCS7_SIGNER_INFO,
|
|
psi,
|
|
pbEncodedSignerNew,
|
|
&cbEncodedSignerNew))
|
|
goto EncodeError;
|
|
|
|
if (cbEncodedSigner != cbEncodedSignerNew)
|
|
goto UnequalEncodedSignerSizeError;
|
|
if (0 != memcmp( pbEncodedSigner, pbEncodedSignerNew, cbEncodedSigner))
|
|
goto UnequalEncodedSignerError;
|
|
|
|
#ifdef CMS_PKCS7
|
|
TestFree(pbEncodedSignerNew);
|
|
pbEncodedSignerNew = NULL;
|
|
|
|
cbsi = 0;
|
|
if (!CryptDecodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
CMS_SIGNER_INFO,
|
|
pbEncodedSigner,
|
|
cbEncodedSigner,
|
|
0, // dwFlags
|
|
NULL,
|
|
&cbsi))
|
|
goto CMSDecodeSizeError;
|
|
if (NULL == (pCMSsi = (PCMSG_CMS_SIGNER_INFO)TestAlloc( cbsi)))
|
|
goto CMSAllocDecodeError;
|
|
if (!CryptDecodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
CMS_SIGNER_INFO,
|
|
pbEncodedSigner,
|
|
cbEncodedSigner,
|
|
0, // dwFlags
|
|
pCMSsi,
|
|
&cbsi))
|
|
goto CMSDecodeError;
|
|
|
|
cbEncodedSignerNew = 0;
|
|
if (!CryptEncodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
CMS_SIGNER_INFO,
|
|
pCMSsi,
|
|
NULL,
|
|
&cbEncodedSignerNew))
|
|
goto CMSEncodeSizeError;
|
|
if (NULL == (pbEncodedSignerNew = (PBYTE)TestAlloc( cbEncodedSignerNew)))
|
|
goto CMSAllocEncodeError;
|
|
if (!CryptEncodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
CMS_SIGNER_INFO,
|
|
pCMSsi,
|
|
pbEncodedSignerNew,
|
|
&cbEncodedSignerNew))
|
|
goto CMSEncodeError;
|
|
|
|
if (cbEncodedSigner != cbEncodedSignerNew)
|
|
goto CMSUnequalEncodedSignerSizeError;
|
|
if (0 != memcmp( pbEncodedSigner, pbEncodedSignerNew, cbEncodedSigner))
|
|
goto CMSUnequalEncodedSignerError;
|
|
#endif // CMS_PKCS7
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
TestFree(psi);
|
|
#ifdef CMS_PKCS7
|
|
TestFree(pCMSsi);
|
|
#endif // CMS_PKCS7
|
|
TestFree(pbEncodedSignerNew);
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(VerifyEncodedSigner,DecodeSizeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,AllocDecodeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,DecodeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,EncodeSizeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,AllocEncodeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,EncodeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,UnequalEncodedSignerSizeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,UnequalEncodedSignerError)
|
|
#ifdef CMS_PKCS7
|
|
PRINT_ERROR(VerifyEncodedSigner,CMSDecodeSizeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,CMSAllocDecodeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,CMSDecodeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,CMSEncodeSizeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,CMSAllocEncodeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,CMSEncodeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,CMSUnequalEncodedSignerSizeError)
|
|
PRINT_ERROR(VerifyEncodedSigner,CMSUnequalEncodedSignerError)
|
|
#endif // CMS_PKCS7
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Countersign the signed message and verify the countersignature
|
|
//--------------------------------------------------------------------------
|
|
BOOL CountersignAndVerify(IN HCRYPTMSG hCryptMsg)
|
|
{
|
|
BOOL fRet;
|
|
HCRYPTMSG hMsgNew = NULL;
|
|
PBYTE pbEncodedMessage = NULL;
|
|
DWORD cbEncodedMessage;
|
|
PBYTE pbSignerInfo = NULL;
|
|
DWORD cbSignerInfo;
|
|
PCRYPT_ATTRIBUTES patrs = NULL;
|
|
DWORD cbatrs;
|
|
PCERT_INFO pciCountersigner = NULL;
|
|
DWORD cbSignerPublicKeyData;
|
|
|
|
// Allocate and get the CERT_INFO containing the SignerId
|
|
// (Issuer and SerialNumber) of the countersigner.
|
|
// NB: For this particular test, the signer and countersigner are the same.
|
|
if (NULL == (pciCountersigner = GetCertIdFromMsg(
|
|
hCryptMsg,
|
|
CMSG_SIGNER_CERT_INFO_PARAM,
|
|
0))) // dwIndex
|
|
goto GetCertIdFromMsgError;
|
|
|
|
// countersign
|
|
if (!CryptMsgCountersign(
|
|
hCryptMsg,
|
|
0, // dwIndex
|
|
1, // cCountersigners
|
|
&rgSignerEncodeInfo[0]))
|
|
goto CountersignError;
|
|
|
|
if (!TCM_AllocGetParam(
|
|
hCryptMsg,
|
|
CMSG_ENCODED_MESSAGE,
|
|
0, // dwIndex
|
|
&pbEncodedMessage,
|
|
&cbEncodedMessage))
|
|
goto GetEncodedMessageError;
|
|
|
|
if (pszFilename)
|
|
TCM_WriteBufToFile( pszFilename, pbEncodedMessage, cbEncodedMessage);
|
|
|
|
// Re-open message to get its decoded content.
|
|
if (NULL == (hMsgNew = CryptMsgOpenToDecode(
|
|
dwMsgEncodingType,
|
|
0, // dwFlags
|
|
0, // dwMsgType
|
|
hDefaultVerifyProv,
|
|
NULL, // pRecipientInfo
|
|
NULL))) // pStreamInfo
|
|
goto CryptMsgOpenToDecodeError;
|
|
if (!CryptMsgUpdate(
|
|
hMsgNew,
|
|
pbEncodedMessage,
|
|
cbEncodedMessage,
|
|
TRUE)) // fFinal
|
|
goto CryptMsgUpdateError;
|
|
|
|
// Get the SignerInfo which was countersigned
|
|
if (!TCM_AllocGetParam(
|
|
hMsgNew,
|
|
CMSG_ENCODED_SIGNER,
|
|
0, // dwIndex
|
|
&pbSignerInfo,
|
|
&cbSignerInfo))
|
|
goto GetEncodedSignerInfoError;
|
|
|
|
if (!VerifyEncodedSigner( pbSignerInfo, cbSignerInfo))
|
|
goto VerifyEncodedSignerError;
|
|
|
|
// Get the unauth attrs, and find the countersignature
|
|
if (!TCM_AllocGetParam(
|
|
hMsgNew,
|
|
CMSG_SIGNER_UNAUTH_ATTR_PARAM,
|
|
0, // dwIndex
|
|
(PBYTE *)&patrs,
|
|
&cbatrs))
|
|
goto GetUnauthAttrsError;
|
|
|
|
// Do some consistency checks
|
|
if (patrs->cAttr != 1)
|
|
goto AttrCountError;
|
|
if (strcmp( patrs->rgAttr->pszObjId, szOID_RSA_counterSign))
|
|
goto AttrOidNotCountersignError;
|
|
if (patrs->rgAttr->cValue != 1)
|
|
goto CountersignCountError;
|
|
|
|
// Get the signer's public key
|
|
cbSignerPublicKeyData = sizeof(SignerPublicKeyData.Data);
|
|
memset(SignerPublicKeyData.Data, 0, cbSignerPublicKeyData);
|
|
if (!CryptExportPublicKeyInfo(
|
|
hCryptProv,
|
|
AT_SIGNATURE,
|
|
X509_ASN_ENCODING,
|
|
(PCERT_PUBLIC_KEY_INFO) SignerPublicKeyData.Data,
|
|
&cbSignerPublicKeyData))
|
|
goto ExportPublicKeyInfoError;
|
|
|
|
pciCountersigner->SubjectPublicKeyInfo =
|
|
*((PCERT_PUBLIC_KEY_INFO) SignerPublicKeyData.Data);
|
|
|
|
// Verify the countersignature
|
|
if (!CryptMsgVerifyCountersignatureEncoded(
|
|
hDefaultVerifyProv,
|
|
PKCS_7_ASN_ENCODING,
|
|
pbSignerInfo,
|
|
cbSignerInfo,
|
|
patrs->rgAttr->rgValue->pbData,
|
|
patrs->rgAttr->rgValue->cbData,
|
|
pciCountersigner))
|
|
goto VerifyCountersignatureEncodedError;
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
if (hMsgNew)
|
|
CryptMsgClose(hMsgNew);
|
|
TestFree(pciCountersigner);
|
|
TestFree(pbEncodedMessage);
|
|
TestFree(pbSignerInfo);
|
|
TestFree(patrs);
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(CountersignAndVerify,GetEncodedMessageError)
|
|
PRINT_ERROR(CountersignAndVerify,CryptMsgOpenToDecodeError)
|
|
PRINT_ERROR(CountersignAndVerify,CryptMsgUpdateError)
|
|
PRINT_ERROR(CountersignAndVerify,GetCertIdFromMsgError)
|
|
PRINT_ERROR(CountersignAndVerify,CountersignError)
|
|
PRINT_ERROR(CountersignAndVerify,GetEncodedSignerInfoError)
|
|
PRINT_ERROR(CountersignAndVerify,VerifyEncodedSignerError)
|
|
PRINT_ERROR(CountersignAndVerify,GetUnauthAttrsError)
|
|
PRINT_ERROR(CountersignAndVerify,AttrCountError)
|
|
PRINT_ERROR(CountersignAndVerify,AttrOidNotCountersignError)
|
|
PRINT_ERROR(CountersignAndVerify,CountersignCountError)
|
|
PRINT_ERROR(CountersignAndVerify,ExportPublicKeyInfoError)
|
|
PRINT_ERROR(CountersignAndVerify,VerifyCountersignatureEncodedError)
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Add signers to the signed message and verify the new signatures
|
|
//--------------------------------------------------------------------------
|
|
BOOL AddSignerAndVerify(IN HCRYPTMSG hCryptMsg)
|
|
{
|
|
BOOL fRet;
|
|
HCRYPTMSG hMsgNew = NULL;
|
|
PBYTE pbEncodedMessage = NULL;
|
|
DWORD cbEncodedMessage;
|
|
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo1 = rgSignerEncodeInfo[0];
|
|
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo2 = rgSignerEncodeInfo[0];
|
|
PCERT_INFO pciSigner0 = NULL;
|
|
PCERT_INFO pciSigner1 = NULL;
|
|
PCERT_INFO pciSigner2 = NULL;
|
|
|
|
if (NULL == (pciSigner0 = GetCertIdFromMsg(
|
|
hCryptMsg,
|
|
CMSG_SIGNER_CERT_INFO_PARAM,
|
|
0))) // dwIndex
|
|
goto GetCertId0Error;
|
|
if (NULL == (pciSigner1 = GetCertIdFromMsg(
|
|
hCryptMsg,
|
|
CMSG_SIGNER_CERT_INFO_PARAM,
|
|
0))) // dwIndex
|
|
goto GetCertId1Error;
|
|
if (NULL == (pciSigner2 = GetCertIdFromMsg(
|
|
hCryptMsg,
|
|
CMSG_SIGNER_CERT_INFO_PARAM,
|
|
0))) // dwIndex
|
|
goto GetCertId2Error;
|
|
|
|
// Give the new signers different serial numbers
|
|
pciSigner1->SerialNumber.pbData = (PBYTE)&dwSignerSerialNumber1;
|
|
pciSigner2->SerialNumber.pbData = (PBYTE)&dwSignerSerialNumber2;
|
|
|
|
// Fill in the public key info
|
|
// NB- We are relying on this already having been filled in by GetSignerInfoAndVerify
|
|
pciSigner0->SubjectPublicKeyInfo =
|
|
*((PCERT_PUBLIC_KEY_INFO) SignerPublicKeyData.Data);
|
|
pciSigner1->SubjectPublicKeyInfo =
|
|
*((PCERT_PUBLIC_KEY_INFO) SignerPublicKeyData.Data);
|
|
pciSigner2->SubjectPublicKeyInfo =
|
|
*((PCERT_PUBLIC_KEY_INFO) SignerPublicKeyData.Data);
|
|
|
|
SignerEncodeInfo1.pCertInfo = pciSigner1;
|
|
SignerEncodeInfo2.pCertInfo = pciSigner2;
|
|
|
|
if (IsDSSProv(dwProvType))
|
|
// DSS only supports signing of sha1
|
|
SignerEncodeInfo2.HashAlgorithm =
|
|
SignDigestAlgorithms[fMD5 ? SIGNDIGEST_ALG_MD5 : SIGNDIGEST_ALG_SHA];
|
|
else
|
|
// Use a different hash algorithm to force adding a hash node and
|
|
// hashing the content again.
|
|
SignerEncodeInfo2.HashAlgorithm =
|
|
SignDigestAlgorithms[ !fMD5 ? SIGNDIGEST_ALG_MD5 : SIGNDIGEST_ALG_SHA];
|
|
|
|
// Add the signers
|
|
if (!CryptMsgControl(
|
|
hCryptMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_ADD_SIGNER,
|
|
&SignerEncodeInfo1))
|
|
goto AddSigner1Error;
|
|
if (!CryptMsgControl(
|
|
hCryptMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_ADD_SIGNER,
|
|
&SignerEncodeInfo2))
|
|
goto AddSigner2Error;
|
|
|
|
if (!AddDelItems(
|
|
hCryptMsg,
|
|
CMSG_SIGNER_COUNT_PARAM,
|
|
CMSG_CTRL_ADD_SIGNER,
|
|
CMSG_CTRL_DEL_SIGNER,
|
|
&SignerEncodeInfo2))
|
|
goto AddDelSignersError;
|
|
|
|
// Verify all the signatures
|
|
if (!CryptMsgControl(
|
|
hCryptMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE,
|
|
pciSigner0))
|
|
goto VerifySigner0Error;
|
|
if (!CryptMsgControl(
|
|
hCryptMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE,
|
|
pciSigner1))
|
|
goto VerifySigner1Error;
|
|
if (!CryptMsgControl(
|
|
hCryptMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE,
|
|
pciSigner2))
|
|
goto VerifySigner2Error;
|
|
|
|
// Re-encode the message, with the new signers
|
|
if (!TCM_AllocGetParam(
|
|
hCryptMsg,
|
|
CMSG_ENCODED_MESSAGE,
|
|
0, // dwIndex
|
|
&pbEncodedMessage,
|
|
&cbEncodedMessage))
|
|
goto GetEncodedMessageError;
|
|
|
|
if (pszFilename)
|
|
TCM_WriteBufToFile( pszFilename, pbEncodedMessage, cbEncodedMessage);
|
|
|
|
// Re-open message to get its decoded content.
|
|
if (NULL == (hMsgNew = CryptMsgOpenToDecode(
|
|
dwMsgEncodingType,
|
|
0, // dwFlags
|
|
0, // dwMsgType
|
|
hDefaultVerifyProv,
|
|
NULL, // pRecipientInfo
|
|
NULL))) // pStreamInfo
|
|
goto CryptMsgOpenToDecodeError;
|
|
if (!CryptMsgUpdate(
|
|
hMsgNew,
|
|
pbEncodedMessage,
|
|
cbEncodedMessage,
|
|
TRUE)) // fFinal
|
|
goto CryptMsgUpdateError;
|
|
|
|
// Verify all the signatures, again
|
|
if (!CryptMsgControl(
|
|
hMsgNew,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE,
|
|
pciSigner0))
|
|
goto ReVerifySigner0Error;
|
|
if (!CryptMsgControl(
|
|
hMsgNew,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE,
|
|
pciSigner1))
|
|
goto ReVerifySigner1Error;
|
|
if (!CryptMsgControl(
|
|
hMsgNew,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE,
|
|
pciSigner2))
|
|
goto ReVerifySigner2Error;
|
|
|
|
fRet = TRUE;
|
|
CommonReturn:
|
|
if (hMsgNew)
|
|
CryptMsgClose(hMsgNew);
|
|
TestFree(pciSigner0);
|
|
TestFree(pciSigner1);
|
|
TestFree(pciSigner2);
|
|
TestFree(pbEncodedMessage);
|
|
return fRet;
|
|
|
|
ErrorReturn:
|
|
fRet = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(AddSignerAndVerify,GetCertId0Error)
|
|
PRINT_ERROR(AddSignerAndVerify,GetCertId1Error)
|
|
PRINT_ERROR(AddSignerAndVerify,GetCertId2Error)
|
|
PRINT_ERROR(AddSignerAndVerify,AddSigner1Error)
|
|
PRINT_ERROR(AddSignerAndVerify,AddSigner2Error)
|
|
PRINT_ERROR(AddSignerAndVerify,VerifySigner0Error)
|
|
PRINT_ERROR(AddSignerAndVerify,VerifySigner1Error)
|
|
PRINT_ERROR(AddSignerAndVerify,VerifySigner2Error)
|
|
PRINT_ERROR(AddSignerAndVerify,GetEncodedMessageError)
|
|
PRINT_ERROR(AddSignerAndVerify,CryptMsgOpenToDecodeError)
|
|
PRINT_ERROR(AddSignerAndVerify,CryptMsgUpdateError)
|
|
PRINT_ERROR(AddSignerAndVerify,ReVerifySigner0Error)
|
|
PRINT_ERROR(AddSignerAndVerify,ReVerifySigner1Error)
|
|
PRINT_ERROR(AddSignerAndVerify,ReVerifySigner2Error)
|
|
PRINT_ERROR(AddSignerAndVerify,AddDelSignersError)
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Verify certificates and CRLs in a signed or enveloped message.
|
|
//--------------------------------------------------------------------------
|
|
BOOL VerifyCerts(IN HCRYPTMSG hMsg)
|
|
{
|
|
BOOL fResult;
|
|
BYTE *pbCertEncoded = NULL;
|
|
DWORD cCert;
|
|
#ifdef CMS_PKCS7
|
|
BYTE *pbCrlEncoded = NULL;
|
|
DWORD cCrl;
|
|
#endif // CMS_PKCS7
|
|
DWORD cbData;
|
|
DWORD dwIndex;
|
|
|
|
//--------------------------------------------------------------
|
|
// Get count of certificates in the message
|
|
cCert = 0;
|
|
cbData = sizeof(cCert);
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CERT_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cCert,
|
|
&cbData
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"VerifyCerts::CryptMsgGetParam(CMSG_CERT_COUNT_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
if (cCert != cSignedCert) {
|
|
PrintError("VerifyCerts::cCert != cSignedCert");
|
|
goto ErrorReturn;
|
|
}
|
|
if (!TCM_CheckGetParam(
|
|
hMsg,
|
|
CMSG_CERT_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cCert,
|
|
cbData))
|
|
goto CheckGetCertCountError;
|
|
|
|
|
|
// Get certs from the message and verify
|
|
for (dwIndex = 0; dwIndex < cCert; dwIndex++) {
|
|
if (!TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_CERT_PARAM,
|
|
dwIndex,
|
|
&pbCertEncoded,
|
|
&cbData))
|
|
goto GetCertError;
|
|
|
|
if (cbData != rgSignedCertBlob[dwIndex].cbData ||
|
|
memcmp(pbCertEncoded, rgSignedCertBlob[dwIndex].pbData,
|
|
cbData) != 0) {
|
|
PrintError("VerifyCerts::Bad Cert content");
|
|
}
|
|
|
|
TestFree(pbCertEncoded);
|
|
pbCertEncoded = NULL;
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
//--------------------------------------------------------------
|
|
// Get count of attribute certificates in the message
|
|
cCert = 0;
|
|
cbData = sizeof(cCert);
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_ATTR_CERT_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cCert,
|
|
&cbData
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"VerifyCerts::CryptMsgGetParam(CMSG_ATTR_CERT_COUNT_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
if (cCert != cAttrCert) {
|
|
PrintError("VerifyCerts::cAttrCert != cAttrCert");
|
|
goto ErrorReturn;
|
|
}
|
|
if (!TCM_CheckGetParam(
|
|
hMsg,
|
|
CMSG_ATTR_CERT_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cCert,
|
|
cbData))
|
|
goto CheckGetCertCountError;
|
|
|
|
|
|
// Get attribute certs from the message and verify
|
|
for (dwIndex = 0; dwIndex < cCert; dwIndex++) {
|
|
if (!TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_ATTR_CERT_PARAM,
|
|
dwIndex,
|
|
&pbCertEncoded,
|
|
&cbData))
|
|
goto GetCertError;
|
|
|
|
if (cbData != rgAttrCertBlob[dwIndex].cbData ||
|
|
memcmp(pbCertEncoded, rgAttrCertBlob[dwIndex].pbData,
|
|
cbData) != 0) {
|
|
PrintError("VerifyCerts::Bad Attribute Cert content");
|
|
}
|
|
|
|
TestFree(pbCertEncoded);
|
|
pbCertEncoded = NULL;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
// Get count of CRLs in the message
|
|
cCrl = 0;
|
|
cbData = sizeof(cCrl);
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CRL_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cCrl,
|
|
&cbData
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"VerifyCrls::CryptMsgGetParam(CMSG_CRL_COUNT_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
if (cCrl != cSignedCrl) {
|
|
PrintError("VerifyCrls::cCrl != cSignedCrl");
|
|
goto ErrorReturn;
|
|
}
|
|
if (!TCM_CheckGetParam(
|
|
hMsg,
|
|
CMSG_CRL_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cCrl,
|
|
cbData))
|
|
goto CheckGetCrlCountError;
|
|
|
|
|
|
// Get CRLs from the message and verify
|
|
for (dwIndex = 0; dwIndex < cCrl; dwIndex++) {
|
|
if (!TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_CRL_PARAM,
|
|
dwIndex,
|
|
&pbCrlEncoded,
|
|
&cbData))
|
|
goto GetCrlError;
|
|
|
|
if (cbData != rgSignedCrlBlob[dwIndex].cbData ||
|
|
memcmp(pbCrlEncoded, rgSignedCrlBlob[dwIndex].pbData,
|
|
cbData) != 0) {
|
|
PrintError("VerifyCrls::Bad Crl content");
|
|
}
|
|
|
|
TestFree(pbCrlEncoded);
|
|
pbCrlEncoded = NULL;
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
|
|
CommonReturn:
|
|
TestFree(pbCertEncoded);
|
|
#ifdef CMS_PKCS7
|
|
TestFree(pbCrlEncoded);
|
|
#endif // CMS_PKCS7
|
|
return fResult;
|
|
PRINT_ERROR(VerifyCerts,CheckGetCertCountError)
|
|
PRINT_ERROR(VerifyCerts,GetCertError)
|
|
#ifdef CMS_PKCS7
|
|
PRINT_ERROR(VerifyCerts,CheckGetCrlCountError)
|
|
PRINT_ERROR(VerifyCerts,GetCrlError)
|
|
#endif // CMS_PKCS7
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get signer info and verify the signed message
|
|
//--------------------------------------------------------------------------
|
|
BOOL GetSignerInfoAndVerify(
|
|
IN HCRYPTMSG hMsg,
|
|
IN BOOL fInnerNonData,
|
|
IN DWORD dwSignerIndex,
|
|
OUT DWORD *pdwSrcIndex
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
PCERT_INFO pSignerCertInfo = NULL;
|
|
PCMSG_SIGNER_INFO pSignerInfo = NULL;
|
|
DWORD cbData;
|
|
BOOL fEqual;
|
|
DWORD i;
|
|
PCRYPT_ATTRIBUTE patr1;
|
|
PCRYPT_ATTRIBUTE patr2;
|
|
|
|
DWORD cbSignerPublicKeyData;
|
|
DWORD dwSrcIndex = 0;
|
|
HCRYPTPROV hVerifyProv;
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fMultiSigner) {
|
|
DWORD cSigner = 0;
|
|
cbData = sizeof(cSigner);
|
|
|
|
if (!CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_SIGNER_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cSigner,
|
|
&cbData) || cSigner != 2) {
|
|
PrintLastError(
|
|
"GetSignerInfoAndVerify:: Invalid multisigner count");
|
|
}
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
// Allocate and get the CERT_INFO containing the SignerId
|
|
// (Issuer and SerialNumber)
|
|
pSignerCertInfo = GetCertIdFromMsg(
|
|
hMsg,
|
|
CMSG_SIGNER_CERT_INFO_PARAM,
|
|
dwSignerIndex
|
|
);
|
|
if (pSignerCertInfo == NULL) {
|
|
PrintLastError(
|
|
"GetSignerInfoAndVerify::CryptMsgGetParam(CMSG_SIGNER_CERT_INFO_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
#ifdef CMS_PKCS7
|
|
if (!(fCertInfoKeyId && fMultiSigner)) {
|
|
#endif // CMS_PKCS7
|
|
|
|
if (pSignerCertInfo->Issuer.cbData != rgSignerCertInfo[0].Issuer.cbData ||
|
|
memcmp(pSignerCertInfo->Issuer.pbData, rgSignerCertInfo[0].Issuer.pbData,
|
|
pSignerCertInfo->Issuer.cbData) != 0) {
|
|
PrintError("GetSignerInfoAndVerify::Bad SignerIssuerName");
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fMultiSigner) {
|
|
|
|
if (pSignerCertInfo->SerialNumber.cbData ==
|
|
rgSignerCertInfo[0].SerialNumber.cbData &&
|
|
memcmp(pSignerCertInfo->SerialNumber.pbData,
|
|
rgSignerCertInfo[0].SerialNumber.pbData,
|
|
pSignerCertInfo->SerialNumber.cbData) == 0) {
|
|
dwSrcIndex = 0;
|
|
} else if (pSignerCertInfo->SerialNumber.cbData ==
|
|
rgSignerCertInfo[1].SerialNumber.cbData &&
|
|
memcmp(pSignerCertInfo->SerialNumber.pbData,
|
|
rgSignerCertInfo[1].SerialNumber.pbData,
|
|
pSignerCertInfo->SerialNumber.cbData) == 0) {
|
|
dwSrcIndex = 1;
|
|
} else {
|
|
PrintError("GetSignerInfoAndVerify::Bad SignerSerialNumber");
|
|
}
|
|
|
|
if (fCertInfoKeyId) {
|
|
if (pSignerCertInfo->Issuer.cbData ==
|
|
rgSignerCertInfo[0].Issuer.cbData &&
|
|
memcmp(pSignerCertInfo->Issuer.pbData,
|
|
rgSignerCertInfo[0].Issuer.pbData,
|
|
pSignerCertInfo->Issuer.cbData) == 0) {
|
|
dwSrcIndex = 0;
|
|
} else if (pSignerCertInfo->Issuer.cbData ==
|
|
rgSignerCertInfo[1].Issuer.cbData &&
|
|
memcmp(pSignerCertInfo->Issuer.pbData,
|
|
rgSignerCertInfo[1].Issuer.pbData,
|
|
pSignerCertInfo->Issuer.cbData) == 0) {
|
|
dwSrcIndex = 1;
|
|
} else {
|
|
PrintError("GetSignerInfoAndVerify::Bad CertInfoKeyId");
|
|
}
|
|
}
|
|
} else
|
|
#endif // CMS_PKCS7
|
|
if (pSignerCertInfo->SerialNumber.cbData !=
|
|
rgSignerCertInfo[0].SerialNumber.cbData ||
|
|
memcmp(pSignerCertInfo->SerialNumber.pbData,
|
|
rgSignerCertInfo[0].SerialNumber.pbData,
|
|
pSignerCertInfo->SerialNumber.cbData) != 0) {
|
|
PrintError("GetSignerInfoAndVerify::Bad SignerSerialNumber");
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
// Allocate and get the CMSG_SIGNER_INFO for the signer
|
|
if (NULL == (pSignerInfo = GetSignerInfoFromMsg(
|
|
hMsg,
|
|
dwSignerIndex))) {
|
|
PrintLastError(
|
|
"GetSignerInfoAndVerify::CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
fEqual = (pSignerInfo->Issuer.cbData ==
|
|
rgSignerCertInfo[dwSrcIndex].Issuer.cbData);
|
|
if (fEqual) {
|
|
fEqual &= (memcmp( pSignerInfo->Issuer.pbData,
|
|
rgSignerCertInfo[dwSrcIndex].Issuer.pbData,
|
|
pSignerInfo->Issuer.cbData) == 0);
|
|
}
|
|
fEqual &= (pSignerInfo->SerialNumber.cbData ==
|
|
rgSignerCertInfo[dwSrcIndex].SerialNumber.cbData);
|
|
if (fEqual) {
|
|
fEqual &= (memcmp( pSignerInfo->SerialNumber.pbData,
|
|
rgSignerCertInfo[dwSrcIndex].SerialNumber.pbData,
|
|
pSignerInfo->SerialNumber.cbData) == 0);
|
|
}
|
|
if (fAuthAttr) {
|
|
fEqual &= EqualAlgorithm( &rgSignerEncodeInfo[dwSrcIndex].HashAlgorithm,
|
|
&pSignerInfo->HashAlgorithm);
|
|
// Allow for the 2 auth attrs which get added automatically
|
|
fEqual &= ((rgSignerEncodeInfo[dwSrcIndex].cAuthAttr + 2) ==
|
|
pSignerInfo->AuthAttrs.cAttr);
|
|
if (fEqual) {
|
|
for (i=pSignerInfo->AuthAttrs.cAttr,
|
|
patr1=rgSignerEncodeInfo[dwSrcIndex].rgAuthAttr,
|
|
patr2=pSignerInfo->AuthAttrs.rgAttr;
|
|
i>0;
|
|
i--, patr2++) {
|
|
// NB: We skip over the 2 auth attrs added by the system.
|
|
if ( (0 == strcmp( szOID_RSA_contentType, patr2->pszObjId)) ||
|
|
(0 == strcmp( szOID_RSA_messageDigest, patr2->pszObjId)))
|
|
continue;
|
|
fEqual &= EqualAttribute( patr1++, patr2);
|
|
}
|
|
}
|
|
|
|
if (!fCountersign) {
|
|
fEqual &= (rgSignerEncodeInfo[dwSrcIndex].cUnauthAttr ==
|
|
pSignerInfo->UnauthAttrs.cAttr);
|
|
if (fEqual) {
|
|
for (i=pSignerInfo->UnauthAttrs.cAttr,
|
|
patr1=rgSignerEncodeInfo[dwSrcIndex].rgUnauthAttr,
|
|
patr2=pSignerInfo->UnauthAttrs.rgAttr;
|
|
i>0;
|
|
i--, patr1++, patr2++) {
|
|
fEqual &= EqualAttribute( patr1, patr2);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// It would be more thorough to check the message digest and
|
|
// content type auth attrs are present in the fInnerContent case.
|
|
if (fInnerNonData)
|
|
{
|
|
fEqual &= (pSignerInfo->AuthAttrs.cAttr == 2) ? 1 : 0;
|
|
}
|
|
else
|
|
{
|
|
fEqual &= (pSignerInfo->AuthAttrs.cAttr == 0) ? 1 : 0;
|
|
}
|
|
|
|
// fEqual &= fInnerNonData
|
|
// ? (2 == pSignerInfo->AuthAttrs.cAttr)
|
|
// : (0 == pSignerInfo->AuthAttrs.cAttr);
|
|
}
|
|
if (!fAuthAttr || fCountersign)
|
|
fEqual &= (0 == pSignerInfo->UnauthAttrs.cAttr);
|
|
if (!fEqual) {
|
|
PrintError("GetSignerInfoAndVerify::Bad SignerInfo");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
VerifyCerts(hMsg);
|
|
|
|
// Get crypt provider's public signature key. It will be used as the
|
|
// signer's public key
|
|
cbSignerPublicKeyData = sizeof(SignerPublicKeyData.Data);
|
|
memset(SignerPublicKeyData.Data, 0, cbSignerPublicKeyData);
|
|
hVerifyProv = hCryptProv;
|
|
#ifdef CMS_PKCS7
|
|
if (fMultiSigner) {
|
|
if (dwSrcIndex != 0)
|
|
hVerifyProv = hMultiSignerCryptProv;
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
if (fNoSignature) {
|
|
CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA Para;
|
|
|
|
memset(&Para, 0, sizeof(Para));
|
|
Para.cbSize = sizeof(Para);
|
|
// Para.hCryptProv =
|
|
Para.dwSignerIndex = dwSignerIndex;
|
|
Para.dwSignerType = CMSG_VERIFY_SIGNER_NULL;
|
|
// Para.pvSigner =
|
|
|
|
fResult = CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE_EX,
|
|
&Para
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"GetSignerInfoAndVerify::CryptMsgControl(CMSG_VERIFY_SIGNER_NULL)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
goto CommonReturn;
|
|
}
|
|
|
|
CryptExportPublicKeyInfo(
|
|
hVerifyProv,
|
|
AT_SIGNATURE,
|
|
X509_ASN_ENCODING,
|
|
(PCERT_PUBLIC_KEY_INFO) SignerPublicKeyData.Data,
|
|
&cbSignerPublicKeyData);
|
|
|
|
pSignerCertInfo->SubjectPublicKeyInfo =
|
|
*((PCERT_PUBLIC_KEY_INFO) SignerPublicKeyData.Data);
|
|
|
|
fResult = CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE,
|
|
pSignerCertInfo
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"GetSignerInfoAndVerify::CryptMsgControl(CMSG_CTRL_VERIFY_SIGNATURE)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
// Modify public key. Verify should fail.
|
|
XORBitBlob(&pSignerCertInfo->SubjectPublicKeyInfo.PublicKey);
|
|
fResult = CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE,
|
|
pSignerCertInfo
|
|
);
|
|
if (fResult)
|
|
printf("GetSignerInfoAndVerify::CryptMsgControl(CMSG_CTRL_VERIFY_SIGNATURE) failed => verified with bad public key");
|
|
XORBitBlob(&pSignerCertInfo->SubjectPublicKeyInfo.PublicKey);
|
|
|
|
if (!fCertInfoKeyId) {
|
|
// Modify serial number. Verify should fail.
|
|
XORBlob(&pSignerCertInfo->SerialNumber);
|
|
fResult = CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE,
|
|
pSignerCertInfo
|
|
);
|
|
if (fResult)
|
|
printf("GetSignerInfoAndVerify::CryptMsgControl(CMSG_CTRL_VERIFY_SIGNATURE) failed => verified with bad serial number");
|
|
XORBlob(&pSignerCertInfo->SerialNumber);
|
|
|
|
// Modify issuer. Verify should fail.
|
|
XORBlob(&pSignerCertInfo->Issuer);
|
|
fResult = CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE,
|
|
pSignerCertInfo
|
|
);
|
|
if (fResult)
|
|
printf("GetSignerInfoAndVerify::CryptMsgControl(CMSG_CTRL_VERIFY_SIGNATURE) failed => verified with bad issuer");
|
|
XORBlob(&pSignerCertInfo->Issuer);
|
|
}
|
|
fResult = TRUE;
|
|
#endif // CMS_PKCS7
|
|
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
|
|
CommonReturn:
|
|
TestFree(pSignerCertInfo);
|
|
TestFree(pSignerInfo);
|
|
*pdwSrcIndex = dwSrcIndex;
|
|
return fResult;
|
|
}
|
|
|
|
BOOL NamedSignerVerify(IN HCRYPTMSG hMsg, IN BOOL fInnerNonData)
|
|
{
|
|
BOOL fResult;
|
|
|
|
#ifdef CMS_PKCS7
|
|
PCCERT_CHAIN_CONTEXT pChainContext = NULL;
|
|
CERT_CHAIN_PARA ChainPara;
|
|
CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA CtrlPara;
|
|
|
|
// Build a chain. This is necessary for DSA with public key algorithm
|
|
// parameter inheritance.
|
|
|
|
memset(&ChainPara, 0, sizeof(ChainPara));
|
|
ChainPara.cbSize = sizeof(ChainPara);
|
|
if (!CertGetCertificateChain(
|
|
NULL, // hChainEngine
|
|
pNamedSigner,
|
|
NULL, // pTime
|
|
hSignerStore,
|
|
&ChainPara,
|
|
CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL,
|
|
NULL, // pvReserved
|
|
&pChainContext
|
|
)) {
|
|
PrintLastError(
|
|
"NamedSignerVerify::CertGetCertificateChain");
|
|
return FALSE;
|
|
}
|
|
|
|
// Test that we can verify a certificate signature using a chain
|
|
if (2 <= pChainContext->rgpChain[0]->cElement) {
|
|
PCCERT_CONTEXT pIssuer =
|
|
pChainContext->rgpChain[0]->rgpElement[1]->pCertContext;
|
|
PCCERT_CHAIN_CONTEXT pIssuerChainContext = NULL;
|
|
|
|
if (!CertGetCertificateChain(
|
|
NULL, // hChainEngine
|
|
pIssuer,
|
|
NULL, // pTime
|
|
hSignerStore,
|
|
&ChainPara,
|
|
CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL,
|
|
NULL, // pvReserved
|
|
&pIssuerChainContext
|
|
)) {
|
|
PrintLastError(
|
|
"NamedSignerVerify::CertGetCertificateChain(Issuer)");
|
|
} else {
|
|
if (!CryptVerifyCertificateSignatureEx(
|
|
0, // hCryptProv
|
|
dwCertEncodingType,
|
|
CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
|
|
(void *) pNamedSigner,
|
|
CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN,
|
|
(void *) pIssuerChainContext,
|
|
0, // dwFlags
|
|
NULL // pvReserved
|
|
)) {
|
|
PrintLastError(
|
|
"NamedSignerVerify::CryptVerifyCertificateSignatureEx(Chain)");
|
|
}
|
|
CertFreeCertificateChain(pIssuerChainContext);
|
|
}
|
|
}
|
|
|
|
memset(&CtrlPara, 0, sizeof(CtrlPara));
|
|
CtrlPara.cbSize = sizeof(CtrlPara);
|
|
CtrlPara.hCryptProv = hNamedSignerCryptProv;
|
|
CtrlPara.dwSignerIndex = 0;
|
|
CtrlPara.dwSignerType = CMSG_VERIFY_SIGNER_CHAIN;
|
|
CtrlPara.pvSigner = (void *) pChainContext;
|
|
|
|
fResult = CryptMsgControl(
|
|
hMsg,
|
|
0,
|
|
CMSG_CTRL_VERIFY_SIGNATURE_EX,
|
|
&CtrlPara
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"NamedSignerVerify::CryptMsgControl(CMSG_CTRL_VERIFY_SIGNATURE_EX)");
|
|
}
|
|
|
|
CertFreeCertificateChain(pChainContext);
|
|
|
|
return fResult;
|
|
#else
|
|
fResult = CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE,
|
|
pNamedSigner->pCertInfo
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"NamedSignerVerify::CryptMsgControl(CMSG_CTRL_VERIFY_SIGNATURE)");
|
|
}
|
|
return fResult;
|
|
#endif // CMS_PKCS7
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get signer info and verify the signed message
|
|
//--------------------------------------------------------------------------
|
|
BOOL GetSignerInfoAndVerify(IN HCRYPTMSG hMsg, IN BOOL fInnerNonData)
|
|
{
|
|
BOOL fResult;
|
|
DWORD dwSrcIndex;
|
|
|
|
if (pNamedSigner)
|
|
fResult = NamedSignerVerify(hMsg, fInnerNonData);
|
|
else
|
|
fResult = GetSignerInfoAndVerify(hMsg, fInnerNonData, 0, &dwSrcIndex);
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fMultiSigner) {
|
|
DWORD dwSrcIndex1;
|
|
|
|
fResult &= GetSignerInfoAndVerify(hMsg, fInnerNonData, 1, &dwSrcIndex1);
|
|
if (fResult && dwSrcIndex == dwSrcIndex1)
|
|
PrintError("Multiple signer:: Didn't get different signers");
|
|
}
|
|
#endif // CMS_PKCS7
|
|
return fResult;
|
|
}
|
|
|
|
|
|
#ifdef CMS_PKCS7
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Allocate and get the CMSG_CMS_RECIPIENT_INFO_PARAM
|
|
// from the message
|
|
//--------------------------------------------------------------------------
|
|
PCMSG_CMS_RECIPIENT_INFO GetCmsRecipientFromMsg(
|
|
IN HCRYPTMSG hMsg,
|
|
IN DWORD dwIndex
|
|
)
|
|
{
|
|
PCMSG_CMS_RECIPIENT_INFO pRecipientInfo;
|
|
DWORD cbData;
|
|
|
|
if (!TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_CMS_RECIPIENT_INFO_PARAM,
|
|
dwIndex,
|
|
(PBYTE *)&pRecipientInfo,
|
|
&cbData))
|
|
return NULL;
|
|
|
|
return pRecipientInfo;
|
|
}
|
|
|
|
BOOL blobcmp(
|
|
IN PCRYPT_DATA_BLOB pBlob1,
|
|
IN PCRYPT_DATA_BLOB pBlob2
|
|
)
|
|
{
|
|
if (pBlob1->cbData != pBlob2->cbData)
|
|
return FALSE;
|
|
else if (0 == pBlob1->cbData)
|
|
return TRUE;
|
|
else if (0 == memcmp(pBlob1->pbData, pBlob2->pbData, pBlob1->cbData))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL bitblobcmp(
|
|
IN PCRYPT_BIT_BLOB pBlob1,
|
|
IN PCRYPT_BIT_BLOB pBlob2
|
|
)
|
|
{
|
|
if (pBlob1->cbData != pBlob2->cbData)
|
|
return FALSE;
|
|
else if (0 == pBlob1->cbData)
|
|
return TRUE;
|
|
else if (0 == memcmp(pBlob1->pbData, pBlob2->pbData, pBlob1->cbData))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get CMS Recipient info and decrypt the message.
|
|
//--------------------------------------------------------------------------
|
|
BOOL GetCmsRecipientInfoAndDecrypt(IN HCRYPTMSG hMsg)
|
|
{
|
|
BOOL fResult;
|
|
PCMSG_CMS_RECIPIENT_INFO pRecipientInfo = NULL;
|
|
DWORD cRecipient;
|
|
DWORD cbData;
|
|
DWORD dwIndex;
|
|
|
|
// Get # of CMS recipients in the message.
|
|
cbData = sizeof(cRecipient);
|
|
cRecipient = 0;
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CMS_RECIPIENT_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cRecipient,
|
|
&cbData
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::CryptMsgGetParam(CMSG_CMS_RECIPIENT_COUNT_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
if (!TCM_CheckGetParam(
|
|
hMsg,
|
|
CMSG_CMS_RECIPIENT_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cRecipient,
|
|
cbData))
|
|
goto CheckGetCmsRecipientCountError;
|
|
if (cRecipient != cCmsRecipients) {
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::cRecipient != cCmsRecipients");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
// Get all the recipients and verify
|
|
for (dwIndex = 0; dwIndex < cRecipient; dwIndex++) {
|
|
pRecipientInfo = GetCmsRecipientFromMsg(
|
|
hMsg,
|
|
dwIndex
|
|
);
|
|
|
|
if (pRecipientInfo == NULL) {
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::CryptMsgGetParam(CMSG_CMS_RECIPIENT_INFO_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (pRecipientInfo->dwRecipientChoice !=
|
|
rgCmsRecipient[dwIndex].dwRecipientChoice) {
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad RecipientChoice");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
switch (pRecipientInfo->dwRecipientChoice) {
|
|
case CMSG_KEY_TRANS_RECIPIENT:
|
|
{
|
|
PCMSG_KEY_TRANS_RECIPIENT_INFO pDecode =
|
|
pRecipientInfo->pKeyTrans;
|
|
PCMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO pEncode =
|
|
&rgKeyTrans[dwIndex];
|
|
|
|
if (0 != strcmp(pDecode->KeyEncryptionAlgorithm.pszObjId,
|
|
pEncode->KeyEncryptionAlgorithm.pszObjId))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad KeyEncryptionAlgorithm");
|
|
if (pDecode->RecipientId.dwIdChoice !=
|
|
pEncode->RecipientId.dwIdChoice)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad dwIdChoice");
|
|
else {
|
|
switch (pDecode->RecipientId.dwIdChoice) {
|
|
case CERT_ID_ISSUER_SERIAL_NUMBER:
|
|
{
|
|
PCERT_ISSUER_SERIAL_NUMBER pDecodeRid =
|
|
&pDecode->RecipientId.IssuerSerialNumber;
|
|
PCERT_ISSUER_SERIAL_NUMBER pEncodeRid =
|
|
&pEncode->RecipientId.IssuerSerialNumber;
|
|
|
|
if (CMSG_KEY_TRANS_PKCS_1_5_VERSION !=
|
|
pDecode->dwVersion)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad KeyTransPkcsVersion");
|
|
if (!blobcmp(&pDecodeRid->Issuer,
|
|
&pEncodeRid->Issuer) ||
|
|
!blobcmp(&pDecodeRid->SerialNumber,
|
|
&pEncodeRid->SerialNumber))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad IssuerSerialNumber");
|
|
}
|
|
break;
|
|
case CERT_ID_KEY_IDENTIFIER:
|
|
{
|
|
PCRYPT_HASH_BLOB pDecodeRid =
|
|
&pDecode->RecipientId.KeyId;
|
|
PCRYPT_HASH_BLOB pEncodeRid =
|
|
&pEncode->RecipientId.KeyId;
|
|
|
|
if (CMSG_KEY_TRANS_CMS_VERSION !=
|
|
pDecode->dwVersion)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad KeyTransCmsVersion");
|
|
if (!blobcmp(pDecodeRid, pEncodeRid))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad KeyId");
|
|
}
|
|
break;
|
|
default:
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad dwIdChoice");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case CMSG_KEY_AGREE_RECIPIENT:
|
|
{
|
|
PCMSG_KEY_AGREE_RECIPIENT_INFO pDecode =
|
|
pRecipientInfo->pKeyAgree;
|
|
PCMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO pEncode =
|
|
&rgKeyAgree[dwIndex];
|
|
|
|
if (CMSG_KEY_AGREE_VERSION != pDecode->dwVersion)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad KeyAgreePkcsVersion");
|
|
|
|
if (!blobcmp(&pEncode->UserKeyingMaterial,
|
|
&pDecode->UserKeyingMaterial))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad UserKeyingMaterial");
|
|
|
|
if (0 != strcmp(pDecode->KeyEncryptionAlgorithm.pszObjId,
|
|
pEncode->KeyEncryptionAlgorithm.pszObjId))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad KeyEncryptionAlgorithm");
|
|
|
|
#if 0
|
|
if (0 == _stricmp(pszEncryptName, "rc2")) {
|
|
if (0 == pDecode->KeyEncryptionAlgorithm.Parameters.cbData)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Missing rc2 KeyEncryptionAlgorithm Parameters");
|
|
else {
|
|
int iVersion;
|
|
DWORD cbData;
|
|
|
|
cbData = sizeof(iVersion);
|
|
if (!CryptDecodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
X509_INTEGER,
|
|
pDecode->KeyEncryptionAlgorithm.Parameters.pbData,
|
|
pDecode->KeyEncryptionAlgorithm.Parameters.cbData,
|
|
0, // dwFlags
|
|
&iVersion,
|
|
&cbData))
|
|
PrintLastError("GetCmsRecipientInfoAndDecrypt::CryptDecodeObject(rc2 KeyEncryptionAlgorithm Parameters)");
|
|
else {
|
|
DWORD dwEncodeBitLen;
|
|
DWORD dwDecodeBitLen;
|
|
|
|
dwEncodeBitLen = dwEncryptBitLen;
|
|
if (0 == dwEncodeBitLen)
|
|
dwEncodeBitLen = 40;
|
|
|
|
switch (iVersion) {
|
|
case CRYPT_RC2_40BIT_VERSION:
|
|
dwDecodeBitLen = 40;
|
|
break;
|
|
case CRYPT_RC2_56BIT_VERSION:
|
|
dwDecodeBitLen = 56;
|
|
break;
|
|
case CRYPT_RC2_64BIT_VERSION:
|
|
dwDecodeBitLen = 64;
|
|
break;
|
|
case CRYPT_RC2_128BIT_VERSION:
|
|
dwDecodeBitLen = 128;
|
|
break;
|
|
default:
|
|
dwDecodeBitLen = 0;
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad Decode BitLen");
|
|
}
|
|
if (dwDecodeBitLen != dwEncodeBitLen)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Decode != Encode BitLen");
|
|
}
|
|
}
|
|
} else {
|
|
BYTE rgbNull[] = {0x5, 0x0};
|
|
CRYPT_DATA_BLOB NullBlob = {sizeof(rgbNull), rgbNull};
|
|
|
|
if (!blobcmp(&NullBlob,
|
|
&pDecode->KeyEncryptionAlgorithm.Parameters))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Expected NULL KeyEncryptionAlgorithm Parameters");
|
|
}
|
|
#endif
|
|
|
|
if (CMSG_KEY_AGREE_ORIGINATOR_PUBLIC_KEY !=
|
|
pDecode->dwOriginatorChoice)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad dwOriginatorChoice");
|
|
else {
|
|
if (0 != strcmp(
|
|
pDecode->OriginatorPublicKeyInfo.Algorithm.pszObjId,
|
|
pEncode->pEphemeralAlgorithm->pszObjId))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad Originator public key Algorithm");
|
|
if (0 != pDecode->OriginatorPublicKeyInfo.Algorithm.Parameters.cbData)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Not NO Originator public key Parameters");
|
|
}
|
|
|
|
if (pEncode->cRecipientEncryptedKeys !=
|
|
pDecode->cRecipientEncryptedKeys)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad Encrypted Key Agree Count");
|
|
else {
|
|
DWORD i;
|
|
for (i = 0; i < pEncode->cRecipientEncryptedKeys; i++) {
|
|
PCMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO pEncodeKey =
|
|
pEncode->rgpRecipientEncryptedKeys[i];
|
|
|
|
PCMSG_RECIPIENT_ENCRYPTED_KEY_INFO pDecodeKey =
|
|
pDecode->rgpRecipientEncryptedKeys[i];
|
|
|
|
if (pDecodeKey->RecipientId.dwIdChoice !=
|
|
pEncodeKey->RecipientId.dwIdChoice)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad dwIdChoice");
|
|
else {
|
|
switch (pDecodeKey->RecipientId.dwIdChoice) {
|
|
case CERT_ID_ISSUER_SERIAL_NUMBER:
|
|
{
|
|
PCERT_ISSUER_SERIAL_NUMBER pDecodeRid =
|
|
&pDecodeKey->RecipientId.IssuerSerialNumber;
|
|
PCERT_ISSUER_SERIAL_NUMBER pEncodeRid =
|
|
&pEncodeKey->RecipientId.IssuerSerialNumber;
|
|
|
|
if (!blobcmp(&pDecodeRid->Issuer,
|
|
&pEncodeRid->Issuer) ||
|
|
!blobcmp(&pDecodeRid->SerialNumber,
|
|
&pEncodeRid->SerialNumber))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad IssuerSerialNumber");
|
|
}
|
|
break;
|
|
case CERT_ID_KEY_IDENTIFIER:
|
|
{
|
|
PCRYPT_HASH_BLOB pDecodeRid =
|
|
&pDecodeKey->RecipientId.KeyId;
|
|
PCRYPT_HASH_BLOB pEncodeRid =
|
|
&pEncodeKey->RecipientId.KeyId;
|
|
|
|
if (!blobcmp(pDecodeRid, pEncodeRid))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad KeyId");
|
|
|
|
if (0 != CompareFileTime(&pDecodeKey->Date,
|
|
&pEncodeKey->Date))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad Date");
|
|
|
|
if (NULL == pEncodeKey->pOtherAttr) {
|
|
if (NULL != pDecodeKey->pOtherAttr)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Unexpected OtherAttr");
|
|
} else if (NULL == pDecodeKey->pOtherAttr) {
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Missing OtherAttr");
|
|
} else {
|
|
PCRYPT_ATTRIBUTE_TYPE_VALUE
|
|
pDecodeOther =
|
|
pDecodeKey->pOtherAttr;
|
|
PCRYPT_ATTRIBUTE_TYPE_VALUE
|
|
pEncodeOther =
|
|
pEncodeKey->pOtherAttr;
|
|
|
|
if (0 != strcmp(pDecodeOther->pszObjId,
|
|
pEncodeOther->pszObjId))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad OtherAttr OID");
|
|
if (!blobcmp(&pDecodeOther->Value, &pEncodeOther->Value))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad OtherAttr Value");
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad dwIdChoice");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case CMSG_MAIL_LIST_RECIPIENT:
|
|
{
|
|
PCMSG_MAIL_LIST_RECIPIENT_INFO pDecode =
|
|
pRecipientInfo->pMailList;
|
|
PCMSG_MAIL_LIST_RECIPIENT_ENCODE_INFO pEncode =
|
|
&rgMailList[dwIndex];
|
|
|
|
if (CMSG_MAIL_LIST_VERSION != pDecode->dwVersion)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad MailListVersion");
|
|
{
|
|
PCRYPT_HASH_BLOB pDecodeKeyId =
|
|
&pDecode->KeyId;
|
|
PCRYPT_HASH_BLOB pEncodeKeyId =
|
|
&pEncode->KeyId;
|
|
|
|
if (!blobcmp(pDecodeKeyId, pEncodeKeyId))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad KeyId");
|
|
}
|
|
if (0 != strcmp(pDecode->KeyEncryptionAlgorithm.pszObjId,
|
|
pEncode->KeyEncryptionAlgorithm.pszObjId))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad KeyEncryptionAlgorithm");
|
|
if (0 == _stricmp(pszEncryptName, "rc2")) {
|
|
if (0 == pDecode->KeyEncryptionAlgorithm.Parameters.cbData)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Missing rc2 KeyEncryptionAlgorithm Parameters");
|
|
else {
|
|
int iVersion;
|
|
DWORD cbData;
|
|
|
|
cbData = sizeof(iVersion);
|
|
if (!CryptDecodeObject(
|
|
PKCS_7_ASN_ENCODING,
|
|
X509_INTEGER,
|
|
pDecode->KeyEncryptionAlgorithm.Parameters.pbData,
|
|
pDecode->KeyEncryptionAlgorithm.Parameters.cbData,
|
|
0, // dwFlags
|
|
&iVersion,
|
|
&cbData))
|
|
PrintLastError("GetCmsRecipientInfoAndDecrypt::CryptDecodeObject(rc2 KeyEncryptionAlgorithm Parameters)");
|
|
else {
|
|
DWORD dwEncodeBitLen;
|
|
DWORD dwDecodeBitLen;
|
|
|
|
dwEncodeBitLen = dwEncryptBitLen;
|
|
if (0 == dwEncodeBitLen)
|
|
dwEncodeBitLen = 40;
|
|
|
|
switch (iVersion) {
|
|
case CRYPT_RC2_40BIT_VERSION:
|
|
dwDecodeBitLen = 40;
|
|
break;
|
|
case CRYPT_RC2_56BIT_VERSION:
|
|
dwDecodeBitLen = 56;
|
|
break;
|
|
case CRYPT_RC2_64BIT_VERSION:
|
|
dwDecodeBitLen = 64;
|
|
break;
|
|
case CRYPT_RC2_128BIT_VERSION:
|
|
dwDecodeBitLen = 128;
|
|
break;
|
|
default:
|
|
dwDecodeBitLen = 0;
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad Decode BitLen");
|
|
}
|
|
if (dwDecodeBitLen != dwEncodeBitLen)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Decode != Encode BitLen");
|
|
}
|
|
}
|
|
} else {
|
|
if (0 != pDecode->KeyEncryptionAlgorithm.Parameters.cbData)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Expected NO, NULL KeyEncryptionAlgorithm Parameters");
|
|
}
|
|
|
|
if (0 != CompareFileTime(&pDecode->Date, &pEncode->Date))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad Date");
|
|
|
|
if (NULL == pEncode->pOtherAttr) {
|
|
if (NULL != pDecode->pOtherAttr)
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Unexpected OtherAttr");
|
|
} else if (NULL == pDecode->pOtherAttr) {
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Missing OtherAttr");
|
|
} else {
|
|
PCRYPT_ATTRIBUTE_TYPE_VALUE pDecodeOther =
|
|
pDecode->pOtherAttr;
|
|
PCRYPT_ATTRIBUTE_TYPE_VALUE pEncodeOther =
|
|
pEncode->pOtherAttr;
|
|
|
|
if (0 != strcmp(pDecodeOther->pszObjId,
|
|
pEncodeOther->pszObjId))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad OtherAttr OID");
|
|
if (!blobcmp(&pDecodeOther->Value, &pEncodeOther->Value))
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad OtherAttr Value");
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
PrintError( "GetCmsRecipientInfoAndDecrypt::Bad RecipientChoice");
|
|
goto ErrorReturn;
|
|
|
|
}
|
|
|
|
TestFree(pRecipientInfo);
|
|
pRecipientInfo = NULL;
|
|
}
|
|
|
|
pRecipientInfo = GetCmsRecipientFromMsg(hMsg, cRecipient -1);
|
|
if (pRecipientInfo == NULL) {
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::CryptMsgGetParam(CMSG_CMS_RECIPIENT_INFO_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
switch (pRecipientInfo->dwRecipientChoice) {
|
|
case CMSG_KEY_TRANS_RECIPIENT:
|
|
{
|
|
CMSG_CTRL_KEY_TRANS_DECRYPT_PARA DecryptPara;
|
|
DWORD dwDecryptIndex;
|
|
|
|
DecryptPara.cbSize = sizeof(DecryptPara);
|
|
DecryptPara.hCryptProv = hCryptProv;
|
|
DecryptPara.dwKeySpec = 0;
|
|
DecryptPara.pKeyTrans = pRecipientInfo->pKeyTrans;
|
|
DecryptPara.dwRecipientIndex = cRecipient -1;
|
|
fResult = CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_KEY_TRANS_DECRYPT,
|
|
&DecryptPara
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::CryptMsgControl(CMSG_CTRL_KEY_TRANS_DECRYPT)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
cbData = sizeof(dwDecryptIndex);
|
|
dwDecryptIndex = 0;
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CMS_RECIPIENT_INDEX_PARAM,
|
|
0, // dwIndex
|
|
&dwDecryptIndex,
|
|
&cbData
|
|
);
|
|
if (!fResult)
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::CryptMsgGetParam(CMSG_CMS_RECIPIENT_INDEX_PARAM)");
|
|
else if (dwDecryptIndex != cRecipient -1)
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::Bad CMS decrypt Index");
|
|
|
|
cbData = sizeof(dwDecryptIndex);
|
|
dwDecryptIndex = 0;
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_RECIPIENT_INDEX_PARAM,
|
|
0, // dwIndex
|
|
&dwDecryptIndex,
|
|
&cbData
|
|
);
|
|
if (!fResult)
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::CryptMsgGetParam(CMSG_RECIPIENT_INDEX_PARAM)");
|
|
else if (dwDecryptIndex != PkcsRecipientCount -1)
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::Bad PKCS decrypt Index");
|
|
}
|
|
break;
|
|
case CMSG_KEY_AGREE_RECIPIENT:
|
|
{
|
|
CMSG_CTRL_KEY_AGREE_DECRYPT_PARA DecryptPara;
|
|
DWORD dwDecryptIndex;
|
|
|
|
DecryptPara.cbSize = sizeof(DecryptPara);
|
|
DecryptPara.hCryptProv = hKeyAgreeProv;
|
|
DecryptPara.dwKeySpec = AT_KEYEXCHANGE;
|
|
DecryptPara.pKeyAgree = pRecipientInfo->pKeyAgree;
|
|
DecryptPara.dwRecipientIndex = cRecipient -1;
|
|
DecryptPara.dwRecipientEncryptedKeyIndex =
|
|
pRecipientInfo->pKeyAgree->cRecipientEncryptedKeys -1;
|
|
DecryptPara.OriginatorPublicKey =
|
|
pRecipientInfo->pKeyAgree->OriginatorPublicKeyInfo.PublicKey;
|
|
fResult = CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_KEY_AGREE_DECRYPT,
|
|
&DecryptPara
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::CryptMsgControl(CMSG_CTRL_KEY_AGREE_DECRYPT)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
cbData = sizeof(dwDecryptIndex);
|
|
dwDecryptIndex = 0;
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CMS_RECIPIENT_INDEX_PARAM,
|
|
0, // dwIndex
|
|
&dwDecryptIndex,
|
|
&cbData
|
|
);
|
|
if (!fResult)
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::CryptMsgGetParam(CMSG_CMS_RECIPIENT_INDEX_PARAM)");
|
|
else if (dwDecryptIndex != cRecipient -1)
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::Bad CMS decrypt Index");
|
|
|
|
cbData = sizeof(dwDecryptIndex);
|
|
dwDecryptIndex = 0;
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CMS_RECIPIENT_ENCRYPTED_KEY_INDEX_PARAM,
|
|
0, // dwIndex
|
|
&dwDecryptIndex,
|
|
&cbData
|
|
);
|
|
if (!fResult)
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::CryptMsgGetParam(CMSG_CMS_RECIPIENT_ENCRYPTED_KEY_INDEX_PARAM)");
|
|
else if (dwDecryptIndex != DecryptPara.dwRecipientEncryptedKeyIndex)
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::Bad CMS encrypted key Index");
|
|
}
|
|
break;
|
|
case CMSG_MAIL_LIST_RECIPIENT:
|
|
{
|
|
CMSG_CTRL_MAIL_LIST_DECRYPT_PARA DecryptPara;
|
|
DWORD dwDecryptIndex;
|
|
|
|
DecryptPara.cbSize = sizeof(DecryptPara);
|
|
DecryptPara.pMailList = pRecipientInfo->pMailList;
|
|
DecryptPara.dwRecipientIndex = cRecipient -1;
|
|
DecryptPara.dwKeyChoice = CMSG_MAIL_LIST_HANDLE_KEY_CHOICE;
|
|
if (fRecipientProv)
|
|
DecryptPara.hCryptProv = GetCryptProv();
|
|
else
|
|
DecryptPara.hCryptProv = hCryptProv;
|
|
|
|
DecryptPara.hKeyEncryptionKey = GenerateMailListKey(
|
|
DecryptPara.hCryptProv,
|
|
&DecryptPara.pMailList->KeyId
|
|
);
|
|
|
|
printf("Decrypting using MailList recipient\n");
|
|
fResult = CryptMsgControl(
|
|
hMsg,
|
|
fRecipientProv ? CMSG_CRYPT_RELEASE_CONTEXT_FLAG : 0,
|
|
CMSG_CTRL_MAIL_LIST_DECRYPT,
|
|
&DecryptPara
|
|
);
|
|
if (DecryptPara.hKeyEncryptionKey) {
|
|
DWORD dwErr = GetLastError();
|
|
CryptDestroyKey(DecryptPara.hKeyEncryptionKey);
|
|
SetLastError(dwErr);
|
|
}
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::CryptMsgControl(CMSG_CTRL_MAIL_LIST_DECRYPT)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
cbData = sizeof(dwDecryptIndex);
|
|
dwDecryptIndex = 0;
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CMS_RECIPIENT_INDEX_PARAM,
|
|
0, // dwIndex
|
|
&dwDecryptIndex,
|
|
&cbData
|
|
);
|
|
if (!fResult)
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::CryptMsgGetParam(CMSG_CMS_RECIPIENT_INDEX_PARAM)");
|
|
else if (dwDecryptIndex != cRecipient -1)
|
|
PrintLastError(
|
|
"GetCmsRecipientInfoAndDecrypt::Bad CMS decrypt Index");
|
|
}
|
|
break;
|
|
default:
|
|
PrintError("GetCmsRecipientInfoAndDecrypt::Bad RecipientChoice");
|
|
goto ErrorReturn;
|
|
|
|
}
|
|
|
|
CommonReturn:
|
|
TestFree(pRecipientInfo);
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
PRINT_ERROR(GetCmsRecipientInfoAndDecrypt,CheckGetCmsRecipientCountError)
|
|
}
|
|
|
|
BOOL VerifyUnprotectedAttr(IN HCRYPTMSG hMsg)
|
|
{
|
|
BOOL fResult;
|
|
DWORD cbAttrs;
|
|
DWORD i;
|
|
PCRYPT_ATTRIBUTES pAttrs = NULL;
|
|
PCRYPT_ATTRIBUTE patr1;
|
|
PCRYPT_ATTRIBUTE patr2;
|
|
|
|
if (!TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_UNPROTECTED_ATTR_PARAM,
|
|
0, // dwIndex
|
|
(PBYTE *) &pAttrs,
|
|
&cbAttrs)) {
|
|
goto GetAttrError;
|
|
}
|
|
|
|
if (pAttrs->cAttr != EnvelopedMsgEncodeInfo.cUnprotectedAttr)
|
|
goto AttrCountError;
|
|
|
|
|
|
for (i=pAttrs->cAttr,
|
|
patr1=EnvelopedMsgEncodeInfo.rgUnprotectedAttr,
|
|
patr2=pAttrs->rgAttr;
|
|
i>0;
|
|
i--, patr1++, patr2++) {
|
|
if (!EqualAttribute( patr1, patr2))
|
|
goto AttrValueError;
|
|
}
|
|
|
|
fResult = TRUE;
|
|
CommonReturn:
|
|
TestFree(pAttrs);
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
|
|
PRINT_ERROR(VerifyUnprotectedAttr,GetAttrError)
|
|
PRINT_ERROR(VerifyUnprotectedAttr,AttrCountError)
|
|
PRINT_ERROR(VerifyUnprotectedAttr,AttrValueError)
|
|
}
|
|
|
|
#endif // CMS_PKCS7
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get recipient info and decrypt the message.
|
|
//--------------------------------------------------------------------------
|
|
BOOL GetRecipientInfoAndDecrypt(IN HCRYPTMSG hMsg)
|
|
{
|
|
BOOL fResult;
|
|
PCERT_INFO pRecipientInfo = NULL;
|
|
DWORD cRecipient;
|
|
DWORD cbData;
|
|
DWORD dwIndex;
|
|
CMSG_CTRL_DECRYPT_PARA DecryptPara;
|
|
#ifdef CMS_PKCS7
|
|
BYTE *pbCiphertext = NULL;
|
|
DWORD cbCiphertext;
|
|
#endif // CMS_PKCS7
|
|
DWORD cKeyIdRecipient;
|
|
|
|
// Get # of recipients in the message.
|
|
cbData = sizeof(cRecipient);
|
|
cRecipient = 0;
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_RECIPIENT_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cRecipient,
|
|
&cbData
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"GetRecipientInfoAndDecrypt::CryptMsgGetParam(CMSG_RECIPIENT_COUNT_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
if (!TCM_CheckGetParam(
|
|
hMsg,
|
|
CMSG_RECIPIENT_COUNT_PARAM,
|
|
0, // dwIndex
|
|
&cRecipient,
|
|
cbData))
|
|
goto CheckGetRecipientCountError;
|
|
if (fNoRecipients
|
|
#ifdef CMS_PKCS7
|
|
|| ((fMailList || fKeyAgree) && !fKeyTrans)
|
|
#endif // CMS_PKCS7
|
|
) {
|
|
if (cRecipient != 0) {
|
|
PrintError("GetRecipientInfoAndDecrypt::cRecipient != 0");
|
|
goto ErrorReturn;
|
|
}
|
|
} else {
|
|
if (cRecipient != PkcsRecipientCount) {
|
|
PrintError("GetRecipientInfoAndDecrypt::cRecipient != PkcsRecipientCount");
|
|
goto ErrorReturn;
|
|
}
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fKeyTrans && fRecipientKeyId && !fNoRecipients) {
|
|
// The first RECIPIENT_COUNT recipients should be KeyId recipients
|
|
cKeyIdRecipient = RECIPIENT_COUNT;
|
|
|
|
// Get all the KeyId recipients and verify
|
|
for (dwIndex = 0; dwIndex < RECIPIENT_COUNT; dwIndex++) {
|
|
// Allocate and get the CERT_INFO containing the Special
|
|
// KeyId RecipientId
|
|
PCERT_NAME_INFO pKeyIdName = NULL;
|
|
DWORD cbKeyIdName;
|
|
CRYPT_HASH_BLOB KeyId;
|
|
|
|
pRecipientInfo = GetCertIdFromMsg(
|
|
hMsg,
|
|
CMSG_RECIPIENT_INFO_PARAM,
|
|
dwIndex
|
|
);
|
|
|
|
if (pRecipientInfo == NULL) {
|
|
PrintLastError(
|
|
"GetRecipientInfoAndDecrypt::CryptMsgGetParam(KEYID CMSG_RECIPIENT_INFO_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
if (pRecipientInfo->SerialNumber.cbData != 1 ||
|
|
*pRecipientInfo->SerialNumber.pbData != 0)
|
|
PrintError("GetRecipientInfoAndDecrypt::Bad KeyId SerialNumber");
|
|
|
|
// Decode the Issuer Name. It should contain the special KeyId
|
|
// RDN
|
|
|
|
if (AllocAndDecodeObject(
|
|
X509_NAME,
|
|
pRecipientInfo->Issuer.pbData,
|
|
pRecipientInfo->Issuer.cbData,
|
|
(void **) &pKeyIdName,
|
|
&cbKeyIdName
|
|
)) {
|
|
|
|
if (pKeyIdName->cRDN != 1 ||
|
|
pKeyIdName->rgRDN[0].cRDNAttr != 1)
|
|
PrintError("GetRecipientInfoAndDecrypt::Bad KeyId Issuer");
|
|
else {
|
|
PCERT_RDN_ATTR pAttr = pKeyIdName->rgRDN[0].rgRDNAttr;
|
|
|
|
if (0 != strcmp(pAttr->pszObjId, szOID_KEYID_RDN) ||
|
|
pAttr->dwValueType != CERT_RDN_OCTET_STRING ||
|
|
pAttr->Value.cbData !=
|
|
strlen(rgpszRecipientIssuerFileName[dwIndex]) ||
|
|
0 != memcmp(pAttr->Value.pbData,
|
|
rgpszRecipientIssuerFileName[dwIndex],
|
|
pAttr->Value.cbData))
|
|
PrintError("GetRecipientInfoAndDecrypt::Bad KeyId Issuer");
|
|
}
|
|
|
|
TestFree(pKeyIdName);
|
|
}
|
|
|
|
if (!Asn1UtilExtractKeyIdFromCertInfo(
|
|
pRecipientInfo,
|
|
&KeyId))
|
|
PrintError("GetRecipientInfoAndDecrypt::Asn1UtilExtractKeyIdFromCertInfo failed");
|
|
else if (KeyId.cbData !=
|
|
strlen(rgpszRecipientIssuerFileName[dwIndex]) ||
|
|
0 != memcmp(KeyId.pbData,
|
|
rgpszRecipientIssuerFileName[dwIndex], KeyId.cbData))
|
|
PrintError("GetRecipientInfoAndDecrypt::Asn1UtilExtractKeyIdFromCertInfo compare failed");
|
|
|
|
TestFree(pRecipientInfo);
|
|
pRecipientInfo = NULL;
|
|
}
|
|
} else
|
|
#endif // CMS_PKCS7
|
|
cKeyIdRecipient = 0;
|
|
|
|
// Get all the non KeyId recipients and verify
|
|
for (dwIndex = 0; dwIndex < cRecipient - cKeyIdRecipient; dwIndex++) {
|
|
// Allocate and get the CERT_INFO containing the RecipientId
|
|
// (Issuer and SerialNumber)
|
|
|
|
#ifdef CMS_PKCS7
|
|
CRYPT_HASH_BLOB KeyId;
|
|
BOOL fExtractKeyId;
|
|
#endif // CMS_PKCS7
|
|
|
|
pRecipientInfo = GetCertIdFromMsg(
|
|
hMsg,
|
|
CMSG_RECIPIENT_INFO_PARAM,
|
|
cKeyIdRecipient + dwIndex
|
|
);
|
|
|
|
if (pRecipientInfo == NULL) {
|
|
PrintLastError(
|
|
"GetRecipientInfoAndDecrypt::CryptMsgGetParam(CMSG_RECIPIENT_INFO_PARAM)");
|
|
goto ErrorReturn;
|
|
}
|
|
if (pRecipientInfo->Issuer.cbData !=
|
|
rgRecipientCertInfo[dwIndex].Issuer.cbData ||
|
|
memcmp(pRecipientInfo->Issuer.pbData,
|
|
rgRecipientCertInfo[dwIndex].Issuer.pbData,
|
|
pRecipientInfo->Issuer.cbData) != 0 ||
|
|
pRecipientInfo->SerialNumber.cbData !=
|
|
rgRecipientCertInfo[dwIndex].SerialNumber.cbData ||
|
|
memcmp(pRecipientInfo->SerialNumber.pbData,
|
|
rgRecipientCertInfo[dwIndex].SerialNumber.pbData,
|
|
pRecipientInfo->SerialNumber.cbData) != 0) {
|
|
PrintError("GetRecipientInfoAndDecrypt::Bad RecipientInfo");
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
fExtractKeyId = Asn1UtilExtractKeyIdFromCertInfo(
|
|
pRecipientInfo,
|
|
&KeyId);
|
|
if (fCertInfoKeyId) {
|
|
if (!fExtractKeyId)
|
|
PrintError("GetRecipientInfoAndDecrypt::Asn1UtilExtractKeyIdFromCertInfo failed for CertInfoKeyId");
|
|
} else if (fExtractKeyId)
|
|
PrintError("GetRecipientInfoAndDecrypt::Asn1UtilExtractKeyIdFromCertInfo should have failed for nonKeyId");
|
|
#endif // CMS_PKCS7
|
|
|
|
TestFree(pRecipientInfo);
|
|
pRecipientInfo = NULL;
|
|
}
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (fOriginatorInfo)
|
|
VerifyCerts(hMsg);
|
|
|
|
if (fAuthAttr)
|
|
VerifyUnprotectedAttr(hMsg);
|
|
|
|
// Get ciphertext
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CONTENT_PARAM,
|
|
0, // dwIndex
|
|
NULL, // pvData
|
|
&cbCiphertext
|
|
);
|
|
if (!fResult)
|
|
PrintLastError("GetRecipientInfoAndDecrypt::CryptMsgGetParam(ciphertext length)");
|
|
else {
|
|
if (pbCiphertext = (BYTE *) TestAlloc(cbCiphertext)) {
|
|
fResult = CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CONTENT_PARAM,
|
|
0, // dwIndex
|
|
pbCiphertext,
|
|
&cbCiphertext
|
|
);
|
|
if (!fResult)
|
|
PrintLastError("GetRecipientInfoAndDecrypt::CryptMsgGetParam(ciphertext content)");
|
|
TestFree(pbCiphertext);
|
|
pbCiphertext = NULL;
|
|
}
|
|
}
|
|
|
|
if (fCmsRecipient) {
|
|
fResult = GetCmsRecipientInfoAndDecrypt(hMsg);
|
|
goto CommonReturn;
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
if (fNoRecipients) {
|
|
fResult = TRUE;
|
|
goto CommonReturn;
|
|
}
|
|
|
|
DecryptPara.cbSize = sizeof(DecryptPara);
|
|
DecryptPara.hCryptProv = hCryptProv;
|
|
DecryptPara.dwKeySpec = 0;
|
|
DecryptPara.dwRecipientIndex = RECIPIENT_COUNT -1;
|
|
fResult = CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_DECRYPT,
|
|
&DecryptPara
|
|
);
|
|
if (!fResult) {
|
|
PrintLastError(
|
|
"GetRecipientInfoAndDecrypt::CryptMsgControl(CMSG_CTRL_DECRYPT)");
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
goto CommonReturn;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
|
|
CommonReturn:
|
|
TestFree(pRecipientInfo);
|
|
|
|
return fResult;
|
|
PRINT_ERROR(GetRecipientInfoAndDecrypt,CheckGetRecipientCountError)
|
|
}
|
|
|
|
void CompareCertIdWithCertInfo(
|
|
IN PCERT_ID pCertId,
|
|
IN PCERT_INFO pCertInfo
|
|
)
|
|
{
|
|
BOOL fKeyId;
|
|
CRYPT_HASH_BLOB KeyId;
|
|
|
|
fKeyId = Asn1UtilExtractKeyIdFromCertInfo(pCertInfo, &KeyId);
|
|
switch(pCertId->dwIdChoice) {
|
|
case CERT_ID_ISSUER_SERIAL_NUMBER:
|
|
if (fKeyId)
|
|
printf("CompareCertIdWithCertInfo:: failed => bad IssuerSerialNumber choice\n");
|
|
else if (pCertInfo->Issuer.cbData !=
|
|
pCertId->IssuerSerialNumber.Issuer.cbData ||
|
|
0 != memcmp(pCertInfo->Issuer.pbData,
|
|
pCertId->IssuerSerialNumber.Issuer.pbData,
|
|
pCertInfo->Issuer.cbData) ||
|
|
pCertInfo->SerialNumber.cbData !=
|
|
pCertId->IssuerSerialNumber.SerialNumber.cbData ||
|
|
0 != memcmp(pCertInfo->SerialNumber.pbData,
|
|
pCertId->IssuerSerialNumber.SerialNumber.pbData,
|
|
pCertInfo->SerialNumber.cbData))
|
|
printf("CompareCertIdWithCertInfo:: failed => bad IssuerSerialNumber comparison\n");
|
|
break;
|
|
case CERT_ID_KEY_IDENTIFIER:
|
|
if (!fKeyId)
|
|
printf("CompareCertIdWithCertInfo:: failed => bad KeyId choice\n");
|
|
else if (KeyId.cbData != pCertId->KeyId.cbData ||
|
|
0 != memcmp(KeyId.pbData,
|
|
pCertId->KeyId.pbData,
|
|
KeyId.cbData))
|
|
printf("CompareCertIdWithCertInfo:: failed => bad KeyId comparison\n");
|
|
break;
|
|
default:
|
|
printf("CompareCertIdWithCertInfo:: failed => invalid dwIdChoice\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Allocate and get the CMSG_SIGNER_INFO_PARAM from the message
|
|
//--------------------------------------------------------------------------
|
|
PCMSG_SIGNER_INFO GetSignerInfoFromMsg(
|
|
IN HCRYPTMSG hMsg,
|
|
IN DWORD dwIndex
|
|
)
|
|
{
|
|
PCMSG_SIGNER_INFO psi;
|
|
DWORD cbData;
|
|
|
|
if (!TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_SIGNER_INFO_PARAM,
|
|
dwIndex,
|
|
(PBYTE *)&psi,
|
|
&cbData))
|
|
return NULL;
|
|
|
|
#ifdef CMS_PKCS7
|
|
PCMSG_CMS_SIGNER_INFO pCMSsi;
|
|
|
|
if (TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_CMS_SIGNER_INFO_PARAM,
|
|
dwIndex,
|
|
(PBYTE *)&pCMSsi,
|
|
&cbData)) {
|
|
CERT_INFO CertInfo;
|
|
CertInfo.Issuer = psi->Issuer;
|
|
CertInfo.SerialNumber = psi->SerialNumber;
|
|
CompareCertIdWithCertInfo(&pCMSsi->SignerId, &CertInfo);
|
|
TestFree(pCMSsi);
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
return psi;
|
|
}
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Allocate and get the CMSG_SIGNER_CERT_INFO_PARAM or CMSG_RECIPIENT_INFO_PARAM
|
|
// from the message
|
|
//--------------------------------------------------------------------------
|
|
PCERT_INFO GetCertIdFromMsg(
|
|
IN HCRYPTMSG hMsg,
|
|
IN DWORD dwParamType,
|
|
IN DWORD dwIndex
|
|
)
|
|
{
|
|
PCERT_INFO pCertId;
|
|
DWORD cbData;
|
|
|
|
if (!TCM_AllocGetParam(
|
|
hMsg,
|
|
dwParamType,
|
|
dwIndex,
|
|
(PBYTE *)&pCertId,
|
|
&cbData))
|
|
return NULL;
|
|
|
|
#ifdef CMS_PKCS7
|
|
if (CMSG_SIGNER_CERT_INFO_PARAM == dwParamType) {
|
|
PCERT_ID pSignerId;
|
|
|
|
if (TCM_AllocGetParam(
|
|
hMsg,
|
|
CMSG_SIGNER_CERT_ID_PARAM,
|
|
dwIndex,
|
|
(PBYTE *)&pSignerId,
|
|
&cbData)) {
|
|
CompareCertIdWithCertInfo(pSignerId, pCertId);
|
|
TestFree(pSignerId);
|
|
}
|
|
}
|
|
#endif // CMS_PKCS7
|
|
|
|
return pCertId;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
// Get computed digest and digest data from a decoded CMSG_HASHED
|
|
//--------------------------------------------------------------------------
|
|
BOOL Undigest(IN HCRYPTMSG hMsg)
|
|
{
|
|
return CryptMsgControl( hMsg, 0, CMSG_CTRL_VERIFY_HASH, NULL);
|
|
}
|