📄 lib_sign.c
字号:
}
if( cryptStatusOK( status ) )
status = krnlSendMessage( sigCheckKey, RESOURCE_MESSAGE_GETDEPENDENT,
&sigCheckContext, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
/* Try and determine the length of the signature data. This should be
specified as a user parameter, unfortunately the early cryptlib API
didn't take length parameters when it wasn't absolutely necessary so
we have to take a guess at a safe size limit and hope that the data
isn't all done with an indefinite encoding */
signatureLength = getObjectLength( signature, 512 );
if( cryptStatusError( signatureLength ) )
return( CRYPT_ERROR_PARAM1 );
/* Call the low-level signature check function to check the signature */
status = checkSignature( signature, signatureLength, sigCheckContext,
hashContext, SIGNATURE_CRYPTLIB );
if( cryptArgError( status ) )
/* If we get an argument error from the mechanism-level code, map the
mechanism parameter number to the function argument number */
status = ( status == CRYPT_ARGERROR_NUM1 ) ? \
CRYPT_ERROR_PARAM3 : CRYPT_ERROR_PARAM2;
return( status );
}
/****************************************************************************
* *
* Extended Create/Check a Signature *
* *
****************************************************************************/
/* The maximum size for the encoded CMS signed attributes */
#define ENCODED_ATTRIBUTE_SIZE 512
/* Create a CMS signature */
static int createSignedAttributes( CRYPT_CONTEXT iAttributeHash,
BYTE *encodedAttributes,
int *encodedAttributeSize,
const CRYPT_CERTIFICATE iCmsAttributes,
const CRYPT_CONTEXT iMessageHash,
const BOOLEAN lengthCheckOnly )
{
RESOURCE_DATA msgData;
BYTE temp, hash[ CRYPT_MAX_HASHSIZE ];
int status;
/* Extract the message hash information and add it as a messageDigest
attribute, replacing any existing value if necessary. If we're
doing a call just to get the length of the exported data, we use a
dummy hash value since the hashing may not have completed yet */
krnlSendMessage( iCmsAttributes, RESOURCE_IMESSAGE_DELETEATTRIBUTE,
NULL, CRYPT_CERTINFO_CMS_MESSAGEDIGEST );
setResourceData( &msgData, hash, CRYPT_MAX_HASHSIZE );
if( lengthCheckOnly )
status = krnlSendMessage( iMessageHash,
RESOURCE_IMESSAGE_GETATTRIBUTE,
&msgData.length, CRYPT_CTXINFO_BLOCKSIZE );
else
status = krnlSendMessage( iMessageHash,
RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iCmsAttributes,
RESOURCE_IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_CMS_MESSAGEDIGEST );
if( cryptStatusError( status ) )
return( status );
/* Export the attributes into an encoded signedAttributes data block,
replace the IMPLICIT [ 0 ] tag at the start with a SET OF tag to allow
the attributes to be hashed, hash them into the attribute hash context,
and replace the original tag */
if( lengthCheckOnly )
{
setResourceData( &msgData, NULL, 0 );
}
else
setResourceData( &msgData, encodedAttributes, ENCODED_ATTRIBUTE_SIZE );
status = krnlSendMessage( iCmsAttributes, RESOURCE_IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_ENC_OBJDATA );
if( cryptStatusError( status ) )
return( status );
*encodedAttributeSize = msgData.length;
temp = encodedAttributes[ 0 ];
encodedAttributes[ 0 ] = BER_SET;
krnlSendMessage( iAttributeHash, RESOURCE_IMESSAGE_CTX_HASH,
encodedAttributes, *encodedAttributeSize );
status = krnlSendMessage( iAttributeHash, RESOURCE_IMESSAGE_CTX_HASH,
"", 0 );
encodedAttributes[ 0 ] = temp;
return( status );
}
static int createSignatureCMS( void *signature, int *signatureLength,
const CRYPT_CONTEXT signContext,
const CRYPT_CONTEXT iHashContext,
const CRYPT_CERTIFICATE extraData,
const CRYPT_SESSION iTspSession )
{
CRYPT_CONTEXT iCmsHashContext = iHashContext;
CRYPT_CERTIFICATE iCmsAttributes = extraData, iSigningCert;
CRYPT_ALGO hashAlgo;
STREAM stream;
BYTE encodedAttributes[ ENCODED_ATTRIBUTE_SIZE ];
BYTE dataSignature[ CRYPT_MAX_PKCSIZE ];
const BOOLEAN lengthOnly = ( signature == NULL ) ? TRUE : FALSE;
int encodedAttributeSize, dataSignatureSize, length, status;
/* Get the message hash algo and signing cert */
status = krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( signContext, RESOURCE_IMESSAGE_GETDEPENDENT,
&iSigningCert, OBJECT_TYPE_CERTIFICATE );
else
if( status == CRYPT_ARGERROR_OBJECT )
/* Remap the error code to refer to the correct parameter */
status = CRYPT_ARGERROR_NUM1;
if( cryptStatusError( status ) )
return( status );
/* If we're using signed attributes, set them up to be added to the
signature info */
if( extraData != CRYPT_UNUSED )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
if( extraData == CRYPT_USE_DEFAULT )
{
/* If there are no attributes included as extra data, generate
them ourselves */
setMessageCreateObjectInfo( &createInfo,
CRYPT_CERTTYPE_CMS_ATTRIBUTES );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
iCmsAttributes = createInfo.cryptHandle;
}
/* Generate the signed attributes and hash them into the CMS hash
context */
setMessageCreateObjectInfo( &createInfo, hashAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
{
if( extraData == CRYPT_USE_DEFAULT )
krnlSendNotifier( iCmsAttributes,
RESOURCE_IMESSAGE_DECREFCOUNT );
return( status );
}
status = createSignedAttributes( createInfo.cryptHandle,
encodedAttributes, &encodedAttributeSize,
iCmsAttributes, iHashContext, lengthOnly );
if( extraData == CRYPT_USE_DEFAULT )
krnlSendNotifier( iCmsAttributes,
RESOURCE_IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle,
RESOURCE_IMESSAGE_DECREFCOUNT );
return( status );
}
iCmsHashContext = createInfo.cryptHandle;
}
else
/* No signed attributes present */
encodedAttributeSize = 0;
/* Create the signature */
status = createSignature( lengthOnly ? NULL : dataSignature,
&dataSignatureSize, signContext,
iCmsHashContext, SIGNATURE_CMS );
if( iCmsHashContext != iHashContext )
krnlSendNotifier( iCmsHashContext, RESOURCE_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 )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
STREAM stream;
BYTE headerBuffer[ 8 ];
int headerLength;
/* Create the OCTET STRING wrapper for the signature */
sMemOpen( &stream, headerBuffer, 8 );
writeTag( &stream, BER_OCTETSTRING );
writeLength( &stream, dataSignatureSize );
headerLength = stell( &stream );
sMemDisconnect( &stream );
/* Hash the signature value to create the hash value to
countersign and send the result to the TSA */
setMessageCreateObjectInfo( &createInfo, hashAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
krnlSendMessage( createInfo.cryptHandle, RESOURCE_IMESSAGE_CTX_HASH,
headerBuffer, headerLength );
krnlSendMessage( createInfo.cryptHandle, RESOURCE_IMESSAGE_CTX_HASH,
dataSignature, dataSignatureSize );
status = krnlSendMessage( createInfo.cryptHandle,
RESOURCE_IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iTspSession,
RESOURCE_IMESSAGE_SETATTRIBUTE,
&createInfo.cryptHandle,
CRYPT_SESSINFO_TSP_MSGIMPRINT );
krnlSendNotifier( createInfo.cryptHandle,
RESOURCE_IMESSAGE_DECREFCOUNT );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iTspSession,
RESOURCE_IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE,
CRYPT_SESSINFO_ACTIVE );
if( cryptStatusError( status ) )
return( status );
}
/* Write the signerInfo record */
sMemOpen( &stream, signature, lengthOnly ? 0 : STREAMSIZE_UNKNOWN );
status = writeSignerInfo( &stream, iSigningCert, hashAlgo,
encodedAttributes, encodedAttributeSize,
dataSignature, dataSignatureSize,
lengthOnly ? CRYPT_UNUSED : iTspSession );
length = stell( &stream );
sMemDisconnect( &stream );
if( iTspSession != CRYPT_UNUSED && lengthOnly )
/* If we're countersigning the signature with a timestamp, inflate
the total size to the nearest multiple of MIN_BUFFER_SIZE, the
envelope auxData buffer size (that is, 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 which 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 */
length = roundUp( length, MIN_BUFFER_SIZE ) + MIN_BUFFER_SIZE;
if( !cryptStatusError( status ) )
*signatureLength = length;
return( status );
}
/* Check a CMS signature */
static int checkSignatureCMS( const void *signature, const int signatureLength,
const CRYPT_CONTEXT sigCheckContext,
const CRYPT_CONTEXT iHashContext,
CRYPT_CERTIFICATE *iExtraData,
const CRYPT_HANDLE iSigCheckKey )
{
CRYPT_CONTEXT iCmsHashContext = iHashContext;
CRYPT_ALGO hashAlgo;
MESSAGE_CREATEOBJECT_INFO createInfo;
QUERY_INFO queryInfo;
RESOURCE_DATA msgData;
STREAM stream;
BYTE hashValue[ CRYPT_MAX_HASHSIZE ];
int status;
if( iExtraData != NULL )
*iExtraData = CRYPT_ERROR;
/* Get the message hash algo */
status = krnlSendMessage( iHashContext, RESOURCE_IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
/* Remap the error code to refer to the correct parameter if
necessary */
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ARGERROR_NUM1 : 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 = queryObject( &stream, &queryInfo );
if( queryInfo.formatType != CRYPT_FORMAT_CMS )
status = CRYPT_ERROR_BADDATA;
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
return( status );
setResourceData( &msgData, queryInfo.iAndSStart, queryInfo.iAndSLength );
if( krnlSendMessage( iSigCheckKey, RESOURCE_IMESSAGE_COMPARE, &msgData,
RESOURCE_MESSAGE_COMPARE_ISSUERANDSERIALNUMBER ) != CRYPT_OK )
return( CRYPT_ERROR_WRONGKEY );
if( queryInfo.hashAlgo != hashAlgo )
return( CRYPT_ARGERROR_NUM1 );
/* If there are signedAttributes present, hash the data, substituting a
SET OF tag for the IMPLICIT [ 0 ] tag at the start */
if( queryInfo.attributeStart != NULL )
{
static const BYTE setTag[] = { BER_SET };
MESSAGE_CREATEOBJECT_INFO createInfo;
setMessageCreateObjectInfo( &createInfo, queryInfo.hashAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
RESOURCE_IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
krnlSendMessage( createInfo.cryptHandle, RESOURCE_IMESSAGE_CTX_HASH,
( BYTE * ) setTag, sizeof( BYTE ) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -