📄 cms_denv.c
字号:
envelopeInfoPtr->usage = ACTION_CRYPT;
*state = DEENVSTATE_SET_ENCR;
break;
case ACTION_CRYPT:
envelopeInfoPtr->usage = ACTION_CRYPT;
*state = DEENVSTATE_ENCRCONTENT;
break;
case ACTION_SIGN:
envelopeInfoPtr->usage = ACTION_SIGN;
*state = DEENVSTATE_SET_HASH;
break;
case ACTION_MAC:
/* MACd envelopes have key exchange information at the start
just like ACTION_KEYEXCHANGE but the later processing is
different, so we treat them as a special case here */
envelopeInfoPtr->usage = ACTION_MAC;
*state = DEENVSTATE_SET_ENCR;
break;
case ACTION_COMPRESS:
/* With compressed data all that we need to do is check that the
fixed AlgorithmIdentifier is present and set up the
decompression stream, after which we go straight to the
content */
status = readGenericAlgoID( stream, OID_ZLIB,
sizeofOID( OID_ZLIB ) );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->usage = ACTION_COMPRESS;
#ifdef USE_COMPRESSION
if( inflateInit( &envelopeInfoPtr->zStream ) != Z_OK )
return( CRYPT_ERROR_MEMORY );
envelopeInfoPtr->flags |= ENVELOPE_ZSTREAMINITED;
*state = DEENVSTATE_CONTENT;
#else
return( CRYPT_ERROR_NOTAVAIL );
#endif /* USE_COMPRESSION */
break;
case ACTION_NONE:
/* Since we're going straight to the data payload there's no
nested content type so we explicitly set it to "data" */
envelopeInfoPtr->contentType = CRYPT_CONTENT_DATA;
*state = DEENVSTATE_DATA;
break;
default:
retIntError();
}
return( CRYPT_OK );
}
/* Process the encrypted content header */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int processEncryptionHeader( INOUT ENVELOPE_INFO *envelopeInfoPtr,
INOUT STREAM *stream )
{
QUERY_INFO queryInfo;
int status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
/* Read the encrypted content header */
status = readCMSencrHeader( stream, nestedContentOIDinfo,
FAILSAFE_ARRAYSIZE( nestedContentOIDinfo, OID_INFO ),
NULL, &queryInfo );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->contentType = status;
envelopeInfoPtr->payloadSize = queryInfo.size;
/* We've reached encrypted data, we can't go any further until we can
either recover the session key from a key exchange object or are fed
the session key directly */
if( envelopeInfoPtr->actionList == NULL )
{
int dummy;
/* Since the content can be indefinite-length we clear the size
field to give it a sensible setting */
queryInfo.size = 0;
return( addContentListItem( envelopeInfoPtr, NULL, &queryInfo,
&dummy ) );
}
REQUIRES( envelopeInfoPtr->actionList != NULL && \
envelopeInfoPtr->actionList->action == ACTION_CRYPT );
/* If the session key was recovered from a key exchange action but we
ran out of input data before we could read the encryptedContent info
it'll be present in the action list so we use it to set things up for
the decryption. This can only happen if the caller pushes in just
enough data to get past the key exchange actions but not enough to
recover the encryptedContent info and then pushes in a key exchange
action in response to the CRYPT_ERROR_UNDERFLOW error */
return( initEnvelopeEncryption( envelopeInfoPtr,
envelopeInfoPtr->actionList->iCryptHandle,
queryInfo.cryptAlgo, queryInfo.cryptMode,
queryInfo.iv, queryInfo.ivLength,
FALSE ) );
}
/* Process the hash object header */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int processHashHeader( INOUT ENVELOPE_INFO *envelopeInfoPtr,
INOUT STREAM *stream )
{
CRYPT_ALGO_TYPE hashAlgo = DUMMY_INIT;
CRYPT_CONTEXT iHashContext;
ACTION_LIST *actionListPtr;
int iterationCount, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
/* Create the hash object from the data */
status = readContextAlgoID( stream, &iHashContext, NULL, DEFAULT_TAG );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
/* Check whether an identical hash action is already present either
through being supplied externally or from a duplicate entry in the
set */
for( actionListPtr = envelopeInfoPtr->actionList, iterationCount = 0;
actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
actionListPtr = actionListPtr->next, iterationCount++ )
{
CRYPT_ALGO_TYPE actionHashAlgo;
status = krnlSendMessage( actionListPtr->iCryptHandle,
IMESSAGE_GETATTRIBUTE, &actionHashAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) && actionHashAlgo == hashAlgo )
{
/* There's a duplicate action present, destroy the one that
we've just created and continue */
krnlSendNotifier( iHashContext, IMESSAGE_DECREFCOUNT );
return( CRYPT_OK );
}
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
/* We didn't find any duplicates, append the new hash action to the
action list and remember that hashing is now active */
status = addAction( &envelopeInfoPtr->actionList,
envelopeInfoPtr->memPoolState,
( envelopeInfoPtr->usage == ACTION_MAC ) ? \
ACTION_MAC : ACTION_HASH, iHashContext );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->dataFlags |= ENVDATA_HASHACTIONSACTIVE;
ENSURES( envelopeInfoPtr->actionList != NULL && \
( envelopeInfoPtr->actionList->action == ACTION_HASH || \
envelopeInfoPtr->actionList->action == ACTION_MAC ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Trailer Processing Routines *
* *
****************************************************************************/
/* Process EOCs that separate the payload from the trailer */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int processPayloadEOCs( INOUT ENVELOPE_INFO *envelopeInfoPtr,
INOUT STREAM *stream )
{
int status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
/* If the payload has an indefinite-length encoding, make sure that the
required EOCs are present */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
{
if( ( status = checkEOC( stream ) ) != TRUE || \
( status = checkEOC( stream ) ) != TRUE )
{
return( cryptStatusError( status ) ? \
status : CRYPT_ERROR_BADDATA );
}
return( CRYPT_OK );
}
/* If the data was encoded using a mixture of definite and indefinite
encoding there may be EOC's present even though the length is known
so we skip them if necessary */
if( ( status = checkEOC( stream ) ) == TRUE )
status = checkEOC( stream );
if( cryptStatusError( status ) )
return( status );
return( CRYPT_OK );
}
/* Complete processing of the authenticated payload */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int completePayloadProcessing( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
/* When we reach this point there may still be unhashed data left in the
buffer. It won't have been hashed yet because the hashing is
performed when the data is copied out, after unwrapping and
deblocking and whatnot, so we hash it before we wrap up the
hashing */
if( envelopeInfoPtr->dataLeft > 0 )
{
int status;
status = envelopeInfoPtr->processExtraData( envelopeInfoPtr,
envelopeInfoPtr->buffer,
envelopeInfoPtr->dataLeft );
if( cryptStatusError( status ) )
return( status );
}
/* Wrap up the hashing */
return( envelopeInfoPtr->processExtraData( envelopeInfoPtr, "", 0 ) );
}
/* Process the signed data trailer */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int processSignedTrailer( INOUT ENVELOPE_INFO *envelopeInfoPtr,
INOUT STREAM *stream,
INOUT_ENUM( DEENV_STATE ) DEENV_STATE *state )
{
DEENV_STATE newState;
int tag, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( state, sizeof( DEENV_STATE ) ) );
/* Read the SignedData EOC's if necessary */
status = processPayloadEOCs( envelopeInfoPtr, stream );
if( cryptStatusError( status ) )
return( status );
/* Check whether there's a certificate chain to follow */
tag = peekTag( stream );
if( cryptStatusError( tag ) )
return( tag );
newState = ( tag == MAKE_CTAG( 0 ) ) ? \
DEENVSTATE_CERTSET : DEENVSTATE_SET_SIG;
/* If we've seen all of the signed data complete the hashing */
if( !( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) )
{
status = completePayloadProcessing( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
}
/* Move on to the next state */
*state = newState;
return( CRYPT_OK );
}
/* Process the MACd data trailer */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
static int processMacTrailer( INOUT ENVELOPE_INFO *envelopeInfoPtr,
INOUT STREAM *stream,
OUT_BOOL BOOLEAN *failedMAC )
{
MESSAGE_DATA msgData;
BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ];
int hashSize, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isWritePtr( failedMAC, sizeof( BOOLEAN ) ) );
/* Clear return value */
*failedMAC = FALSE;
/* Read the AuthenticatedData EOC's if necessary */
status = processPayloadEOCs( envelopeInfoPtr, stream );
if( cryptStatusError( status ) )
return( status );
/* Read the MAC value that follows the payload */
status = readOctetString( stream, hash, &hashSize, 16,
CRYPT_MAX_HASHSIZE );
if( cryptStatusError( status ) )
return( status );
/* Complete the payload processing and compare the read MAC value with
the calculated one */
status = completePayloadProcessing( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
setMessageData( &msgData, hash, hashSize );
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
IMESSAGE_COMPARE, &msgData,
MESSAGE_COMPARE_HASH );
if( cryptStatusError( status ) )
{
/* Unlike signatures a failed MAC check (reported as a CRYPT_ERROR
comparison result) is detected immediately rather than after the
payload processing has completed. However if we bail out now
then any later checks of things like signature metadata will fail
because the envelope regards processing as still being incomplete
so we have to continue processing data until we at least get the
envelope to the finished state */
assert( status == CRYPT_ERROR );
*failedMAC = TRUE;
}
return( CRYPT_OK );
}
/* Process any remaining EOCs. This gets a bit complicated because there
can be a variable number of EOCs depending on where definite and
indefinite encodings were used so we look for at least one EOC and at
most a number that depends on the data type being processed */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -