📄 cms_env.c
字号:
envelopeInfoPtr->preActionList == NULL )
{
/* 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
inform the caller that we're done */
if( envelopeInfoPtr->usage != ACTION_CRYPT )
envelopeInfoPtr->blockSizeMask = -1;
envelopeInfoPtr->lastAction = NULL;
return( OK_SPECIAL );
}
/* 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 );
ENSURES( envelopeInfoPtr->lastAction != NULL );
return( CRYPT_OK );
}
/* Write key exchange actions */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeKeyex( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
const CRYPT_CONTEXT iCryptContext = \
( envelopeInfoPtr->usage == ACTION_CRYPT ) ? \
envelopeInfoPtr->iCryptContext : \
envelopeInfoPtr->actionList->iCryptHandle;
ACTION_LIST *actionListPtr;
int iterationCount, status = CRYPT_OK;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
/* Export the session key/MAC 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 */
for( actionListPtr = envelopeInfoPtr->lastAction, iterationCount = 0;
actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
actionListPtr = actionListPtr->next, iterationCount++ )
{
const CRYPT_FORMAT_TYPE formatType = \
( actionListPtr->action == ACTION_KEYEXCHANGE ) ? \
CRYPT_FORMAT_CMS : envelopeInfoPtr->type;
const int dataLeft = min( envelopeInfoPtr->bufSize - \
envelopeInfoPtr->bufPos,
MAX_INTLENGTH_SHORT - 1 );
int keyexSize;
ENSURES( dataLeft >= 0 && dataLeft < MAX_INTLENGTH_SHORT );
/* Make sure that there's enough room to emit this key exchange
action */
if( actionListPtr->encodedSize + 128 > dataLeft )
{
status = CRYPT_ERROR_OVERFLOW;
break;
}
/* Emit the key exchange action */
status = iCryptExportKey( envelopeInfoPtr->buffer + \
envelopeInfoPtr->bufPos, dataLeft,
&keyexSize, formatType, iCryptContext,
actionListPtr->iCryptHandle );
if( cryptStatusError( status ) )
break;
envelopeInfoPtr->bufPos += keyexSize;
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
envelopeInfoPtr->lastAction = actionListPtr;
if( cryptStatusError( status ) )
return( status );
/* If it's an indefinite-length header close off the set of key
exchange actions */
if( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED )
return( writeEOCs( envelopeInfoPtr, 1 ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Trailer Processing Routines *
* *
****************************************************************************/
/* Write the signing certificate chain. This can grow arbitrarily large and
in particular can become larger than the main envelope buffer if multiple
signatures with long chains and a small envelope buffer are used, so we
emit the certificate chain into a dynamically-allocated auxiliary buffer
if there isn't enough room to emit it into the main buffer */
CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeCertchainTrailer( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
STREAM stream;
void *certChainBufPtr;
const int dataLeft = min( envelopeInfoPtr->bufSize - \
envelopeInfoPtr->bufPos,
MAX_INTLENGTH_SHORT - 1 );
const int eocSize = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
( 3 * 2 ) : 0;
int certChainBufSize, certChainSize = DUMMY_INIT, status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
ENSURES( dataLeft >= 0 && dataLeft < MAX_INTLENGTH_SHORT );
/* Check whether there's enough room left in the buffer to emit the
signing certificate chain directly into it */
if( envelopeInfoPtr->extraDataSize + 64 < dataLeft )
{
/* The certificate chain will fit into the envelope buffer */
certChainBufPtr = envelopeInfoPtr->buffer + \
envelopeInfoPtr->bufPos + eocSize;
certChainBufSize = dataLeft - eocSize;
}
else
{
/* If there's almost no room left in the buffer anyway tell the
caller that they have to pop some data before they can continue.
Hopefully this will create enough room to emit the certificates
directly into the buffer */
if( dataLeft < 1024 )
return( CRYPT_ERROR_OVERFLOW );
/* We can't emit the certificates directly into the envelope buffer,
allocate an auxiliary buffer for them and from there copy them
into the main buffer */
REQUIRES( envelopeInfoPtr->auxBuffer == NULL );
if( ( envelopeInfoPtr->auxBuffer = \
clDynAlloc( "emitPostamble",
envelopeInfoPtr->extraDataSize + 64 ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
certChainBufPtr = envelopeInfoPtr->auxBuffer;
certChainBufSize = envelopeInfoPtr->auxBufSize = \
envelopeInfoPtr->extraDataSize + 64;
}
/* Write the end-of-contents octets for the Data OCTET STRING, [0], and
SEQUENCE if necessary */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
{
status = writeEOCs( envelopeInfoPtr, 3 );
if( cryptStatusError( status ) )
return( status );
}
envelopeInfoPtr->lastAction = envelopeInfoPtr->postActionList;
/* Write the signing certificate chain if it's a CMS signature and
they're not explicitly excluded, followed by the SET OF SignerInfo
header */
sMemOpen( &stream, certChainBufPtr, certChainBufSize );
if( ( envelopeInfoPtr->type == CRYPT_FORMAT_CMS || \
envelopeInfoPtr->type == CRYPT_FORMAT_SMIME ) && \
!( envelopeInfoPtr->flags & ENVELOPE_NOSIGNINGCERTS ) )
{
status = exportCertToStream( &stream,
( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR ) ? \
envelopeInfoPtr->iExtraCertChain : \
envelopeInfoPtr->lastAction->iCryptHandle,
CRYPT_ICERTFORMAT_CERTSET );
if( cryptStatusError( status ) )
{
sMemDisconnect( &stream );
return( status );
}
}
if( envelopeInfoPtr->dataFlags & ENVDATA_HASINDEFTRAILER )
status = writeSetIndef( &stream );
else
status = writeSet( &stream, envelopeInfoPtr->signActionSize );
if( cryptStatusOK( status ) )
certChainSize = stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
/* If we're copying data via the auxBuffer flush as much as we can into
the main buffer. If we can't copy it all in, resulting in an overflow
error, we use the OK_SPECIAL status to tell the caller that although
an overflow occurred it was due to the auxBuffer copy and not the
certificate chain write and it's OK to move on to the next state */
if( envelopeInfoPtr->auxBufSize > 0 )
{
envelopeInfoPtr->auxBufPos = certChainSize;
status = copyFromAuxBuffer( envelopeInfoPtr );
return( ( status == CRYPT_ERROR_OVERFLOW ) ? OK_SPECIAL : status );
}
/* Since we're in the post-data state any necessary payload data
segmentation has been completed, however the caller can't copy out
any post-payload data because it's past the end-of-segment position.
In order to allow the buffer to be emptied to make room for signature
data we set the end-of-segment position to the end of the new data */
envelopeInfoPtr->bufPos += certChainSize;
envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;
return( CRYPT_OK );
}
/* Write signatures */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeSignatures( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
ACTION_LIST *actionListPtr;
int iterationCount, status = CRYPT_OK;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
/* Sign each hash using the associated signature key */
for( actionListPtr = envelopeInfoPtr->lastAction, iterationCount = 0;
actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
actionListPtr = actionListPtr->next, iterationCount++ )
{
const int sigBufSize = min( envelopeInfoPtr->bufSize - \
envelopeInfoPtr->bufPos, \
MAX_INTLENGTH_SHORT - 1 );
int sigSize, signingAttributes = actionListPtr->iExtraData;
REQUIRES( actionListPtr->action == ACTION_SIGN );
ENSURES( sigBufSize >= 0 && sigBufSize < MAX_INTLENGTH_SHORT );
/* Check whether there's enough room left in the buffer to emit the
signature directly into it. Since signatures are fairly small (a
few hundred bytes) we always require enough room in the buffer
and don't bother with any overflow handling via the auxBuffer */
if( actionListPtr->encodedSize + 64 > sigBufSize )
{
status = CRYPT_ERROR_OVERFLOW;
break;
}
/* 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) we either get the signing code
to add the default ones for us or use none at all if the use of
default attributes is disabled */
if( signingAttributes == CRYPT_ERROR )
{
/* If it's a raw signature there are no signing attributes */
if( envelopeInfoPtr->type == CRYPT_FORMAT_CRYPTLIB )
signingAttributes = CRYPT_UNUSED;
else
{
int useDefaultAttributes;
/* It's a CMS/SMIME signature, use whatever the default is */
status = krnlSendMessage( envelopeInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE,
&useDefaultAttributes,
CRYPT_OPTION_CMS_DEFAULTATTRIBUTES );
if( cryptStatusError( status ) )
break;
signingAttributes = useDefaultAttributes ? \
CRYPT_USE_DEFAULT : CRYPT_UNUSED;
}
}
/* Sign the data */
REQUIRES( actionListPtr->associatedAction != NULL );
status = iCryptCreateSignature( envelopeInfoPtr->buffer + \
envelopeInfoPtr->bufPos, sigBufSize,
&sigSize, envelopeInfoPtr->type,
actionListPtr->iCryptHandle,
actionListPtr->associatedAction->iCryptHandle,
signingAttributes,
( actionListPtr->iTspSession != CRYPT_ERROR ) ? \
actionListPtr->iTspSession : CRYPT_UNUSED );
if( cryptStatusError( status ) )
break;
envelopeInfoPtr->bufPos += sigSize;
}
ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
envelopeInfoPtr->lastAction = actionListPtr;
return( status );
}
/* Write MAC value */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeMAC( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
STREAM stream;
MESSAGE_DATA msgData;
BYTE hash[ CRYPT_MAX_HASHSIZE + 8 ];
const int eocSize = ( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
( 3 * 2 ) : 0;
const int dataLeft = min( envelopeInfoPtr->bufSize - \
envelopeInfoPtr->bufPos, 512 );
int length = DUMMY_INIT, status;
/* Make sure that there's room for the MAC data in the buffer */
if( dataLeft < eocSize + sizeofObject( CRYPT_MAX_HASHSIZE ) )
return( CRYPT_ERROR_OVERFLOW );
/* Write the end-of-contents octets for the Data OCTET STRING, [0], and
SEQUENCE if necessary */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
{
status = writeEOCs( envelopeInfoPtr, 3 );
if( cryptStatusError( status ) )
return( status );
}
/* Get the MAC value and write it to the buffer */
setMessageData( &msgData, hash, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusError( status ) )
return( status );
sMemOpen( &stream, envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos,
dataLeft );
status = writeOctetString( &stream, hash, msgData.length, DEFAULT_TAG );
if( cryptStatusOK( status ) )
length = stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->bufPos += length;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Emit Envelope Preamble/Postamble *
* *
****************************************************************************/
/* Output as much of the preamble as possible into the envelope buffer */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int emitPreamble( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
int status = CRYPT_OK;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES( sanityCheck( envelopeInfoPtr ) );
/* If we've finished processing the header information, don't do
anything */
if( envelopeInfoPtr->envState == ENVSTATE_DONE )
return( CRYPT_OK );
/* If we haven't started doing anything yet perform various final
initialisations */
if( envelopeInfoPtr->envState == ENVSTATE_NONE )
{
/* If there's no nested content type set default to plain data */
if( envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
envelopeInfoPtr->contentType = CRYPT_CONTENT_DATA;
/* If there's an absolute data length set, remember it for when we
copy in data */
if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
envelopeInfoPtr->segmentSize = envelopeInfoPtr->payloadSize;
/* Perform any remaining initialisation. MAC'd data is a special-
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -