📄 cryptenv.c
字号:
}
}
return( status );
}
/* Pop data from an envelope */
static int envelopePop( ENVELOPE_INFO *envelopeInfoPtr, void *buffer,
const int length, int *bytesCopied )
{
int bytesOut;
/* If we're enveloping data, just copy as much as we can to the output */
if( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) )
{
/* Copy the data from the envelope to the output */
bytesOut = envelopeInfoPtr->copyFromEnvelope( envelopeInfoPtr,
buffer, length );
if( cryptStatusError( bytesOut ) )
{
envelopeInfoPtr->errorState = bytesOut;
return( bytesOut );
}
*bytesCopied = bytesOut;
return( CRYPT_OK );
}
/* We're de-enveloping data, if we haven't reached the data yet force a
push 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 push to resolve the state of
the data in the envelope */
if( envelopeInfoPtr->state == STATE_PREDATA )
{
int dummy, status;
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 */
bytesOut = envelopeInfoPtr->copyFromDeenvelope( envelopeInfoPtr,
buffer, length );
if( cryptStatusError( bytesOut ) )
{
envelopeInfoPtr->errorState = bytesOut;
return( bytesOut );
}
*bytesCopied = bytesOut;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Envelope Message Handler *
* *
****************************************************************************/
/* Handle a message sent to an envelope */
static int envelopeMessageFunction( const CRYPT_ENVELOPE cryptEnvelope,
const RESOURCE_MESSAGE_TYPE message,
void *messageDataPtr,
const int messageValue )
{
ENVELOPE_INFO *envelopeInfoPtr;
getCheckInternalResource( cryptEnvelope, envelopeInfoPtr, OBJECT_TYPE_ENVELOPE );
/* Process destroy object messages */
if( message == RESOURCE_MESSAGE_DESTROY )
{
int status = CRYPT_OK;
/* Envelope deletion has an extra complication in that instead of
simply decrementing its reference count like other objects, we
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 which can't be popped). We can't perform this check in
the delete function because this may be called from other sections
of the code, so we have to do it here.
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 ) )
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->preActionList );
deleteActionList( envelopeInfoPtr->actionList );
deleteActionList( envelopeInfoPtr->postActionList );
deleteContentList( envelopeInfoPtr->contentList );
#ifndef NO_COMPRESSION
/* Delete the zlib compression state information if necessary */
if( envelopeInfoPtr->zStreamInited )
if( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE )
inflateEnd( &envelopeInfoPtr->zStream );
else
deflateEnd( &envelopeInfoPtr->zStream );
#endif /* NO_COMPRESSION */
/* Handle the keyset cleanup by calling the internal keyset close
function */
if( envelopeInfoPtr->iSigCheckKeyset != CRYPT_ERROR )
krnlSendNotifier( envelopeInfoPtr->iSigCheckKeyset,
RESOURCE_IMESSAGE_DECREFCOUNT );
if( envelopeInfoPtr->iEncryptionKeyset != CRYPT_ERROR )
krnlSendNotifier( envelopeInfoPtr->iEncryptionKeyset,
RESOURCE_IMESSAGE_DECREFCOUNT );
if( envelopeInfoPtr->iDecryptionKeyset != CRYPT_ERROR )
krnlSendNotifier( envelopeInfoPtr->iDecryptionKeyset,
RESOURCE_IMESSAGE_DECREFCOUNT );
/* Clean up other envelope objects */
if( envelopeInfoPtr->iOriginatorChain != CRYPT_ERROR )
krnlSendNotifier( envelopeInfoPtr->iOriginatorChain,
RESOURCE_IMESSAGE_DECREFCOUNT );
/* Clear and free the buffers if necessary */
if( envelopeInfoPtr->buffer != NULL )
{
zeroise( envelopeInfoPtr->buffer, envelopeInfoPtr->bufSize );
free( envelopeInfoPtr->buffer );
}
if( envelopeInfoPtr->auxBuffer != NULL )
{
zeroise( envelopeInfoPtr->auxBuffer, envelopeInfoPtr->auxBufSize );
free( envelopeInfoPtr->auxBuffer );
}
/* Delete the objects locking variables and the object itself */
unlockResource( envelopeInfoPtr );
deleteResourceLock( envelopeInfoPtr );
zeroise( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) );
free( envelopeInfoPtr );
return( status );
}
/* Process attribute get/set/delete messages */
if( isAttributeMessage( message ) )
{
int status;
assert( message == RESOURCE_MESSAGE_GETATTRIBUTE || \
message == RESOURCE_MESSAGE_GETATTRIBUTE_S || \
message == RESOURCE_MESSAGE_SETATTRIBUTE || \
message == RESOURCE_MESSAGE_SETATTRIBUTE_S );
if( message == RESOURCE_MESSAGE_GETATTRIBUTE )
status = processGetAttribute( envelopeInfoPtr, messageDataPtr,
messageValue );
if( message == RESOURCE_MESSAGE_GETATTRIBUTE_S )
status = processGetAttributeS( envelopeInfoPtr, messageDataPtr,
messageValue );
if( message == RESOURCE_MESSAGE_SETATTRIBUTE )
status = processSetAttribute( envelopeInfoPtr, messageDataPtr,
messageValue );
if( message == RESOURCE_MESSAGE_SETATTRIBUTE_S )
status = processSetAttributeS( envelopeInfoPtr, messageDataPtr,
messageValue );
unlockResourceExit( envelopeInfoPtr, status );
}
/* Process messages which lock/unlock an object for exclusive use */
if( message == RESOURCE_MESSAGE_LOCK )
/* Exit without unlocking the object. Any other threads trying to
use the object after this point will be blocked */
return( CRYPT_OK );
if( message == RESOURCE_MESSAGE_UNLOCK )
{
/* "Wenn drei Leute in ein Zimmer reingehen und fuenf kommen raus,
dann muessen erst mal zwei wieder reingehen bis das Zimmer leer
ist" */
unlockResource( envelopeInfoPtr ); /* Undo RESOURCE_MESSAGE_LOCK lock */
unlockResourceExit( envelopeInfoPtr, CRYPT_OK );
}
/* Process object-specific messages */
if( message == RESOURCE_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 everything is in order */
if( msgData->length == 0 )
{
/* If it's a flush, make sure 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 */
if( envelopeInfoPtr->state == STATE_FINISHED )
unlockResourceExit( envelopeInfoPtr, CRYPT_OK );
if( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) && \
( envelopeInfoPtr->state != STATE_DATA && \
envelopeInfoPtr->state != STATE_POSTDATA ) )
unlockResourceExit( envelopeInfoPtr,
CRYPT_ERROR_INCOMPLETE );
}
if( envelopeInfoPtr->state == STATE_FINISHED )
unlockResourceExit( envelopeInfoPtr, CRYPT_ERROR_COMPLETE );
if( envelopeInfoPtr->errorState != CRYPT_OK )
unlockResourceExit( envelopeInfoPtr,
envelopeInfoPtr->errorState );
if( ( ( envelopeInfoPtr->flags & \
( ENVELOPE_NOSEGMENT & ENVELOPE_ISDEENVELOPE ) ) == ENVELOPE_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 */
setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_DATASIZE,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
/* 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;
unlockResourceExit( envelopeInfoPtr, status );
}
if( message == RESOURCE_MESSAGE_ENV_POPDATA )
{
RESOURCE_DATA *msgData = ( RESOURCE_DATA * ) messageDataPtr;
int bytesCopied, status;
assert( msgData->data != NULL && msgData->length > 0 );
/* Make sure everything is in order */
if( envelopeInfoPtr->errorState != CRYPT_OK )
unlockResourceExit( envelopeInfoPtr,
envelopeInfoPtr->errorState );
/* Get the data from the envelope */
status = envelopePop( envelopeInfoPtr, msgData->data,
msgData->length, &bytesCopied );
msgData->length = bytesCopied;
unlockResourceExit( envelopeInfoPtr, status );
}
assert( NOTREACHED );
return( CRYPT_ERROR ); /* Get rid of compiler warning */
}
/* Create an envelope. This is a low-level function encapsulated by
createEnvelope() and used to manage error exits */
static int initEnvelope( CRYPT_ENVELOPE *iCryptEnvelope,
const CRYPT_USER cryptOwner,
const CRYPT_FORMAT_TYPE formatType,
ENVELOPE_INFO **envelopeInfoPtrPtr )
{
ENVELOPE_INFO *envelopeInfoPtr;
const BOOLEAN isDeenvelope = ( formatType == CRYPT_FORMAT_AUTO ) ? \
TRUE : FALSE;
const int subType = \
isDeenvelope ? SUBTYPE_ENV_DEENV : \
( formatType == CRYPT_FORMAT_PGP ) ? \
SUBTYPE_ENV_ENV_PGP : SUBTYPE_ENV_ENV;
void *auxBuffer;
int status;
/* Clear the return values */
*iCryptEnvelope = CRYPT_ERROR;
*envelopeInfoPtrPtr = NULL;
/* If PGP support is disabled, we can't specify PGP as a target format */
#ifdef NO_PGP
if( createInfo->arg1 == CRYPT_FORMAT_PGP )
return( CRYPT_ARGERROR_NUM1 );
#endif /* NO_PGP */
/* Allocate the auxiliary buffer (for enveloping only) */
if( !isDeenvelope && \
( auxBuffer = malloc( DEFAULT_AUXBUFFER_SIZE ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
/* Create the envelope object */
status = krnlCreateObject( ( void ** ) &envelopeInfoPtr, cryptOwner,
OBJECT_TYPE_ENVELOPE, subType,
sizeof( ENVELOPE_INFO ), 0, 0,
envelopeMessageFunction );
if( cryptStatusError( status ) )
{
if( !isDeenvelope )
free( auxBuffer );
return( status );
}
initResourceLock( envelopeInfoPtr );
lockResource( envelopeInfoPtr );
*envelopeInfoPtrPtr = envelopeInfoPtr;
*iCryptEnvelope = envelopeInfoPtr->objectHandle = status;
envelopeInfoPtr->ownerHandle = cryptOwner;
envelopeInfoPtr->bufSize = DEFAULT_BUFFER_SIZE;
if( isDeenvelope )
envelopeInfoPtr->flags = ENVELOPE_ISDEENVELOPE;
else
{
envelopeInfoPtr->auxBuffer = auxBuffer;
memset( envelopeInfoPtr->auxBuffer, 0, DEFAULT_AUXBUFFER_SIZE );
envelopeInfoPtr->auxBufSize = DEFAULT_AUXBUFFER_SIZE;
}
envelopeInfoPtr->type = formatType;
envelopeInfoPtr->state = STATE_PREDATA;
/* Set up any internal objects to contain invalid handles */
envelopeInfoPtr->iCryptContext = \
envelopeInfoPtr->iOriginatorChain = CRYPT_ERROR;
envelopeInfoPtr->iSigCheckKeyset = envelopeInfoPtr->iEncryptionKeyset = \
envelopeInfoPtr->iDecryptionKeyset = CRYPT_ERROR;
envelopeInfoPtr->payloadSize = CRYPT_UNUSED;
/* Set up the enveloping methods */
if( formatType == CRYPT_FORMAT_PGP )
initPGPEnveloping( envelopeInfoPtr );
else
initCMSEnveloping( envelopeInfoPtr );
initDataStreaming( envelopeInfoPtr );
initResourceHandling( envelopeInfoPtr );
/* Set up the de-enveloping methods. We default to PKCS #7/CMS/SMIME,
if the data is in some other format we'll adjust the function
pointers once the user pushes in the first data quantity */
if( isDeenvelope )
initCMSDeenveloping( envelopeInfoPtr );
return( CRYPT_OK );
}
int createEnvelope( MESSAGE_CREATEOBJECT_INFO *createInfo,
const void *auxDataPtr, const int auxValue )
{
CRYPT_ENVELOPE iCryptEnvelope;
ENVELOPE_INFO *envelopeInfoPtr;
int initStatus, status;
assert( auxDataPtr == NULL );
assert( auxValue == 0 );
/* Perform basic error checking */
if( createInfo->arg1 <= CRYPT_FORMAT_NONE || \
createInfo->arg1 >= CRYPT_FORMAT_LAST )
return( CRYPT_ARGERROR_NUM1 );
/* Pass the call on to the lower-level open function */
initStatus = initEnvelope( &iCryptEnvelope, createInfo->cryptOwner,
createInfo->arg1, &envelopeInfoPtr );
if( envelopeInfoPtr == NULL )
return( initStatus ); /* Create object failed, return immediately */
if( cryptStatusError( initStatus ) )
/* The session open failed, make sure the object gets destroyed when
we notify the kernel that the setup process is complete */
krnlSendNotifier( iCryptEnvelope, RESOURCE_IMESSAGE_DESTROY );
/* We've finished setting up the object-type-specific info, tell the
kernel the object is ready for use */
unlockResource( envelopeInfoPtr );
status = krnlSendMessage( iCryptEnvelope, RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_OK, CRYPT_IATTRIBUTE_STATUS );
if( cryptStatusError( initStatus ) || cryptStatusError( status ) )
return( cryptStatusError( initStatus ) ? initStatus : status );
createInfo->cryptHandle = iCryptEnvelope;
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -