📄 envelope.c
字号:
{
status = initEnvelopeEncryption( envelopeInfoPtr,
envelopeInfoPtr->actionList->iCryptHandle,
CRYPT_UNUSED, CRYPT_UNUSED, NULL, 0, FALSE );
if( cryptStatusError( status ) )
return( status );
}
/* Write the appropriate CMS header based on the envelope usage.
Since this is the first data written, we can write it directly to
the envelope buffer without having to go via the auxBuffer. The
DigestedData action is never taken since the higher-level code
assumes that the presence of hash actions indicates the desire to
create signed data and returns an error if no signature actions
are present */
sMemOpen( &stream, envelopeInfoPtr->buffer, envelopeInfoPtr->bufSize );
switch( envelopeInfoPtr->usage )
{
case ACTION_CRYPT:
if( envelopeInfoPtr->preActionList == NULL )
status = writeEncryptedDataHeader( &stream, envelopeInfoPtr );
else
status = writeEnvelopedDataHeader( &stream, envelopeInfoPtr );
break;
case ACTION_SIGN:
status = writeAuthenticatedDataHeader( &stream,
envelopeInfoPtr, TRUE );
break;
case ACTION_HASH:
status = writeAuthenticatedDataHeader( &stream,
envelopeInfoPtr, FALSE );
break;
case ACTION_COMPRESS:
writeCompressedDataHeader( &stream, envelopeInfoPtr );
break;
case ACTION_NONE:
writeCMSheader( &stream, OID_CMS_DATA,
envelopeInfoPtr->payloadSize, FALSE );
break;
default:
assert( NOTREACHED );
}
envelopeInfoPtr->bufPos = ( int ) stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
/* If we're not encrypting with key exchange actions, we're done */
if( envelopeInfoPtr->usage != ACTION_CRYPT || \
envelopeInfoPtr->preActionList == NULL )
{
/* Make sure we start a new segment if we try to add any data,
set the block size mask to all ones if we're not encrypting
(since we can begin and end data segments on arbitrary
boundaries), and record the fact that we're done */
envelopeInfoPtr->segmentComplete = TRUE;
if( envelopeInfoPtr->usage != ACTION_CRYPT )
envelopeInfoPtr->blockSizeMask = -1;
envelopeInfoPtr->lastAction = NULL;
envelopeInfoPtr->envState = ENVSTATE_DONE;
return( CRYPT_OK );
}
/* Start emitting the key exchange actions */
envelopeInfoPtr->lastAction = findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE_PKC );
if( envelopeInfoPtr->lastAction == NULL )
envelopeInfoPtr->lastAction = findAction( envelopeInfoPtr->preActionList,
ACTION_KEYEXCHANGE );
state = ENVSTATE_KEYINFO;
/* In very rare instances (when we're using a key agreement key and
there's a lot of originator info) the header can contain a large
amount of data which won't fit into the main buffer, so we copy it
into the auxBuffer instead. If this happens we need to tell the
user to pop some data so we can move more of it out of the
auxBuffer */
if( envelopeInfoPtr->auxBufPos && copyFromAuxBuffer( envelopeInfoPtr ) )
{
envelopeInfoPtr->envState = ENVSTATE_KEYINFO;
return( CRYPT_ERROR_OVERFLOW );
}
}
/* Keep producing output until we fill the envelope buffer or run out of
header information to encode */
while( state != ENVSTATE_DONE )
{
/* Handle key export actions */
if( state == ENVSTATE_KEYINFO )
{
ACTION_LIST *lastActionPtr = envelopeInfoPtr->lastAction;
/* Export the session key using each of the PKC or conventional
keys. If it's a conventional key exchange, we force the use
of the CMS format since there's no reason to use the cryptlib
format */
while( cryptStatusOK( status ) && lastActionPtr != NULL )
{
status = iCryptExportKeyEx( envelopeInfoPtr->auxBuffer,
&envelopeInfoPtr->auxBufPos,
( lastActionPtr->action == ACTION_KEYEXCHANGE ) ? \
CRYPT_FORMAT_CMS : envelopeInfoPtr->type,
envelopeInfoPtr->iCryptContext,
lastActionPtr->iCryptHandle,
( envelopeInfoPtr->iOriginatorChain != CRYPT_ERROR ) ? \
envelopeInfoPtr->iOriginatorChain : CRYPT_UNUSED );
if( !cryptStatusError( status ) )
{
lastActionPtr = lastActionPtr->next;
if( copyFromAuxBuffer( envelopeInfoPtr ) )
status = CRYPT_ERROR_OVERFLOW;
}
}
envelopeInfoPtr->lastAction = lastActionPtr;
/* If we've reached the last key exchange action, move on to the
next state. Since the emission of the key exchange
information is interruptible, we only move on to the next
state if there are no errors */
if( cryptStatusError( status ) )
break;
if( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED )
/* If it's an indefinite-length header, close off the set of
key exchange actions */
writeEndIndef( &envelopeInfoPtr->auxStream );
state = ENVSTATE_ENCRINFO;
}
/* Handle encrypted content information */
if( state == ENVSTATE_ENCRINFO )
{
/* Write the encrypted content header */
status = writeEncryptedContentHeader( &envelopeInfoPtr->auxStream,
getContentOID( envelopeInfoPtr->contentType ),
envelopeInfoPtr->iCryptContext, envelopeInfoPtr->payloadSize,
envelopeInfoPtr->blockSize );
if( cryptStatusOK( status ) && \
copyFromAuxStream( envelopeInfoPtr ) )
status = CRYPT_ERROR_OVERFLOW;
/* Make sure we start a new segment if we try to add any data */
envelopeInfoPtr->segmentComplete = TRUE;
/* We're done */
state = ENVSTATE_DONE;
}
}
/* Remember the state information */
envelopeInfoPtr->envState = state;
return( status );
}
/* Output as much of the postamble as possible into the envelope buffer */
static int emitPostamble( ENVELOPE_INFO *envelopeInfoPtr )
{
ENV_STATE state = envelopeInfoPtr->envState;
int status = CRYPT_OK;
/* If there's any data left in the auxiliary buffer, try and empty that
first */
if( envelopeInfoPtr->auxBufPos && copyFromAuxBuffer( envelopeInfoPtr ) )
return( CRYPT_ERROR_OVERFLOW );
/* Emit the trailer */
if( state == ENVSTATE_NONE )
{
/* Finish the OCTET STRING encoding by flushing any remaining data
from internal buffers into the envelope buffer and adding PKCS #5
padding if we're using a block encryption mode */
status = envelopeInfoPtr->copyToEnvelope( envelopeInfoPtr,
( BYTE * ) "", 0 );
if( cryptStatusError( status ) )
return( status );
/* If it's something other than pure encrypted data, emit the data
end-of-contents octets and follow it with the trailer */
if( envelopeInfoPtr->usage == ACTION_SIGN )
{
/* Write the end-of-contents octets for the Data OCTET STRING,
[0], and SEQUENCE if necessary */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
{
writeEndIndef( &envelopeInfoPtr->auxStream );
writeEndIndef( &envelopeInfoPtr->auxStream );
writeEndIndef( &envelopeInfoPtr->auxStream );
}
envelopeInfoPtr->lastAction = envelopeInfoPtr->postActionList;
/* Write the signing cert chain if it's a CMS signature and
they're not explicitly excluded, followed by the SET OF
SignerInfo header */
if( ( envelopeInfoPtr->type == CRYPT_FORMAT_CMS || \
envelopeInfoPtr->type == CRYPT_FORMAT_SMIME ) && \
!( envelopeInfoPtr->flags & ENVELOPE_NOSIGNINGCERTS ) )
{
RESOURCE_DATA msgData;
setResourceData( &msgData,
sMemBufPtr( &envelopeInfoPtr->auxStream ),
sMemDataLeft( &envelopeInfoPtr->auxStream ) );
status = krnlSendMessage( envelopeInfoPtr->lastAction->iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_CERTSET );
if( cryptStatusError( status ) )
return( status );
sSkip( &envelopeInfoPtr->auxStream,
envelopeInfoPtr->extraDataSize );
}
if( envelopeInfoPtr->hasIndefiniteTrailer )
writeSetIndef( &envelopeInfoPtr->auxStream );
else
writeSet( &envelopeInfoPtr->auxStream,
envelopeInfoPtr->signActionSize );
state = ENVSTATE_SIGNATURE;
if( copyFromAuxStream( envelopeInfoPtr ) )
{
envelopeInfoPtr->envState = state;
return( CRYPT_ERROR_OVERFLOW );
}
}
else
{
/* There's no trailer, emit the various end-of-contents octets if
necessary */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
{
/* Write the end-of-contents octets for the encapsulated data
if necessary */
if( envelopeInfoPtr->usage == ACTION_CRYPT || \
envelopeInfoPtr->usage == ACTION_COMPRESS )
{
writeEndIndef( &envelopeInfoPtr->auxStream );
writeEndIndef( &envelopeInfoPtr->auxStream );
if( envelopeInfoPtr->usage == ACTION_COMPRESS )
/* Compressed data requires an extra EOC due to the
explicit tagging */
writeEndIndef( &envelopeInfoPtr->auxStream );
}
state = ENVSTATE_EOC;
}
else
state = ENVSTATE_DONE;
}
}
/* Keep producing output until we fill the envelope buffer or run out of
trailer information to encode */
while( state != ENVSTATE_DONE )
{
/* Handle signing actions */
if( state == ENVSTATE_SIGNATURE )
{
ACTION_LIST *lastActionPtr = envelopeInfoPtr->lastAction;
assert( lastActionPtr != NULL && lastActionPtr->action == ACTION_SIGN );
/* Sign each hash using the associated signature key */
while( cryptStatusOK( status ) && lastActionPtr != NULL )
{
int signingAttributes;
/* Determine the type of signing attributes to use. If none
are specified (which can only happen under circumstances
controlled by the pre-envelope-signing code), either get
the signing code to add the default ones for use, or use
none at all if the use of default attributes is disabled */
signingAttributes = lastActionPtr->iExtraData;
if( signingAttributes == CRYPT_ERROR )
{
int useDefaultAttributes;
krnlSendMessage( envelopeInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&useDefaultAttributes,
CRYPT_OPTION_CMS_DEFAULTATTRIBUTES );
signingAttributes = useDefaultAttributes ? \
CRYPT_USE_DEFAULT : CRYPT_UNUSED;
}
/* Generate the signature into the aux.buffer and copy as
much as possible of it into the envelope buffer */
status = iCryptCreateSignatureEx( envelopeInfoPtr->auxBuffer,
&envelopeInfoPtr->auxBufPos, envelopeInfoPtr->type,
lastActionPtr->iCryptHandle,
lastActionPtr->associatedAction->iCryptHandle,
signingAttributes,
( lastActionPtr->iTspSession != CRYPT_ERROR ) ? \
lastActionPtr->iTspSession : CRYPT_UNUSED );
lastActionPtr = lastActionPtr->next;
if( !cryptStatusError( status ) && \
copyFromAuxBuffer( envelopeInfoPtr ) )
status = CRYPT_ERROR_OVERFLOW;
}
envelopeInfoPtr->lastAction = lastActionPtr;
/* If we've reached the last signature action, move on to the
next state. Since the emission of the signature information
is interruptible, we only move on to the next state if there
are no errors */
if( cryptStatusError( status ) )
break;
if( envelopeInfoPtr->hasIndefiniteTrailer )
{
/* The trailer has an indefinite length, write the EOC for
the trailer to the output */
writeEndIndef( &envelopeInfoPtr->auxStream );
if( copyFromAuxStream( envelopeInfoPtr ) )
status = CRYPT_ERROR_OVERFLOW;
}
state = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED || \
envelopeInfoPtr->hasIndefiniteTrailer ) ? \
ENVSTATE_EOC : ENVSTATE_DONE;
}
/* Handle the final end-of-contents octets */
if( state == ENVSTATE_EOC )
{
/* Write the end-of-contents octets for the OCTET STRING/SEQUENCE,
[0], and SEQUENCE if necessary */
writeEndIndef( &envelopeInfoPtr->auxStream );
writeEndIndef( &envelopeInfoPtr->auxStream );
writeEndIndef( &envelopeInfoPtr->auxStream );
if( copyFromAuxStream( envelopeInfoPtr ) )
status = CRYPT_ERROR_OVERFLOW;
/* We're done */
state = ENVSTATE_DONE;
}
}
/* Remember the state information */
envelopeInfoPtr->envState = state;
/* Now that we've written the final end-of-contents octets, set the end-
of-segment-data pointer to the end of the data in the buffer so
copyFromEnvelope() can copy out the remaining data */
if( cryptStatusOK( status ) && state == ENVSTATE_DONE )
envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;
return( status );
}
/****************************************************************************
* *
* Envelope Access Routines *
* *
****************************************************************************/
void initCMSEnveloping( ENVELOPE_INFO *envelopeInfoPtr )
{
/* Set the access method pointers */
envelopeInfoPtr->emitPreamble = emitPreamble;
envelopeInfoPtr->emitPostamble = emitPostamble;
envelopeInfoPtr->checkCryptAlgo = checkCryptAlgo;
envelopeInfoPtr->checkHashAlgo = checkHashAlgo;
/* Set up the processing state information */
envelopeInfoPtr->envState = ENVSTATE_NONE;
/* Remember the current default settings for use with the envelope.
We force the use of the CBC encryption mode because this is the
safest and most efficient encryption mode, and the only mode defined
for many CMS algorithms. Since the CMS algorithms represent only a
subset of what's available, we have to drop back to fixed values if
the caller has selected something exotic */
krnlSendMessage( envelopeInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultHash, CRYPT_OPTION_ENCR_HASH );
if( !checkAlgoID( envelopeInfoPtr->defaultHash, CRYPT_MODE_NONE ) )
envelopeInfoPtr->defaultHash = CRYPT_ALGO_SHA;
krnlSendMessage( envelopeInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultAlgo, CRYPT_OPTION_ENCR_ALGO );
if( !checkAlgoID( envelopeInfoPtr->defaultAlgo,
( envelopeInfoPtr->defaultAlgo == CRYPT_ALGO_RC4 ) ? \
CRYPT_MODE_OFB : CRYPT_MODE_CBC ) )
envelopeInfoPtr->defaultAlgo = CRYPT_ALGO_3DES;
krnlSendMessage( envelopeInfoPtr->ownerHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultMAC, CRYPT_OPTION_ENCR_MAC );
if( !checkAlgoID( envelopeInfoPtr->defaultMAC, CRYPT_MODE_NONE ) )
envelopeInfoPtr->defaultMAC = CRYPT_ALGO_HMAC_SHA;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -