📄 sign.c
字号:
{
BYTE buffer[ 8 ], *bufPtr = buffer + 2;
/* Hash in even more stuff at the end. This is a complex jumble of
items constituting a version number, an 0xFF, and another length.
This was motivated by a concern that something that meant one
thing in a version n sig could mean something different when
interpreted as a version n+1 sig. For this reason a hash-
convention version (v4) was added, along with a disambiguator
0xFF that will never be found at that position in older (v3)
hash-convention sigs (the 0x04 is in fact redundant, but may be
needed at some point if the hash convention moves to a v5
format). The length has something to do with parsing the packet
from the end, so that out-of-band data doesn't run into payload
data */
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, CRYPT_UNUSED, SIGNATURE_PGP );
if( cryptStatusOK( status ) && \
( 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
header and trailer around it */
sMemOpen( &stream, signature,
1 + pgpSizeofLength( extraDataLength + 2 + \
signatureDataLength ) + \
extraDataLength + 2 + signatureDataLength );
pgpWritePacketHeader( &stream, PGP_PACKET_SIGNATURE,
extraDataLength + 2 + signatureDataLength );
swrite( &stream, extraData, extraDataLength );
swrite( &stream, hash, 2 ); /* Hash check */
status = swrite( &stream, signatureData, signatureDataLength );
if( cryptStatusOK( status ) )
*signatureLength = stell( &stream );
sMemDisconnect( &stream );
zeroise( extraDataPtr, extraDataLength );
zeroise( signatureData, CRYPT_MAX_PKCSIZE + 128 );
if( extraDataPtr != extraData )
clFree( "createSignaturePGP", extraDataPtr );
return( status );
}
/* Check a PGP signature */
static int checkSignaturePGP( const void *signature, const int signatureLength,
const CRYPT_CONTEXT sigCheckContext,
const CRYPT_CONTEXT iHashContext )
{
QUERY_INFO queryInfo;
STREAM stream;
int status;
/* Determine whether there are any authenticated attributes attached to
the signature */
memset( &queryInfo, 0, sizeof( QUERY_INFO ) );
sMemConnect( &stream, signature, signatureLength );
status = sigReadTable[ SIGNATURE_PGP ]( &stream, &queryInfo );
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
{
zeroise( &queryInfo, sizeof( QUERY_INFO ) );
return( status );
}
/* After hashing the content, PGP also hashes in extra authenticated
attributes */
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
queryInfo.attributeStart,
queryInfo.attributeLength );
if( cryptStatusOK( status ) && queryInfo.attributeLength != 5 )
{
BYTE buffer[ 8 ], *bufPtr = buffer + 2;
/* In addition to the standard authenticated attributes, OpenPGP
hashes in even more stuff at the end */
buffer[ 0 ] = 0x04;
buffer[ 1 ] = 0xFF;
mputLong( bufPtr, queryInfo.attributeLength );
status = krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH,
buffer, 6 );
}
zeroise( &queryInfo, sizeof( QUERY_INFO ) );
if( cryptStatusOK( status ) )
krnlSendMessage( iHashContext, IMESSAGE_CTX_HASH, "", 0 );
if( cryptStatusError( status ) )
return( status );
/* Check the signature */
return( checkSignature( signature, signatureLength, sigCheckContext,
iHashContext, CRYPT_UNUSED, SIGNATURE_PGP ) );
}
#endif /* USE_PGP */
/****************************************************************************
* *
* Extended Create/Check a Signature *
* *
****************************************************************************/
/* Create/check an extended signature type */
C_RET cryptCreateSignatureEx( C_OUT void C_PTR signature,
C_IN int signatureMaxLength,
C_OUT int C_PTR signatureLength,
C_IN CRYPT_FORMAT_TYPE formatType,
C_IN CRYPT_CONTEXT signContext,
C_IN CRYPT_CONTEXT hashContext,
C_IN CRYPT_HANDLE extraData )
{
BOOLEAN isCertChain = FALSE;
int certType, value, status;
/* Perform basic error checking. We have to use an internal message to
check for signing capability because the DLP algorithms have
specialised data-formatting requirements that can't normally be
directly accessed via external messages, and even the non-DLP
algorithms may be internal-use-only if there's a cert attached to
the context. If we're performing a sign operation this is OK since
they're being used from cryptlib-internal routines, but to make sure
that the context is OK we first check its external accessibility by
performing a dummy attribute read */
if( signature != NULL )
{
if( signatureMaxLength < MIN_CRYPT_OBJECTSIZE )
return( CRYPT_ERROR_PARAM2 );
if( !isWritePtr( signature, signatureMaxLength ) )
return( CRYPT_ERROR_PARAM1 );
memset( signature, 0, MIN_CRYPT_OBJECTSIZE );
}
if( !isWritePtr( signatureLength, sizeof( int ) ) )
return( CRYPT_ERROR_PARAM3 );
*signatureLength = 0;
if( formatType <= CRYPT_FORMAT_NONE || \
formatType >= CRYPT_FORMAT_LAST_EXTERNAL )
return( CRYPT_ERROR_PARAM4 );
status = krnlSendMessage( signContext, MESSAGE_GETATTRIBUTE,
&value, CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ERROR_PARAM5 : status );
status = krnlSendMessage( signContext, IMESSAGE_CHECK, NULL,
MESSAGE_CHECK_PKC_SIGN );
if( cryptStatusError( status ) )
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ERROR_PARAM5 : status );
status = krnlSendMessage( hashContext, MESSAGE_CHECK, NULL,
MESSAGE_CHECK_HASH );
if( cryptStatusError( status ) )
return( ( status == CRYPT_ARGERROR_OBJECT ) ? \
CRYPT_ERROR_PARAM6 : status );
/* If the signing context has a cert chain attached, the currently-
selected cert may not be the leaf cert. To ensure that we use the
correct cert, we lock the chain (which both protects us from having
the user select a different cert while we're using it, and saves the
selection state for when we later unlock it) and explicitly select
the leaf cert */
status = krnlSendMessage( signContext, IMESSAGE_GETATTRIBUTE,
&certType, CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusOK( status ) && certType == CRYPT_CERTTYPE_CERTCHAIN )
{
status = krnlSendMessage( signContext, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_TRUE,
CRYPT_IATTRIBUTE_LOCKED );
if( cryptStatusError( status ) )
return( status );
krnlSendMessage( signContext, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_CURSORFIRST,
CRYPT_CERTINFO_CURRENT_CERTIFICATE );
isCertChain = TRUE;
}
/* Call the low-level signature create function to create the
signature */
switch( formatType )
{
case CRYPT_FORMAT_AUTO:
case CRYPT_FORMAT_CRYPTLIB:
/* If it's a cryptlib-format signature, there can't be any extra
signing attributes present */
if( extraData != CRYPT_USE_DEFAULT )
{
status = CRYPT_ERROR_PARAM7;
break;
}
status = createSignature( signature, signatureLength,
signatureMaxLength, signContext,
hashContext, CRYPT_UNUSED,
SIGNATURE_CRYPTLIB );
break;
case CRYPT_FORMAT_CMS:
case CRYPT_FORMAT_SMIME:
/* Make sure that the signing context has a cert attached to
it */
status = krnlSendMessage( signContext, MESSAGE_GETATTRIBUTE,
&certType, CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusError( status ) ||
( certType != CRYPT_CERTTYPE_CERTIFICATE && \
certType != CRYPT_CERTTYPE_CERTCHAIN ) )
{
status = CRYPT_ERROR_PARAM5;
break;
}
/* Make sure that the extra data object is in order */
if( extraData != CRYPT_USE_DEFAULT )
{
status = krnlSendMessage( extraData, MESSAGE_GETATTRIBUTE,
&certType, CRYPT_CERTINFO_CERTTYPE );
if( cryptStatusError( status ) || \
certType != CRYPT_CERTTYPE_CMS_ATTRIBUTES )
{
status = CRYPT_ERROR_PARAM7;
break;
}
}
status = createSignatureCMS( signature, signatureLength,
signatureMaxLength, signContext,
hashContext, extraData,
CRYPT_UNUSED, formatType );
break;
#ifdef USE_PGP
case CRYPT_FORMAT_PGP:
status = createSignaturePGP( signature, signatureLength,
signatureMaxLength, signContext,
hashContext );
break;
#endif /* USE_PGP */
default:
assert( NOTREACHED );
status = CRYPT_ERROR_PARAM4;
}
if( isCertChain )
/* We're signing with a cert chain, restore its state and unlock it
to allow others access */
krnlSendMessage( signContext, IMESSAGE_SETATTRIBUTE,
MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED );
if( cryptArgError( status ) )
/* Remap the error code to refer to the correct parameter */
status = ( status == CRYPT_ARGERROR_NUM1 ) ? \
CRYPT_ERROR_PARAM5 : CRYPT_ERROR_PARAM6;
return( status );
}
C_RET cryptCreateSignature( C_OUT void C_PTR signature,
C_IN int signatureMaxLength,
C_OUT int C_PTR signatureLength,
C_IN CRYPT_CONTEXT signContext,
C_IN CRYPT_CONTEXT hashContext )
{
int status;
status = cryptCreateSignatureEx( signature, signatureMaxLength,
signatureLength, CRYPT_FORMAT_CRYPTLIB,
signContext, hashContext,
CRYPT_USE_DEFAULT );
if( cryptStatusError( status ) )
{
/* Remap parameter errors to the correct position */
if( status == CRYPT_ERROR_PARAM5 )
status = CRYPT_ERROR_PARAM4;
if( status == CRYPT_ERROR_PARAM6 )
status = CRYPT_ERROR_PARAM5;
}
return( status );
}
static CRYPT_FORMAT_TYPE getFormatType( const void *data )
{
STREAM stream;
const BYTE *dataPtr = data;
#ifdef USE_PGP
long length;
#endif /* USE_PGP */
int status;
/* Figure out what we've got. A PKCS #7/CMS/SMIME signature begins:
cryptlibSignature ::= SEQUENCE {
version INTEGER (3),
keyID [ 0 ] OCTET STRING
while a CMS signature begins:
cmsSignature ::= SEQUENCE {
version INTEGER (1),
digestAlgo SET OF {
which allows us to determine which type of object we have */
if( *dataPtr == BER_SEQUENCE )
{
CRYPT_FORMAT_TYPE formatType = CRYPT_FORMAT_NONE;
sMemConnect( &stream, data, 16 );
status = readSequence( &stream, NULL );
if( cryptStatusOK( status ) )
{
long version;
if( cryptStatusOK( readShortInteger( &stream, &version ) ) )
formatType = ( version == 1 ) ? CRYPT_FORMAT_CMS : \
( version == 3 ) ? CRYPT_FORMAT_CRYPTLIB : \
CRYPT_FORMAT_NONE;
}
sMemDisconnect( &stream );
return( formatType );
}
#ifdef USE_PGP
/* It's not ASN.1 data, check for PGP data */
sMemConnect( &stream, data, 16 );
status = pgpR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -