Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

3413 lines
113 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1997 - 1999
//
// File: msgstrm.cpp
//
// Contents: Cryptographic Message Streaming API support
//
// APIs:
//
// History: 20-Feb-97 kevinr created
//
//--------------------------------------------------------------------------
#include "global.hxx"
#define ICMS_NOCRYPT 0
#if (DBG && ICMS_NOCRYPT)
#define CryptEncrypt ICMS_PlainEncrypt
#define CryptDecrypt ICMS_PlainDecrypt
//+-------------------------------------------------------------------------
// Encrypt a buffer using a NOP algorithm, ie. ciphertext == plaintext
// Assumes that all but the last block are a multiple of the block
// size in length.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_PlainEncrypt(
IN HCRYPTKEY hkeyCrypt,
IN HCRYPTHASH hHash,
IN BOOL fFinal,
IN DWORD dwFlags,
IN OUT PBYTE pbData,
IN OUT PDWORD pcbData,
IN DWORD cbBuf)
{
BOOL fRet;
DWORD cbBlockLen;
BOOL fBlockCipher;
DWORD cbCipher;
DWORD cbPlain = *pcbData;
DWORD cbPad;
DWORD i;
if (!fFinal)
goto SuccessReturn;
if (!ICM_GetKeyBlockSize( hkeyCrypt, &cbBlockLen, &fBlockCipher))
goto GetKeyBlockSizeError;
if (!fBlockCipher)
goto SuccessReturn; // if stream, cipher == plain
cbCipher = cbPlain;
cbCipher += cbBlockLen;
cbCipher -= cbCipher % cbBlockLen; // make a multiple of block size
cbPad = cbCipher - cbPlain;
if (cbCipher > cbBuf)
goto BufferTooSmallError;
// pad the "ciphertext"
FillMemory( pbData + cbPlain, cbPad, cbPad);
*pcbData = cbCipher;
SuccessReturn:
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetKeyBlockSizeError) // error already set
TRACE_ERROR(BufferTooSmallError) // error already set
}
//+-------------------------------------------------------------------------
// Decrypt a buffer using a NOP algorithm, ie. ciphertext == plaintext
// Assumes all input sizes are multiples of the block size.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_PlainDecrypt(
IN HCRYPTKEY hkeyCrypt,
IN HCRYPTHASH hHash,
IN BOOL fFinal,
IN DWORD dwFlags,
IN OUT PBYTE pbData,
IN OUT PDWORD pcbData)
{
BOOL fRet;
PBYTE pb;
DWORD cbBlockLen;
BOOL fBlockCipher;
DWORD cbCipher = *pcbData;
DWORD cbPlain;
DWORD cbPad;
if (!fFinal)
goto SuccessReturn;
if (!ICM_GetKeyBlockSize( hkeyCrypt, &cbBlockLen, &fBlockCipher))
goto GetKeyBlockSizeError;
if (!fBlockCipher)
goto SuccessReturn; // if stream, cipher == plain
cbPad = (DWORD)(*(pbData + cbCipher - 1)); // check last byte
if (cbCipher < cbPad)
goto CipherTextTooSmallError;
cbPlain = cbCipher - cbPad;
*pcbData = cbPlain;
SuccessReturn:
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetKeyBlockSizeError) // error already set
TRACE_ERROR(CipherTextTooSmallError) // error already set
}
#endif // (DBG && ICMS_NOCRYPT)
//+-------------------------------------------------------------------------
// Do a CryptMsgGetParam to a buffer alloc'd by ICM_Alloc
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_AllocGetParam(
IN HCRYPTMSG hCryptMsg,
IN DWORD dwParamType,
IN DWORD dwIndex,
OUT PBYTE *ppbData,
OUT DWORD *pcbData)
{
BOOL fRet;
DWORD cb;
PBYTE pb = NULL;
if (!CryptMsgGetParam(
hCryptMsg,
dwParamType,
dwIndex,
NULL,
&cb))
goto GetEncodedSizeError;
if (NULL == (pb = (PBYTE)ICM_Alloc(cb)))
goto AllocEncodedError;
if (!CryptMsgGetParam(
hCryptMsg,
dwParamType,
dwIndex,
pb,
&cb))
goto GetEncodedError;
fRet = TRUE;
CommonReturn:
*ppbData = pb;
*pcbData = cb;
return fRet;
ErrorReturn:
ICM_Free(pb);
pb = NULL;
cb = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetEncodedSizeError)
TRACE_ERROR(AllocEncodedError)
TRACE_ERROR(GetEncodedError)
}
//+-------------------------------------------------------------------------
// Peel off the identifier and length octets.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_ExtractContent(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbDER,
IN DWORD cbDER,
OUT PDWORD pcbContent,
OUT const BYTE **ppbContent)
{
BOOL fRet;
LONG cbSkipped = 0;
DWORD cbEntireContent;
if (!pcmi->fStreamContentExtracted) {
if (0 > (cbSkipped = Asn1UtilExtractContent(
pbDER,
cbDER,
&cbEntireContent,
ppbContent)))
goto ExtractContentError;
pcmi->fStreamContentExtracted = TRUE;
} else {
*ppbContent = pbDER;
}
*pcbContent = cbDER - cbSkipped;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(ExtractContentError) // error already set
}
//+-------------------------------------------------------------------------
// Get the next token from the buffer.
// If the encoding is definite-length, set *pcbContent to be the size of the
// contents octets.
//
// Here, a "token" is either identifier/length octets, or the double-NULL
// terminating an indefinite-length encoding.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_GetToken(
IN PICM_BUFFER pbuf,
OUT PDWORD pdwToken,
OUT OPTIONAL PDWORD pcbContent)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
DWORD dwToken;
LONG lth;
DWORD cbContent = 0;
const BYTE *pbContent;
PBYTE pbData = pbuf->pbData + pbuf->cbDead;
DWORD cbData = pbuf->cbUsed - pbuf->cbDead;
DWORD cbConsumed = 0;
if (2 > cbData) {
dwToken = ICMS_TOKEN_INCOMPLETE;
} else if (0 == pbData[0] && 0 == pbData[1]) {
dwToken = ICMS_TOKEN_NULLPAIR;
cbConsumed = 2;
} else {
if (0 > (lth = Asn1UtilExtractContent(
pbData,
cbData,
&cbContent,
&pbContent))) {
if (ASN1UTIL_INSUFFICIENT_DATA != lth)
goto ExtractContentError;
dwToken = ICMS_TOKEN_INCOMPLETE;
} else {
dwToken = (CMSG_INDEFINITE_LENGTH == cbContent) ?
ICMS_TOKEN_INDEFINITE : ICMS_TOKEN_DEFINITE;
cbConsumed = (DWORD)lth;
}
}
if (ICMS_TOKEN_INCOMPLETE != dwToken)
pbuf->cbDead += cbConsumed;
fRet = TRUE;
CommonReturn:
*pdwToken = dwToken;
if (pcbContent)
*pcbContent = cbContent;
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
dwToken = 0;
cbContent = 0;
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(ExtractContentError) // error already set
}
//+-------------------------------------------------------------------------
// Process incremental content data, for a string.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_ProcessStringContent(
IN PICM_BUFFER pbuf,
IN OUT PDWORD paflStream,
IN OUT PDWORD pcbPending,
IN OUT PDWORD pcLevelIndefiniteInner,
IN POSTRCALLBACK postrcbk,
IN const void *pvArg)
{
BOOL fRet;
DWORD dwToken;
DWORD cbContent;
while (TRUE) {
if (*pcbPending) {
// *pcbPending bytes need to be processed, so we process
// as many as possible from the buffer.
if (!postrcbk( pvArg, pbuf, pcbPending, FALSE))
goto CallbackError;
}
if (0 == *pcbPending) {
// No bytes currently counted for processing. One of:
// 1. first time through
// 2. last time through
// 3. nested within an indefinite-length encoding
if (0 == *pcLevelIndefiniteInner) {
// The first time through, and also when we have processed the
// entire octet string, we get here. The flag is clear
// the first time (so we set it after getting a token, which
// either sets *pcbPending or bumps *pcLevelIndefiniteInner),
// and set afterwards (so we mark done and bail).
if (*paflStream & ICMS_PROCESS_CONTENT_BEGUN) {
// 2. last time through
if (!postrcbk( pvArg, pbuf, pcbPending, TRUE))
goto CallbackFinalError;
*paflStream |= ICMS_PROCESS_CONTENT_DONE;
goto SuccessReturn; // All done
}
}
// One of:
// 1. first time through
// 3. nested within an indefinite-length encoding
if (!ICMS_GetToken( pbuf, &dwToken, &cbContent))
goto GetTokenError;
switch(dwToken) {
case ICMS_TOKEN_INDEFINITE: ++*pcLevelIndefiniteInner; break;
case ICMS_TOKEN_NULLPAIR: --*pcLevelIndefiniteInner; break;
case ICMS_TOKEN_DEFINITE: *pcbPending = cbContent; break;
case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn; // need input
default: goto InvalidTokenError;
}
*paflStream |= ICMS_PROCESS_CONTENT_BEGUN;
} else {
// More definite-length data remains to be copied out, but it
// is not yet in the buffer.
break;
}
}
SuccessReturn:
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(InvalidTokenError) // error already set
TRACE_ERROR(GetTokenError) // error already set
TRACE_ERROR(CallbackError) // error already set
TRACE_ERROR(CallbackFinalError) // error already set
}
//+-------------------------------------------------------------------------
// Queue data to the buffer.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_QueueToBuffer(
IN PICM_BUFFER pbuf,
IN PBYTE pbData,
IN DWORD cbData)
{
BOOL fRet;
DWORD cbNewSize;
DWORD cbNewUsed;
if (0 == cbData)
goto SuccessReturn;
if (pbuf->pbData && pbuf->cbDead) {
// Move the still-active bytes up to the front of the buffer.
// NB- Might overlap, so use MoveMemory.
MoveMemory(
pbuf->pbData,
pbuf->pbData + pbuf->cbDead,
pbuf->cbUsed - pbuf->cbDead);
pbuf->cbUsed -= pbuf->cbDead;
pbuf->cbDead = 0;
}
for (cbNewUsed=pbuf->cbUsed + cbData, cbNewSize=pbuf->cbSize;
cbNewUsed > cbNewSize;
cbNewSize += ICM_BUFFER_SIZE_INCR)
;
if (cbNewSize > pbuf->cbSize) {
if (NULL == (pbuf->pbData=(PBYTE)ICM_ReAlloc( pbuf->pbData, cbNewSize)))
goto ReAllocBufferError;
pbuf->cbSize = cbNewSize;
}
CopyMemory( pbuf->pbData + pbuf->cbUsed, pbData, cbData);
pbuf->cbUsed += cbData;
SuccessReturn:
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(ReAllocBufferError) // error already set
}
//+-------------------------------------------------------------------------
// Copy out or queue some data eventually destined for the callback.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_Output(
IN PCRYPT_MSG_INFO pcmi,
IN PBYTE pbData,
IN DWORD cbData,
IN BOOL fFinal)
{
BOOL fRet;
PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
PFN_CMSG_STREAM_OUTPUT pfnStreamOutput = pcsi->pfnStreamOutput;
void *pvArg = pcsi->pvArg;
PICM_BUFFER pbuf = &pcmi->bufOutput;
if (pcmi->fStreamCallbackOutput) {
if (pbuf->cbUsed) {
// Copy out the queued data
if (!pfnStreamOutput( pvArg, pbuf->pbData, pbuf->cbUsed, FALSE))
goto OutputBufferError;
pbuf->cbUsed = 0;
}
if (cbData || fFinal) {
if (!pfnStreamOutput( pvArg, pbData, cbData, fFinal))
goto OutputError;
}
} else {
if (!ICMS_QueueToBuffer( pbuf, pbData, cbData))
goto QueueOutputError;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(OutputBufferError) // error already set
TRACE_ERROR(QueueOutputError) // error already set
TRACE_ERROR(OutputError) // error already set
}
//+-------------------------------------------------------------------------
// Copy out the pair of NULLs following the contents octets of an indefinite-
// length encoding.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_OutputNullPairs(
IN PCRYPT_MSG_INFO pcmi,
IN DWORD cPairs,
IN BOOL fFinal)
{
BOOL fRet;
BYTE abNULL[8*2]; ZEROSTRUCT(abNULL);
if (cPairs > (sizeof(abNULL)/2))
goto CountOfNullPairsTooLargeError;
if (!ICMS_Output( pcmi, abNULL, cPairs * 2, fFinal))
goto OutputError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(CountOfNullPairsTooLargeError) // error already set
TRACE_ERROR(OutputError) // error already set
}
//+-------------------------------------------------------------------------
// Copy out the part of the encoding preceding the contents octets.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_OutputEncodedPrefix(
IN PCRYPT_MSG_INFO pcmi,
IN BYTE bTag,
IN DWORD cbData)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
BYTE abPrefix[6];
DWORD cbPrefix;
abPrefix[0] = bTag;
if (CMSG_INDEFINITE_LENGTH == cbData) {
abPrefix[1] = ICM_LENGTH_INDEFINITE;
cbPrefix = 1;
} else {
cbPrefix = sizeof(abPrefix) - 1;
ICM_GetLengthOctets( cbData, abPrefix + 1, &cbPrefix);
}
if (!ICMS_Output( pcmi, abPrefix, cbPrefix + 1, FALSE))
goto OutputError;
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(OutputError) // error already set
}
//+-------------------------------------------------------------------------
// Copy out the part of the ContentInfo encoding preceding
// the content's content.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_OutputEncodedPrefixContentInfo(
IN PCRYPT_MSG_INFO pcmi,
IN LPSTR pszContentType,
IN DWORD cbData,
IN DWORD dwFlags = 0)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
ASN1error_e Asn1Err;
ASN1encoding_t pEnc = ICM_GetEncoder();
PBYTE pbEncoded = NULL;
DWORD cbEncoded;
ObjectID ossObjID;
BYTE abContentInfo[6];
DWORD cbContentInfo;
BYTE abContent[6];
DWORD cbContent = 0;
BYTE abContentOctetString[6];
DWORD cbContentOctetString = 0;
DWORD cbSize = cbData;
if (dwFlags & CMSG_DETACHED_FLAG) {
// NoContent
if (CMSG_INDEFINITE_LENGTH != cbData)
cbSize = 0;
} else {
if (NULL == pszContentType
#ifdef CMS_PKCS7
|| (dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
#endif // CMS_PKCS7
) {
// The content is not already encoded, so encode it as an octet string.
abContentOctetString[0] = ICM_TAG_OCTETSTRING;
if (CMSG_INDEFINITE_LENGTH == cbData) {
abContentOctetString[0] |= ICM_TAG_CONSTRUCTED;
abContentOctetString[1] = ICM_LENGTH_INDEFINITE;
cbContentOctetString = 1;
} else {
cbContentOctetString = sizeof(abContentOctetString) - 1;
ICM_GetLengthOctets(
cbData,
abContentOctetString + 1,
&cbContentOctetString);
cbSize += 1 + cbContentOctetString;
}
}
// content, [0] EXPLICIT
abContent[0] = ICM_TAG_CONSTRUCTED | ICM_TAG_CONTEXT_0;
if (CMSG_INDEFINITE_LENGTH == cbData) {
abContent[1] = ICM_LENGTH_INDEFINITE;
cbContent = 1;
} else {
cbContent = sizeof(abContent) - 1;
ICM_GetLengthOctets( cbSize, abContent + 1, &cbContent);
cbSize += 1 + cbContent;
}
}
// contentType
ossObjID.count = SIZE_OSS_OID;
if (!PkiAsn1ToObjectIdentifier(
pszContentType ? pszContentType : pszObjIdDataType,
&ossObjID.count,
ossObjID.value))
goto ConvToObjectIdentifierError;
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
&ossObjID,
ObjectIdentifierType_PDU,
&pbEncoded,
&cbEncoded)))
goto EncodeObjectIdentifierError;
cbSize += cbEncoded;
abContentInfo[0] = ICM_TAG_SEQ;
if (CMSG_INDEFINITE_LENGTH == cbData) {
abContentInfo[1] = ICM_LENGTH_INDEFINITE;
cbContentInfo = 1;
} else {
cbContentInfo = sizeof(abContentInfo) - 1;
ICM_GetLengthOctets( cbSize, abContentInfo + 1, &cbContentInfo);
}
if (!ICMS_Output( pcmi, abContentInfo, cbContentInfo + 1, FALSE))
goto OutputContentInfoError;
if (!ICMS_Output( pcmi, pbEncoded, cbEncoded, FALSE))
goto OutputContentTypeError;
if (0 == (dwFlags & CMSG_DETACHED_FLAG)) {
if (!ICMS_Output( pcmi, abContent, cbContent + 1, FALSE))
goto OutputContentError;
if (NULL == pszContentType
#ifdef CMS_PKCS7
|| (dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
#endif // CMS_PKCS7
) {
if (!ICMS_Output(
pcmi,
abContentOctetString,
cbContentOctetString + 1,
FALSE))
goto OutputContentOctetStringError;
}
}
fRet = TRUE;
CommonReturn:
PkiAsn1FreeEncoded(pEnc, pbEncoded);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(EncodeObjectIdentifierError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(ConvToObjectIdentifierError) // error already set
TRACE_ERROR(OutputContentInfoError) // error already set
TRACE_ERROR(OutputContentTypeError) // error already set
TRACE_ERROR(OutputContentError) // error already set
TRACE_ERROR(OutputContentOctetStringError) // error already set
}
//+-------------------------------------------------------------------------
// Copy out the part of the EncryptedContentInfo encoding preceding
// the content's content.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_OutputEncodedPrefixEncryptedContentInfo(
IN PCRYPT_MSG_INFO pcmi,
IN LPSTR pszContentType,
IN AlgorithmIdentifier *poaiContentEncryption,
IN DWORD cbData)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
ASN1error_e Asn1Err;
ASN1encoding_t pEnc = ICM_GetEncoder();
PBYTE pbEncodedContentType = NULL;
DWORD cbEncodedContentType;
PBYTE pbEncodedContentEncryptionAlgorithm = NULL;
DWORD cbEncodedContentEncryptionAlgorithm;
ObjectID ossObjID;
BYTE abEncryptedContentInfo[6];
DWORD cbEncryptedContentInfo;
BYTE abEncryptedContent[6];
DWORD cbEncryptedContent;
DWORD cbSize = 0;
DWORD cbCipher = cbData;
DWORD cbBlockSize = pcmi->cbBlockSize;
if (pcmi->fBlockCipher && 0 < cbCipher) {
cbCipher += cbBlockSize;
cbCipher -= cbCipher % cbBlockSize;
}
// encryptedContent, [0] IMPLICIT
abEncryptedContent[0] = ICM_TAG_CONTEXT_0;
if (CMSG_INDEFINITE_LENGTH == cbData) {
abEncryptedContent[0] |= ICM_TAG_CONSTRUCTED;
abEncryptedContent[1] = ICM_LENGTH_INDEFINITE;
cbEncryptedContent = 1;
} else {
// NOTE: for nonData, either encapsulated or the cbData excludes
// the outer tag and length octets.
cbEncryptedContent = sizeof(abEncryptedContent) - 1;
ICM_GetLengthOctets( cbCipher, abEncryptedContent + 1, &cbEncryptedContent);
cbSize = 1 + cbEncryptedContent + cbCipher;
}
// contentType
ossObjID.count = SIZE_OSS_OID;
if (!PkiAsn1ToObjectIdentifier(
pszContentType ? pszContentType : pszObjIdDataType,
&ossObjID.count,
ossObjID.value))
goto ConvToObjectIdentifierError;
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
&ossObjID,
ObjectIdentifierType_PDU,
&pbEncodedContentType,
&cbEncodedContentType)))
goto EncodeObjectIdentifierError;
cbSize += cbEncodedContentType;
// contentEncryptionAlgorithm
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
poaiContentEncryption,
AlgorithmIdentifier_PDU,
&pbEncodedContentEncryptionAlgorithm,
&cbEncodedContentEncryptionAlgorithm)))
goto EncodeContentEncryptionAlgorithmError;
cbSize += cbEncodedContentEncryptionAlgorithm;
// EncryptedContentInfo
abEncryptedContentInfo[0] = ICM_TAG_SEQ;
if (CMSG_INDEFINITE_LENGTH == cbData) {
abEncryptedContentInfo[1] = ICM_LENGTH_INDEFINITE;
cbEncryptedContentInfo = 1;
} else {
cbEncryptedContentInfo = sizeof(abEncryptedContentInfo) - 1;
ICM_GetLengthOctets(
cbSize,
abEncryptedContentInfo + 1,
&cbEncryptedContentInfo);
}
// Queue the encoded header
if (!ICMS_Output(
pcmi,
abEncryptedContentInfo,
cbEncryptedContentInfo + 1,
FALSE))
goto OutputContentInfoError;
if (!ICMS_Output(
pcmi,
pbEncodedContentType,
cbEncodedContentType,
FALSE))
goto OutputContentTypeError;
if (!ICMS_Output(
pcmi,
pbEncodedContentEncryptionAlgorithm,
cbEncodedContentEncryptionAlgorithm,
FALSE))
goto OutputContentEncryptionAlgorithmError;
if (!ICMS_Output(
pcmi,
abEncryptedContent,
cbEncryptedContent + 1,
FALSE))
goto OutputEncryptedContentError;
fRet = TRUE;
CommonReturn:
PkiAsn1FreeEncoded(pEnc, pbEncodedContentType);
PkiAsn1FreeEncoded(pEnc, pbEncodedContentEncryptionAlgorithm);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(EncodeObjectIdentifierError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR_VAR(EncodeContentEncryptionAlgorithmError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(ConvToObjectIdentifierError) // error already set
TRACE_ERROR(OutputContentInfoError) // error already set
TRACE_ERROR(OutputContentTypeError) // error already set
TRACE_ERROR(OutputContentEncryptionAlgorithmError) // error already set
TRACE_ERROR(OutputEncryptedContentError) // error already set
}
//+-------------------------------------------------------------------------
// Copy out the encoding of an OSS type.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_OutputEncoded(
IN PCRYPT_MSG_INFO pcmi,
IN int iPDU,
IN OPTIONAL BYTE bTag,
IN PVOID pv,
IN BOOL fFinal)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
ASN1error_e Asn1Err;
ASN1encoding_t pEnc = ICM_GetEncoder();
PBYTE pbEncoded = NULL;
DWORD cbEncoded;
if (0 != (Asn1Err = PkiAsn1Encode(
pEnc,
pv,
iPDU,
&pbEncoded,
&cbEncoded)))
goto EncodeError;
if (bTag)
pbEncoded[0] = bTag; // poke in the right tag
if (!ICMS_Output(pcmi, pbEncoded, cbEncoded, fFinal))
goto OutputError;
fRet = TRUE;
CommonReturn:
PkiAsn1FreeEncoded(pEnc, pbEncoded);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(EncodeError, PkiAsn1ErrToHr(Asn1Err))
TRACE_ERROR(OutputError) // error already set
}
//+-------------------------------------------------------------------------
// Create the buffer for an enveloped message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_CreateEnvelopedBuffer(
IN PCRYPT_MSG_INFO pcmi)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PBYTE pbBuffer = NULL;
DWORD cbBuffer;
DWORD cbAlloc;
DWORD cbBlockSize;
BOOL fBlockCipher;
PICM_BUFFER pbuf = &pcmi->bufCrypt;
if (!ICM_GetKeyBlockSize(
pcmi->hkeyContentCrypt,
&cbBlockSize,
&fBlockCipher))
goto GetEncryptBlockSizeError;
pcmi->cbBlockSize = cbBlockSize;
pcmi->fBlockCipher = fBlockCipher;
cbBuffer = min( cbBlockSize * CMSGP_STREAM_CRYPT_BLOCK_COUNT,
CMSGP_STREAM_MAX_ENCRYPT_BUFFER);
if (fBlockCipher) {
cbBuffer += cbBlockSize;
cbBuffer -= cbBuffer % cbBlockSize; // make a multiple of block size
}
// Add one block for growth during encrypt, and to save during decrypt.
cbAlloc = cbBuffer + 1 * cbBlockSize;
// Block ciphers pad the ciphertext, and if the plaintext is a
// multiple of the block size the padding is one block.
if (NULL == (pbBuffer = (PBYTE)ICM_Alloc( cbAlloc)))
goto AllocBufferError;
pbuf->pbData = pbBuffer;
pbuf->cbSize = cbBuffer;
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
ICM_Free( pbBuffer);
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetEncryptBlockSizeError) // error already set
TRACE_ERROR(AllocBufferError) // error already set
}
//+-------------------------------------------------------------------------
// Encode and copy out the part of the data message up to the inner content.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_OpenToEncodeData(
IN PCRYPT_MSG_INFO pcmi)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
DWORD cbData = pcmi->pStreamInfo->cbContent;
if (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG) {
BYTE bTag;
if (CMSG_INDEFINITE_LENGTH == cbData)
bTag = ICM_TAG_OCTETSTRING | ICM_TAG_CONSTRUCTED;
else
bTag = ICM_TAG_OCTETSTRING;
// Output octet string
if (!ICMS_OutputEncodedPrefix(
pcmi,
bTag,
cbData))
goto OutputOctetStringError;
} else {
// Output ContentInfo
if (!ICMS_OutputEncodedPrefixContentInfo(
pcmi,
NULL,
cbData))
goto OutputContentInfoError;
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(OutputContentInfoError) // error already set
TRACE_ERROR(OutputOctetStringError) // error already set
}
//+-------------------------------------------------------------------------
// Encode and copy out the part of the data message after the inner content.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_UpdateEncodingData(
IN PCRYPT_MSG_INFO pcmi,
IN PBYTE pbData,
IN DWORD cbData,
IN BOOL fFinal)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
BOOL fDefinite = (CMSG_INDEFINITE_LENGTH != pcmi->pStreamInfo->cbContent);
DWORD cNullPairs;
pcmi->fStreamCallbackOutput = TRUE; // Enable the callback
if (!fDefinite) {
// The content is an indefinite-length octet string encoded by us,
// so make each output chunk definite-length.
if (!ICMS_OutputEncodedPrefix(
pcmi,
ICM_TAG_OCTETSTRING,
cbData))
goto OutputOctetStringError;
}
if (!ICMS_Output( pcmi, pbData, cbData, fFinal && fDefinite))
goto OutputError;
if (fFinal && !fDefinite) {
// End of indefinite-length encoding, so emit some NULL pairs
cNullPairs = 1; // content
if (0 == (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG))
cNullPairs += 2;
if (!ICMS_OutputNullPairs( pcmi, cNullPairs, TRUE))
goto OutputNullPairsError;
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(OutputOctetStringError) // error already set
TRACE_ERROR(OutputError) // error already set
TRACE_ERROR(OutputNullPairsError) // error already set
}
//+-------------------------------------------------------------------------
// Encode and copy out the part of the signed message up to the inner content.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_OpenToEncodeSignedData(
IN PCRYPT_MSG_INFO pcmi,
IN PCMSG_SIGNED_ENCODE_INFO psmei)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
SignedData *psd = (SignedData *)pcmi->pvMsg;
DWORD cbData = pcmi->pStreamInfo->cbContent;
LPSTR pszInnerContentObjID = pcmi->pszInnerContentObjID;
DWORD cbSigned;
DWORD cbSignedDataContent;
// Output ContentInfo, if appropriate
if (CMSG_INDEFINITE_LENGTH == cbData) {
cbSigned = CMSG_INDEFINITE_LENGTH;
cbSignedDataContent = CMSG_INDEFINITE_LENGTH;
} else {
if (INVALID_ENCODING_SIZE == (cbSigned = ICM_LengthSigned(
psmei,
pcmi->dwFlags,
pszInnerContentObjID,
cbData,
&cbSignedDataContent)))
goto LengthSignedError;
}
if (0 == (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG)) {
if (!ICMS_OutputEncodedPrefixContentInfo(
pcmi,
szOID_RSA_signedData,
cbSigned))
goto OutputContentInfoError;
}
if (!ICMS_OutputEncodedPrefix(
pcmi,
ICM_TAG_SEQ,
cbSignedDataContent))
goto OutputSignedDataError;
// version
if (!ICMS_OutputEncoded(
pcmi,
IntegerType_PDU,
0, // bTag
&psd->version,
FALSE))
goto OutputIntegerError;
// digestAlgorithms
if (!ICMS_OutputEncoded(
pcmi,
AlgorithmIdentifiers_PDU,
0, // bTag
&psd->digestAlgorithms,
FALSE))
goto OutputAlgorithmIdentifiersError;
// contentInfo
if (!ICMS_OutputEncodedPrefixContentInfo(
pcmi,
pcmi->pszInnerContentObjID,
cbData,
pcmi->dwFlags))
goto OutputInnerContentInfoError;
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(LengthSignedError) // error already set
TRACE_ERROR(OutputContentInfoError) // error already set
TRACE_ERROR(OutputSignedDataError) // error already set
TRACE_ERROR(OutputIntegerError) // error already set
TRACE_ERROR(OutputAlgorithmIdentifiersError) // error already set
TRACE_ERROR(OutputInnerContentInfoError) // error already set
}
//+-------------------------------------------------------------------------
// Encode and copy out the part of the signed message after the inner content.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_UpdateEncodingSignedData(
IN PCRYPT_MSG_INFO pcmi,
IN PBYTE pbData,
IN DWORD cbData,
IN BOOL fFinal)
{
BOOL fRet;
DWORD dwError = ERROR_SUCCESS;
SignedData *psd = (SignedData *)pcmi->pvMsg;
PCMSG_STREAM_INFO pcsi = pcmi->pStreamInfo;
BOOL fDefinite = (CMSG_INDEFINITE_LENGTH != pcsi->cbContent);
DWORD cNullPairs;
if (pcmi->pszInnerContentObjID
#ifdef CMS_PKCS7
&& 0 == (pcmi->dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
#endif // CMS_PKCS7
) {
if (0 == (pcmi->aflStream & ICMS_PROCESS_CONTENT_DONE)) {
if (!ICMS_HashContent( pcmi, pbData, cbData))
goto HashContentError;
}
} else {
if (!ICM_UpdateListDigest( pcmi->pHashList, pbData, cbData))
goto UpdateDigestError;
}
pcmi->fStreamCallbackOutput = TRUE; // Enable the callback
if (0 == (pcmi->dwFlags & CMSG_DETACHED_FLAG)) {
if (!fDefinite && (NULL == pcmi->pszInnerContentObjID
#ifdef CMS_PKCS7
|| (pcmi->dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
#endif // CMS_PKCS7
)) {
// The content is an indefinite-length octet string encoded by us,
// so make each output chunk definite-length.
if (!ICMS_OutputEncodedPrefix(
pcmi,
ICM_TAG_OCTETSTRING,
cbData))
goto OutputOctetStringError;
}
if (!ICMS_Output( pcmi, pbData, cbData, FALSE))
goto OutputError;
}
// else
// detached => don't output the detached content to be hashed
if (fFinal) {
if (!fDefinite) {
// End of indefinite-length encoding, so emit some NULL pairs
cNullPairs = 1; // ContentInfo
if (0 == (pcmi->dwFlags & CMSG_DETACHED_FLAG)) {
cNullPairs++; // [0] EXPLICIT
if (NULL == pcmi->pszInnerContentObjID
#ifdef CMS_PKCS7
|| (pcmi->dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
#endif // CMS_PKCS7
)
cNullPairs++; // We did the octet string encoding
}
// else
// detached => no content ([0] EXPLICIT)
if (!ICMS_OutputNullPairs( pcmi, cNullPairs, FALSE))
goto OutputNullPairsError;
}
if ((psd->bit_mask & certificates_present) &&
!ICMS_OutputEncoded(
pcmi,
SetOfAny_PDU,
ICM_TAG_CONSTRUCTED | ICM_TAG_CONTEXT_0,
&psd->certificates,
FALSE))
goto OutputCertsError;
if ((psd->bit_mask & crls_present) &&
!ICMS_OutputEncoded(
pcmi,
SetOfAny_PDU,
ICM_TAG_CONSTRUCTED | ICM_TAG_CONTEXT_1,
&psd->crls,
FALSE))
goto OutputCrlsError;
#ifdef CMS_PKCS7
if (pcmi->rgSignerEncodeDataInfo) {
if (!ICM_FillSignerEncodeEncryptedDigests(
pcmi,
fDefinite)) // fMaxLength
goto FillSignerEncodeEncryptedDigestsError;
}
#else
if (pcmi->pHashList) {
if (!ICM_FillSignerEncryptedDigest(
psd->signerInfos.value,
pcmi->pszInnerContentObjID,
pcmi->pHashList->Head(),
pcmi->dwKeySpec,
fDefinite)) // fMaxLength
goto FillSignerEncryptedDigestError;
}
#endif // CMS_PKCS7
if (!ICMS_OutputEncoded(
pcmi,
SignerInfos_PDU,
0, // bTag
&psd->signerInfos,
fDefinite))
goto OutputSignerInfosError;
if (!fDefinite) {
// End of indefinite-length encoding, so emit some NULL pairs
cNullPairs = 1; // SignedData
if (0 == (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG))
cNullPairs += 2;
if (!ICMS_OutputNullPairs( pcmi, cNullPairs, TRUE))
goto OutputNullPairsError;
}
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(HashContentError) // error already set
TRACE_ERROR(UpdateDigestError) // error already set
TRACE_ERROR(OutputOctetStringError) // error already set
TRACE_ERROR(OutputError) // error already set
TRACE_ERROR(OutputCertsError) // error already set
TRACE_ERROR(OutputCrlsError) // error already set
#ifdef CMS_PKCS7
TRACE_ERROR(FillSignerEncodeEncryptedDigestsError) // error already set
#else
TRACE_ERROR(FillSignerEncryptedDigestError) // error already set
#endif // CMS_PKCS7
TRACE_ERROR(OutputSignerInfosError) // error already set
TRACE_ERROR(OutputNullPairsError) // error already set
}
//+-------------------------------------------------------------------------
// Encode and copy out the part of the enveloped message up to the inner
// content.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_OpenToEncodeEnvelopedData(
IN PCRYPT_MSG_INFO pcmi,
IN PCMSG_ENVELOPED_ENCODE_INFO pemei)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
#ifdef CMS_PKCS7
CmsEnvelopedData *ped = (CmsEnvelopedData *)pcmi->pvMsg;
#else
EnvelopedData *ped = (EnvelopedData *)pcmi->pvMsg;
#endif // CMS_PKCS7
DWORD cbData = pcmi->pStreamInfo->cbContent;
LPSTR pszInnerContentObjID = pcmi->pszInnerContentObjID;
DWORD cbEnveloped;
DWORD cbEnvelopedDataContent;
if (!ICMS_CreateEnvelopedBuffer( pcmi))
goto CreateEnvelopedBufferError;
// Output ContentInfo, if appropriate
if (CMSG_INDEFINITE_LENGTH == cbData) {
cbEnveloped = CMSG_INDEFINITE_LENGTH;
cbEnvelopedDataContent = CMSG_INDEFINITE_LENGTH;
} else {
// NOTE: for nonData, either encapsulated or cbData excludes the
// outer tag and length octets.
if (INVALID_ENCODING_SIZE == (cbEnveloped = ICM_LengthEnveloped(
pemei,
pcmi->dwFlags,
pszInnerContentObjID,
cbData,
&cbEnvelopedDataContent)))
goto LengthEnvelopedError;
}
if (0 == (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG)) {
if (!ICMS_OutputEncodedPrefixContentInfo(
pcmi,
szOID_RSA_envelopedData,
cbEnveloped))
goto OutputContentInfoError;
}
if (!ICMS_OutputEncodedPrefix(
pcmi,
ICM_TAG_SEQ,
cbEnvelopedDataContent))
goto OutputEnvelopedDataError;
// version
if (!ICMS_OutputEncoded(
pcmi,
IntegerType_PDU,
0, // bTag
&ped->version,
FALSE))
goto OutputIntegerError;
#ifdef CMS_PKCS7
// originatorInfo OPTIONAL
if (ped->bit_mask & originatorInfo_present) {
if (!ICMS_OutputEncoded(
pcmi,
OriginatorInfo_PDU,
ICM_TAG_CONSTRUCTED | ICM_TAG_CONTEXT_0,
&ped->originatorInfo,
FALSE))
goto OutputOriginatorInfoError;
}
#endif // CMS_PKCS7
// recipientInfos
if (!ICMS_OutputEncoded(
pcmi,
#ifdef CMS_PKCS7
CmsRecipientInfos_PDU,
#else
RecipientInfos_PDU,
#endif // CMS_PKCS7
0, // bTag
&ped->recipientInfos,
FALSE))
goto OutputRecipientInfosError;
// encryptedContentInfo
if (!ICMS_OutputEncodedPrefixEncryptedContentInfo(
pcmi,
pcmi->pszInnerContentObjID,
&ped->encryptedContentInfo.contentEncryptionAlgorithm,
cbData))
goto OutputInnerContentInfoError;
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(CreateEnvelopedBufferError) // error already set
TRACE_ERROR(LengthEnvelopedError) // error already set
TRACE_ERROR(OutputContentInfoError) // error already set
TRACE_ERROR(OutputEnvelopedDataError) // error already set
TRACE_ERROR(OutputIntegerError) // error already set
#ifdef CMS_PKCS7
TRACE_ERROR(OutputOriginatorInfoError) // error already set
#endif // CMS_PKCS7
TRACE_ERROR(OutputRecipientInfosError) // error already set
TRACE_ERROR(OutputInnerContentInfoError) // error already set
}
//+-------------------------------------------------------------------------
// Encrypt and copy out some bytes.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_EncodeEncryptAndOutput(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbPlainOrg,
IN DWORD cbPlainOrg,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
BOOL fDefinite = (CMSG_INDEFINITE_LENGTH != pcmi->pStreamInfo->cbContent);
BOOL fBlockCipher = pcmi->fBlockCipher;
PICM_BUFFER pbufCrypt = &pcmi->bufCrypt;
PBYTE pbPlain;
DWORD cbPlainRemain;
DWORD cb;
for (cbPlainRemain = cbPlainOrg, pbPlain = (PBYTE)pbPlainOrg;
cbPlainRemain > 0;) {
cb = min( cbPlainRemain, pbufCrypt->cbSize - pbufCrypt->cbUsed); // must fit
CopyMemory(
pbufCrypt->pbData + pbufCrypt->cbUsed,
pbPlain,
cb);
pbufCrypt->cbUsed += cb;
pbPlain += cb;
cbPlainRemain -= cb;
if (pbufCrypt->cbSize == pbufCrypt->cbUsed) {
// Encrypt and copy out the buffer
cb = pbufCrypt->cbSize;
if (fBlockCipher) {
// Leave the last block
cb -= pcmi->cbBlockSize;
}
if (!CryptEncrypt(
pcmi->hkeyContentCrypt,
NULL, // hHash
FALSE, // fFinal
0, // dwFlags
pbufCrypt->pbData,
&cb,
pbufCrypt->cbSize + pcmi->cbBlockSize))
goto EncryptError;
if (!fDefinite) {
// The ciphertext is indefinite-length, so make each
// output chunk definite-length.
if (!ICMS_OutputEncodedPrefix(
pcmi,
ICM_TAG_OCTETSTRING,
cb))
goto OutputOctetStringError;
}
if (!ICMS_Output(
pcmi,
pbufCrypt->pbData,
cb,
FALSE)) // fFinal
goto OutputError;
if (fBlockCipher) {
// Move the last block to the beginning of the buffer
// and reset the count to start after this block.
// Since we are sure the src and dst do not overlap,
// use CopyMemory (faster than MoveMemory).
cb = pbufCrypt->cbSize - pcmi->cbBlockSize;
CopyMemory(
pbufCrypt->pbData,
pbufCrypt->pbData + cb,
pcmi->cbBlockSize);
pbufCrypt->cbUsed = pcmi->cbBlockSize;
} else {
pbufCrypt->cbUsed = 0;
}
}
}
if (fFinal) {
#ifdef CMS_PKCS7
CmsEnvelopedData *ped = (CmsEnvelopedData *)pcmi->pvMsg;
#else
EnvelopedData *ped = (EnvelopedData *)pcmi->pvMsg;
#endif // CMS_PKCS7
if (cb = pbufCrypt->cbUsed) {
if (!CryptEncrypt(
pcmi->hkeyContentCrypt,
NULL, // hHash
TRUE, // fFinal
0, // dwFlags
pbufCrypt->pbData,
&cb,
pbufCrypt->cbSize + pcmi->cbBlockSize))
goto FinalEncryptError;
}
if (!fDefinite && cb) {
// The ciphertext is indefinite-length, so make each
// output chunk definite-length.
if (!ICMS_OutputEncodedPrefix(
pcmi,
ICM_TAG_OCTETSTRING,
cb))
goto OutputOctetStringError;
}
if (!ICMS_Output(
pcmi,
pbufCrypt->pbData,
cb,
fDefinite &&
0 == (ped->bit_mask & unprotectedAttrs_present) // fFinal
))
goto FinalOutputError;
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(EncryptError) // error already set
TRACE_ERROR(FinalEncryptError) // error already set
TRACE_ERROR(OutputOctetStringError) // error already set
TRACE_ERROR(OutputError) // error already set
TRACE_ERROR(FinalOutputError) // error already set
}
//+-------------------------------------------------------------------------
// Encode encrypt callback for octet string.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_EncryptCallback(
IN const void *pvArg,
IN OUT PICM_BUFFER pbuf,
IN OUT PDWORD pcbPending,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PBYTE pbData = pbuf->pbData + pbuf->cbDead;
DWORD cbData = min( *pcbPending, pbuf->cbUsed - pbuf->cbDead);
if (!ICMS_EncodeEncryptAndOutput(
(PCRYPT_MSG_INFO)pvArg,
pbData,
cbData,
fFinal))
goto EncodeEncryptAndOutputError;
pbuf->cbDead += cbData;
*pcbPending -= cbData;
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(EncodeEncryptAndOutputError) // error already set
}
//+-------------------------------------------------------------------------
// Encode and copy out the part of the enveloped message after the inner content.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_UpdateEncodingEnvelopedData(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbPlain,
IN DWORD cbPlain,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
BOOL fDefinite = (CMSG_INDEFINITE_LENGTH != pcmi->pStreamInfo->cbContent);
DWORD cNullPairs;
if (!pcmi->fStreamCallbackOutput) {
pcmi->fStreamCallbackOutput = TRUE; // Enable the callback
if (!ICMS_Output( pcmi, NULL, 0, FALSE)) // Flush the header
goto FlushOutputError;
}
if (pcmi->pszInnerContentObjID
#ifdef CMS_PKCS7
&& 0 == (pcmi->dwFlags & CMSG_CMS_ENCAPSULATED_CONTENT_FLAG)
#endif // CMS_PKCS7
) {
if (!ICMS_QueueToBuffer( &pcmi->bufEncode, (PBYTE)pbPlain, cbPlain))
goto QueueToBufferError;
if (!ICMS_ProcessStringContent(
&pcmi->bufEncode,
&pcmi->aflStream,
&pcmi->cbDefiniteRemain,
&pcmi->cLevelIndefiniteInner,
ICMS_EncryptCallback,
pcmi))
goto ProcessContentError;
} else {
if (!ICMS_EncodeEncryptAndOutput(
pcmi,
pbPlain,
cbPlain,
fFinal))
goto EncodeEncryptAndOutputError;
}
if (fFinal) {
#ifdef CMS_PKCS7
CmsEnvelopedData *ped = (CmsEnvelopedData *)pcmi->pvMsg;
#else
EnvelopedData *ped = (EnvelopedData *)pcmi->pvMsg;
#endif // CMS_PKCS7
if (!fDefinite) {
// End of indefinite-length encoding, so emit some NULL pairs,
// one each for encryptedContent, encryptedContentInfo
if (!ICMS_OutputNullPairs( pcmi, 2, FALSE))
goto OutputNullPairsError;
}
if (ped->bit_mask & unprotectedAttrs_present) {
#ifdef CMS_PKCS7
if (!ICMS_OutputEncoded(
pcmi,
Attributes_PDU,
ICM_TAG_CONSTRUCTED | ICM_TAG_CONTEXT_1,
&ped->unprotectedAttrs,
fDefinite)) // fFinal
goto OutputAttributesError;
#endif // CMS_PKCS7
}
if (!fDefinite) {
// End of indefinite-length encoding, so emit some NULL pairs
cNullPairs = 1; // EnvelopedData
if (0 == (pcmi->dwFlags & CMSG_BARE_CONTENT_FLAG))
cNullPairs += 2;
if (!ICMS_OutputNullPairs( pcmi, cNullPairs, TRUE))
goto OutputNullPairsError;
}
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(FlushOutputError) // error already set
TRACE_ERROR(QueueToBufferError) // error already set
TRACE_ERROR(ProcessContentError) // error already set
TRACE_ERROR(EncodeEncryptAndOutputError) // error already set
TRACE_ERROR(OutputNullPairsError) // error already set
#ifdef CMS_PKCS7
TRACE_ERROR(OutputAttributesError) // error already set
#endif // CMS_PKCS7
}
//+-------------------------------------------------------------------------
// Decode a PDU from the decode buffer.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodePDU(
IN PCRYPT_MSG_INFO pcmi,
IN ASN1decoding_t pDec,
IN ASN1uint32_t pdunum,
OUT PVOID *ppvPDU,
OUT OPTIONAL PDWORD pcbConsumed = NULL)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
ASN1error_e Asn1Err;
PICM_BUFFER pbuf = &pcmi->bufDecode;
PVOID pvPDU = NULL;
DWORD cbBufSizeOrg;
PBYTE pbData = pbuf->pbData + pbuf->cbDead;
DWORD cbData = pbuf->cbUsed - pbuf->cbDead;
#if DBG && defined(OSS_CRYPT_ASN1)
DWORD dwDecodingFlags;
dwDecodingFlags = ossGetDecodingFlags((OssGlobal *) pDec);
ossSetDecodingFlags( (OssGlobal *) pDec, RELAXBER); // turn off squirties
#endif
cbBufSizeOrg = cbData;
if (0 != (Asn1Err = PkiAsn1Decode2(
pDec,
&pvPDU,
pdunum,
&pbData,
&cbData))) {
if (ASN1_ERR_EOD != Asn1Err)
goto DecodeError;
}
#if DBG && defined(OSS_CRYPT_ASN1)
ossSetDecodingFlags( (OssGlobal *) pDec, dwDecodingFlags); // restore
#endif
if (ASN1_ERR_EOD == Asn1Err ||
(cbData > pbuf->cbUsed - pbuf->cbDead)) {
PkiAsn1FreeInfo(pDec, pdunum, pvPDU);
pvPDU = NULL;
cbData = cbBufSizeOrg;
}
pbuf->cbDead += cbBufSizeOrg - cbData;
if (pcbConsumed)
*pcbConsumed = cbBufSizeOrg - cbData;
fRet = TRUE;
CommonReturn:
*ppvPDU = pvPDU;
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
if (pcbConsumed)
*pcbConsumed = 0;
pvPDU = NULL;
fRet = FALSE;
goto CommonReturn;
SET_ERROR_VAR(DecodeError, PkiAsn1ErrToHr(Asn1Err))
}
//+-------------------------------------------------------------------------
// Decode a ContentInfo prefix
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodePrefixContentInfo(
IN PCRYPT_MSG_INFO pcmi,
OUT ObjectIdentifierType **ppooidContentType,
IN OUT PDWORD pcTrailingNullPairs,
IN OUT PDWORD pafl,
OUT BOOL *pfNoContent)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
ASN1decoding_t pDec = ICM_GetDecoder();
DWORD dwToken;
// ContentInfo sequence, step into it
if (0 == (*pafl & ICMS_DECODED_CONTENTINFO_SEQ)) {
if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, &pcmi->cbContentInfo))
goto ContentInfoGetTokenError;
switch (dwToken) {
case ICMS_TOKEN_INDEFINITE: ++*pcTrailingNullPairs; break;
case ICMS_TOKEN_DEFINITE: break;
case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn;
default: goto InvalidTokenError;
}
*pafl |= ICMS_DECODED_CONTENTINFO_SEQ;
}
// contentType, decode it
if (NULL == *ppooidContentType) {
DWORD cbConsumed;
if (!ICMS_DecodePDU(
pcmi,
pDec,
ObjectIdentifierType_PDU,
(void **)ppooidContentType,
&cbConsumed))
goto DecodeContentTypeError;
if (NULL != *ppooidContentType &&
CMSG_INDEFINITE_LENGTH != pcmi->cbContentInfo &&
cbConsumed == pcmi->cbContentInfo) {
// Only has contentType. The optional content has
// been omitted.
*pfNoContent = TRUE;
*pafl |= ICMS_DECODED_CONTENTINFO_CONTENT;
goto SuccessReturn;
}
}
if (NULL == *ppooidContentType)
goto SuccessReturn; // not enough data
// [0] EXPLICIT, step into it
if (0 == (*pafl & ICMS_DECODED_CONTENTINFO_CONTENT)) {
if (CMSG_INDEFINITE_LENGTH == pcmi->cbContentInfo) {
PICM_BUFFER pbuf = &pcmi->bufDecode;
if (pbuf->cbUsed > pbuf->cbDead) {
// Check for trailing Null Pairs (00, 00)
if (ICM_TAG_NULL == *(pbuf->pbData + pbuf->cbDead)) {
// Only has contentType. The optional content has
// been omitted.
*pfNoContent = TRUE;
*pafl |= ICMS_DECODED_CONTENTINFO_CONTENT;
goto SuccessReturn;
}
} else
goto SuccessReturn; // not enough data
}
if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, NULL))
goto ContentGetTokenError;
switch (dwToken) {
case ICMS_TOKEN_INDEFINITE: ++*pcTrailingNullPairs; break;
case ICMS_TOKEN_DEFINITE: break;
case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn;
default: goto InvalidTokenError;
}
*pfNoContent = FALSE;
*pafl |= ICMS_DECODED_CONTENTINFO_CONTENT;
}
SuccessReturn:
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(DecodeContentTypeError) // error already set
TRACE_ERROR(ContentGetTokenError) // error already set
TRACE_ERROR(InvalidTokenError) // error already set
TRACE_ERROR(ContentInfoGetTokenError) // error already set
}
//+-------------------------------------------------------------------------
// Consume the NULL pairs which terminate the indefinite-length encoding.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_ConsumeTrailingNulls(
IN PCRYPT_MSG_INFO pcmi,
IN OUT PDWORD pcNullPairs,
IN BOOL fFinal)
{
BOOL fRet;
DWORD dwToken;
for (; *pcNullPairs; (*pcNullPairs)--) {
if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, NULL))
goto GetTokenError;
if ((ICMS_TOKEN_INCOMPLETE == dwToken) && !fFinal)
goto SuccessReturn;
if (ICMS_TOKEN_NULLPAIR != dwToken)
goto WrongTokenError;
}
SuccessReturn:
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(GetTokenError) // error already set
TRACE_ERROR(WrongTokenError) // error already set
}
//+-------------------------------------------------------------------------
// Handle incremental suffix data to be decoded, for a data message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodeSuffixData(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
BOOL fRet;
if (!ICMS_ConsumeTrailingNulls( pcmi, &pcmi->cEndNullPairs, fFinal))
goto ConsumeTrailingNullsError;
if (0 == pcmi->cEndNullPairs)
pcmi->aflStream |= ICMS_DECODED_SUFFIX;
if (fFinal && (pcmi->bufDecode.cbUsed > pcmi->bufDecode.cbDead))
goto ExcessDataError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(ConsumeTrailingNullsError) // error already set
TRACE_ERROR(ExcessDataError) // error already set
}
//+-------------------------------------------------------------------------
// Handle incremental suffix data to be decoded, for a signed message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodeSuffixSigned(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
ASN1decoding_t pDec = ICM_GetDecoder();
PSIGNED_DATA_INFO psdi = pcmi->psdi;
PICM_BUFFER pbuf = &pcmi->bufDecode;
CertificatesNC *pCertificates = NULL;
CrlsNC *pCrls = NULL;
SignerInfosNC *pSignerInfos = NULL;
Any *pAny;
DWORD i;
if (!ICMS_ConsumeTrailingNulls( pcmi, &pcmi->cInnerNullPairs, fFinal))
goto ConsumeInnerNullsError;
if (pcmi->cInnerNullPairs)
goto SuccessReturn;
// certificates
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_CERTIFICATES)) {
if (pbuf->cbUsed > pbuf->cbDead) {
if (ICM_TAG_CONSTRUCTED_CONTEXT_0 ==
*(pbuf->pbData + pbuf->cbDead)) {
// Detected the [0] IMPLICIT indicating certificates.
// Change the identifier octet so it will decode properly.
*(pbuf->pbData + pbuf->cbDead) = ICM_TAG_SET;
if (!ICMS_DecodePDU(
pcmi,
pDec,
CertificatesNC_PDU,
(void **)&pCertificates))
goto DecodeCertificatesError;
if (pCertificates) {
for (i=pCertificates->count,
#ifdef OSS_CRYPT_ASN1
pAny=pCertificates->certificates;
#else
pAny=pCertificates->value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pAny++) {
if (!ICM_InsertTailBlob( psdi->pCertificateList, pAny))
goto CertInsertTailBlobError;
}
pcmi->aflDecode |= ICMS_DECODED_SIGNED_CERTIFICATES;
} else {
// The decode failed, presumably due to insufficient data.
// Restore the original tag, so we will enter this block
// and try again on the next call.
*(pbuf->pbData + pbuf->cbDead) = ICM_TAG_CONSTRUCTED_CONTEXT_0;
}
} else {
// Certificates not present. Mark them as decoded.
pcmi->aflDecode |= ICMS_DECODED_SIGNED_CERTIFICATES;
}
}
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_CERTIFICATES))
goto SuccessReturn;
// crls
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_CRLS)) {
if (pbuf->cbUsed > pbuf->cbDead) {
if (ICM_TAG_CONSTRUCTED_CONTEXT_1 ==
*(pbuf->pbData + pbuf->cbDead)) {
// Detected the [1] IMPLICIT indicating crls.
// Change the identifier octet so it will decode properly.
*(pbuf->pbData + pbuf->cbDead) = ICM_TAG_SET;
if (!ICMS_DecodePDU(
pcmi,
pDec,
CrlsNC_PDU,
(void **)&pCrls))
goto DecodeCrlsError;
if (pCrls) {
for (i=pCrls->count,
#ifdef OSS_CRYPT_ASN1
pAny=pCrls->crls;
#else
pAny=pCrls->value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pAny++) {
if (!ICM_InsertTailBlob( psdi->pCrlList, pAny))
goto CrlInsertTailBlobError;
}
pcmi->aflDecode |= ICMS_DECODED_SIGNED_CRLS;
} else {
// The decode failed, presumably due to insufficient data.
// Restore the original tag, so we will enter this block
// and try again on the next call.
*(pbuf->pbData + pbuf->cbDead) = ICM_TAG_CONSTRUCTED_CONTEXT_1;
}
} else {
// Crls not present. Mark them as decoded.
pcmi->aflDecode |= ICMS_DECODED_SIGNED_CRLS;
}
}
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_CRLS))
goto SuccessReturn;
// signerInfos
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_SIGNERINFOS)) {
if (!ICMS_DecodePDU(
pcmi,
pDec,
SignerInfosNC_PDU,
(void **)&pSignerInfos))
goto DecodeSignerInfosError;
if (pSignerInfos) {
for (i=pSignerInfos->count, pAny=pSignerInfos->value;
i>0;
i--, pAny++) {
if (!ICM_InsertTailSigner( psdi->pSignerList, pAny))
goto SignerInfoInsertTailBlobError;
}
pcmi->aflDecode |= ICMS_DECODED_SIGNED_SIGNERINFOS;
}
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_SIGNERINFOS))
goto SuccessReturn;
if (!ICMS_ConsumeTrailingNulls( pcmi, &pcmi->cEndNullPairs, fFinal))
goto ConsumeEndNullsError;
if (0 == pcmi->cEndNullPairs)
pcmi->aflStream |= ICMS_DECODED_SUFFIX;
SuccessReturn:
fRet = TRUE;
CommonReturn:
PkiAsn1FreeInfo( pDec, CertificatesNC_PDU, pCertificates);
PkiAsn1FreeInfo( pDec, CrlsNC_PDU, pCrls);
PkiAsn1FreeInfo( pDec, SignerInfosNC_PDU, pSignerInfos);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(ConsumeInnerNullsError) // error already set
TRACE_ERROR(DecodeCertificatesError) // error already set
TRACE_ERROR(CertInsertTailBlobError) // error already set
TRACE_ERROR(DecodeCrlsError) // error already set
TRACE_ERROR(CrlInsertTailBlobError) // error already set
TRACE_ERROR(DecodeSignerInfosError) // error already set
TRACE_ERROR(SignerInfoInsertTailBlobError) // error already set
TRACE_ERROR(ConsumeEndNullsError) // error already set
}
//+-------------------------------------------------------------------------
// Handle incremental suffix data to be decoded, for an enveloped message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodeSuffixEnveloped(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
BOOL fRet;
ASN1decoding_t pDec = ICM_GetDecoder();
PICM_BUFFER pbuf = &pcmi->bufDecode;
Attributes *pAttributes = NULL;
#ifdef CMS_PKCS7
CmsEnvelopedData *ped = (CmsEnvelopedData *)pcmi->pvMsg;
#endif // CMS_PKCS7
OSS_DECODE_INFO odi;
COssDecodeInfoNode *pnOssDecodeInfo;
if (!ICMS_ConsumeTrailingNulls( pcmi, &pcmi->cInnerNullPairs, fFinal))
goto ConsumeInnerNullsError;
if (pcmi->cInnerNullPairs)
goto SuccessReturn;
// unprotectedAttrs[1] IMPLICIT UnprotectedAttributes OPTIONAL
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ATTR)) {
if (pbuf->cbUsed > pbuf->cbDead) {
if (ICM_TAG_CONSTRUCTED_CONTEXT_1 ==
*(pbuf->pbData + pbuf->cbDead)) {
// Detected the [1] IMPLICIT indicating unprotectedAttrs.
// Change the identifier octet so it will decode properly.
*(pbuf->pbData + pbuf->cbDead) = ICM_TAG_SET;
if (!ICMS_DecodePDU(
pcmi,
pDec,
Attributes_PDU,
(void **)&pAttributes))
goto DecodeAttributesError;
if (pAttributes) {
#ifdef CMS_PKCS7
ped->unprotectedAttrs = *pAttributes;
ped->bit_mask |= unprotectedAttrs_present;
#endif // CMS_PKCS7
odi.iPDU = Attributes_PDU;
odi.pvPDU = pAttributes;
if (NULL == (pnOssDecodeInfo =
new COssDecodeInfoNode( &odi))) {
PkiAsn1FreeInfo( pDec, odi.iPDU, odi.pvPDU);
goto NewOssDecodeInfoNodeError;
}
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ATTR;
pcmi->plDecodeInfo->InsertTail( pnOssDecodeInfo);
} else {
// The decode failed, presumably due to insufficient data.
// Restore the original tag, so we will enter this block
// and try again on the next call.
*(pbuf->pbData + pbuf->cbDead) =
ICM_TAG_CONSTRUCTED_CONTEXT_1;
}
} else {
// unprotectedAttrs not present. Mark them as decoded.
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ATTR;
}
} else if (fFinal)
// unprotectedAttrs not present. Mark them as decoded.
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ATTR;
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ATTR))
goto SuccessReturn;
if (!ICMS_ConsumeTrailingNulls( pcmi, &pcmi->cEndNullPairs, fFinal))
goto ConsumeEndNullsError;
if (0 == pcmi->cEndNullPairs)
pcmi->aflStream |= ICMS_DECODED_SUFFIX;
SuccessReturn:
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(ConsumeInnerNullsError) // error already set
TRACE_ERROR(DecodeAttributesError) // error already set
TRACE_ERROR(NewOssDecodeInfoNodeError) // error already set
TRACE_ERROR(ConsumeEndNullsError) // error already set
}
//+-------------------------------------------------------------------------
// Handle incremental suffix data to be decoded.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodeSuffix(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
switch (pcmi->dwMsgType) {
case CMSG_DATA:
fRet = ICMS_DecodeSuffixData( pcmi, fFinal);
break;
case CMSG_SIGNED:
fRet = ICMS_DecodeSuffixSigned( pcmi, fFinal);
break;
case CMSG_ENVELOPED:
fRet = ICMS_DecodeSuffixEnveloped( pcmi, fFinal);
break;
case CMSG_HASHED:
// fRet = ICMS_DecodeSuffixDigested( pcmi, fFinal);
// break;
case CMSG_SIGNED_AND_ENVELOPED:
case CMSG_ENCRYPTED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
if (!fRet)
goto ErrorReturn;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
TRACE_ERROR(InvalidMsgType) // error already set
}
//+-------------------------------------------------------------------------
// Decrypt and output pending decode data.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodeDecryptAndOutput(
IN PCRYPT_MSG_INFO pcmi,
IN OUT PICM_BUFFER pbufDecode,
IN OUT PDWORD pcbPending,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
BOOL fBlockCipher = pcmi->fBlockCipher;
PICM_BUFFER pbufCrypt = &pcmi->bufCrypt;
DWORD cbCipher;
DWORD cb;
for (cbCipher = min( *pcbPending, pbufDecode->cbUsed - pbufDecode->cbDead);
cbCipher > 0;) {
cb = min( cbCipher, pbufCrypt->cbSize - pbufCrypt->cbUsed); // must fit
CopyMemory(
pbufCrypt->pbData + pbufCrypt->cbUsed,
pbufDecode->pbData + pbufDecode->cbDead,
cb);
pbufCrypt->cbUsed += cb;
pbufDecode->cbDead += cb;
*pcbPending -= cb;
cbCipher -= cb;
if (pbufCrypt->cbSize == pbufCrypt->cbUsed) {
// Decrypt and copy out the buffer
cb = pbufCrypt->cbSize;
if (fBlockCipher) {
// Keep the last block
cb -= pcmi->cbBlockSize;
}
if (!CryptDecrypt(
pcmi->hkeyContentCrypt,
NULL, // hHash
FALSE, // fFinal
0, // dwFlags
pbufCrypt->pbData,
&cb))
goto DecryptError;
if (!ICMS_Output(
pcmi,
pbufCrypt->pbData,
cb,
FALSE)) // fFinal
goto OutputError;
if (fBlockCipher) {
// Move the last block to the beginning of the buffer
// and reset the count to start after this block.
// Since we are sure the src and dst do not overlap,
// use CopyMemory (faster than MoveMemory).
cb = pbufCrypt->cbSize - pcmi->cbBlockSize;
CopyMemory(
pbufCrypt->pbData,
pbufCrypt->pbData + cb,
pcmi->cbBlockSize);
pbufCrypt->cbUsed = pcmi->cbBlockSize;
} else {
pbufCrypt->cbUsed = 0;
}
}
}
if (fFinal) {
if (cb = pbufCrypt->cbUsed) {
if (!CryptDecrypt(
pcmi->hkeyContentCrypt,
NULL, // hHash
TRUE, // fFinal
0, // dwFlags
pbufCrypt->pbData,
&cb))
goto FinalDecryptError;
}
if (!ICMS_Output(
pcmi,
pbufCrypt->pbData,
cb,
TRUE)) // fFinal
goto FinalOutputError;
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(DecryptError) // error already set
TRACE_ERROR(FinalDecryptError) // error already set
TRACE_ERROR(OutputError) // error already set
TRACE_ERROR(FinalOutputError) // error already set
}
//+-------------------------------------------------------------------------
// Given a key for decryption, prepare for the decryption to proceed.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_SetDecryptKey(
IN PCRYPT_MSG_INFO pcmi,
IN HCRYPTKEY hkeyDecrypt)
{
BOOL fRet;
DWORD cbPending;
PICM_BUFFER pbufPendingCrypt = &pcmi->bufPendingCrypt;
if (pcmi->hkeyContentCrypt) {
SetLastError((DWORD) CRYPT_E_ALREADY_DECRYPTED);
return FALSE;
}
pcmi->hkeyContentCrypt = hkeyDecrypt;
if (!ICMS_CreateEnvelopedBuffer( pcmi))
goto CreateEnvelopedBufferError;
pcmi->bufCrypt.cbSize += pcmi->cbBlockSize; // use whole thing for decode
// Decrypt any pending ciphertext
cbPending = pbufPendingCrypt->cbUsed - pbufPendingCrypt->cbDead;
if (!ICMS_DecodeDecryptAndOutput(
pcmi,
pbufPendingCrypt,
&cbPending,
0 != (pcmi->aflStream & (ICMS_DECODED_CONTENT | ICMS_FINAL))))
goto DecryptAndOutputError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
pcmi->hkeyContentCrypt = 0; // caller closes hkeyDecrypt on
// error
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(CreateEnvelopedBufferError) // error already set
TRACE_ERROR(DecryptAndOutputError) // error already set
}
//+-------------------------------------------------------------------------
// Decode callback.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodeCallback(
IN const void *pvArg,
IN OUT PICM_BUFFER pbuf,
IN OUT PDWORD pcbPending,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PCRYPT_MSG_INFO pcmi = (PCRYPT_MSG_INFO)pvArg;
PBYTE pbData = pbuf->pbData + pbuf->cbDead;
DWORD cbData = min( *pcbPending, pbuf->cbUsed - pbuf->cbDead);
if (CMSG_ENVELOPED == pcmi->dwMsgType) {
if (NULL == pcmi->hkeyContentCrypt) {
// Allow ciphertext to pile up until the decrypt key is set via
// CryptMsgControl(... CMSG_CTRL_DECRYPT ...)
if (!ICMS_QueueToBuffer(&pcmi->bufPendingCrypt, pbData, cbData))
goto QueuePendingCryptError;
pbuf->cbDead += cbData;
*pcbPending -= cbData;
} else if (!ICMS_DecodeDecryptAndOutput(
pcmi,
pbuf,
pcbPending,
fFinal))
goto DecryptAndOutputError;
} else {
if (cbData && pcmi->pHashList) {
if (!ICM_UpdateListDigest( pcmi->pHashList, pbData, cbData))
goto UpdateDigestError;
}
pbuf->cbDead += cbData;
*pcbPending -= cbData;
if (!ICMS_Output( pcmi, pbData, cbData, fFinal))
goto OutputError;
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(QueuePendingCryptError) // error already set
TRACE_ERROR(DecryptAndOutputError) // error already set
TRACE_ERROR(UpdateDigestError) // error already set
TRACE_ERROR(OutputError) // error already set
}
//+-------------------------------------------------------------------------
// Hash callback.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_HashCallback(
IN const void *pvArg,
IN OUT PICM_BUFFER pbuf,
IN OUT PDWORD pcbPending,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PBYTE pbData = pbuf->pbData + pbuf->cbDead;
DWORD cbData = min( *pcbPending, pbuf->cbUsed - pbuf->cbDead);
if (pvArg) {
if (!ICM_UpdateListDigest( (CHashList *)pvArg, pbData, cbData))
goto UpdateDigestError;
}
pbuf->cbDead += cbData;
*pcbPending -= cbData;
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(UpdateDigestError) // error already set
fFinal;
}
//+-------------------------------------------------------------------------
// Hash incremental content data to be encoded, for an octet string.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_HashContent(
IN PCRYPT_MSG_INFO pcmi,
IN PBYTE pbData,
IN DWORD cbData)
{
BOOL fRet;
if (!ICMS_QueueToBuffer( &pcmi->bufEncode, (PBYTE)pbData, cbData))
goto QueueToBufferError;
if (!ICMS_ProcessStringContent(
&pcmi->bufEncode,
&pcmi->aflStream,
&pcmi->cbDefiniteRemain,
&pcmi->cLevelIndefiniteInner,
ICMS_HashCallback,
pcmi->pHashList))
goto ProcessStringContentError;
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(QueueToBufferError) // error already set
TRACE_ERROR(ProcessStringContentError) // error already set
}
//+-------------------------------------------------------------------------
// Handle incremental content data to be decoded, for an octet string.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodeContentOctetString(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
BOOL fRet;
if (!ICMS_ProcessStringContent(
&pcmi->bufDecode,
&pcmi->aflStream,
&pcmi->cbDefiniteRemain,
&pcmi->cLevelIndefiniteInner,
ICMS_DecodeCallback,
pcmi))
goto ProcessStringContentError;
if (pcmi->aflStream & ICMS_PROCESS_CONTENT_DONE)
pcmi->aflStream |= ICMS_DECODED_CONTENT;
if (fFinal &&
(pcmi->cbDefiniteRemain ||
pcmi->cLevelIndefiniteInner ||
(0 == (pcmi->aflStream & ICMS_DECODED_CONTENT)))) {
goto PrematureFinalError;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(PrematureFinalError,CRYPT_E_STREAM_INSUFFICIENT_DATA)
TRACE_ERROR(ProcessStringContentError) // error already set
}
//+-------------------------------------------------------------------------
// Handle incremental content data to be decoded, for a sequence.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodeContentSequence(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
BOOL fRet;
PICM_BUFFER pbuf = &pcmi->bufDecode;
PBYTE pbData = pbuf->pbData + pbuf->cbDead;
DWORD cbData = pbuf->cbUsed - pbuf->cbDead;
LONG lSkipped;
DWORD cbContent;
const BYTE *pbContent;
if (pcmi->aflStream & ICMS_PROCESS_CONTENT_BEGUN)
goto MultipleContentSequenceError;
// Get the tag and length for the inner content
if (0 > (lSkipped = Asn1UtilExtractContent(
pbData,
cbData,
&cbContent,
&pbContent))) {
if (ASN1UTIL_INSUFFICIENT_DATA != lSkipped)
goto ExtractContentError;
else
goto SuccessReturn;
}
if (CMSG_INDEFINITE_LENGTH == cbContent)
goto IndefiniteLengthInnerContentNotImplemented;
// Output the tag and length octets for the encoded inner content.
// Note, not included in the content to be verified in a signature.
if (!ICMS_Output( pcmi, pbData, (DWORD) lSkipped, FALSE))
goto OutputError;
pcmi->aflStream |= ICMS_INNER_OCTETSTRING;
// Decode as an octet string. Will skip the tag and length octets
fRet = ICMS_DecodeContentOctetString(pcmi, fFinal);
CommonReturn:
return fRet;
SuccessReturn:
fRet = TRUE;
goto CommonReturn;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
SET_ERROR(MultipleContentSequenceError, CRYPT_E_MSG_ERROR)
TRACE_ERROR(ExtractContentError)
SET_ERROR(IndefiniteLengthInnerContentNotImplemented, E_NOTIMPL)
TRACE_ERROR(OutputError)
}
//+-------------------------------------------------------------------------
// Handle incremental prefix data to be decoded.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodeContent(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PICM_BUFFER pbuf = &pcmi->bufDecode;
if (pcmi->aflStream & ICMS_RAW_DATA) {
// Should be able to skip bufDecode for this case.
if (!ICMS_Output(
pcmi,
pbuf->pbData + pbuf->cbDead,
pbuf->cbUsed - pbuf->cbDead,
fFinal))
goto RawOutputError;
pbuf->cbDead = pbuf->cbUsed;
if (fFinal)
pcmi->aflStream |= ICMS_DECODED_CONTENT | ICMS_DECODED_SUFFIX;
} else if (pcmi->aflStream & ICMS_INNER_OCTETSTRING) {
if (!ICMS_DecodeContentOctetString( pcmi, fFinal))
goto DecodeContentOctetStringError;
} else {
if (!ICMS_DecodeContentSequence( pcmi, fFinal))
goto DecodeContentSequenceError;
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(RawOutputError) // error already set
TRACE_ERROR(DecodeContentOctetStringError) // error already set
TRACE_ERROR(DecodeContentSequenceError) // error already set
}
//+-------------------------------------------------------------------------
// Handle incremental prefix data to be decoded, for a data message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodePrefixData(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
if (0 ==(pcmi->aflStream & ICMS_NONBARE))
pcmi->aflStream |= ICMS_RAW_DATA;
pcmi->aflStream |= ICMS_DECODED_PREFIX | ICMS_INNER_OCTETSTRING;
return TRUE;
}
//+-------------------------------------------------------------------------
// Handle incremental prefix data to be decoded, for a signed message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodePrefixSigned(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
ASN1decoding_t pDec = ICM_GetDecoder();
PSIGNED_DATA_INFO psdi = pcmi->psdi;
DWORD dwToken;
int *piVersion = NULL;
DigestAlgorithmIdentifiersNC *pDigestAlgorithms = NULL;
Any *pAny;
DWORD cb;
DWORD i;
BOOL fNoContent;
if (NULL == psdi) {
if (NULL == (psdi = (PSIGNED_DATA_INFO)ICM_AllocZero(
sizeof(SIGNED_DATA_INFO))))
goto SdiAllocError;
pcmi->psdi = psdi;
if (NULL == (psdi->pAlgidList = new CBlobList))
goto NewAlgidListError;
if (NULL == (psdi->pCertificateList = new CBlobList))
goto NewCertificateListError;
if (NULL == (psdi->pCrlList = new CBlobList))
goto NewCrlListError;
if (NULL == (psdi->pSignerList = new CSignerList))
goto NewSignerListError;
}
// SignedData sequence
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_SEQ)) {
if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, NULL))
goto GetTokenError;
switch(dwToken) {
case ICMS_TOKEN_INDEFINITE: pcmi->cEndNullPairs++; break;
case ICMS_TOKEN_DEFINITE: break;
case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn;
default: goto InvalidTokenError;
}
pcmi->aflDecode |= ICMS_DECODED_SIGNED_SEQ;
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_SEQ))
goto SuccessReturn;
// version
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_VERSION)) {
if (!ICMS_DecodePDU(
pcmi,
pDec,
IntegerType_PDU,
(void **)&piVersion))
goto DecodeVersionError;
if (piVersion) {
psdi->version = *piVersion;
pcmi->aflDecode |= ICMS_DECODED_SIGNED_VERSION;
}
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_VERSION))
goto SuccessReturn;
// digestAlgorithms
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_DIGESTALGOS)) {
if (!ICMS_DecodePDU(
pcmi,
pDec,
DigestAlgorithmIdentifiersNC_PDU,
(void **)&pDigestAlgorithms))
goto DecodeDigestAlgorithmsError;
if (pDigestAlgorithms) {
for (i=pDigestAlgorithms->count, pAny=pDigestAlgorithms->value;
i>0;
i--, pAny++) {
if (!ICM_InsertTailBlob( psdi->pAlgidList, pAny))
goto DigestAlgorithmInsertTailBlobError;
}
// We have the algorithms. Now create the hash handles.
if (!ICM_CreateHashList(
pcmi->hCryptProv,
&pcmi->pHashList,
pcmi->psdi->pAlgidList))
goto CreateHashListError;
pcmi->aflDecode |= ICMS_DECODED_SIGNED_DIGESTALGOS;
}
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_DIGESTALGOS))
goto SuccessReturn;
// contentInfo
if (0 == (pcmi->aflDecode & ICMS_DECODED_SIGNED_CONTENTINFO)) {
if (!ICMS_DecodePrefixContentInfo(
pcmi,
&pcmi->pooid,
&pcmi->cInnerNullPairs,
&pcmi->aflInner,
&fNoContent))
goto DecodePrefixSignedContentInfoError;
if (pcmi->aflInner & ICMS_DECODED_CONTENTINFO_CONTENT) {
// We cracked the whole header.
// Translate the inner contentType oid into a string.
if (!PkiAsn1FromObjectIdentifier(
pcmi->pooid->count,
pcmi->pooid->value,
NULL,
&cb))
goto PkiAsn1FromObjectIdentifierSizeError;
if (NULL == (psdi->pci = (PCONTENT_INFO)ICM_Alloc(
cb + INFO_LEN_ALIGN(sizeof(CONTENT_INFO)))))
goto AllocContentInfoError;
psdi->pci->pszContentType = (LPSTR)(psdi->pci) +
INFO_LEN_ALIGN(sizeof(CONTENT_INFO));
psdi->pci->content.cbData = 0;
psdi->pci->content.pbData = NULL;
if (!PkiAsn1FromObjectIdentifier(
pcmi->pooid->count,
pcmi->pooid->value,
psdi->pci->pszContentType,
&cb))
goto PkiAsn1FromObjectIdentifierError;
PkiAsn1FreeDecoded(pDec, pcmi->pooid, ObjectIdentifierType_PDU);
pcmi->pooid = NULL;
pcmi->aflDecode |= ICMS_DECODED_SIGNED_CONTENTINFO;
if (fNoContent) {
// No content. Output final flag with no content.
if (!ICMS_Output(pcmi, NULL, 0, TRUE))
goto OutputError;
pcmi->aflStream |= ICMS_DECODED_CONTENT;
} else {
if (0 == strcmp( psdi->pci->pszContentType, pszObjIdDataType)
#ifdef CMS_PKCS7
|| psdi->version >= CMSG_SIGNED_DATA_V3
#endif // CMS_PKCS7
)
pcmi->aflStream |= ICMS_INNER_OCTETSTRING;
}
pcmi->aflStream |= ICMS_DECODED_PREFIX;
}
}
SuccessReturn:
fRet = TRUE;
CommonReturn:
PkiAsn1FreeInfo( pDec, IntegerType_PDU, piVersion);
PkiAsn1FreeInfo( pDec, DigestAlgorithmIdentifiersNC_PDU, pDigestAlgorithms);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
// note, pcmi->psdi and pcmi->pooid are freed in CryptMsgClose
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(SdiAllocError) // error already set
TRACE_ERROR(NewAlgidListError) // error already set
TRACE_ERROR(NewCertificateListError) // error already set
TRACE_ERROR(NewCrlListError) // error already set
TRACE_ERROR(NewSignerListError) // error already set
TRACE_ERROR(GetTokenError) // error already set
TRACE_ERROR(InvalidTokenError) // error already set
TRACE_ERROR(DecodeVersionError) // error already set
TRACE_ERROR(DecodeDigestAlgorithmsError) // error already set
TRACE_ERROR(DigestAlgorithmInsertTailBlobError) // error already set
TRACE_ERROR(CreateHashListError) // error already set
TRACE_ERROR(DecodePrefixSignedContentInfoError) // error already set
TRACE_ERROR(PkiAsn1FromObjectIdentifierSizeError) // error already set
TRACE_ERROR(AllocContentInfoError) // error already set
TRACE_ERROR(PkiAsn1FromObjectIdentifierError) // error already set
TRACE_ERROR(OutputError) // error already set
}
//+-------------------------------------------------------------------------
// Handle incremental prefix data to be decoded, for an enveloped message.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodePrefixEnveloped(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
ASN1decoding_t pDec = ICM_GetDecoder();
PICM_BUFFER pbuf = &pcmi->bufDecode;
#ifdef CMS_PKCS7
CmsEnvelopedData *ped = (CmsEnvelopedData *)pcmi->pvMsg;
#else
EnvelopedData *ped = (EnvelopedData *)pcmi->pvMsg;
#endif // CMS_PKCS7
DWORD dwToken;
int *piVersion = NULL;
#ifdef CMS_PKCS7
CmsRecipientInfos *pRecipientInfos = NULL;
#else
RecipientInfos *pRecipientInfos = NULL;
#endif // CMS_PKCS7
ObjectIdentifierType *pooidContentType = NULL;
AlgorithmIdentifier *poaidContentEncryption = NULL;
COssDecodeInfoNode *pnOssDecodeInfo;
OSS_DECODE_INFO odi;
DWORD cbConsumed;
#ifdef CMS_PKCS7
OriginatorInfoNC *pOriginatorInfo = NULL;
Any *pAny;
DWORD i;
#endif // CMS_PKCS7
if (NULL == ped) {
#ifdef CMS_PKCS7
if (NULL == (ped = (CmsEnvelopedData *)ICM_AllocZero(
sizeof(CmsEnvelopedData))))
#else
if (NULL == (ped = (EnvelopedData *)ICM_AllocZero(
sizeof(EnvelopedData))))
#endif // CMS_PKCS7
goto AllocEnvelopedDataError;
pcmi->pvMsg = ped;
if (NULL == (pcmi->plDecodeInfo = new COssDecodeInfoList))
goto NewCOssDecodeInfoListError;
#ifdef CMS_PKCS7
if (NULL == (pcmi->pCertificateList = new CBlobList))
goto NewCertificateListError;
if (NULL == (pcmi->pCrlList = new CBlobList))
goto NewCrlListError;
#endif // CMS_PKCS7
}
// EnvelopedData SEQ
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_SEQ)) {
if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, NULL))
goto EnvelopedDataSeqGetTokenError;
switch(dwToken) {
case ICMS_TOKEN_INDEFINITE: pcmi->cEndNullPairs++; break;
case ICMS_TOKEN_DEFINITE: break;
case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn;
default: goto InvalidTokenError;
}
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_SEQ;
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_SEQ))
goto SuccessReturn;
// version
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_VERSION)) {
if (!ICMS_DecodePDU(
pcmi,
pDec,
IntegerType_PDU,
(void **)&piVersion))
goto DecodeVersionError;
if (piVersion) {
ped->version = *piVersion;
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_VERSION;
}
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_VERSION))
goto SuccessReturn;
#ifdef CMS_PKCS7
// originatorInfo OPTIONAL
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ORIGINATOR)) {
if (pbuf->cbUsed > pbuf->cbDead) {
if (ICM_TAG_CONSTRUCTED_CONTEXT_0 ==
*(pbuf->pbData + pbuf->cbDead)) {
// Detected the [0] IMPLICIT indicating originatorInfo.
// Change the identifier octet so it will decode properly.
*(pbuf->pbData + pbuf->cbDead) = ICM_TAG_SEQ;
if (!ICMS_DecodePDU(
pcmi,
pDec,
OriginatorInfoNC_PDU,
(void **)&pOriginatorInfo))
goto DecodeOriginatorInfoError;
if (pOriginatorInfo) {
if (pOriginatorInfo->bit_mask & certificates_present) {
for (i=pOriginatorInfo->certificates.count,
#ifdef OSS_CRYPT_ASN1
pAny=pOriginatorInfo->certificates.certificates;
#else
pAny=pOriginatorInfo->certificates.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pAny++) {
if (!ICM_InsertTailBlob( pcmi->pCertificateList,
pAny))
goto CertInsertTailBlobError;
}
}
if (pOriginatorInfo->bit_mask & crls_present) {
for (i=pOriginatorInfo->crls.count,
#ifdef OSS_CRYPT_ASN1
pAny=pOriginatorInfo->crls.crls;
#else
pAny=pOriginatorInfo->crls.value;
#endif // OSS_CRYPT_ASN1
i>0;
i--, pAny++) {
if (!ICM_InsertTailBlob( pcmi->pCrlList, pAny))
goto CrlInsertTailBlobError;
}
}
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ORIGINATOR;
} else {
// The decode failed, presumably due to insufficient data.
// Restore the original tag, so we will enter this block
// and try again on the next call.
*(pbuf->pbData + pbuf->cbDead) =
ICM_TAG_CONSTRUCTED_CONTEXT_0;
}
} else {
// originatorInfo not present. Mark as decoded.
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ORIGINATOR;
}
}
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ORIGINATOR))
goto SuccessReturn;
#endif // CMS_PKCS7
// recipientInfos
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_RECIPINFOS)) {
if (!ICMS_DecodePDU(
pcmi,
pDec,
#ifdef CMS_PKCS7
CmsRecipientInfos_PDU,
#else
RecipientInfos_PDU,
#endif // CMS_PKCS7
(void **)&pRecipientInfos))
goto DecodeRecipientInfosError;
if (pRecipientInfos) {
ped->recipientInfos = *pRecipientInfos;
#ifdef CMS_PKCS7
odi.iPDU = CmsRecipientInfos_PDU;
#else
odi.iPDU = RecipientInfos_PDU;
#endif // CMS_PKCS7
odi.pvPDU = pRecipientInfos;
if (NULL == (pnOssDecodeInfo = new COssDecodeInfoNode( &odi))) {
PkiAsn1FreeInfo( pDec, odi.iPDU, odi.pvPDU);
goto NewOssDecodeInfoNodeError;
}
pcmi->plDecodeInfo->InsertTail( pnOssDecodeInfo);
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_RECIPINFOS;
}
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_RECIPINFOS))
goto SuccessReturn;
// encryptedContentInfo SEQ
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECISEQ)) {
if (!ICMS_GetToken( &pcmi->bufDecode, &dwToken, &pcmi->cbContentInfo))
goto EncryptedContentInfoSeqGetTokenError;
switch(dwToken) {
case ICMS_TOKEN_INDEFINITE: pcmi->cInnerNullPairs++; break;
case ICMS_TOKEN_DEFINITE: break;
case ICMS_TOKEN_INCOMPLETE: goto SuccessReturn;
default: goto InvalidTokenError;
}
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECISEQ;
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECISEQ))
goto SuccessReturn;
// contentType
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECITYPE)) {
if (!ICMS_DecodePDU(
pcmi,
pDec,
ObjectIdentifierType_PDU,
(void **)&pooidContentType,
&cbConsumed))
goto DecodeContentTypeError;
if (pooidContentType) {
ICM_CopyOssObjectIdentifier(&ped->encryptedContentInfo.contentType,
pooidContentType);
// NB- Since ContentType is self-contained and we have saved
// a copy, we can always free pooidContentType when this
// routine exits.
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECITYPE;
if (CMSG_INDEFINITE_LENGTH != pcmi->cbContentInfo) {
if (cbConsumed > pcmi->cbContentInfo)
goto InvalidEncryptedContentInfoLength;
pcmi->cbContentInfo -= cbConsumed;
}
}
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECITYPE))
goto SuccessReturn;
// contentEncryptionAlgorithm
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECIALGID)) {
if (!ICMS_DecodePDU(
pcmi,
pDec,
AlgorithmIdentifier_PDU,
(void **)&poaidContentEncryption,
&cbConsumed))
goto DecodeContentEncryptionAlgorithmError;
if (poaidContentEncryption) {
ped->encryptedContentInfo.contentEncryptionAlgorithm =
*poaidContentEncryption;
odi.iPDU = AlgorithmIdentifier_PDU;
odi.pvPDU = poaidContentEncryption;
if (NULL == (pnOssDecodeInfo = new COssDecodeInfoNode( &odi))) {
PkiAsn1FreeInfo( pDec, AlgorithmIdentifier_PDU,
poaidContentEncryption);
goto NewOssDecodeInfoNodeError;
}
pcmi->plDecodeInfo->InsertTail( pnOssDecodeInfo);
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECIALGID;
if (CMSG_INDEFINITE_LENGTH != pcmi->cbContentInfo &&
cbConsumed == pcmi->cbContentInfo) {
// The encryptedContent has been omitted
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECICONTENT;
pcmi->aflStream |= ICMS_DECODED_PREFIX | ICMS_DECODED_CONTENT;
if (pcmi->hkeyContentCrypt) {
if (!ICMS_Output(
pcmi,
NULL, // pbData
0, // cbData
TRUE)) // fFinal
goto FinalOutputError;
}
}
}
}
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECIALGID))
goto SuccessReturn;
// encryptedContent [0] IMPLICIT OPTIONAL
//
// Only support DATA or encapsulated encrypted content.
if (0 == (pcmi->aflDecode & ICMS_DECODED_ENVELOPED_ECICONTENT)) {
BOOL fNoEncryptedContent = FALSE;
if (pbuf->cbUsed > pbuf->cbDead) {
BYTE bTag = *(pbuf->pbData + pbuf->cbDead);
if (ICM_TAG_CONTEXT_0 == (bTag & ~ICM_TAG_CONSTRUCTED)) {
// Detected the [0] IMPLICIT indicating encryptedContent.
// Change the identifier octet so it will decode properly.
*(pbuf->pbData + pbuf->cbDead) = ICM_TAG_OCTETSTRING |
(bTag & ICM_TAG_CONSTRUCTED);
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECICONTENT;
// The inner type is always OCTET STRING
pcmi->aflStream |= ICMS_DECODED_PREFIX | ICMS_INNER_OCTETSTRING;
} else
fNoEncryptedContent = TRUE;
} else if (fFinal)
fNoEncryptedContent = TRUE;
if (fNoEncryptedContent) {
// The encryptedContent has been omitted
pcmi->aflDecode |= ICMS_DECODED_ENVELOPED_ECICONTENT;
pcmi->aflStream |= ICMS_DECODED_PREFIX | ICMS_DECODED_CONTENT;
if (pcmi->hkeyContentCrypt) {
if (!ICMS_Output(
pcmi,
NULL, // pbData
0, // cbData
TRUE)) // fFinal
goto FinalOutputError;
}
}
}
SuccessReturn:
fRet = TRUE;
CommonReturn:
PkiAsn1FreeInfo( pDec, IntegerType_PDU, piVersion);
#ifdef CMS_PKCS7
PkiAsn1FreeInfo( pDec, OriginatorInfoNC_PDU, pOriginatorInfo);
#endif // CMS_PKCS7
PkiAsn1FreeInfo( pDec, ObjectIdentifierType_PDU, pooidContentType);
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(EnvelopedDataSeqGetTokenError) // error already set
TRACE_ERROR(EncryptedContentInfoSeqGetTokenError) // error already set
TRACE_ERROR(InvalidTokenError) // error already set
TRACE_ERROR(DecodeVersionError) // error already set
TRACE_ERROR(AllocEnvelopedDataError) // error already set
TRACE_ERROR(NewCOssDecodeInfoListError) // error already set
#ifdef CMS_PKCS7
TRACE_ERROR(NewCertificateListError) // error already set
TRACE_ERROR(NewCrlListError) // error already set
TRACE_ERROR(DecodeOriginatorInfoError) // error already set
TRACE_ERROR(CertInsertTailBlobError) // error already set
TRACE_ERROR(CrlInsertTailBlobError) // error already set
#endif // CMS_PKCS7
TRACE_ERROR(DecodeRecipientInfosError) // error already set
TRACE_ERROR(DecodeContentTypeError) // error already set
SET_ERROR(InvalidEncryptedContentInfoLength, CRYPT_E_MSG_ERROR)
TRACE_ERROR(DecodeContentEncryptionAlgorithmError) // error already set
TRACE_ERROR(NewOssDecodeInfoNodeError) // error already set
TRACE_ERROR(FinalOutputError) // error already set
}
//+-------------------------------------------------------------------------
// Handle incremental prefix data to be decoded.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_DecodePrefix(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
LONG lth;
BOOL fNoContent;
if (0 == pcmi->dwMsgType) {
pcmi->aflStream |= ICMS_NONBARE;
if (!ICMS_DecodePrefixContentInfo(
pcmi,
&pcmi->pooid,
&pcmi->cEndNullPairs,
&pcmi->aflOuter,
&fNoContent))
goto DecodePrefixContentInfoError;
if (pcmi->aflOuter & ICMS_DECODED_CONTENTINFO_CONTENT) {
// We cracked the whole header.
// Translate the contentType oid into a message type.
if (0 == (lth = ICM_ObjIdToIndex( pcmi->pooid)))
goto UnknownContentTypeError;
pcmi->dwMsgType = (DWORD)lth;
PkiAsn1FreeDecoded(ICM_GetDecoder(), pcmi->pooid,
ObjectIdentifierType_PDU);
pcmi->pooid = NULL;
// Address case of no content
}
}
switch (pcmi->dwMsgType) {
case 0:
if (fFinal)
goto FinalWithoutMessageTypeError;
break;
case CMSG_DATA:
if (!ICMS_DecodePrefixData( pcmi, fFinal))
goto DecodePrefixDataError;
break;
case CMSG_SIGNED:
if (!ICMS_DecodePrefixSigned( pcmi, fFinal))
goto DecodePrefixSignedError;
break;
case CMSG_ENVELOPED:
if (!ICMS_DecodePrefixEnveloped( pcmi, fFinal))
goto DecodePrefixEnvelopedError;
break;
case CMSG_HASHED:
// if (!ICMS_DecodePrefixDigested( pcmi, fFinal))
// goto DecodePrefixDigestedError;
// break;
case CMSG_SIGNED_AND_ENVELOPED:
case CMSG_ENCRYPTED:
goto MessageTypeNotSupportedYet;
default:
goto InvalidMsgType;
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
SET_ERROR(FinalWithoutMessageTypeError,CRYPT_E_STREAM_INSUFFICIENT_DATA)
TRACE_ERROR(UnknownContentTypeError) // error already set
TRACE_ERROR(DecodePrefixContentInfoError) // error already set
TRACE_ERROR(DecodePrefixDataError) // error already set
TRACE_ERROR(DecodePrefixSignedError) // error already set
TRACE_ERROR(DecodePrefixEnvelopedError) // error already set
SET_ERROR(MessageTypeNotSupportedYet,CRYPT_E_INVALID_MSG_TYPE)
TRACE_ERROR(InvalidMsgType) // error already set
}
//+-------------------------------------------------------------------------
// Handle incremental data to be decoded (work done here).
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_UpdateDecodingInner(
IN PCRYPT_MSG_INFO pcmi,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
if (0 == (pcmi->aflStream & ICMS_DECODED_PREFIX)) {
if (!ICMS_DecodePrefix( pcmi, fFinal))
goto DecodePrefixError;
}
if (0 == (pcmi->aflStream & ICMS_DECODED_PREFIX))
goto SuccessReturn;
if (0 == (pcmi->aflStream & ICMS_DECODED_CONTENT)) {
if (!ICMS_DecodeContent( pcmi, fFinal))
goto DecodeContentError; // NB- Do not trash err from callback!
}
if (0 == (pcmi->aflStream & ICMS_DECODED_CONTENT))
goto SuccessReturn;
if (0 == (pcmi->aflStream & ICMS_DECODED_SUFFIX)) {
if (!ICMS_DecodeSuffix( pcmi, fFinal))
goto DecodeSuffixError;
}
if (0 == (pcmi->aflStream & ICMS_DECODED_SUFFIX))
goto SuccessReturn;
SuccessReturn:
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(DecodePrefixError) // error already set
TRACE_ERROR(DecodeContentError) // error already set
TRACE_ERROR(DecodeSuffixError) // error already set
}
//+-------------------------------------------------------------------------
// Handle incremental data to be decoded.
//
// Note, the buffer to be decoded may have some of its tags modified.
// Therefore, we always need to copy to our own decode buffer.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_UpdateDecoding(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
pcmi->fStreamCallbackOutput = TRUE;
if (!ICMS_QueueToBuffer( &pcmi->bufDecode, (PBYTE)pbData, cbData))
goto QueueToBufferError;
if (!ICMS_UpdateDecodingInner( pcmi, fFinal))
goto UpdateDecodingInnerError;
if (fFinal) {
if (pcmi->bufDecode.cbUsed > pcmi->bufDecode.cbDead)
goto ExcessDataError;
pcmi->aflStream |= ICMS_FINAL;
}
fRet = TRUE;
CommonReturn:
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(QueueToBufferError) // error already set
TRACE_ERROR(UpdateDecodingInnerError) // error already set
SET_ERROR(ExcessDataError, CRYPT_E_MSG_ERROR)
}
#if 0
// When we fix the decoding of [0] Certificates and [1] Crls not to modify
// the encoded data we can replace the above with the following:
//+-------------------------------------------------------------------------
// Handle incremental data to be decoded.
//--------------------------------------------------------------------------
BOOL
WINAPI
ICMS_UpdateDecoding(
IN PCRYPT_MSG_INFO pcmi,
IN const BYTE *pbData,
IN DWORD cbData,
IN BOOL fFinal)
{
DWORD dwError = ERROR_SUCCESS;
BOOL fRet;
PICM_BUFFER pbuf = &pcmi->bufDecode;
BOOL fNoCopy;
pcmi->fStreamCallbackOutput = TRUE;
if (fFinal && NULL == pbuf->pbData) {
// We're able to use the input buffer without copying
fNoCopy = TRUE;
assert(0 == pbuf->cbSize && 0 == pbuf->cbUsed && 0 == pbuf->cbDead);
pbuf->pbData = (PBYTE) pbData;
pbuf->cbSize = cbData;
pbuf->cbUsed = cbData;
pbuf->cbDead = 0;
} else {
fNoCopy = FALSE;
if (!ICMS_QueueToBuffer( pbuf, (PBYTE)pbData, cbData))
goto QueueToBufferError;
}
if (!ICMS_UpdateDecodingInner( pcmi, fFinal))
goto UpdateDecodingInnerError;
if (fFinal) {
if (pcmi->bufDecode.cbUsed > pcmi->bufDecode.cbDead)
goto ExcessDataError;
pcmi->aflStream |= ICMS_FINAL;
}
fRet = TRUE;
CommonReturn:
if (fNoCopy)
memset(pbuf, 0, sizeof(*pbuf));
ICM_SetLastError(dwError);
return fRet;
ErrorReturn:
dwError = GetLastError();
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(QueueToBufferError) // error already set
TRACE_ERROR(UpdateDecodingInnerError) // error already set
SET_ERROR(ExcessDataError, CRYPT_E_MSG_ERROR)
}
#endif