📄 deenvel.c
字号:
break;
/* Remember where we are and move on to the next state. Some
implementations use the indefinite-length encoding for this so
if there's no length given we have to look for the EOC after
each entry read */
streamPos = ( int ) stell( &stream );
envelopeInfoPtr->hdrSetLength = ( length ) ? length : CRYPT_UNUSED;
state = DEENVSTATE_HASH;
}
/* Read and remember a hash object from a DigestAlgorithmIdentifier
record */
if( state == DEENVSTATE_HASH )
{
CRYPT_ALGO hashAlgo;
CRYPT_CONTEXT iHashContext;
ACTION_LIST *actionListPtr;
/* Create the hash object from the data */
status = readContextAlgoID( &stream, &iHashContext, NULL,
DEFAULT_TAG );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iHashContext,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
break;
/* 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;
actionListPtr != NULL; actionListPtr = actionListPtr->next )
{
CRYPT_ALGO actionHashAlgo;
status = krnlSendMessage( actionListPtr->iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&actionHashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) && actionHashAlgo == hashAlgo )
{
/* There's a duplicate action present, destroy the one
we've just created and exit */
krnlSendNotifier( iHashContext,
RESOURCE_IMESSAGE_DECREFCOUNT );
break;
}
}
if( actionListPtr == NULL )
{
/* We didn't find any duplicates, append the new hash action
to the action list and remember that hashing is now
active */
if( addAction( &envelopeInfoPtr->actionList, ACTION_HASH,
iHashContext ) == NULL )
{
status = CRYPT_ERROR_MEMORY;
break;
}
envelopeInfoPtr->hashActionsActive = TRUE;
}
assert( envelopeInfoPtr->actionList->action == ACTION_HASH );
/* Remember where we are and move on to the next state if
necessary */
if( envelopeInfoPtr->hdrSetLength != CRYPT_UNUSED )
{
envelopeInfoPtr->hdrSetLength -= \
( int ) stell( &stream ) - streamPos;
streamPos = ( int ) stell( &stream );
if( envelopeInfoPtr->hdrSetLength <= 0 )
state = DEENVSTATE_CONTENT;
}
else
if( checkEOC( &stream ) )
state = DEENVSTATE_CONTENT;
}
/* Read the encapsulated content header */
if( state == DEENVSTATE_CONTENT )
{
status = readCMSheader( &stream, nestedContentOIDselection,
&envelopeInfoPtr->payloadSize, TRUE );
if( cryptStatusError( status ) )
break;
envelopeInfoPtr->contentType = status;
status = CRYPT_OK;
/* If there's no content included, this is a detached signature
with the content supplied anderswhere */
if( !envelopeInfoPtr->payloadSize )
envelopeInfoPtr->flags |= ENVELOPE_DETACHED_SIG;
/* Remember where we are and move on to the next state */
streamPos = ( int ) stell( &stream );
state = ( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) ? \
DEENVSTATE_DONE : DEENVSTATE_DATA;
}
/* Start the decryption process if necessary */
if( state == DEENVSTATE_DATA )
{
/* Synchronise the data stream processing to the start of the
encrypted data and move back to the start of the data
stream */
status = envelopeInfoPtr->syncDeenvelopeData( envelopeInfoPtr,
&stream );
if( cryptStatusError( status ) )
break;
streamPos = 0;
/* We're done */
state = DEENVSTATE_DONE;
assert( actionsOK( envelopeInfoPtr ) );
}
}
envelopeInfoPtr->deenvState = state;
/* Consume the input we've processed so far by moving everything past the
current position down to the start of the memory buffer */
length = envelopeInfoPtr->bufPos - streamPos;
if( length > 0 && streamPos )
memmove( envelopeInfoPtr->buffer, envelopeInfoPtr->buffer + streamPos,
length );
envelopeInfoPtr->bufPos = length;
/* If all went OK but we're still not out of the header information,
return an underflow error */
if( cryptStatusOK( status ) && state != DEENVSTATE_DONE )
status = CRYPT_ERROR_UNDERFLOW;
/* Clean up */
sMemDisconnect( &stream );
return( status );
}
static int processPostamble( ENVELOPE_INFO *envelopeInfoPtr )
{
DEENV_STATE state = envelopeInfoPtr->deenvState;
STREAM stream;
int length, streamPos = 0, status = CRYPT_OK;
/* If that's all there is, return. This check isn't necessary for the
following code to work, but is required to avoid triggering the stream
check for a zero-length stream open */
if( state == DEENVSTATE_NONE && envelopeInfoPtr->usage != ACTION_SIGN && \
envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
{
/* Definite-length data with no trailer, nothing left to process */
envelopeInfoPtr->deenvState = DEENVSTATE_DONE;
return( CRYPT_OK );
}
/* If there's not enough data left in the stream to do anything with,
return immediately. Again, this isn't necessary but is required to
avoid triggering the zero-length stream check */
if( envelopeInfoPtr->bufPos - envelopeInfoPtr->dataLeft < 2 )
return( CRYPT_ERROR_UNDERFLOW );
/* Start reading the trailer data from the end of the payload */
sMemConnect( &stream, envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft,
envelopeInfoPtr->bufPos - envelopeInfoPtr->dataLeft );
/* If we haven't started doing anything yet, figure out what we should be
looking for */
if( state == DEENVSTATE_NONE )
if( envelopeInfoPtr->usage == ACTION_SIGN )
{
DEENV_STATE newState;
/* Read the SignedData EOC's if necessary */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
{
if( ( sgetc( &stream ) || sgetc( &stream ) || \
sgetc( &stream ) || sgetc( &stream ) ) )
{
status = ( sGetStatus( &stream ) == CRYPT_OK ) ? \
CRYPT_ERROR_BADDATA : sGetStatus( &stream );
sMemDisconnect( &stream );
return( status );
}
}
else
{
/* 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 */
checkEOC( &stream );
checkEOC( &stream );
}
/* Check whether there's a cert chain to follow */
status = peekTag( &stream );
if( cryptStatusError( status ) )
return( status );
newState = ( status == MAKE_CTAG( 0 ) ) ? \
DEENVSTATE_CERTSET : DEENVSTATE_SET_SIG;
/* If we've seen all the signed data, complete the hashing. 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->flags & ENVELOPE_DETACHED_SIG ) )
{
if( envelopeInfoPtr->dataLeft )
status =
envelopeInfoPtr->processExtraData( envelopeInfoPtr,
envelopeInfoPtr->buffer,
envelopeInfoPtr->dataLeft );
if( !cryptStatusError( status ) ) /* Status == tag */
status = \
envelopeInfoPtr->processExtraData( envelopeInfoPtr,
"", 0 );
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
}
/* Move on to the next state */
streamPos = ( int ) stell( &stream );
state = newState;
}
else
/* Just look for EOC's */
state = DEENVSTATE_EOC;
/* Keep consuming information until we run out of input or read the end
of the data */
while( state != DEENVSTATE_DONE )
{
/* Check that various values are within range. They can go out of
range if the header is corrupted */
if( envelopeInfoPtr->hdrSetLength < 0 && \
envelopeInfoPtr->hdrSetLength != CRYPT_UNUSED )
{
status = CRYPT_ERROR_BADDATA;
break;
}
/* Read the cert chain */
if( state == DEENVSTATE_CERTSET )
{
int length;
/* Read the cert chain into the aux.buffer. We can't import it
at this point because we need the SignerInfo to definitively
identify the leaf cert. Usually there's only one leaf, but
there will be more than one if there are multiple signatures
present, or if the sending app decides to shovel in assorted
(non-relevant) certs */
length = getObjectLength( sMemBufPtr( &stream ),
sMemDataLeft( &stream ) );
if( cryptStatusError( length ) )
{
status = length;
break;
}
if( envelopeInfoPtr->auxBuffer == NULL )
{
/* Allocate a buffer for the cert chain if necessary. This
may already be allocated if the previous attempt to read
the chain failed due to there being insufficient data in
the envelope buffer */
if( ( envelopeInfoPtr->auxBuffer = malloc( length ) ) == NULL )
{
status = CRYPT_ERROR_MEMORY;
break;
}
envelopeInfoPtr->auxBufSize = length;
}
assert( envelopeInfoPtr->auxBufSize == length );
status = sread( &stream, envelopeInfoPtr->auxBuffer,
envelopeInfoPtr->auxBufSize );
if( cryptStatusError( status ) )
break;
/* Remember where we are and move on to the next state */
streamPos = ( int ) stell( &stream );
state = DEENVSTATE_SET_SIG;
}
/* Read the start of the SET OF Signature */
if( state == DEENVSTATE_SET_SIG )
{
/* Read the SET tag and length */
status = readSet( &stream, &length );
if( cryptStatusError( status ) )
break;
/* Remember where we are and move on to the next state. Some
implementations use the indefinite-length encoding for this so
if there's no length given we have to look for the EOC after
each entry read */
streamPos = ( int ) stell( &stream );
envelopeInfoPtr->hdrSetLength = ( length ) ? length : CRYPT_UNUSED;
state = DEENVSTATE_SIG;
}
/* Read and remember a signature object from a Signature record */
if( state == DEENVSTATE_SIG )
{
/* Add the object to the content information list */
status = addContentListItem( &stream, envelopeInfoPtr );
if( cryptStatusError( status ) )
break;
/* Remember where we are and move on to the next state if
necessary */
streamPos = ( int ) stell( &stream );
if( envelopeInfoPtr->hdrSetLength != CRYPT_UNUSED )
{
envelopeInfoPtr->hdrSetLength -= status;
if( envelopeInfoPtr->hdrSetLength <= 0 )
state = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
DEENVSTATE_EOC : DEENVSTATE_DONE;
}
else
if( checkEOC( &stream ) )
state = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
DEENVSTATE_EOC : DEENVSTATE_DONE;
}
/* Handle end-of-contents octets */
if( state == DEENVSTATE_EOC )
{
BYTE buffer[ 16 ];
const int eocLen = ( envelopeInfoPtr->usage == ACTION_SIGN ) ? \
6 : 8;
status = sread( &stream, buffer, eocLen );
if( cryptStatusOK( status ) && \
memcmp( buffer, "\x00\x00\x00\x00\x00\x00\x00\x00", eocLen ) )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
break;
/* We're done */
streamPos = ( int ) stell( &stream );
state = DEENVSTATE_DONE;
break;
}
}
envelopeInfoPtr->deenvState = state;
sMemDisconnect( &stream );
/* Consume the input we've processed so far by moving everything past the
current position down to the start of the memory buffer */
length = envelopeInfoPtr->bufPos - ( envelopeInfoPtr->dataLeft + streamPos );
if( length > 0 && streamPos > 0 )
memmove( envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft,
envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft + streamPos,
length );
envelopeInfoPtr->bufPos = envelopeInfoPtr->dataLeft + length;
/* Adjust the error state based on what's left in the envelope buffer.
If there's data still present, we don't report certain types of errors
because they don't affect the data, only the trailer */
if( envelopeInfoPtr->dataLeft )
{
/* If we've got an underflow error but there's payload data left to
be copied out, convert the status to OK since the caller can still
continue before they need to copy in more data. Since there's
more data left to process, we return OK_SPECIAL to tell the
calling function not to perform any cleanup */
if( status == CRYPT_ERROR_UNDERFLOW )
status = OK_SPECIAL;
}
else
/* If all went OK but we're still not out of the header information,
return an underflow error */
if( cryptStatusOK( status ) && state != DEENVSTATE_DONE )
status = CRYPT_ERROR_UNDERFLOW;
return( cryptStatusError( status ) ? status : CRYPT_OK );
}
/****************************************************************************
* *
* Envelope Access Routines *
* *
****************************************************************************/
void initCMSDeenveloping( ENVELOPE_INFO *envelopeInfoPtr )
{
/* Set the access method pointers */
envelopeInfoPtr->processPreamble = processPreamble;
envelopeInfoPtr->processPostamble = processPostamble;
/* Set up the processing state information */
envelopeInfoPtr->deenvState = DEENVSTATE_NONE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -