📄 sign_cms.c
字号:
{ CRYPT_ALGO_NONE, CRYPT_ATTRIBUTE_NONE },
};
int value, i, status;
REQUIRES_V( isHandleRangeValid( iCmsAttributes ) );
/* If there are already sMIMECapabilities present don't try and add
anything further */
status = krnlSendMessage( iCmsAttributes, IMESSAGE_GETATTRIBUTE,
&value, CRYPT_CERTINFO_CMS_SMIMECAPABILITIES );
if( cryptStatusOK( status ) )
return;
/* Add an sMIMECapability for each supported algorithm. Since these are
no-value attributes it's not worth aborting the signature generation
if the attempt to add them fails so we don't bother checking the
return value */
for( i = 0; smimeCapInfo[ i ].cryptAlgo != CRYPT_ALGO_NONE && \
i < FAILSAFE_ARRAYSIZE( smimeCapInfo, SMIMECAP_INFO );
i++ )
{
if( smimeCapInfo[ i ].cryptAlgo )
{
( void ) krnlSendMessage( iCmsAttributes, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_UNUSED,
smimeCapInfo[ i ].smimeCapability );
}
}
ENSURES_V( i < FAILSAFE_ARRAYSIZE( smimeCapInfo, SMIMECAP_INFO ) );
}
/****************************************************************************
* *
* Create CMS Attributes *
* *
****************************************************************************/
/* Finalise processing of and hash the CMS attributes */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int hashCmsAttributes( INOUT CMS_ATTRIBUTE_INFO *cmsAttributeInfo,
IN_HANDLE const CRYPT_CONTEXT iAttributeHash,
const BOOLEAN lengthCheckOnly )
{
MESSAGE_DATA msgData;
BYTE temp, hash[ CRYPT_MAX_HASHSIZE + 8 ];
int status;
assert( isWritePtr( cmsAttributeInfo, sizeof( CMS_ATTRIBUTE_INFO ) ) );
assert( isWritePtr( cmsAttributeInfo->encodedAttributes, \
cmsAttributeInfo->maxEncodedAttributeSize ) );
REQUIRES( isHandleRangeValid( cmsAttributeInfo->iCmsAttributes ) );
REQUIRES( isHandleRangeValid( cmsAttributeInfo->iMessageHash ) );
REQUIRES( isHandleRangeValid( iAttributeHash ) );
/* Extract the message hash information and add it as a messageDigest
attribute, replacing any existing value if necessary (we don't bother
checking the return value because the attribute may or may not be
present, and a failure to delete it will be detected immediately
afterwards when we try and set it). 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 */
( void ) krnlSendMessage( cmsAttributeInfo->iCmsAttributes,
IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CERTINFO_CMS_MESSAGEDIGEST );
setMessageData( &msgData, hash, CRYPT_MAX_HASHSIZE );
if( lengthCheckOnly )
{
memset( hash, 0, CRYPT_MAX_HASHSIZE ); /* Keep mem.checkers happy */
status = krnlSendMessage( cmsAttributeInfo->iMessageHash,
IMESSAGE_GETATTRIBUTE, &msgData.length,
CRYPT_CTXINFO_BLOCKSIZE );
}
else
{
status = krnlSendMessage( cmsAttributeInfo->iMessageHash,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_HASHVALUE );
}
if( cryptStatusOK( status ) )
{
status = krnlSendMessage( cmsAttributeInfo->iCmsAttributes,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_CMS_MESSAGEDIGEST );
}
if( cryptStatusError( status ) )
return( status );
/* If we're creating the attributes for a real signature rather than
just as part of a size check and there's a reliable time source
present, use the time from that instead of the built-in system time.
Although this seems like a trivial thing it's likely that the
presence of a high-assurance time source means that the accuracy of
timekeeping is considered critical so we fail the signature
generation if we can't set the time from the reliable source */
if( !lengthCheckOnly )
{
const time_t currentTime = \
getReliableTime( cmsAttributeInfo->iTimeSource );
if( currentTime > MIN_TIME_VALUE )
{
setMessageData( &msgData, ( void * ) ¤tTime,
sizeof( time_t ) );
( void ) krnlSendMessage( cmsAttributeInfo->iCmsAttributes,
IMESSAGE_DELETEATTRIBUTE, NULL,
CRYPT_CERTINFO_CMS_SIGNINGTIME );
status = krnlSendMessage( cmsAttributeInfo->iCmsAttributes,
IMESSAGE_SETATTRIBUTE_S, &msgData,
CRYPT_CERTINFO_CMS_SIGNINGTIME );
if( cryptStatusError( status ) )
return( status );
}
}
/* Export the attributes into an encoded signedAttributes data block */
if( lengthCheckOnly )
{ setMessageData( &msgData, NULL, 0 ); }
else
{
setMessageData( &msgData, cmsAttributeInfo->encodedAttributes,
cmsAttributeInfo->maxEncodedAttributeSize );
}
status = krnlSendMessage( cmsAttributeInfo->iCmsAttributes,
IMESSAGE_CRT_EXPORT, &msgData,
CRYPT_ICERTFORMAT_DATA );
if( cryptStatusError( status ) )
return( status );
cmsAttributeInfo->encodedAttributeSize = msgData.length;
/* If it's a length check, just generate a dummy hash value and exit */
if( lengthCheckOnly )
return( krnlSendMessage( iAttributeHash, IMESSAGE_CTX_HASH, "", 0 ) );
/* 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 */
temp = cmsAttributeInfo->encodedAttributes[ 0 ];
cmsAttributeInfo->encodedAttributes[ 0 ] = BER_SET;
status = krnlSendMessage( iAttributeHash, IMESSAGE_CTX_HASH,
cmsAttributeInfo->encodedAttributes,
cmsAttributeInfo->encodedAttributeSize );
if( cryptStatusOK( status ) )
status = krnlSendMessage( iAttributeHash, IMESSAGE_CTX_HASH, "", 0 );
cmsAttributeInfo->encodedAttributes[ 0 ] = temp;
return( status );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int createCmsAttributes( INOUT CMS_ATTRIBUTE_INFO *cmsAttributeInfo,
OUT_HANDLE_OPT CRYPT_CONTEXT *iCmsHashContext,
IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
const BOOLEAN lengthCheckOnly )
{
MESSAGE_CREATEOBJECT_INFO createInfo;
BOOLEAN createdLocalAttributes = FALSE, createdHashContext = FALSE;
int status;
assert( isWritePtr( cmsAttributeInfo, sizeof( CMS_ATTRIBUTE_INFO ) ) );
assert( isWritePtr( cmsAttributeInfo->attributeBuffer, \
cmsAttributeInfo->maxEncodedAttributeSize ) );
assert( isWritePtr( iCmsHashContext, sizeof( CRYPT_CONTEXT ) ) );
REQUIRES( cmsAttributeInfo->formatType == CRYPT_FORMAT_CMS || \
cmsAttributeInfo->formatType == CRYPT_FORMAT_SMIME );
REQUIRES( ( cmsAttributeInfo->iCmsAttributes == CRYPT_USE_DEFAULT ) || \
isHandleRangeValid( cmsAttributeInfo->iCmsAttributes ) );
REQUIRES( isHandleRangeValid( cmsAttributeInfo->iMessageHash ) );
REQUIRES( isHandleRangeValid( cmsAttributeInfo->iTimeSource ) );
REQUIRES( ( cmsAttributeInfo->iTspSession == CRYPT_UNUSED ) || \
isHandleRangeValid( cmsAttributeInfo->iTspSession ) );
REQUIRES( cmsAttributeInfo->encodedAttributes == NULL && \
cmsAttributeInfo->encodedAttributeSize == 0 );
REQUIRES( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
hashAlgo <= CRYPT_ALGO_LAST_HASH );
/* Clear return value */
*iCmsHashContext = CRYPT_ERROR;
/* Set up the attribute buffer */
cmsAttributeInfo->encodedAttributes = cmsAttributeInfo->attributeBuffer;
/* If the user hasn't supplied the attributes, generate them ourselves */
if( cmsAttributeInfo->iCmsAttributes == CRYPT_USE_DEFAULT )
{
setMessageCreateObjectInfo( &createInfo,
CRYPT_CERTTYPE_CMS_ATTRIBUTES );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CERTIFICATE );
if( cryptStatusError( status ) )
return( status );
cmsAttributeInfo->iCmsAttributes = createInfo.cryptHandle;
createdLocalAttributes = TRUE;
}
/* If it's an S/MIME (vs.pure CMS) signature add the sMIMECapabilities
to further bloat things up. Since these are no-value attributes
it's not worth aborting the signature generation if the attempt to
add them fails so we don't bother checking a return value */
if( cmsAttributeInfo->formatType == CRYPT_FORMAT_SMIME )
addSmimeCapabilities( cmsAttributeInfo->iCmsAttributes );
/* Generate the attributes and hash them into the CMS hash context */
setMessageCreateObjectInfo( &createInfo, hashAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusOK( status ) )
{
createdHashContext = TRUE;
status = hashCmsAttributes( cmsAttributeInfo, createInfo.cryptHandle,
lengthCheckOnly );
}
if( createdLocalAttributes )
{
krnlSendNotifier( cmsAttributeInfo->iCmsAttributes,
IMESSAGE_DECREFCOUNT );
cmsAttributeInfo->iCmsAttributes = CRYPT_UNUSED;
}
if( cryptStatusError( status ) )
{
if( createdHashContext )
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( status );
}
/* Return the hash of the attributes to the caller */
*iCmsHashContext = createInfo.cryptHandle;
return( CRYPT_OK );
}
/****************************************************************************
* *
* Create/Check a CMS Signature *
* *
****************************************************************************/
/* Create a CMS signature. The extraData parameter contains the information
for signed attributes, and can take one of three values:
Cert.object handle: Signed attributes to use.
CRYPT_USE_DEFAULT: Generate default signing attributes when we create
the signature.
CRYPT_UNUSED: Don't use signing attributes */
CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
int createSignatureCMS( OUT_BUFFER_OPT( sigMaxLength, *signatureLength ) \
void *signature,
IN_LENGTH_Z const int sigMaxLength,
OUT_LENGTH_Z int *signatureLength,
IN_HANDLE const CRYPT_CONTEXT signContext,
IN_HANDLE const CRYPT_CONTEXT iHashContext,
IN_HANDLE_OPT const CRYPT_CERTIFICATE extraData,
IN_HANDLE_OPT const CRYPT_SESSION iTspSession,
IN_ENUM( CRYPT_FORMAT ) \
const CRYPT_FORMAT_TYPE formatType )
{
CRYPT_CONTEXT iCmsHashContext = iHashContext;
CRYPT_CERTIFICATE iSigningCert;
CRYPT_ALGO_TYPE hashAlgo;
STREAM stream;
CMS_ATTRIBUTE_INFO cmsAttributeInfo;
BYTE buffer[ CRYPT_MAX_PKCSIZE + 128 + 8 ];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -