📄 cms_env.c
字号:
{
long length;
int status;
assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
assert( isReadPtr( contentOID, contentOIDlength ) );
assert( isWritePtr( blockedPayloadSize, sizeof( long ) ) );
assert( isWritePtr( encrContentInfoSize, sizeof( long ) ) );
REQUIRES( contentOIDlength >= MIN_OID_SIZE && \
contentOIDlength <= MAX_OID_SIZE );
/* Clear return values */
*blockedPayloadSize = *encrContentInfoSize = 0;
/* Calculate the size of the payload after encryption blocking */
status = getBlockedPayloadSize( envelopeInfoPtr->payloadSize,
envelopeInfoPtr->blockSize,
blockedPayloadSize );
if( cryptStatusError( status ) )
return( status );
/* Calculate the size of the CMS ContentInfo header */
length = sizeofCMSencrHeader( contentOID, contentOIDlength,
*blockedPayloadSize,
envelopeInfoPtr->iCryptContext );
if( cryptStatusError( length ) )
return( ( int ) length );
*encrContentInfoSize = length;
return( CRYPT_OK );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int writeEncryptionHeader( INOUT STREAM *stream,
IN_BUFFER( oidLength ) const BYTE *oid,
IN_LENGTH_OID const int oidLength,
IN_RANGE( 0, 2 ) const int version,
IN_LENGTH_INDEF const long blockedPayloadSize,
IN_LENGTH_INDEF const long extraSize )
{
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( oid, oidLength ) );
REQUIRES_S( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE );
REQUIRES_S( version >= 0 && version <= 2 );
REQUIRES_S( ( oidLength == sizeofOID( OID_CMS_AUTHDATA ) && \
!memcmp( oid, OID_CMS_AUTHDATA, \
sizeofOID( OID_CMS_AUTHDATA ) ) ) || \
blockedPayloadSize == CRYPT_UNUSED || \
( blockedPayloadSize >= 8 && \
blockedPayloadSize < MAX_INTLENGTH ) );
REQUIRES_S( extraSize == CRYPT_UNUSED || \
( extraSize > 0 && extraSize < MAX_INTLENGTH ) );
status = writeCMSheader( stream, oid, oidLength,
( blockedPayloadSize == CRYPT_UNUSED || \
extraSize == CRYPT_UNUSED ) ? \
CRYPT_UNUSED : \
sizeofShortInteger( 0 ) + extraSize + \
blockedPayloadSize,
FALSE );
if( cryptStatusError( status ) )
return( status );
return( writeShortInteger( stream, version, DEFAULT_TAG ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int writeEncryptedDataHeader( INOUT STREAM *stream,
const ENVELOPE_INFO *envelopeInfoPtr )
{
const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
long blockedPayloadSize, encrContentInfoSize;
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES_S( contentOID != NULL );
/* Calculate the size of the payload due to blocking and the ContentInfo
header */
status = getEncrypedContentSize( envelopeInfoPtr, contentOID,
sizeofOID( contentOID ),
&blockedPayloadSize,
&encrContentInfoSize );
if( cryptStatusError( status ) )
return( status );
/* Write the EncryptedData header, version number, and
EncryptedContentInfo header */
status = writeEncryptionHeader( stream, OID_CMS_ENCRYPTEDDATA,
sizeofOID( OID_CMS_ENCRYPTEDDATA ), 0,
blockedPayloadSize, encrContentInfoSize );
if( cryptStatusError( status ) )
return( status );
return( writeEncryptedContentHeader( stream, contentOID,
sizeofOID( contentOID ), envelopeInfoPtr->iCryptContext,
envelopeInfoPtr->payloadSize, envelopeInfoPtr->blockSize ) );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int writeEnvelopedDataHeader( INOUT STREAM *stream,
const ENVELOPE_INFO *envelopeInfoPtr )
{
const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
long blockedPayloadSize, encrContentInfoSize;
#ifdef USE_KEA
const int originatorInfoSize = ( envelopeInfoPtr->extraDataSize > 0 ) ? \
( int ) sizeofObject( envelopeInfoPtr->extraDataSize ) : 0;
#endif /* USE_KEA */
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES_S( contentOID != NULL );
/* Calculate the size of the payload due to blocking and the ContentInfo
header */
status = getEncrypedContentSize( envelopeInfoPtr, contentOID,
sizeofOID( contentOID ),
&blockedPayloadSize,
&encrContentInfoSize );
if( cryptStatusError( status ) )
return( status );
/* Write the EnvelopedData header and version number and start of the
SET OF RecipientInfo/EncryptionKeyInfo */
#ifndef USE_KEA
status = writeEncryptionHeader( stream, OID_CMS_ENVELOPEDDATA,
sizeofOID( OID_CMS_ENVELOPEDDATA ), 0,
blockedPayloadSize,
( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) ? \
CRYPT_UNUSED : \
sizeofObject( envelopeInfoPtr->cryptActionSize ) + \
encrContentInfoSize );
if( cryptStatusError( status ) )
return( status );
#else
status = writeEncryptionHeader( stream, OID_CMS_ENVELOPEDDATA,
sizeofOID( OID_CMS_ENVELOPEDDATA ),
( originatorInfoSize > 0 ) ? 2 : 0,
blockedPayloadSize,
( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) ? \
CRYPT_UNUSED : \
sizeofObject( envelopeInfoPtr->cryptActionSize ) + \
originatorInfoSize + encrContentInfoSize );
if( cryptStatusError( status ) )
return( status );
if( originatorInfoSize > 0 )
{
int status;
/* Write the wrapper for the originator info and the originator info
itself */
writeConstructed( stream, envelopeInfoPtr->extraDataSize, 0 );
/* Export the originator certificate chain either directly into the
main buffer or into the auxBuffer if there's not enough room */
if( originatorInfoSize >= sMemDataLeft( stream ) )
{
/* The originator chain is too big for the main buffer so we
have to write everything from this point on into the
auxBuffer. This is then flushed into the main buffer in the
calling code before anything else is written */
stream = ( STREAM * ) &envelopeInfoPtr->auxStream;
}
status = exportCertToStream( stream, envelopeInfoPtr->iExtraCertChain,
CRYPT_ICERTFORMAT_CERTSET );
if( cryptStatusError( status ) )
return( status );
}
#endif /* USE_KEA */
return( ( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) ? \
writeSetIndef( stream ) : \
writeSet( stream, envelopeInfoPtr->cryptActionSize ) );
}
/* AuthenticatedData */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int writeAuthenticatedDataHeader( INOUT STREAM *stream,
const ENVELOPE_INFO *envelopeInfoPtr )
{
const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
const int macActionSize = \
sizeofContextAlgoID( envelopeInfoPtr->actionList->iCryptHandle,
CRYPT_ALGO_NONE );
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES_S( contentOID != NULL );
if( cryptStatusError( macActionSize ) )
return( macActionSize );
/* Write the AuthenticatedData header and version number and start of
the SET OF RecipientInfo. Technically this isn't an encryption
header but it uses the same format */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
{
status = writeEncryptionHeader( stream, OID_CMS_AUTHDATA,
sizeofOID( OID_CMS_AUTHDATA ), 0, 1,
CRYPT_UNUSED );
}
else
{
int macSize, contentInfoSize;
/* Determine the size of the MAC and the encapsulated content
header */
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
IMESSAGE_GETATTRIBUTE, &macSize,
CRYPT_CTXINFO_BLOCKSIZE );
if( cryptStatusError( status ) )
return( status );
contentInfoSize = sizeofObject( \
sizeofObject( envelopeInfoPtr->payloadSize ) );
contentInfoSize = sizeofObject( sizeofOID( contentOID ) + \
contentInfoSize ) - \
envelopeInfoPtr->payloadSize;
REQUIRES_S( contentInfoSize >= 16 && \
contentInfoSize < MAX_INTLENGTH );
/* Write the data header */
status = writeEncryptionHeader( stream, OID_CMS_AUTHDATA,
sizeofOID( OID_CMS_AUTHDATA ), 0,
envelopeInfoPtr->payloadSize,
( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) ? \
CRYPT_UNUSED : \
sizeofObject( envelopeInfoPtr->cryptActionSize ) + \
macActionSize + contentInfoSize + \
sizeofObject( macSize ) );
}
if( cryptStatusError( status ) )
return( status );
return( ( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) ? \
writeSetIndef( stream ) : \
writeSet( stream, envelopeInfoPtr->cryptActionSize ) );
}
/* CompressedData */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int writeCompressedDataHeader( INOUT STREAM *stream,
INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
int status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
REQUIRES_S( contentOID != NULL );
/* Since compressing the data changes its length we have to use the
indefinite-length encoding even if we know how big the payload is */
envelopeInfoPtr->payloadSize = CRYPT_UNUSED;
/* Write the CompressedData header, version number, and Zlib algoID */
status = writeCMSheader( stream, OID_CMS_COMPRESSEDDATA,
sizeofOID( OID_CMS_COMPRESSEDDATA ),
CRYPT_UNUSED, FALSE );
if( cryptStatusError( status ) )
return( status );
writeShortInteger( stream, 0, DEFAULT_TAG );
writeGenericAlgoID( stream, OID_ZLIB, sizeofOID( OID_ZLIB ) );
/* Write the inner Data header */
return( writeCMSheader( stream, contentOID, sizeofOID( contentOID ),
CRYPT_UNUSED, TRUE ) );
}
/****************************************************************************
* *
* Header Processing Routines *
* *
****************************************************************************/
/* Write the envelope header */
CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1 ) ) \
static int writeEnvelopeHeader( INOUT ENVELOPE_INFO *envelopeInfoPtr )
{
STREAM stream;
int status;
assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
/* If we're encrypting, set up the encryption-related information */
if( envelopeInfoPtr->usage == ACTION_CRYPT )
{
REQUIRES( envelopeInfoPtr->actionList != NULL );
status = initEnvelopeEncryption( envelopeInfoPtr,
envelopeInfoPtr->actionList->iCryptHandle,
CRYPT_ALGO_NONE, CRYPT_MODE_NONE, NULL, 0,
FALSE );
if( cryptStatusError( status ) )
return( status );
}
/* Write the appropriate CMS header based on the envelope usage. The
DigestedData/ACTION_HASH 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 = writeSignedDataHeader( &stream, envelopeInfoPtr, TRUE );
break;
case ACTION_HASH:
status = writeSignedDataHeader( &stream, envelopeInfoPtr, FALSE );
break;
case ACTION_COMPRESS:
status = writeCompressedDataHeader( &stream, envelopeInfoPtr );
break;
case ACTION_NONE:
{
const BYTE *contentOID = \
getContentOID( envelopeInfoPtr->contentType );
REQUIRES( contentOID != NULL );
status = writeCMSheader( &stream, contentOID,
sizeofOID( contentOID ),
envelopeInfoPtr->payloadSize, FALSE );
break;
}
case ACTION_MAC:
status = writeAuthenticatedDataHeader( &stream, envelopeInfoPtr );
break;
default:
retIntError();
}
if( cryptStatusOK( status ) )
envelopeInfoPtr->bufPos = 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->usage != ACTION_MAC ) || \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -