📄 sign_cms.c
字号:
/****************************************************************************
* *
* CMS Signature Routines *
* Copyright Peter Gutmann 1993-2007 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "crypt.h"
#include "mech.h"
#include "asn1.h"
#include "asn1_ext.h"
#include "misc_rw.h"
#else
#include "crypt.h"
#include "mechs/mech.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#include "misc/misc_rw.h"
#endif /* Compiler-specific includes */
/* CMS version */
#define CMS_VERSION 1
/* The maximum size for the encoded CMS signed attributes */
#define ENCODED_ATTRIBUTE_SIZE 512
/* A structure to store CMS attribute information */
typedef struct {
/* The format of the signature: Basic CMS or full S/MIME */
CRYPT_FORMAT_TYPE formatType;
/* Objects needed to create the attributes. The time source is a device
associated with the signing key (usually the system device, but can
be a crypto device) used to obtain the signing time. The TSP session
is an optional session that's used to timestamp the signature */
CRYPT_CERTIFICATE iCmsAttributes; /* CMS attributes */
CRYPT_CONTEXT iMessageHash; /* Hash for MessageDigest */
CRYPT_HANDLE iTimeSource; /* Time source for signing time */
CRYPT_SESSION iTspSession; /* Optional TSP session */
/* The encoded attributes. The encodedAttributes pointer is null if
there are no attributes present, or points to the buffer containing
the encoded attributes */
BYTE attributeBuffer[ ENCODED_ATTRIBUTE_SIZE + 8 ];
BUFFER_OPT( maxEncodedAttributeSize, encodedAttributeSize ) \
BYTE *encodedAttributes;
int maxEncodedAttributeSize;
/* Returned data: The size of the encoded attribute information in the
buffer */
int encodedAttributeSize;
} CMS_ATTRIBUTE_INFO;
#define initCmsAttributeInfo( attributeInfo, format, cmsAttributes, messageHash, timeSource, tspSession ) \
memset( attributeInfo, 0, sizeof( CMS_ATTRIBUTE_INFO ) ); \
( attributeInfo )->formatType = format; \
( attributeInfo )->iCmsAttributes = cmsAttributes; \
( attributeInfo )->iMessageHash = messageHash; \
( attributeInfo )->iTimeSource = timeSource; \
( attributeInfo )->iTspSession = tspSession; \
( attributeInfo )->maxEncodedAttributeSize = ENCODED_ATTRIBUTE_SIZE;
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
/* Write CMS signer information:
SignerInfo ::= SEQUENCE {
version INTEGER (1),
issuerAndSerialNumber IssuerAndSerialNumber,
digestAlgorithm AlgorithmIdentifier,
signedAttrs [ 0 ] IMPLICIT SET OF Attribute OPTIONAL,
signatureAlgorithm AlgorithmIdentifier,
signature OCTET STRING,
unsignedAttrs [ 1 ] IMPLICIT SET OF Attribute OPTIONAL
} */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4, 6 ) ) \
static int writeCmsSignerInfo( INOUT STREAM *stream,
IN_HANDLE const CRYPT_CERTIFICATE certificate,
IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
IN_BUFFER_OPT( attributeSize ) \
const void *attributes,
IN_LENGTH_Z const int attributeSize,
IN_BUFFER( signatureSize ) const void *signature,
IN_LENGTH_SHORT const int signatureSize,
IN_HANDLE_OPT const CRYPT_HANDLE unsignedAttrObject )
{
MESSAGE_DATA msgData;
DYNBUF iAndSDB;
const int sizeofHashAlgoID = sizeofAlgoID( hashAlgo );
int timeStampSize = DUMMY_INIT, unsignedAttributeSize = 0, status;
assert( isWritePtr( stream, sizeof( STREAM ) ) );
assert( ( attributes == NULL && attributeSize == 0 ) || \
isReadPtr( attributes, attributeSize ) );
assert( isReadPtr( signature, signatureSize ) );
REQUIRES( isHandleRangeValid( certificate ) );
REQUIRES( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
hashAlgo <= CRYPT_ALGO_LAST_HASH );
REQUIRES( ( attributes == NULL && attributeSize == 0 ) || \
( attributes != NULL && \
attributeSize > 0 && attributeSize < MAX_INTLENGTH ) );
REQUIRES( signatureSize > MIN_CRYPT_OBJECTSIZE && \
signatureSize < MAX_INTLENGTH_SHORT );
REQUIRES( unsignedAttrObject == CRYPT_UNUSED || \
isHandleRangeValid( unsignedAttrObject ) );
if( cryptStatusError( sizeofHashAlgoID ) )
return( sizeofHashAlgoID );
/* Get the signerInfo information */
if( unsignedAttrObject != CRYPT_UNUSED )
{
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( unsignedAttrObject, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_ENC_TIMESTAMP );
if( cryptStatusError( status ) )
return( status );
timeStampSize = msgData.length;
unsignedAttributeSize = ( int ) \
sizeofObject( sizeofOID( OID_TSP_TSTOKEN ) + \
sizeofObject( timeStampSize ) );
}
status = dynCreate( &iAndSDB, certificate,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( cryptStatusError( status ) )
return( status );
/* Write the outer SEQUENCE wrapper and version number */
writeSequence( stream, sizeofShortInteger( CMS_VERSION ) + \
dynLength( iAndSDB ) + sizeofHashAlgoID + \
attributeSize + signatureSize + \
( ( unsignedAttributeSize ) ? \
( int ) sizeofObject( unsignedAttributeSize ) : 0 ) );
writeShortInteger( stream, CMS_VERSION, DEFAULT_TAG );
/* Write the issuerAndSerialNumber, digest algorithm identifier,
attributes (if there are any) and signature */
swrite( stream, dynData( iAndSDB ), dynLength( iAndSDB ) );
writeAlgoID( stream, hashAlgo );
if( attributeSize > 0 )
swrite( stream, attributes, attributeSize );
status = swrite( stream, signature, signatureSize );
dynDestroy( &iAndSDB );
if( cryptStatusError( status ) || unsignedAttributeSize <= 0 )
return( status );
/* Write the unsigned attributes. Note that the only unsigned attribute
in use at this time is a (not-quite) countersignature containing a
timestamp, so the following code always assumes that the attribute is
a timestamp. First we write the [1] IMPLICT SET OF attribute
wrapper */
writeConstructed( stream, unsignedAttributeSize, 1 );
writeSequence( stream, sizeofOID( OID_TSP_TSTOKEN ) + \
sizeofObject( timeStampSize ) );
writeOID( stream, OID_TSP_TSTOKEN );
status = writeSet( stream, timeStampSize );
if( cryptStatusError( status ) )
return( status );
/* Then we copy the timestamp data directly into the stream */
return( exportAttributeToStream( stream, unsignedAttrObject,
CRYPT_IATTRIBUTE_ENC_TIMESTAMP ) );
}
/* Create a CMS countersignature */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int createCmsCountersignature( IN_BUFFER( dataSignatureSize ) \
const void *dataSignature,
IN_LENGTH_SHORT const int dataSignatureSize,
IN_ALGO const CRYPT_ALGO_TYPE hashAlgo,
IN_HANDLE const CRYPT_SESSION iTspSession )
{
CRYPT_CONTEXT iHashContext;
MESSAGE_CREATEOBJECT_INFO createInfo;
STREAM stream;
int length, status;
assert( isReadPtr( dataSignature, dataSignatureSize ) );
REQUIRES( dataSignatureSize > MIN_CRYPT_OBJECTSIZE && \
dataSignatureSize < MAX_INTLENGTH_SHORT );
REQUIRES( hashAlgo >= CRYPT_ALGO_FIRST_HASH && \
hashAlgo <= CRYPT_ALGO_LAST_HASH );
REQUIRES( isHandleRangeValid( iTspSession ) );
/* Hash the signature data to create the hash value to countersign.
The CMS spec requires that the signature is calculated on the
contents octets (in other words the V of the TLV) of the signature,
so we have to skip the signature algorithm and OCTET STRING wrapper */
setMessageCreateObjectInfo( &createInfo, hashAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT, &createInfo,
OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
iHashContext = createInfo.cryptHandle;
#if 1 /* Standard CMS countersignature */
sMemConnect( &stream, dataSignature, dataSignatureSize );
readUniversal( &stream );
status = readOctetStringHole( &stream, &length, 16, DEFAULT_TAG );
if( cryptStatusOK( status ) )
{
void *dataPtr;
status = sMemGetDataBlock( &stream, &dataPtr, length );
if( cryptStatusOK( status ) )
{
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
dataPtr, length );
}
}
sMemDisconnect( &stream );
#else /* Broken TSP not-quite-countersignature */
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
( void * ) dataSignature, dataSignatureSize );
#endif /* 1 */
if( cryptStatusOK( status ) )
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusOK( status ) )
{
status = krnlSendMessage( iTspSession, IMESSAGE_SETATTRIBUTE,
&iHashContext,
CRYPT_SESSINFO_TSP_MSGIMPRINT );
}
krnlSendNotifier( iHashContext, IMESSAGE_DECREFCOUNT );
if( cryptStatusError( status ) )
return( status );
/* Send the result to the TSA for countersigning */
return( krnlSendMessage( iTspSession, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE, CRYPT_SESSINFO_ACTIVE ) );
}
/* Add sMimeCapabilities to a CMS attribute object */
static void addSmimeCapabilities( IN_HANDLE const CRYPT_CERTIFICATE iCmsAttributes )
{
typedef struct {
CRYPT_ALGO_TYPE cryptAlgo;
CRYPT_ATTRIBUTE_TYPE smimeCapability;
} SMIMECAP_INFO;
static const SMIMECAP_INFO smimeCapInfo[] = {
{ CRYPT_ALGO_3DES, CRYPT_CERTINFO_CMS_SMIMECAP_3DES },
{ CRYPT_ALGO_AES, CRYPT_CERTINFO_CMS_SMIMECAP_AES },
#ifdef USE_CAST
{ CRYPT_ALGO_CAST, CRYPT_CERTINFO_CMS_SMIMECAP_CAST128 },
#endif /* USE_CAST */
#ifdef USE_IDEA
{ CRYPT_ALGO_IDEA, CRYPT_CERTINFO_CMS_SMIMECAP_IDEA },
#endif /* USE_IDEA */
#ifdef USE_RC2
{ CRYPT_ALGO_RC2, CRYPT_CERTINFO_CMS_SMIMECAP_RC2 },
#endif /* USE_RC2 */
#ifdef USE_SKIPJACK
{ CRYPT_ALGO_SKIPJACK, CRYPT_CERTINFO_CMS_SMIMECAP_SKIPJACK },
#endif /* USE_SKIPJACK */
{ CRYPT_ALGO_NONE, CRYPT_ATTRIBUTE_NONE },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -