📄 cryptenv.c
字号:
memcpy( envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos,
bufPtr, bytesToCopy );
envelopeInfoPtr->bufPos += bytesToCopy;
*bytesCopied += bytesToCopy;
}
#else
const int bytesToCopy = \
min( envelopeInfoPtr->bufSize - envelopeInfoPtr->dataLeft,
bytesIn );
if( bytesToCopy )
{
memcpy( envelopeInfoPtr->buffer + envelopeInfoPtr->dataLeft,
bufPtr, bytesToCopy );
envelopeInfoPtr->bufPos = envelopeInfoPtr->dataLeft + \
bytesToCopy;
*bytesCopied += bytesToCopy;
}
#endif /* 1 */
}
/* Process the postamble. During this processing we can encounter
two special types of recoverable error, CRYPT_ERROR_UNDERFLOW (we
need more data to continue) or OK_SPECIAL (we processed all the
data, but there's out-of-band information still to go), if it's
one of these we don't treat it as a standard error */
status = envelopeInfoPtr->processPostambleFunction( envelopeInfoPtr );
if( cryptStatusError( status ) && status != OK_SPECIAL )
{
if( !isRecoverableError( status ) )
envelopeInfoPtr->errorState = status;
return( status );
}
/* If the routine returns OK_SPECIAL then it's processed enough of
the postamble for the caller to continue, but there's more to go
so we shouldn't change the overall state yet */
if( status == OK_SPECIAL )
status = CRYPT_OK;
else
/* We've processed all data, we're done unless it's a detached
sig with the data supplied out-of-band */
envelopeInfoPtr->state = \
( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) ? \
STATE_EXTRADATA : STATE_FINISHED;
/* At this point we always exit since the out-of-band data has to be
processed in a separate push */
return( status );
}
/* If there's extra out-of-band data present, process it separately.
This is slightly complicated by the fact that the single envelope is
being used to process two independent lots of data, so we have to be
careful to distinguish between handling of the main payload data and
handling of this additional out-of-band data */
if( envelopeInfoPtr->state == STATE_EXTRADATA )
{
/* We pass this point twice, the first time round we check the state
and if it's DEENVSTATE_DONE (set when processing of the main data
was completed) we reset it to DEENVSTATE_NONE and make sure that
it's a flush */
if( envelopeInfoPtr->deenvState == DEENVSTATE_DONE )
{
/* We've finished with the main payload data, reset the state for
the additional out-of-band data. Normally we exit here since
it's a flush, however if the hash value was supplied
externally (which means hashing was never active, since it was
done by the caller), we drop through to the wrap-up, since
there's no second flush of payload data to be performed and so
the flush applies to both sets of data */
envelopeInfoPtr->deenvState = DEENVSTATE_NONE;
if( envelopeInfoPtr->dataFlags & ENVDATA_HASHACTIONSACTIVE )
return( length ? CRYPT_ERROR_BADDATA : CRYPT_OK );
}
/* This is just raw additional data so we feed it directly to the
processing function */
status = envelopeInfoPtr->processExtraData( envelopeInfoPtr, buffer,
length );
if( cryptStatusOK( status ) )
{
*bytesCopied = length;
if( !length )
envelopeInfoPtr->state = STATE_FINISHED;
}
}
return( status );
}
/* Pop data from an envelope */
static int envelopePop( ENVELOPE_INFO *envelopeInfoPtr, void *buffer,
const int length, int *bytesCopied )
{
int status;
/* Copy the data from the envelope to the output */
status = envelopeInfoPtr->copyFromEnvelopeFunction( envelopeInfoPtr,
buffer, length );
if( cryptStatusError( status ) )
{
envelopeInfoPtr->errorState = status;
return( status );
}
*bytesCopied = status;
return( CRYPT_OK );
}
static int deenvelopePop( ENVELOPE_INFO *envelopeInfoPtr, void *buffer,
const int length, int *bytesCopied )
{
int status;
/* If we haven't reached the data yet force a flush to try and get to the
data. We can end up with this condition if the caller pushes in
deenveloping information and then immediately tries to pop data
without an intervening flush (or implicit flush on the initial push) to
resolve the state of the data in the envelope */
if( envelopeInfoPtr->state == STATE_PREDATA )
{
int dummy;
status = deenvelopePush( envelopeInfoPtr, NULL, 0, &dummy );
if( cryptStatusError( status ) )
return( status );
/* If we still haven't got anywhere, return an underflow error */
if( envelopeInfoPtr->state == STATE_PREDATA )
return( CRYPT_ERROR_UNDERFLOW );
}
/* Copy the data from the envelope to the output */
status = envelopeInfoPtr->copyFromEnvelopeFunction( envelopeInfoPtr,
buffer, length );
if( cryptStatusError( status ) )
{
envelopeInfoPtr->errorState = status;
return( status );
}
*bytesCopied = status;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Envelope Message Handler *
* *
****************************************************************************/
/* Handle a message sent to an envelope */
static int envelopeMessageFunction( const void *objectInfoPtr,
const MESSAGE_TYPE message,
void *messageDataPtr,
const int messageValue )
{
ENVELOPE_INFO *envelopeInfoPtr = ( ENVELOPE_INFO * ) objectInfoPtr;
/* Process destroy object messages */
if( message == MESSAGE_DESTROY )
{
int status = CRYPT_OK;
/* Check to see whether the envelope still needs operations performed
on it to resolve the state of the data within it (for example if
the caller pushes data but doesn't flush it, there will be a few
bytes left that can't be popped). For enveloping, destroying the
envelope while it's in any state other than STATE_PREDATA or
STATE_FINISHED is regarded as an error. For de-enveloping we have
to be more careful, since deenveloping information required to
resolve the envelope state could be unavailable, so we shouldn't
return an error if something like a signature check remains to be
done. What we therefore do is check to see whether we've processed
any data yet and report an error if there's any data left in the
envelope or if we destroy it in the middle of processing data */
if( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE )
{
/* If we've got to the point of processing data in the envelope
and there's either more to come or some left to pop, we
shouldn't be destroying it yet */
if( envelopeInfoPtr->state == STATE_DATA || \
( ( envelopeInfoPtr->state == STATE_POSTDATA || \
envelopeInfoPtr->state == STATE_FINISHED ) && \
envelopeInfoPtr->dataLeft > 0 ) )
status = CRYPT_ERROR_INCOMPLETE;
}
else
/* If we're in the middle of processing data, we shouldn't be
destroying the envelope yet */
if( envelopeInfoPtr->state != STATE_PREDATA && \
envelopeInfoPtr->state != STATE_FINISHED )
status = CRYPT_ERROR_INCOMPLETE;
/* Delete the action and content lists */
deleteActionList( envelopeInfoPtr->memPoolState,
envelopeInfoPtr->preActionList );
deleteActionList( envelopeInfoPtr->memPoolState,
envelopeInfoPtr->actionList );
deleteActionList( envelopeInfoPtr->memPoolState,
envelopeInfoPtr->postActionList );
deleteContentList( envelopeInfoPtr->memPoolState,
envelopeInfoPtr->contentList );
#ifdef USE_COMPRESSION
/* Delete the zlib compression state information if necessary */
if( envelopeInfoPtr->flags & ENVELOPE_ZSTREAMINITED )
{
if( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE )
inflateEnd( &envelopeInfoPtr->zStream );
else
deflateEnd( &envelopeInfoPtr->zStream );
}
#endif /* USE_COMPRESSION */
/* Clean up keysets */
if( envelopeInfoPtr->iSigCheckKeyset != CRYPT_ERROR )
krnlSendNotifier( envelopeInfoPtr->iSigCheckKeyset,
IMESSAGE_DECREFCOUNT );
if( envelopeInfoPtr->iEncryptionKeyset != CRYPT_ERROR )
krnlSendNotifier( envelopeInfoPtr->iEncryptionKeyset,
IMESSAGE_DECREFCOUNT );
if( envelopeInfoPtr->iDecryptionKeyset != CRYPT_ERROR )
krnlSendNotifier( envelopeInfoPtr->iDecryptionKeyset,
IMESSAGE_DECREFCOUNT );
/* Clean up other envelope objects */
if( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR )
krnlSendNotifier( envelopeInfoPtr->iExtraCertChain,
IMESSAGE_DECREFCOUNT );
/* Clear and free the buffers if necessary */
if( envelopeInfoPtr->buffer != NULL )
{
zeroise( envelopeInfoPtr->buffer, envelopeInfoPtr->bufSize );
clFree( "envelopeMessageFunction", envelopeInfoPtr->buffer );
}
if( envelopeInfoPtr->auxBuffer != NULL )
{
zeroise( envelopeInfoPtr->auxBuffer, envelopeInfoPtr->auxBufSize );
clFree( "envelopeMessageFunction", envelopeInfoPtr->auxBuffer );
}
/* Delete the object itself */
zeroise( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) );
clFree( "envelopeMessageFunction", envelopeInfoPtr );
return( status );
}
/* Process attribute get/set/delete messages */
if( isAttributeMessage( message ) )
{
assert( message == MESSAGE_GETATTRIBUTE || \
message == MESSAGE_GETATTRIBUTE_S || \
message == MESSAGE_SETATTRIBUTE || \
message == MESSAGE_SETATTRIBUTE_S );
if( message == MESSAGE_GETATTRIBUTE )
return( processGetAttribute( envelopeInfoPtr, messageDataPtr,
messageValue ) );
if( message == MESSAGE_GETATTRIBUTE_S )
return( processGetAttributeS( envelopeInfoPtr, messageDataPtr,
messageValue ) );
if( message == MESSAGE_SETATTRIBUTE )
return( processSetAttribute( envelopeInfoPtr, messageDataPtr,
messageValue ) );
if( message == MESSAGE_SETATTRIBUTE_S )
return( processSetAttributeS( envelopeInfoPtr, messageDataPtr,
messageValue ) );
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warn */
}
/* Process object-specific messages */
if( message == MESSAGE_ENV_PUSHDATA )
{
RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
int bytesCopied, status;
assert( ( msgData->data == NULL && msgData->length == 0 ) || \
( msgData->data != NULL && msgData->length > 0 ) );
/* Make sure that everything is in order */
if( msgData->length == 0 )
{
/* If it's a flush, make sure that we're in a state where this is
valid. We can only perform a flush on enveloping if we're in
the data or postdata state, on deenveloping a flush can
happen at any time since the entire payload could be buffered
pending the addition of a deenveloping resource, so the
envelope goes from pre -> post in one step. There is however
one special case in which a push in the pre-data state is
valid and that's when we're creating a zero-length CMS signed
message as a means of communicating authenticated attributes
(of all the standard users of CMS, only SCEP normally does
this). In order to indicate that this special case is in
effect, we require that the user set the ENVELOPE_ATTRONLY
flag before pushing data, although for completeness we could
also check the CMS attributes for the presence of SCEP
attributes. The downside of this additional checking is that
it makes any non-SCEP use of signature-only CMS envelopes
impossible */
if( envelopeInfoPtr->state == STATE_FINISHED )
return( CRYPT_OK );
if( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) && \
( envelopeInfoPtr->state != STATE_DATA && \
envelopeInfoPtr->state != STATE_POSTDATA ) && \
!( envelopeInfoPtr->state == STATE_PREDATA && \
envelopeInfoPtr->usage == ACTION_SIGN && \
envelopeInfoPtr->type == CRYPT_FORMAT_CMS && \
( envelopeInfoPtr->flags & ENVELOPE_ATTRONLY ) ) )
return( CRYPT_ERROR_INCOMPLETE );
}
else
if( envelopeInfoPtr->state == STATE_FINISHED )
return( CRYPT_ERROR_COMPLETE );
if( envelopeInfoPtr->errorState != CRYPT_OK )
return( envelopeInfoPtr->errorState );
if( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) && \
( envelopeInfoPtr->dataFlags & ENVDATA_NOSEGMENT ) && \
envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
/* If we're enveloping using a non-segmenting encoding of the
payload, the caller has to explicitly set the payload size
before they can add any data */
return( exitErrorNotInited( envelopeInfoPtr,
CRYPT_ENVINFO_DATASIZE ) );
/* Send the data to the envelope */
if( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE )
status = deenvelopePush( envelopeInfoPtr, msgData->data,
msgData->length, &bytesCopied );
else
status = envelopePush( envelopeInfoPtr, msgData->data,
msgData->length, &bytesCopied );
msgData->length = bytesCopied;
return( status );
}
if( message == MESSAGE_ENV_POPDATA )
{
RESOURCE_DATA *msgDa
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -