📄 cms_denv.c
字号:
"Couldn't synchronise envelope state prior "
"to data payload processing", 68 );
break;
}
streamPos = 0; /* Data has been resync'd with start of stream */
/* We're done */
state = DEENVSTATE_DONE;
ENSURES( checkActions( envelopeInfoPtr ) );
}
}
sMemDisconnect( &stream );
if( iterationCount >= FAILSAFE_ITERATIONS_LARGE )
{
/* Technically this would be an overflow but that's a recoverable
error so we make it a BADDATA, which is really what it is */
return( CRYPT_ERROR_BADDATA );
}
envelopeInfoPtr->deenvState = state;
ENSURES( streamPos >= 0 && streamPos < MAX_INTLENGTH && \
envelopeInfoPtr->bufPos - streamPos >= 0 );
/* Consume the input that we've processed so far by moving everything
past the current position down to the start of the envelope buffer */
remainder = envelopeInfoPtr->bufPos - streamPos;
REQUIRES( remainder >= 0 && remainder < MAX_INTLENGTH && \
streamPos + remainder <= envelopeInfoPtr->bufSize );
if( remainder > 0 && streamPos > 0 )
{
memmove( envelopeInfoPtr->buffer, envelopeInfoPtr->buffer + streamPos,
remainder );
}
envelopeInfoPtr->bufPos = remainder;
ENSURES( sanityCheck( envelopeInfoPtr ) );
if( cryptStatusError( status ) )
return( status );
/* If all went OK but we're still not out of the header information,
return an underflow error */
return( ( state != DEENVSTATE_DONE ) ? \
CRYPT_ERROR_UNDERFLOW : CRYPT_OK );
}
CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1 ) ) \
static int processPostamble( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
DEENV_STATE state = envelopeInfoPtr->deenvState;
STREAM stream;
BOOLEAN failedMAC = FALSE;
int remainder, streamPos = 0, iterationCount = 0, status = CRYPT_OK;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES( sanityCheck( envelopeInfoPtr ) );
/* If that's all that there is, return */
if( state == DEENVSTATE_NONE && \
( envelopeInfoPtr->usage != ACTION_SIGN && \
envelopeInfoPtr->usage != ACTION_MAC ) && \
envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
{
/* Definite-length data with no trailer, there's nothing left to
process */
envelopeInfoPtr->deenvState = DEENVSTATE_DONE;
return( CRYPT_OK );
}
/* If there's not enough data left in the stream to do anything, don't
try and go any further */
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 )
{
switch( envelopeInfoPtr->usage )
{
case ACTION_SIGN:
status = processSignedTrailer( envelopeInfoPtr, &stream,
&state );
break;
case ACTION_MAC:
status = processMacTrailer( envelopeInfoPtr, &stream,
&failedMAC );
if( cryptStatusOK( status ) )
{
state = \
( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
DEENVSTATE_EOC : DEENVSTATE_DONE;
}
break;
default:
/* Just look for EOC's */
state = DEENVSTATE_EOC;
break;
}
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
setErrorString( ENVELOPE_ERRINFO,
"Invalid CMS signed/MACd data trailer", 36 );
}
streamPos = stell( &stream );
}
/* Keep consuming information until we run out of input or reach the end
of the data */
while( state != DEENVSTATE_DONE && \
iterationCount++ < FAILSAFE_ITERATIONS_MED )
{
/* Read the certificate chain */
if( state == DEENVSTATE_CERTSET )
{
int certSetLength;
/* Read the certificate chain into the aux.buffer. We can't
import it yet at this point because we need the SignerInfo to
definitively identify the leaf certificate. 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) certificates */
status = getStreamObjectLength( &stream, &certSetLength );
if( cryptStatusError( status ) )
{
setErrorString( ENVELOPE_ERRINFO,
"Invalid signing certificate chain header",
40 );
break;
}
if( envelopeInfoPtr->auxBuffer == NULL )
{
/* Allocate a buffer for the certificate 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 = \
clAlloc( "processPostamble", certSetLength ) ) == NULL )
{
status = CRYPT_ERROR_MEMORY;
break;
}
envelopeInfoPtr->auxBufSize = certSetLength;
}
ENSURES( envelopeInfoPtr->auxBufSize == certSetLength );
status = sread( &stream, envelopeInfoPtr->auxBuffer,
envelopeInfoPtr->auxBufSize );
if( cryptStatusError( status ) )
break;
/* Remember where we are and move on to the next state */
streamPos = stell( &stream );
state = DEENVSTATE_SET_SIG;
}
/* Read the start of the SET OF Signature */
if( state == DEENVSTATE_SET_SIG )
{
int setLength;
/* Read the SET tag and length */
status = readSetI( &stream, &setLength );
if( cryptStatusError( status ) )
{
setErrorString( ENVELOPE_ERRINFO,
"Invalid SET OF Signature header", 31 );
break;
}
envelopeInfoPtr->hdrSetLength = setLength;
/* 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 = stell( &stream );
state = DEENVSTATE_SIG;
}
/* Read and remember a signature object from a Signature record */
if( state == DEENVSTATE_SIG )
{
int contentItemLength;
/* Add the object to the content information list */
status = addContentListItem( envelopeInfoPtr, &stream, NULL,
&contentItemLength );
if( cryptStatusError( status ) )
{
setErrorString( ENVELOPE_ERRINFO,
"Invalid CMS signature record", 28 );
break;
}
/* Remember where we are and move on to the next state if
necessary */
streamPos = stell( &stream );
if( envelopeInfoPtr->hdrSetLength != CRYPT_UNUSED )
{
if( contentItemLength < 0 || \
contentItemLength > envelopeInfoPtr->hdrSetLength )
{
status = CRYPT_ERROR_BADDATA;
break;
}
envelopeInfoPtr->hdrSetLength -= contentItemLength;
if( envelopeInfoPtr->hdrSetLength <= 0 )
{
state = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
DEENVSTATE_EOC : DEENVSTATE_DONE;
}
}
else
{
const int value = checkEOC( &stream );
if( cryptStatusError( value ) )
{
status = value;
setErrorString( ENVELOPE_ERRINFO,
"Invalid CMS EOC trailer", 23 );
break;
}
if( value == TRUE )
{
state = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
DEENVSTATE_EOC : DEENVSTATE_DONE;
}
}
}
/* Handle end-of-contents octets */
if( state == DEENVSTATE_EOC )
{
status = processEOCTrailer( &stream, envelopeInfoPtr->usage );
if( cryptStatusError( status ) )
break;
/* We're done */
streamPos = stell( &stream );
state = DEENVSTATE_DONE;
break;
}
}
sMemDisconnect( &stream );
if( iterationCount >= FAILSAFE_ITERATIONS_MED )
{
/* We can only go once through the loop on a MAC check, so we
shouldn't get here with a failed MAC */
ENSURES( !failedMAC );
/* Technically this would be an overflow but that's a recoverable
error so we make it a BADDATA, which is really what it is */
return( CRYPT_ERROR_BADDATA );
}
envelopeInfoPtr->deenvState = state;
ENSURES( streamPos >= 0 && streamPos < MAX_INTLENGTH );
/* Consume the input that we've processed so far by moving everything
past the current position down to the start of the memory buffer:
bufPos
| bufSize
v v
+-----------+-------+-----------+---+
| dataLeft | | | |
+-----------+-------+-----------+---+
|<--+-->|<-- rem -->|
|
streamPos */
remainder = envelopeInfoPtr->bufPos - \
( envelopeInfoPtr->dataLeft + streamPos );
REQUIRES( remainder >= 0 && remainder < MAX_INTLENGTH && \
envelopeInfoPtr->dataLeft + streamPos + \
remainder <= envelopeInfoPtr->bufPos );
if( remainder > 0 && streamPos > 0 )
{
memmove( envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft,
envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft + streamPos,
remainder );
}
envelopeInfoPtr->bufPos = envelopeInfoPtr->dataLeft + remainder;
ENSURES( sanityCheck( envelopeInfoPtr ) );
if( failedMAC )
{
/* If the MAC check failed then this overrides any other status */
return( CRYPT_ERROR_SIGNATURE );
}
if( cryptStatusError( status ) )
{
/* If we 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 && envelopeInfoPtr->dataLeft > 0 )
return( OK_SPECIAL );
return( status );
}
/* If all went OK but we're still not out of the header information,
return an underflow error */
return( ( state != DEENVSTATE_DONE ) ? CRYPT_ERROR_UNDERFLOW : CRYPT_OK );
}
/****************************************************************************
* *
* Envelope Access Routines *
* *
****************************************************************************/
STDC_NONNULL_ARG( ( 1 ) ) \
void initCMSDeenveloping( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES_V( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE );
/* Set the access method pointers */
envelopeInfoPtr->processPreambleFunction = processPreamble;
envelopeInfoPtr->processPostambleFunction = processPostamble;
envelopeInfoPtr->checkAlgo = cmsCheckAlgo;
/* Set up the processing state information */
envelopeInfoPtr->deenvState = DEENVSTATE_NONE;
}
#endif /* USE_ENVELOPES */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -