📄 denv_cms.c
字号:
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 */
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. This isn't strictly 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( checkEOC( &stream ) != TRUE || \
checkEOC( &stream ) != TRUE )
{
status = sGetStatus( &stream );
sMemDisconnect( &stream );
return( cryptStatusOK( status ) ? \
CRYPT_ERROR_BADDATA : 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 = 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 )
{
/* 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 = getStreamObjectLength( &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 = \
clAlloc( "processPostamble", 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 = 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 = readSetI( &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 = stell( &stream );
envelopeInfoPtr->hdrSetLength = length;
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, NULL );
if( cryptStatusError( status ) )
break;
/* Remember where we are and move on to the next state if
necessary */
streamPos = stell( &stream );
if( envelopeInfoPtr->hdrSetLength != CRYPT_UNUSED )
{
envelopeInfoPtr->hdrSetLength -= status;
if( envelopeInfoPtr->hdrSetLength <= 0 )
state = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
DEENVSTATE_EOC : DEENVSTATE_DONE;
}
else
{
status = checkEOC( &stream );
if( cryptStatusError( status ) )
break;
if( status == TRUE )
state = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
DEENVSTATE_EOC : DEENVSTATE_DONE;
}
}
/* Handle end-of-contents octets. 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 ENC and at most a number that depends on the data type
being processed */
if( state == DEENVSTATE_EOC )
{
const int noEOCs = \
( envelopeInfoPtr->usage == ACTION_SIGN ) ? 3 : \
( envelopeInfoPtr->usage == ACTION_COMPRESS ) ? 5 : 4;
int i;
/* We need at least one EOC */
status = checkEOC( &stream );
if( status == FALSE )
status = CRYPT_ERROR_BADDATA;
if( cryptStatusError( status ) )
break;
/* Consume any further EOCs up to the maximum amount possible */
for( i = 1; !cryptStatusError( status ) && i < noEOCs && \
sMemDataLeft( &stream ) >= 2; i++ )
{
status = checkEOC( &stream );
if( status == FALSE )
status = CRYPT_ERROR_BADDATA;
}
if( cryptStatusError( status ) )
break;
/* We're done */
streamPos = 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->processPreambleFunction = processPreamble;
envelopeInfoPtr->processPostambleFunction = processPostamble;
/* Set up the processing state information */
envelopeInfoPtr->deenvState = DEENVSTATE_NONE;
}
#endif /* USE_ENVELOPES */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -