📄 cms_env.c
字号:
case form of encrypted data so we treat them as the same thing
at the key exchange level */
if( envelopeInfoPtr->usage == ACTION_CRYPT || \
envelopeInfoPtr->usage == ACTION_MAC )
status = cmsPreEnvelopeEncrypt( envelopeInfoPtr );
else
{
if( envelopeInfoPtr->usage == ACTION_SIGN )
status = cmsPreEnvelopeSign( envelopeInfoPtr );
}
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't perform final %s initialisation prior to "
"enveloping data",
( envelopeInfoPtr->usage == ACTION_SIGN ) ? \
"signing" : "encryption" ) );
}
/* Delete any orphaned actions such as automatically-added hash
actions that were overridden with user-supplied alternate
actions */
deleteUnusedActions( envelopeInfoPtr );
/* Make sure that we start a new segment when we add the first lot
of payload data after we've emitted the header info */
envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;
/* We're ready to go, prepare to emit the outer header */
envelopeInfoPtr->envState = ENVSTATE_HEADER;
ENSURES( checkActions( envelopeInfoPtr ) );
}
/* Emit the outer header. This always follows directly from the final
initialisation step but we keep the two logically distinct to
emphasise the fact that the former is merely finalising enveloping
actions without performing any header processing while the latter is
the first stage that actually emits header data */
if( envelopeInfoPtr->envState == ENVSTATE_HEADER )
{
status = writeEnvelopeHeader( envelopeInfoPtr );
if( cryptStatusError( status ) )
{
/* If there's nothing else to emit, we're done */
if( status == OK_SPECIAL )
{
envelopeInfoPtr->envState = ENVSTATE_DONE;
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't create envelope header" ) );
}
/* Move on to the next state */
envelopeInfoPtr->envState = ENVSTATE_KEYINFO;
}
/* Handle key export actions */
if( envelopeInfoPtr->envState == ENVSTATE_KEYINFO )
{
status = writeKeyex( envelopeInfoPtr );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't emit key exchange actions to envelope "
"header" ) );
}
/* Move on to the next state */
envelopeInfoPtr->envState = ENVSTATE_ENCRINFO;
}
/* Handle encrypted content information */
if( envelopeInfoPtr->envState == ENVSTATE_ENCRINFO )
{
STREAM stream;
const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
const int dataLeft = min( envelopeInfoPtr->bufSize - \
envelopeInfoPtr->bufPos, \
MAX_INTLENGTH_SHORT - 1 );
REQUIRES( contentOID != NULL );
ENSURES( dataLeft >= dataLeft && dataLeft < MAX_INTLENGTH_SHORT );
/* Make sure that there's enough room to emit the data header. The
value used is only approximate, if there's not enough room left
the write will also return an overflow error */
if( dataLeft < 256 )
return( CRYPT_ERROR_OVERFLOW );
/* Write the encrypted content header */
sMemOpen( &stream, envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos,
dataLeft );
if( envelopeInfoPtr->usage == ACTION_MAC )
{
/* If it's authenticated data, there's a MAC algorithm ID
preceding standard EncapContent */
status = writeContextAlgoID( &stream,
envelopeInfoPtr->actionList->iCryptHandle,
CRYPT_ALGO_NONE );
if( cryptStatusOK ( status ) )
{
status = writeCMSheader( &stream, contentOID,
sizeofOID( contentOID ),
envelopeInfoPtr->payloadSize,
TRUE );
}
}
else
{
/* It's encrypted data, it's EncrContent */
status = writeEncryptedContentHeader( &stream, contentOID,
sizeofOID( contentOID ),
envelopeInfoPtr->iCryptContext,
envelopeInfoPtr->payloadSize,
envelopeInfoPtr->blockSize );
}
if( cryptStatusOK( status ) )
envelopeInfoPtr->bufPos += stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't emit encrypted content header to envelope "
"header" ) );
}
#if 0 /* ?/?/08 Commented out between 3.3.1 and 3.3.2 although there's no
indication why */
/* Make sure that we start a new segment if we try to add any data */
envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;
#endif /* 0 */
/* We're done */
envelopeInfoPtr->envState = ENVSTATE_DONE;
}
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
/* Output as much of the postamble as possible into the envelope buffer */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int emitPostamble( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
int status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES( sanityCheck( envelopeInfoPtr ) );
/* Before we can emit the trailer we need to flush any remaining data
from internal buffers */
if( envelopeInfoPtr->envState == ENVSTATE_NONE )
{
status = envelopeInfoPtr->copyToEnvelopeFunction( envelopeInfoPtr,
( BYTE * ) "", 0 );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't flush remaining data into envelope "
"buffer" ) );
}
envelopeInfoPtr->envState = \
( envelopeInfoPtr->usage == ACTION_SIGN ) ? \
ENVSTATE_FLUSHED : ENVSTATE_SIGNATURE;
}
/* The only message type that has a trailer is signed or authenticated
data so if we're not signing/authenticating data we can exit now */
if( envelopeInfoPtr->usage != ACTION_SIGN && \
envelopeInfoPtr->usage != ACTION_MAC )
{
/* Emit the various end-of-contents octets if necessary */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED || \
( envelopeInfoPtr->usage == ACTION_CRYPT &&
envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) )
{
/* Write the end-of-contents octets for the encapsulated data if
necessary. Normally we have two EOCs, however compressed
data requires an extra one due to the explicit tagging */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED && \
( envelopeInfoPtr->usage == ACTION_CRYPT || \
envelopeInfoPtr->usage == ACTION_COMPRESS ) )
{
status = writeEOCs( envelopeInfoPtr, 3 + \
( ( envelopeInfoPtr->usage == \
ACTION_COMPRESS ) ? \
3 : 2 ) );
}
else
{
/* Write the remaining end-of-contents octets for the OCTET
STRING/SEQUENCE, [0], and SEQUENCE */
status = writeEOCs( envelopeInfoPtr, 3 );
}
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't emit final EOC octets" ) );
}
}
/* 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 that
copyFromEnvelope() can copy out the remaining data */
envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;
envelopeInfoPtr->envState = ENVSTATE_DONE;
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
/* If there's any signature data left in the auxiliary buffer try and
empty that first */
if( envelopeInfoPtr->auxBufPos > 0 )
{
status = copyFromAuxBuffer( envelopeInfoPtr );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't flush remaining signature data into "
"envelope buffer" ) );
}
}
/* Handle signing certificate chain */
if( envelopeInfoPtr->envState == ENVSTATE_FLUSHED )
{
status = writeCertchainTrailer( envelopeInfoPtr );
if( cryptStatusError( status ) && status != OK_SPECIAL )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't emit certificate chain to envelope "
"trailer" ) );
}
/* Move on to the next state */
envelopeInfoPtr->envState = ENVSTATE_SIGNATURE;
/* If we were writing the certificate chain using the auxBuffer as
an intermediate stage because there wasn't enough room to
assemble the complete chain in the main buffer and we then got an
overflow error moving the data out into the main buffer we have
to resume later in the signature state */
if( status == OK_SPECIAL )
return( CRYPT_ERROR_OVERFLOW );
}
/* Handle signing actions */
REQUIRES( envelopeInfoPtr->envState == ENVSTATE_SIGNATURE );
/* Write the signatures/MACs */
if( envelopeInfoPtr->usage == ACTION_SIGN )
status = writeSignatures( envelopeInfoPtr );
else
status = writeMAC( envelopeInfoPtr );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't emit %s to envelope trailer",
( envelopeInfoPtr->usage == ACTION_SIGN ) ? \
"signatures" : "MAC" ) );
}
/* Write the end-of-contents octets for the OCTET STRING/SEQUENCE, [0],
and SEQUENCE if necessary. If the trailer has an indefinite length
then we need to add an EOC for the trailer as well */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED || \
( envelopeInfoPtr->dataFlags & ENVDATA_HASINDEFTRAILER ) )
{
status = writeEOCs( envelopeInfoPtr,
3 + ( ( envelopeInfoPtr->dataFlags & \
ENVDATA_HASINDEFTRAILER ) ? \
1 : 0 ) );
if( cryptStatusError( status ) )
{
retExt( status,
( status, ENVELOPE_ERRINFO,
"Couldn't emit final EOC octets" ) );
}
}
/* 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 that
copyFromEnvelope() can copy out the remaining data */
envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;
envelopeInfoPtr->envState = ENVSTATE_DONE;
ENSURES( sanityCheck( envelopeInfoPtr ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Envelope Access Routines *
* *
****************************************************************************/
STDC_NONNULL_ARG( ( 1 ) ) \
void initCMSEnveloping( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
int status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES_V( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) );
/* Set the access method pointers */
envelopeInfoPtr->processPreambleFunction = emitPreamble;
envelopeInfoPtr->processPostambleFunction = emitPostamble;
envelopeInfoPtr->checkAlgo = cmsCheckAlgo;
/* 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 */
status = krnlSendMessage( envelopeInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultHash,
CRYPT_OPTION_ENCR_HASH );
if( cryptStatusError( status ) || \
!checkAlgoID( envelopeInfoPtr->defaultHash, CRYPT_MODE_NONE ) )
envelopeInfoPtr->defaultHash = CRYPT_ALGO_SHA1;
status = krnlSendMessage( envelopeInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultAlgo,
CRYPT_OPTION_ENCR_ALGO );
if( cryptStatusError( status ) || \
!checkAlgoID( envelopeInfoPtr->defaultAlgo,
( envelopeInfoPtr->defaultAlgo == CRYPT_ALGO_RC4 ) ? \
CRYPT_MODE_OFB : CRYPT_MODE_CBC ) )
envelopeInfoPtr->defaultAlgo = CRYPT_ALGO_3DES;
status = krnlSendMessage( envelopeInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultMAC,
CRYPT_OPTION_ENCR_MAC );
if( cryptStatusError( status ) || \
!checkAlgoID( envelopeInfoPtr->defaultMAC, CRYPT_MODE_NONE ) )
envelopeInfoPtr->defaultMAC = CRYPT_ALGO_HMAC_SHA;
}
#endif /* USE_ENVELOPES */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -