📄 sign_cms.c
字号:
BYTE *bufPtr = ( signature == NULL ) ? NULL : buffer;
const int bufSize = ( signature == NULL ) ? 0 : CRYPT_MAX_PKCSIZE + 128;
int dataSignatureSize, length = DUMMY_INIT, status;
assert( ( signature == NULL && sigMaxLength == 0 ) || \
isReadPtr( signature, sigMaxLength ) );
assert( isWritePtr( signatureLength, sizeof( int ) ) );
REQUIRES( ( signature == NULL && sigMaxLength == 0 ) || \
( signature != NULL && \
sigMaxLength > MIN_CRYPT_OBJECTSIZE && \
sigMaxLength < MAX_INTLENGTH ) );
REQUIRES( isHandleRangeValid( signContext ) );
REQUIRES( isHandleRangeValid( iHashContext ) );
REQUIRES( ( extraData == CRYPT_UNUSED ) || \
( extraData == CRYPT_USE_DEFAULT ) || \
isHandleRangeValid( extraData ) );
REQUIRES( ( iTspSession == CRYPT_UNUSED ) || \
isHandleRangeValid( iTspSession ) );
REQUIRES( formatType == CRYPT_FORMAT_CMS || \
formatType == CRYPT_FORMAT_SMIME );
/* Clear return value */
*signatureLength = 0;
initCmsAttributeInfo( &cmsAttributeInfo, formatType, extraData, \
iHashContext, signContext, iTspSession );
/* Get the message hash algo and signing cert */
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM2 : status );
status = krnlSendMessage( signContext, IMESSAGE_GETDEPENDENT,
&iSigningCert, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM1 : status );
/* If we're using signed attributes, set them up to be added to the
signature info */
if( cmsAttributeInfo.iCmsAttributes != CRYPT_UNUSED )
{
status = createCmsAttributes( &cmsAttributeInfo, &iCmsHashContext,
hashAlgo, ( signature == NULL ) ? \
TRUE : FALSE );
if( cryptStatusError( status ) )
return( status );
}
/* Create the signature */
status = createSignature( bufPtr, bufSize, &dataSignatureSize,
signContext, iCmsHashContext, CRYPT_UNUSED,
SIGNATURE_CMS );
if( iCmsHashContext != iHashContext )
krnlSendNotifier( iCmsHashContext, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
return( status );
/* If we're countersigning the signature (typically done via a
timestamp), create the countersignature */
if( iTspSession != CRYPT_UNUSED && signature != NULL )
{
status = createCmsCountersignature( buffer, dataSignatureSize,
hashAlgo, iTspSession );
if( cryptStatusError( status ) )
return( status );
}
/* Write the signerInfo record */
sMemOpenOpt( &stream, signature, ( signature == NULL ) ? 0 : sigMaxLength );
status = writeCmsSignerInfo( &stream, iSigningCert, hashAlgo,
cmsAttributeInfo.encodedAttributes,
cmsAttributeInfo.encodedAttributeSize,
buffer, dataSignatureSize,
( signature == NULL ) ? CRYPT_UNUSED : iTspSession );
if( cryptStatusOK( status ) )
length = stell( &stream );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
if( iTspSession != CRYPT_UNUSED && signature == NULL )
{
/* If we're countersigning the signature with a timestamp and doing
a length check only, inflate the total size to the nearest
multiple of the envelope parameter MIN_BUFFER_SIZE, which is the
size of the envelope's auxData buffer used to contain the
signature. In other words we're always going to trigger an
increase in the auxBuffer size because its initial size is
MIN_BUFFER_SIZE, so when we grow it we grow it to a nice round
value rather than just ( length + MIN_BUFFER_SIZE ). The actual
size increase is just a guess since we can't really be sure how
much bigger it'll get without contacting the TSA, however this
should be big enough to hold a simple SignedData value without
attached certs. If a TSA gets the implementation wrong and
returns a timestamp with an attached cert chain and the chain is
too large the worst that'll happen is that we'll get a
CRYPT_ERROR_OVERFLOW when we try and read the TSA data from the
session object. Note that this behaviour is envelope-specific
and assumes that we're being called from the enveloping code,
this is curently the only location from which we can be called
because a timestamp only makes sense as a countersignature on CMS
data. It's somewhat ugly because it asumes internal knowledge
of the envelope abstraction but there isn't really any clean way
to handle this because we can't tell in advance how much data the
TSA will send us */
if( MIN_BUFFER_SIZE - length <= 1024 )
length = roundUp( length, MIN_BUFFER_SIZE ) + MIN_BUFFER_SIZE;
else
{
/* It should fit in the buffer, don't bother expanding it */
length = 1024;
}
}
*signatureLength = length;
return( CRYPT_OK );
}
/* Check a CMS signature */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
int checkSignatureCMS( IN_BUFFER( signatureLength ) const void *signature,
IN_LENGTH_SHORT const int signatureLength,
IN_HANDLE const CRYPT_CONTEXT sigCheckContext,
IN_HANDLE const CRYPT_CONTEXT iHashContext,
OUT_OPT_HANDLE_OPT CRYPT_CERTIFICATE *iExtraData,
IN_HANDLE const CRYPT_HANDLE iSigCheckKey )
{
CRYPT_CERTIFICATE iLocalExtraData;
CRYPT_CONTEXT iCmsHashContext = iHashContext;
CRYPT_ALGO_TYPE hashAlgo;
MESSAGE_CREATEOBJECT_INFO createInfo;
QUERY_INFO queryInfo;
MESSAGE_DATA msgData;
STREAM stream;
static const BYTE setTag[] = { BER_SET };
BYTE hashValue[ CRYPT_MAX_HASHSIZE + 8 ];
int status;
assert( isReadPtr( signature, signatureLength ) );
assert( ( iExtraData == NULL ) || \
isWritePtr( iExtraData, sizeof( CRYPT_CERTIFICATE ) ) );
REQUIRES( signatureLength > 40 && signatureLength < MAX_INTLENGTH );
REQUIRES( isHandleRangeValid( sigCheckContext ) );
REQUIRES( isHandleRangeValid( iHashContext ) );
REQUIRES( isHandleRangeValid( iSigCheckKey ) );
if( iExtraData != NULL )
*iExtraData = CRYPT_ERROR;
/* Get the message hash algo */
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( cryptArgError( status ) ? CRYPT_ARGERROR_NUM2 : status );
/* Unpack the SignerInfo record and make sure that the supplied key is
the correct one for the sig.check and the supplied hash context
matches the algorithm used in the signature */
sMemConnect( &stream, signature, signatureLength );
status = queryAsn1Object( &stream, &queryInfo );
if( cryptStatusOK( status ) && \
( queryInfo.formatType != CRYPT_FORMAT_CMS && \
queryInfo.formatType != CRYPT_FORMAT_SMIME ) )
status = CRYPT_ERROR_BADDATA;
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
REQUIRES( rangeCheck( queryInfo.iAndSStart, queryInfo.iAndSLength,
queryInfo.size ) );
setMessageData( &msgData, \
( BYTE * ) signature + queryInfo.iAndSStart, \
queryInfo.iAndSLength );
status = krnlSendMessage( iSigCheckKey, IMESSAGE_COMPARE, &msgData,
MESSAGE_COMPARE_ISSUERANDSERIALNUMBER );
if( cryptStatusError( status ) )
{
/* A failed comparison is reported as a generic CRYPT_ERROR,
convert it into a wrong-key error if necessary */
return( ( status == CRYPT_ERROR ) ? \
CRYPT_ERROR_WRONGKEY : status );
}
if( queryInfo.hashAlgo != hashAlgo )
return( CRYPT_ARGERROR_NUM2 );
/* If there are no signed attributes present, just check the signature
and exit */
if( queryInfo.attributeStart <= 0 )
{
return( checkSignature( signature, signatureLength, sigCheckContext,
iCmsHashContext, CRYPT_UNUSED,
SIGNATURE_CMS ) );
}
/* There are signedAttributes present, hash the data, substituting a SET
OF tag for the IMPLICIT [ 0 ] tag at the start */
REQUIRES( rangeCheck( queryInfo.attributeStart,
queryInfo.attributeLength, queryInfo.size ) );
setMessageCreateObjectInfo( &createInfo, queryInfo.hashAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
iCmsHashContext = createInfo.cryptHandle;
status = krnlSendMessage( iCmsHashContext, IMESSAGE_CTX_HASH,
( BYTE * ) setTag, sizeof( BYTE ) );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCmsHashContext, IMESSAGE_CTX_HASH,
( BYTE * ) signature + queryInfo.attributeStart + 1,
queryInfo.attributeLength - 1 );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCmsHashContext, IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusError( status ) )
{
krnlSendNotifier( iCmsHashContext, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Check the signature */
status = checkSignature( signature, signatureLength, sigCheckContext,
iCmsHashContext, CRYPT_UNUSED, SIGNATURE_CMS );
krnlSendNotifier( iCmsHashContext, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
return( status );
/* Import the attributes and make sure that the data hash value given in
the signed attributes matches the user-supplied hash */
REQUIRES( rangeCheck( queryInfo.attributeStart,
queryInfo.attributeLength, queryInfo.size ) );
setMessageCreateObjectIndirectInfo( &createInfo,
( BYTE * ) signature + queryInfo.attributeStart,
queryInfo.attributeLength,
CRYPT_CERTTYPE_CMS_ATTRIBUTES );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT_INDIRECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
iLocalExtraData = createInfo.cryptHandle;
setMessageData( &msgData, hashValue, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iLocalExtraData, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_CMS_MESSAGEDIGEST );
if( cryptStatusOK( status ) )
{
status = krnlSendMessage( iHashContext, IMESSAGE_COMPARE, &msgData,
MESSAGE_COMPARE_HASH );
if( cryptStatusError( status ) )
status = CRYPT_ERROR_SIGNATURE;
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( iLocalExtraData, IMESSAGE_DECREFCOUNT );
return( status );
}
/* If the user wants to look at the authenticated attributes, make them
externally visible, otherwise delete them */
if( iExtraData != NULL )
*iExtraData = iLocalExtraData;
else
krnlSendNotifier( iLocalExtraData, IMESSAGE_DECREFCOUNT );
return( CRYPT_OK );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -