📄 env_cms.c
字号:
/* Write the AuthenticatedData header and version number and start of the SET
OF RecipientInfo */
if( envelopeInfoPtr->payloadSize == CRYPT_UNUSED )
writeEncryptionHeader( stream, OID_CMS_AUTHDATA, 0, CRYPT_UNUSED, 1,
CRYPT_UNUSED );
else
{
int dataSize;
dataSize = ( envelopeInfoPtr->payloadSize ) ? \
sizeofObject( sizeofObject( envelopeInfoPtr->payloadSize ) ) : 0;
dataSize = sizeofObject( sizeofOID( contentOID ) + dataSize );
writeEncryptionHeader( stream, OID_CMS_AUTHDATA, 0,
envelopeInfoPtr->payloadSize, 1,
( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) ? \
CRYPT_UNUSED : \
sizeofObject( envelopeInfoPtr->cryptActionSize ) +
macActionSize + dataSize );
}
return( ( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) ? \
writeSetIndef( stream ) : \
writeSet( stream, envelopeInfoPtr->cryptActionSize ) );
}
/* CompressedData */
static int 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 */
return( writeCMSheader( stream, getContentOID( envelopeInfoPtr->contentType ),
CRYPT_UNUSED, TRUE ) );
}
/****************************************************************************
* *
* Content-Specific Pre-processing *
* *
****************************************************************************/
/* Pre-process information for encrypted enveloping */
static int processKeyexchangeAction( ENVELOPE_INFO *envelopeInfoPtr,
ACTION_LIST *actionListPtr,
const CRYPT_DEVICE iCryptDevice )
{
int cryptAlgo, status;
#ifdef USE_KEA
BYTE originatorDomainParams[ CRYPT_MAX_HASHSIZE ];
int originatorDomainParamSize = 0;
#endif /* USE_KEA */
assert( actionListPtr->action == ACTION_KEYEXCHANGE_PKC || \
actionListPtr->action == ACTION_KEYEXCHANGE );
/* If the session key/MAC context is tied to a device, make sure that
the key exchange object is in the same device */
if( iCryptDevice != CRYPT_ERROR )
{
CRYPT_DEVICE iKeyexDevice;
status = krnlSendMessage( actionListPtr->iCryptHandle,
MESSAGE_GETDEPENDENT, &iKeyexDevice,
OBJECT_TYPE_DEVICE );
if( cryptStatusError( status ) || iCryptDevice != iKeyexDevice )
return( CRYPT_ERROR_INVALID );
}
#ifdef USE_KEA
/* If there's an originator chain present, get the originator's domain
parameters and if the key is tied to a device, get the device's handle
so that we can create the session key object in it */
if( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR )
{
RESOURCE_DATA msgData;
setMessageData( &msgData, originatorDomainParams,
CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( envelopeInfoPtr->iExtraCertChain,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_KEY_KEADOMAINPARAMS );
if( cryptStatusError( status ) )
return( status );
originatorDomainParamSize = msgData.length;
status = krnlSendMessage( envelopeInfoPtr->iExtraCertChain,
IMESSAGE_GETDEPENDENT, &iCryptDevice,
OBJECT_TYPE_DEVICE );
if( cryptStatusError( status ) )
iCryptDevice = CRYPT_ERROR;
}
/* If it's a key agreement action, make sure that there's originator
info present and that the domain parameters match */
if( actionListPtr->action == ACTION_KEYEXCHANGE_PKC && \
cryptStatusOK( krnlSendMessage( actionListPtr->iCryptHandle,
IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC_KA_EXPORT ) ) )
{
RESOURCE_DATA msgData;
BYTE domainParams[ CRYPT_MAX_HASHSIZE ];
if( !originatorDomainParamSize )
{
setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_ORIGINATOR,
CRYPT_ERRTYPE_ATTR_ABSENT );
return( CRYPT_ERROR_NOTINITED );
}
setMessageData( &msgData, domainParams, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( actionListPtr->iCryptHandle,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_KEY_DOMAINPARAMS );
if( cryptStatusError( status ) )
return( status );
if( ( originatorDomainParamSize != msgData.length ) || \
memcmp( originatorDomainParams, domainParams,
originatorDomainParamSize ) )
{
setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_ORIGINATOR,
CRYPT_ERRTYPE_CONSTRAINT );
return( CRYPT_ERROR_INVALID );
}
}
#endif /* USE_KEA */
/* Remember that we now have a controlling action and connect the
controller to the subject */
envelopeInfoPtr->actionList->flags &= ~ACTION_NEEDSCONTROLLER;
actionListPtr->associatedAction = envelopeInfoPtr->actionList;
/* Evaluate the size of the exported action. 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 */
status = iCryptExportKeyEx( NULL, &actionListPtr->encodedSize, 0,
( actionListPtr->action == ACTION_KEYEXCHANGE ) ? \
CRYPT_FORMAT_CMS : envelopeInfoPtr->type,
envelopeInfoPtr->actionList->iCryptHandle,
actionListPtr->iCryptHandle,
( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR ) ? \
envelopeInfoPtr->iExtraCertChain : CRYPT_UNUSED );
if( cryptStatusOK( status ) )
status = krnlSendMessage( actionListPtr->iCryptHandle,
IMESSAGE_GETATTRIBUTE, &cryptAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
/* If there are any key exchange actions that will result in indefinite-
length encodings present, we can't use a definite-length encoding for
the key exchange actions */
return( ( cryptAlgo == CRYPT_ALGO_ELGAMAL ) ? OK_SPECIAL : CRYPT_OK );
}
static int preEnvelopeEncrypt( ENVELOPE_INFO *envelopeInfoPtr )
{
CRYPT_DEVICE iCryptDevice = CRYPT_ERROR;
ACTION_LIST *actionListPtr;
BOOLEAN hasIndefSizeActions = FALSE;
int totalSize, status;
#ifdef USE_KEA
/* If there's originator info present, find out what it'll take to encode
it into the envelope header */
if( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR )
{
RESOURCE_DATA msgData;
int status;
/* Determine how big the originator cert chain will be */
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( envelopeInfoPtr->iExtraCertChain,
IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_ICERTFORMAT_CERTSET );
if( cryptStatusError( status ) )
return( status );
envelopeInfoPtr->extraDataSize = msgData.length;
/* If we have very long originator cert chains the auxBuffer may not
be large enough to contain the resulting chain, so we have to
expand it to handle the chain */
if( envelopeInfoPtr->auxBufSize < envelopeInfoPtr->extraDataSize + 64 )
{
if( ( envelopeInfoPtr->auxBuffer = \
clDynAlloc( "preEnvelopeEncrypt", \
envelopeInfoPtr->extraDataSize + 64 ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
envelopeInfoPtr->auxBufSize = envelopeInfoPtr->extraDataSize + 64;
}
}
#endif /* USE_KEA */
/* If there are no key exchange actions present, we're done */
if( envelopeInfoPtr->preActionList == NULL )
return( CRYPT_OK );
/* Create the session/MAC key if necessary */
if( envelopeInfoPtr->actionList == NULL )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
/* Create a default encryption action and add it to the action
list */
setMessageCreateObjectInfo( &createInfo,
( envelopeInfoPtr->usage == ACTION_CRYPT ) ? \
envelopeInfoPtr->defaultAlgo : \
envelopeInfoPtr->defaultMAC );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusOK( status ) )
{
status = krnlSendMessage( createInfo.cryptHandle,
IMESSAGE_CTX_GENKEY, NULL, FALSE );
if( cryptStatusOK( status ) && \
addAction( &envelopeInfoPtr->actionList,
envelopeInfoPtr->memPoolState,
envelopeInfoPtr->usage,
createInfo.cryptHandle ) == NULL )
status = CRYPT_ERROR_MEMORY;
if( cryptStatusError( status ) )
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
}
if( cryptStatusError( status ) )
return( status );
}
else
{
/* If the session key/MAC context is tied to a device, get its handle
so we can check that all key exchange objects are also in the same
device */
status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
MESSAGE_GETDEPENDENT, &iCryptDevice,
OBJECT_TYPE_DEVICE );
if( cryptStatusError( status ) )
iCryptDevice = CRYPT_ERROR;
}
/* Notify the kernel that the session key/MAC context is attached to the
envelope. This is an internal object used only by the envelope, so
we tell the kernel not to increment its reference count when it
attaches it */
krnlSendMessage( envelopeInfoPtr->objectHandle, IMESSAGE_SETDEPENDENT,
&envelopeInfoPtr->actionList->iCryptHandle,
SETDEP_OPTION_NOINCREF );
/* Now walk down the list of key exchange actions evaluating their size
and connecting each one to the session key action */
totalSize = 0;
for( actionListPtr = envelopeInfoPtr->preActionList;
actionListPtr != NULL; actionListPtr = actionListPtr->next )
{
status = processKeyexchangeAction( envelopeInfoPtr, actionListPtr,
iCryptDevice );
if( cryptStatusError( status ) )
{
if( status != OK_SPECIAL )
return( status );
hasIndefSizeActions = TRUE;
}
totalSize += actionListPtr->encodedSize;
}
envelopeInfoPtr->cryptActionSize = hasIndefSizeActions ? \
CRYPT_UNUSED : totalSize;
return( CRYPT_OK );
}
/* Pre-process information for signed enveloping */
static int processSignatureAction( ENVELOPE_INFO *envelopeInfoPtr,
ACTION_LIST *actionListPtr )
{
int cryptAlgo, signatureSize, signingAttributes, status;
assert( actionListPtr->action == ACTION_SIGN );
/* Process signing certs if necessary and match the content-type in the
authenticated attributes with the signed content type if it's anything
other than 'data' (the data content-type is added automatically) */
if( envelopeInfoPtr->type == CRYPT_FORMAT_CMS || \
envelopeInfoPtr->type == CRYPT_FORMAT_SMIME )
{
/* If we're including signing certs and there are multiple signing
certs present, add the currently-selected one to the overall cert
collection */
if( !( envelopeInfoPtr->flags & ENVELOPE_NOSIGNINGCERTS ) && \
envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR )
{
status = krnlSendMessage( envelopeInfoPtr->iExtraCertChain,
IMESSAGE_SETATTRIBUTE,
&actionListPtr->iCryptHandle,
CRYPT_IATTRIBUTE_CERTCOLLECTION );
if( cryptStatusError( status ) )
return( status );
}
/* If there's no content-type present and the signed content type
isn't 'data' or it's an S/MIME envelope, create signing attributes
to hold the content-type and smimeCapabilities. Then, make sure
that the content-type in the attributes matches the actual content
type */
if( actionListPtr->iExtraData == CRYPT_ERROR && \
( envelopeInfoPtr->contentType != CRYPT_CONTENT_DATA || \
envelopeInfoPtr->type == CRYPT_FORMAT_SMIME ) )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
setMessageCreateObjectInfo( &createInfo,
CRYPT_CERTTYPE_CMS_ATTRIBUTES );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
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,
IMESSAGE_GETATTRIBUTE, &value,
CRYPT_CERTINFO_CMS_CONTENTTYPE ) != CRYPT_ERROR_NOTFOUND )
krnlSendMessage( actionListPtr->iExtraData,
IMESSAGE_DELETEATTRIBUTE, NULL,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -