📄 envelope.c
字号:
MESSAGE_CREATEOBJECT_INFO createInfo;
setMessageCreateObjectInfo( &createInfo,
CRYPT_CERTTYPE_CMS_ATTRIBUTES );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
actionListPtr->iExtraData = createInfo.cryptHandle;
}
if( actionListPtr->iExtraData != CRYPT_ERROR )
{
int value;
/* Delete any existing content-type (quietly fixing things if
necessary is easier than trying to report this error back
to the caller) and add our one */
if( krnlSendMessage( actionListPtr->iExtraData,
RESOURCE_IMESSAGE_GETATTRIBUTE, &value,
CRYPT_CERTINFO_CMS_CONTENTTYPE ) != CRYPT_ERROR_NOTFOUND )
krnlSendMessage( actionListPtr->iExtraData,
RESOURCE_IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CERTINFO_CMS_CONTENTTYPE );
krnlSendMessage( actionListPtr->iExtraData,
RESOURCE_IMESSAGE_SETATTRIBUTE, &envelopeInfoPtr->contentType,
CRYPT_CERTINFO_CMS_CONTENTTYPE );
/* If it's an S/MIME (vs pure CMS) envelope, add the
sMIMECapabilities to further bloat things up */
if( envelopeInfoPtr->type == CRYPT_FORMAT_SMIME )
{
krnlSendMessage( actionListPtr->iExtraData,
RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
CRYPT_CERTINFO_CMS_SMIMECAP_3DES );
if( algoAvailable( CRYPT_ALGO_AES ) )
krnlSendMessage( actionListPtr->iExtraData,
RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
CRYPT_CERTINFO_CMS_SMIMECAP_AES );
if( algoAvailable( CRYPT_ALGO_CAST ) )
krnlSendMessage( actionListPtr->iExtraData,
RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
CRYPT_CERTINFO_CMS_SMIMECAP_CAST128 );
if( algoAvailable( CRYPT_ALGO_IDEA ) )
krnlSendMessage( actionListPtr->iExtraData,
RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
CRYPT_CERTINFO_CMS_SMIMECAP_IDEA );
if( algoAvailable( CRYPT_ALGO_RC2 ) )
krnlSendMessage( actionListPtr->iExtraData,
RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
CRYPT_CERTINFO_CMS_SMIMECAP_RC2 );
if( algoAvailable( CRYPT_ALGO_SKIPJACK ) )
krnlSendMessage( actionListPtr->iExtraData,
RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
CRYPT_CERTINFO_CMS_SMIMECAP_SKIPJACK );
}
}
}
/* Determine the type of signing attributes to use. If none are
specified (which can only happen if the signed content is data),
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 = actionListPtr->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;
}
/* Evaluate the size of the exported action. Even though it's not
required for encoding the length for DLP-based PKC's, we still
need to evaluate it to check that everything will be OK later on
and to determine whether the allocated auxBuffer is big enough to
contain the largest possible signature */
status = iCryptCreateSignatureEx( NULL, &signatureSize,
envelopeInfoPtr->type, actionListPtr->iCryptHandle,
actionListPtr->associatedAction->iCryptHandle,
signingAttributes,
( actionListPtr->iTspSession != CRYPT_ERROR ) ? \
actionListPtr->iTspSession : CRYPT_UNUSED );
if( cryptStatusError( status ) )
return( status );
status = krnlSendMessage( actionListPtr->iCryptHandle,
RESOURCE_IMESSAGE_GETATTRIBUTE, &cryptAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
if( cryptAlgo == CRYPT_ALGO_DSA || \
actionListPtr->iTspSession != CRYPT_ERROR )
{
/* If there are any signature actions which will result in
indefinite-length encodings present, we can't use a definite-
length encoding for the signatures */
envelopeInfoPtr->hasIndefiniteTrailer = TRUE;
actionListPtr->encodedSize = CRYPT_UNUSED;
}
else
{
actionListPtr->encodedSize = signatureSize;
envelopeInfoPtr->signActionSize += signatureSize;
}
if( signatureSize > largestSignatureSize )
largestSignatureSize = signatureSize;
}
largestSignatureSize += 64; /* Add some slop for ASN.1 wrappers */
/* If we're signing with very long cert chains or chains where the certs
have half the Verisign CPS included as text, the auxBuffer may not be
large enough to contain the resulting signature, so we have to expand
it to handle the signature */
if( envelopeInfoPtr->auxBufSize < largestSignatureSize )
{
if( envelopeInfoPtr->auxBuffer != NULL )
free( envelopeInfoPtr->auxBuffer );
if( ( envelopeInfoPtr->auxBuffer = malloc( largestSignatureSize ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
envelopeInfoPtr->auxBufSize = largestSignatureSize;
}
/* Hashing is now active */
envelopeInfoPtr->hashActionsActive = TRUE;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Emit Header Functions *
* *
****************************************************************************/
/* Write the header fields which encapsulate any enveloped data:
SignedData/DigestedData */
static int writeAuthenticatedDataHeader( STREAM *stream,
const ENVELOPE_INFO *envelopeInfoPtr,
const BOOLEAN isSignedData )
{
const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
ACTION_LIST *actionListPtr;
long dataSize;
int hashActionSize = 0;
/* Determine the size of the hash actions */
for( actionListPtr = envelopeInfoPtr->actionList; actionListPtr != NULL;
actionListPtr = actionListPtr->next )
hashActionSize += sizeofContextAlgoID( actionListPtr->iCryptHandle,
CRYPT_ALGO_NONE,
ALGOID_FLAG_ALGOID_ONLY );
/* Determine the size of the SignedData/DigestedData */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED || \
envelopeInfoPtr->hasIndefiniteTrailer )
dataSize = CRYPT_UNUSED;
else
{
/* Determine the size of the content OID + content */
dataSize = ( envelopeInfoPtr->payloadSize ) ? \
sizeofObject( sizeofObject( envelopeInfoPtr->payloadSize ) ) : 0;
dataSize = sizeofObject( sizeofOID( contentOID ) + dataSize );
/* Determine the size of the version, hash algoID, content, cert
chain, and signatures */
dataSize = sizeofShortInteger( 1 ) + sizeofObject( hashActionSize ) + \
dataSize + envelopeInfoPtr->extraDataSize + \
sizeofObject( envelopeInfoPtr->signActionSize );
}
/* Write the SignedData/DigestedData header, version number, and SET OF
DigestInfo */
writeCMSheader( stream, ( isSignedData ) ? \
OID_CMS_SIGNEDDATA : OID_CMS_DIGESTEDDATA, dataSize,
FALSE );
writeShortInteger( stream, 1, DEFAULT_TAG );
writeSet( stream, hashActionSize );
for( actionListPtr = envelopeInfoPtr->actionList; actionListPtr != NULL;
actionListPtr = actionListPtr->next )
{
int status = writeContextAlgoID( stream,
actionListPtr->iCryptHandle, CRYPT_ALGO_NONE,
ALGOID_FLAG_ALGOID_ONLY );
if( cryptStatusError( status ) )
return( status );
}
/* Write the inner Data header */
return( writeCMSheader( stream, contentOID, envelopeInfoPtr->payloadSize,
TRUE ) );
}
/* EncryptedContentInfo contained within EnvelopedData */
static int writeEncryptedContentHeader( STREAM *stream,
const BYTE *contentOID,
const CRYPT_CONTEXT iCryptContext,
const long payloadSize, const long blockSize )
{
const long blockedPayloadSize = ( payloadSize == CRYPT_UNUSED ) ? \
CRYPT_UNUSED : paddedSize( payloadSize, blockSize );
return( writeCMSencrHeader( stream, contentOID, blockedPayloadSize,
iCryptContext ) );
}
/* EncryptedData, EnvelopedData */
static void writeEncryptionHeader( STREAM *stream, const BYTE *oid,
const int version, const long payloadSize,
const long blockSize, const long extraSize )
{
const long blockedPayloadSize = ( payloadSize == CRYPT_UNUSED ) ? \
CRYPT_UNUSED : paddedSize( payloadSize, blockSize );
writeCMSheader( stream, oid,
( payloadSize == CRYPT_UNUSED || extraSize == CRYPT_UNUSED ) ? \
CRYPT_UNUSED : \
sizeofShortInteger( 0 ) + extraSize + blockedPayloadSize,
FALSE );
writeShortInteger( stream, version, DEFAULT_TAG );
}
static int writeEncryptedDataHeader( STREAM *stream,
const ENVELOPE_INFO *envelopeInfoPtr )
{
const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
const int encrContentInfoSize = sizeofCMSencrHeader( contentOID,
envelopeInfoPtr->payloadSize, envelopeInfoPtr->iCryptContext );
if( cryptStatusError( encrContentInfoSize ) )
return( encrContentInfoSize );
/* Write the EncryptedData header and version number, and
EncryptedContentInfo header */
writeEncryptionHeader( stream, OID_CMS_ENCRYPTEDDATA, 0,
envelopeInfoPtr->payloadSize, envelopeInfoPtr->blockSize,
encrContentInfoSize );
return( writeEncryptedContentHeader( stream, contentOID,
envelopeInfoPtr->iCryptContext, envelopeInfoPtr->payloadSize,
envelopeInfoPtr->blockSize ) );
}
static int writeEnvelopedDataHeader( STREAM *stream,
const ENVELOPE_INFO *envelopeInfoPtr )
{
const BYTE *contentOID = getContentOID( envelopeInfoPtr->contentType );
const int encrContentInfoSize = sizeofCMSencrHeader( contentOID,
envelopeInfoPtr->payloadSize, envelopeInfoPtr->iCryptContext );
const int originatorInfoSize = envelopeInfoPtr->extraDataSize ? \
( int ) sizeofObject( envelopeInfoPtr->extraDataSize ) : 0;
if( cryptStatusError( encrContentInfoSize ) )
return( encrContentInfoSize );
/* Write the EnvelopedData header and version number and start of the SET
OF RecipientInfo/EncryptionKeyInfo */
writeEncryptionHeader( stream, OID_CMS_ENVELOPEDDATA,
originatorInfoSize ? 2 : 0, envelopeInfoPtr->payloadSize,
envelopeInfoPtr->blockSize,
( ( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) ? \
CRYPT_UNUSED : \
sizeofObject( envelopeInfoPtr->cryptActionSize ) +
originatorInfoSize + encrContentInfoSize ) );
if( originatorInfoSize )
{
RESOURCE_DATA msgData;
int status;
/* Write the wrapper for the originator info and the originator info
itself */
writeCtag( stream, 0 );
writeLength( stream, envelopeInfoPtr->extraDataSize );
/* Export the originator cert 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, 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;
setResourceData( &msgData, envelopeInfoPtr->auxBuffer,
envelopeInfoPtr->auxBufSize );
}
else
setResourceData( &msgData, sMemBufPtr( stream ),
sMemDataLeft( stream ) );
status = krnlSendMessage( envelopeInfoPtr->iOriginatorChain,
RESOURCE_IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_CERTSET );
if( cryptStatusError( status ) )
return( status );
sSkip( stream, msgData.length );
}
return( ( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) ? \
writeSetIndef( stream ) : \
writeSet( stream, envelopeInfoPtr->cryptActionSize ) );
}
/* CompressedData */
static void writeCompressedDataHeader( STREAM *stream,
ENVELOPE_INFO *envelopeInfoPtr )
{
/* 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 */
writeCMSheader( stream, OID_CMS_COMPRESSEDDATA, CRYPT_UNUSED, FALSE );
writeShortInteger( stream, 0, DEFAULT_TAG );
swrite( stream, ALGOID_CMS_ZLIB, sizeofOID( ALGOID_CMS_ZLIB ) );
/* Write the inner Data header */
writeCMSheader( stream, getContentOID( envelopeInfoPtr->contentType ),
CRYPT_UNUSED, TRUE );
}
/****************************************************************************
* *
* Emit Envelope Preamble/Postamble *
* *
****************************************************************************/
/* Output as much of the preamble as possible into the envelope buffer */
static int emitPreamble( 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 );
/* If we've finished processing the header information, don't do
anything */
if( state == ENVSTATE_DONE )
return( CRYPT_OK );
/* If we haven't started doing anything yet, perform various final
initialisations */
if( state == 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;
/* Perform any remaining initialisation. MAC'd data is a special-
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 = preEnvelopeEncrypt( envelopeInfoPtr );
else
if( envelopeInfoPtr->usage == ACTION_SIGN )
status = preEnvelopeSign( envelopeInfoPtr );
if( cryptStatusError( status ) )
return( status );
/* Delete any orphaned actions (for example automatically added
hash actions which were overridden with user-supplied alternate
actions) */
deleteUnusedActions( envelopeInfoPtr );
/* We're ready to go, connect a write stream to the auxBuffer and
prepare to emit the outer header */
sMemOpen( &envelopeInfoPtr->auxStream, envelopeInfoPtr->auxBuffer,
envelopeInfoPtr->auxBufSize );
state = ENVSTATE_HEADER;
assert( actionsOK( envelopeInfoPtr ) );
}
/* Emit the outer header */
if( state == ENVSTATE_HEADER )
{
STREAM stream;
/* If we're encrypting, set up the encryption-related information */
if( envelopeInfoPtr->usage == ACTION_CRYPT )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -