mirror of https://github.com/tongzx/nt5src
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
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
|