📄 env_cms.c
字号:
{
status = writeEOCs( envelopeInfoPtr, 1 );
if( cryptStatusError( status ) )
return( status );
}
/* Move on to the next state */
envelopeInfoPtr->envState = ENVSTATE_ENCRINFO;
}
/* Handle encrypted content information */
if( envelopeInfoPtr->envState == ENVSTATE_ENCRINFO )
{
STREAM stream;
const int dataLeft = min( envelopeInfoPtr->bufSize - \
envelopeInfoPtr->bufPos, 8192 );
int length;
/* 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 );
status = writeEncryptedContentHeader( &stream,
getContentOID( envelopeInfoPtr->contentType ),
envelopeInfoPtr->iCryptContext,
envelopeInfoPtr->payloadSize,
envelopeInfoPtr->blockSize );
length = stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->bufPos += length;
/* Make sure that we start a new segment if we try to add any data */
envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;
/* We're done */
envelopeInfoPtr->envState = ENVSTATE_DONE;
}
return( status );
}
/* Output as much of the postamble as possible into the envelope buffer */
static int emitPostamble( ENVELOPE_INFO *envelopeInfoPtr )
{
ACTION_LIST *lastActionPtr;
int status;
/* 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 ) )
return( status );
envelopeInfoPtr->envState = ENVSTATE_FLUSHED;
}
/* The only message type that has a trailer is signed data, if we're not
signing data we can exit now */
if( envelopeInfoPtr->usage != ACTION_SIGN )
{
/* 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 EOC's, 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 ) )
return( status );
}
/* 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;
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 ) )
return( status );
}
/* Handle signing cert 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 cert chain into a dynamically-allocated
auxiliary buffer if there isn't enough room to emit it into the main
buffer */
if( envelopeInfoPtr->envState == ENVSTATE_FLUSHED )
{
STREAM stream;
void *certChainBufPtr;
const int dataLeft = min( envelopeInfoPtr->bufSize - \
envelopeInfoPtr->bufPos, 32767 );
const int eocSize = \
( envelopeInfoPtr->payloadSize == CRYPT_UNUSED ) ? \
( 3 * 2 ) : 0;
int certChainBufSize, certChainSize;
/* Check whether there's enough room left in the buffer to emit the
signing cert chain directly into it */
if( envelopeInfoPtr->extraDataSize + 64 < dataLeft )
{
certChainBufPtr = envelopeInfoPtr->buffer + \
envelopeInfoPtr->bufPos + eocSize;
certChainBufSize = dataLeft - eocSize;
}
else
{
/* If there's almost no room left in the buffer anyway, tell the
user that they have to pop some data before they can
continue. Hopefully this will create enough room to emit the
certs directly into the buffer */
if( dataLeft < 1024 )
return( CRYPT_ERROR_OVERFLOW );
/* We can't emit the certs directly into the envelope buffer,
allocate an auxiliary buffer for it and from there copy it
into the main buffer */
if( ( envelopeInfoPtr->auxBuffer = \
clDynAlloc( "emitPostamble",
envelopeInfoPtr->extraDataSize + 64 ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
certChainBufSize = envelopeInfoPtr->auxBufSize = \
envelopeInfoPtr->extraDataSize + 64;
certChainBufPtr = envelopeInfoPtr->auxBuffer;
}
/* 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 cert 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 ) )
return( status );
}
if( envelopeInfoPtr->dataFlags & ENVDATA_HASINDEFTRAILER )
status = writeSetIndef( &stream );
else
status = writeSet( &stream, envelopeInfoPtr->signActionSize );
certChainSize = stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
if( envelopeInfoPtr->auxBufSize > 0 )
{
envelopeInfoPtr->auxBufPos = certChainSize;
status = copyFromAuxBuffer( envelopeInfoPtr );
}
else
{
envelopeInfoPtr->bufPos += certChainSize;
/* 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->segmentDataEnd = envelopeInfoPtr->bufPos;
}
envelopeInfoPtr->envState = ENVSTATE_SIGNATURE;
if( cryptStatusError( status ) )
/* If we're copying from the auxBuffer, we'll get an overflow
error at this point and have to resume later in the
signature state */
return( status );
}
/* Handle signing actions */
assert( envelopeInfoPtr->envState == ENVSTATE_SIGNATURE );
/* Sign each hash using the associated signature key */
for( lastActionPtr = envelopeInfoPtr->lastAction;
lastActionPtr != NULL; lastActionPtr = lastActionPtr->next )
{
const int sigBufSize = min( envelopeInfoPtr->bufSize - \
envelopeInfoPtr->bufPos, 32767 );
int sigSize, signingAttributes;
assert( lastActionPtr->action == ACTION_SIGN );
/* Check whether there's enough room left in the buffer to emit the
signature directly into it. Since sigs 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( lastActionPtr->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), 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 */
signingAttributes = lastActionPtr->iExtraData;
if( signingAttributes == CRYPT_ERROR )
{
int useDefaultAttributes;
krnlSendMessage( envelopeInfoPtr->ownerHandle,
IMESSAGE_GETATTRIBUTE, &useDefaultAttributes,
CRYPT_OPTION_CMS_DEFAULTATTRIBUTES );
signingAttributes = useDefaultAttributes ? CRYPT_USE_DEFAULT : \
CRYPT_UNUSED;
}
/* Sign the data */
status = iCryptCreateSignatureEx( envelopeInfoPtr->buffer + \
envelopeInfoPtr->bufPos, &sigSize,
sigBufSize, envelopeInfoPtr->type,
lastActionPtr->iCryptHandle,
lastActionPtr->associatedAction->iCryptHandle,
signingAttributes,
( lastActionPtr->iTspSession != CRYPT_ERROR ) ? \
lastActionPtr->iTspSession : CRYPT_UNUSED );
if( cryptStatusError( status ) )
break;
envelopeInfoPtr->bufPos += sigSize;
}
envelopeInfoPtr->lastAction = lastActionPtr;
if( cryptStatusError( status ) )
return( status );
/* 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 ) )
return( status );
}
/* 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;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Envelope Access Routines *
* *
****************************************************************************/
void initCMSEnveloping( ENVELOPE_INFO *envelopeInfoPtr )
{
/* Set the access method pointers */
envelopeInfoPtr->processPreambleFunction = emitPreamble;
envelopeInfoPtr->processPostambleFunction = 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, IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultHash, CRYPT_OPTION_ENCR_HASH );
if( !checkAlgoID( envelopeInfoPtr->defaultHash, CRYPT_MODE_NONE ) )
envelopeInfoPtr->defaultHash = CRYPT_ALGO_SHA;
krnlSendMessage( envelopeInfoPtr->ownerHandle, 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, IMESSAGE_GETATTRIBUTE,
&envelopeInfoPtr->defaultMAC, CRYPT_OPTION_ENCR_MAC );
if( !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 + -