📄 sign.c
字号:
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 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 };
setMessageCreateObjectInfo( &createInfo, queryInfo.hashAlgo );
status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
IMESSAGE_DEV_CREATEOBJECT,
&createInfo, OBJECT_TYPE_CONTEXT );
if( cryptStatusError( status ) )
return( status );
krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CTX_HASH,
( BYTE * ) setTag, sizeof( BYTE ) );
krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CTX_HASH,
( ( BYTE * ) queryInfo.attributeStart ) + 1,
queryInfo.attributeLength - 1 );
krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CTX_HASH,
"", 0 );
iCmsHashContext = createInfo.cryptHandle;
}
/* Check the signature */
status = checkSignature( signature, signatureLength, sigCheckContext,
iCmsHashContext, SIGNATURE_CMS );
if( queryInfo.attributeStart == NULL )
/* No signed attributes, we're done */
return( status );
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 */
setMessageCreateObjectIndirectInfo( &createInfo,
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 );
setMessageData( &msgData, hashValue, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CERTINFO_CMS_MESSAGEDIGEST );
if( cryptStatusOK( status ) )
{
status = krnlSendMessage( iHashContext, IMESSAGE_COMPARE, &msgData,
MESSAGE_COMPARE_HASH );
if( status == CRYPT_ERROR )
/* A failed comparison is reported as a generic CRYPT_ERROR,
convert it into a signature error if necessary */
status = CRYPT_ERROR_SIGNATURE;
}
if( cryptStatusError( status ) )
{
krnlSendNotifier( createInfo.cryptHandle, 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 = createInfo.cryptHandle;
else
krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
return( status );
}
/****************************************************************************
* *
* Create/Check a PGP Signature *
* *
****************************************************************************/
#ifdef USE_PGP
/* Write a PGP signature packet header:
-- Start of hashed data --
byte version = 4
byte sigType
byte sigAlgo
byte hashAlgo
byte[2] length of auth.attributes
byte[] authenticated attributes
-- End of hashed data --
byte[2] length of unauth.attributes = 0
[ byte[2] hash check ]
[ mpi(s) signature ]
PGP processes the authenticated attributes in an odd way, first hashing
part of the packet from the version number to the end of the authenticated
attributes, then some more stuff, and finally signing that. Because of
this complex way of handling things, we can't write the signature packet
in one go but instead have to write the part that's hashed, hash it, and
then go back and reassemble the whole thing from the pre-hashed data and
the length, hash check, and signature */
static int writePgpSigPacketHeader( void *dataBuffer, const int dataBufSize,
const CRYPT_CONTEXT iSignContext,
const CRYPT_CONTEXT iHashContext,
const int iAndSlength )
{
CRYPT_ALGO_TYPE hashAlgo, signAlgo;
STREAM stream;
RESOURCE_DATA msgData;
BYTE keyID[ PGP_KEYID_SIZE ];
BYTE iAndSHeader[ 64 ];
BYTE buffer[ 8 ], *bufPtr = buffer;
const time_t currentTime = getApproxTime();
int length, iAndSHeaderLength = 0, status;
/* Get the signature information */
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE,
&hashAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ARGERROR_NUM2 : status );
status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE,
&signAlgo, CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, keyID, PGP_KEYID_SIZE );
status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_IATTRIBUTE_KEYID_OPENPGP );
}
if( cryptStatusError( status ) )
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ARGERROR_NUM1 : status );
/* Write the issuerAndSerialNumber packet header if necessary. Since
this is a variable-length packet we need to pre-encode it before we
can write the main packet data:
byte[] length
byte subpacketType
byte[4] flags = 0
byte[2] typeLength
byte[2] valueLength
byte[] type
byte[] value
Note that type and value are reversed, this is required by the spec */
if( iAndSlength > 0 )
{
STREAM headerStream;
sMemOpen( &headerStream, iAndSHeader, 64 );
pgpWriteLength( &headerStream, 1 + 4 + 2 + 2 + 21 + iAndSlength );
sputc( &headerStream, PGP_SUBPACKET_TYPEANDVALUE );
swrite( &headerStream, "\x00\x00\x00\x00", 4 );
sputc( &headerStream, 0 );
sputc( &headerStream, 21 );
sputc( &headerStream, ( iAndSlength >> 8 ) & 0xFF );
sputc( &headerStream, iAndSlength & 0xFF );
swrite( &headerStream, "issuerAndSerialNumber", 21 );
iAndSHeaderLength = stell( &headerStream );
assert( sStatusOK( &headerStream ) );
sMemDisconnect( &headerStream );
}
/* Write the general header information */
sMemOpen( &stream, dataBuffer, dataBufSize );
sputc( &stream, PGP_VERSION_OPENPGP );
sputc( &stream, PGP_SIG_DATA );
sputc( &stream, cryptlibToPgpAlgo( signAlgo ) );
sputc( &stream, cryptlibToPgpAlgo( hashAlgo ) );
/* Write the authenticated attributes. The signer ID is optional, but
if we omit it GPG fails the signature check so we always include it */
length = 1 + 1 + 4 + 1 + 1 + PGP_KEYID_SIZE;
if( iAndSlength )
length += iAndSHeaderLength + iAndSlength;
sputc( &stream, ( length >> 8 ) & 0xFF );
sputc( &stream, length & 0xFF );
sputc( &stream, 1 + 4 );
sputc( &stream, PGP_SUBPACKET_TIME );
mputLong( bufPtr, currentTime );
swrite( &stream, buffer, 4 );
sputc( &stream, 1 + PGP_KEYID_SIZE );
sputc( &stream, PGP_SUBPACKET_KEYID );
swrite( &stream, keyID, PGP_KEYID_SIZE );
if( iAndSlength )
{
swrite( &stream, iAndSHeader, iAndSHeaderLength );
if( dataBuffer == NULL )
{ setMessageData( &msgData, NULL, 0 ); }
else
{ setMessageData( &msgData, sMemBufPtr( &stream ),
sMemDataLeft( &stream ) - 2 ); }
status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE_S,
&msgData,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( cryptStatusError( status ) )
{
sMemClose( &stream );
return( status );
}
sSkip( &stream, msgData.length );
}
/* Write the unauthenticated attributes */
sputc( &stream, 0 );
status = sputc( &stream, 0 );
/* Clean up */
length = stell( &stream );
sMemDisconnect( &stream );
return( cryptStatusError( status ) ? status : length );
}
static int createSignaturePGP( void *signature, int *signatureLength,
const int sigMaxLength,
const CRYPT_CONTEXT iSignContext,
const CRYPT_CONTEXT iHashContext )
{
RESOURCE_DATA msgData;
STREAM stream;
BYTE hash[ CRYPT_MAX_HASHSIZE ], signatureData[ CRYPT_MAX_PKCSIZE + 128 ];
BYTE extraData[ 1024 ], *extraDataPtr = extraData;
int extraDataLength = 1024, signatureDataLength, iAndSlength = 0, status;
/* If it's a length check only, determine how large the signature data
will be */
if( signature == NULL )
{
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE_S,
&msgData,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( cryptStatusOK( status ) )
iAndSlength = msgData.length;
status = extraDataLength = \
writePgpSigPacketHeader( NULL, 0, iSignContext, iHashContext,
iAndSlength );
if( !cryptStatusError( status ) )
status = createSignature( NULL, &signatureDataLength, 0,
iSignContext, iHashContext,
SIGNATURE_PGP );
if( cryptStatusError( status ) )
return( status );
*signatureLength = 1 + pgpSizeofLength( extraDataLength + 2 + \
signatureDataLength ) + \
extraDataLength + 2 + signatureDataLength;
return( CRYPT_OK );
}
/* Check whether there's an issuerAndSerialNumber present and allocate a
larger buffer for it if necessary. Note that we can't use a dynBuf
for this because we're allocating a buffer larger than the attribute,
not the same size as the attribute */
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
if( cryptStatusOK( status ) )
{
if( msgData.length > extraDataLength - 128 )
{
extraDataLength = 128 + msgData.length;
if( ( extraDataPtr = clDynAlloc( "createSignaturePGP", \
extraDataLength ) ) == NULL )
return( CRYPT_ERROR_MEMORY );
}
iAndSlength = msgData.length;
}
/* Complete the hashing and create the signature. In theory this could
get ugly because there could be multiple one-pass signature packets
present, however PGP handles multiple signatures by nesting them so
this isn't a problem.
PGP processes the authenticated attributes in an odd way, first
hashing part of the packet from the version number to the end of the
authenticated attributes, then some more stuff, and finally signing
that. Because of this complex way of handling things, we can't write
the signature packet in one go but instead have to write the part
we can create now, hash the portion that's hashed (all but the last
16 bits, the length of the unathenticated attributes), and then go
back and assemble the whole thing including the length and signature
later on from the individual parts */
status = extraDataLength = \
writePgpSigPacketHeader( extraData, extraDataLength, iSignContext,
iHashContext, iAndSlength );
if( !cryptStatusError( status ) )
{
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
extraData, extraDataLength - 2 );
if( status == CRYPT_ERROR_COMPLETE )
/* Unlike standard signatures, PGP requires that the hashing
not be wrapped up before the signature is generated, since
it needs to hash in further data before it can generate
the signature. Since completing the hashing is likely to be
a common error, we specifically check for this and return an
appropriate error code */
status = CRYPT_ARGERROR_NUM2;
}
if( cryptStatusOK( status ) )
{
BYTE buffer[ 8 ], *bufPtr = buffer + 2;
/* Hash in even more stuff at the end */
buffer[ 0 ] = 0x04;
buffer[ 1 ] = 0xFF;
mputLong( bufPtr, extraDataLength - 2 );
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, buffer, 6 );
}
if( cryptStatusOK( status ) )
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, hash, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE_S,
&msgData, CRYPT_CTXINFO_HASHVALUE );
}
if( cryptStatusOK( status ) )
{
status = createSignature( signatureData, &signatureDataLength,
CRYPT_MAX_PKCSIZE + 128, iSignContext,
iHashContext, SIGNATURE_PGP );
if( cryptStatusOK( status ) && \
sigMaxLength != STREAMSIZE_UNKNOWN && \
( 1 + pgpSizeofLength( extraDataLength + 1024 ) + \
extraDataLength + 16 + signatureDataLength ) > sigMaxLength )
status = CRYPT_ERROR_OVERFLOW;
}
if( cryptStatusError( status ) )
{
zeroise( extraDataPtr, extraDataLength );
if( extraDataPtr != extraData )
clFree( "createSignaturePGP", extraDataPtr );
return( status );
}
/* Write the signature packet:
[ signature packet header ]
byte[2] hash check
mpi signature
Since we've already had to write half the packet earlier on in order
to hash it, we copy this pre-encoded information across and add the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -