📄 mech_sig.c
字号:
/****************************************************************************
* *
* cryptlib Signature Mechanism Routines *
* Copyright Peter Gutmann 1992-2004 *
* *
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef INC_ALL
#include "crypt.h"
#include "asn1.h"
#include "asn1_ext.h"
#elif defined( INC_CHILD )
#include "../crypt.h"
#include "../misc/asn1.h"
#include "../misc/asn1_ext.h"
#else
#include "crypt.h"
#include "misc/asn1.h"
#include "misc/asn1_ext.h"
#endif /* Compiler-specific includes */
/* Prototypes for functions in mech_enc.c */
int adjustPKCS1Data( BYTE *outData, const BYTE *inData, const int inLength,
const int keySize );
BOOLEAN pgpCalculateChecksum( BYTE *dataPtr, const int length,
const BOOLEAN writeChecksum );
int pgpExtractKey( CRYPT_CONTEXT *iCryptContext, STREAM *stream,
const int length );
/****************************************************************************
* *
* Signature Mechanisms *
* *
****************************************************************************/
/* Perform signing. There are several variations of this that are handled
through common signature mechanism functions */
typedef enum { SIGN_PKCS1, SIGN_SSL } SIGN_TYPE;
/* Perform PKCS #1 signing/sig.checking */
static int sign( MECHANISM_SIGN_INFO *mechanismInfo, const SIGN_TYPE type )
{
CRYPT_ALGO_TYPE hashAlgo;
RESOURCE_DATA msgData;
STREAM stream;
BYTE hash[ CRYPT_MAX_HASHSIZE ], hash2[ CRYPT_MAX_HASHSIZE ];
BYTE preSigData[ CRYPT_MAX_PKCSIZE + 8 ];
BOOLEAN useSideChannelProtection;
int hashSize, hashSize2, length, i, status;
/* Sanity check the input data */
assert( ( mechanismInfo->signature == NULL && \
mechanismInfo->signatureLength == 0 ) || \
( mechanismInfo->signatureLength >= 64 ) );
/* Clear the return value */
if( mechanismInfo->signature != NULL )
memset( mechanismInfo->signature, 0,
mechanismInfo->signatureLength );
/* Get various algorithm and config parameters */
status = krnlSendMessage( mechanismInfo->hashContext,
IMESSAGE_GETATTRIBUTE, &hashAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->signContext,
IMESSAGE_GETATTRIBUTE, &length,
CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusOK( status ) )
status = krnlSendMessage( mechanismInfo->signContext,
IMESSAGE_GETATTRIBUTE,
&useSideChannelProtection,
CRYPT_OPTION_MISC_SIDECHANNELPROTECTION );
if( cryptStatusError( status ) )
return( status );
/* If this is just a length check, we're done */
if( mechanismInfo->signature == NULL )
{
mechanismInfo->signatureLength = length;
return( CRYPT_OK );
}
/* Get the hash data and determine the encoded payload size */
setMessageData( &msgData, hash, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( mechanismInfo->hashContext,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusOK( status ) )
{
hashSize = msgData.length;
if( type == SIGN_SSL )
{
setMessageData( &msgData, hash2, CRYPT_MAX_HASHSIZE );
status = krnlSendMessage( mechanismInfo->hashContext2,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_CTXINFO_HASHVALUE );
if( cryptStatusOK( status ) )
hashSize2 = msgData.length;
}
}
if( cryptStatusError( status ) )
return( status );
/* Encode the payload as required */
sMemOpen( &stream, mechanismInfo->signature, length );
switch( type )
{
case SIGN_PKCS1:
{
int payloadSize;
/* Encode the payload using the PKCS #1 format:
[ 0 ][ 1 ][ 0xFF padding ][ 0 ][ payload ] */
payloadSize = sizeofMessageDigest( hashAlgo, hashSize );
sputc( &stream, 0 );
sputc( &stream, 1 );
for( i = 0; i < length - ( payloadSize + 3 ); i++ )
sputc( &stream, 0xFF );
sputc( &stream, 0 );
status = writeMessageDigest( &stream, hashAlgo, hash, hashSize );
break;
}
case SIGN_SSL:
assert( hashAlgo == CRYPT_ALGO_MD5 );
/* Encode the payload using the PKCS #1 SSL format:
[ 0 ][ 1 ][ 0xFF padding ][ 0 ][ MD5 hash ][ SHA1 hash ] */
sputc( &stream, 0 );
sputc( &stream, 1 );
for( i = 0; i < length - ( hashSize + hashSize2 + 3 ); i++ )
sputc( &stream, 0xFF );
sputc( &stream, 0 );
swrite( &stream, hash, hashSize );
status = swrite( &stream, hash2, hashSize2 );
break;
default:
assert( NOTREACHED );
status = CRYPT_ERROR_NOTAVAIL;
}
sMemDisconnect( &stream );
if( cryptStatusError( status ) )
{
zeroise( mechanismInfo->signature, mechanismInfo->signatureLength );
return( status );
}
/* If we're using side-channel protection, remember a copy of the
signature data for later so we can check it against the recovered
signature data */
if( useSideChannelProtection )
memcpy( preSigData, mechanismInfo->signature, length );
/* Sign the data */
status = krnlSendMessage( mechanismInfo->signContext,
IMESSAGE_CTX_SIGN, mechanismInfo->signature,
length );
if( cryptStatusError( status ) )
return( status );
mechanismInfo->signatureLength = length;
/* If we're using side-channel protection, check that the signature
verifies */
if( useSideChannelProtection )
{
BYTE recoveredSignature[ CRYPT_MAX_PKCSIZE + 8 ];
/* Make sure that the recovered signature data matches what we
signed, unless we're in the unlikely situation that the key
isn't valid for sig.checking. The rationale behind this
operation is covered (in great detail) in ctx_rsa.c */
memcpy( recoveredSignature, mechanismInfo->signature, length );
status = krnlSendMessage( mechanismInfo->signContext,
IMESSAGE_CTX_SIGCHECK, recoveredSignature,
length );
if( status != CRYPT_ERROR_PERMISSION && \
status != CRYPT_ERROR_NOTAVAIL && \
memcmp( preSigData, recoveredSignature, length ) )
{
assert( NOTREACHED );
zeroise( mechanismInfo->signature, length );
mechanismInfo->signatureLength = 0;
return( CRYPT_ERROR_FAILED );
}
zeroise( recoveredSignature, length );
zeroise( preSigData, length );
}
return( CRYPT_OK );
}
int sigcheck( MECHANISM_SIGN_INFO *mechanismInfo, const SIGN_TYPE type )
{
CRYPT_ALGO_TYPE contextHashAlgo, hashAlgo;
RESOURCE_DATA msgData;
STREAM stream;
BYTE decryptedSignature[ CRYPT_MAX_PKCSIZE + 8 ];
BYTE hash[ CRYPT_MAX_HASHSIZE ], hash2[ CRYPT_MAX_HASHSIZE ];
int length, hashSize, hashSize2 = 0, ch, i, status;
/* Sanity check the input data */
assert( mechanismInfo->signatureLength >= 60 );
/* Get various algorithm parameters */
status = krnlSendMessage( mechanismInfo->hashContext,
IMESSAGE_GETATTRIBUTE, &contextHashAlgo,
CRYPT_CTXINFO_ALGO );
if( cryptStatusError( status ) )
return( status );
/* Format the input data as required for the sig check to work */
status = krnlSendMessage( mechanismInfo->signContext,
IMESSAGE_GETATTRIBUTE, &length,
CRYPT_CTXINFO_KEYSIZE );
if( cryptStatusOK( status ) )
status = adjustPKCS1Data( decryptedSignature,
mechanismInfo->signature, mechanismInfo->signatureLength,
length );
if( cryptStatusError( status ) )
return( status );
/* Recover the signed data */
status = krnlSendMessage( mechanismInfo->signContext,
IMESSAGE_CTX_SIGCHECK, decryptedSignature,
length );
if( cryptStatusError( status ) )
return( status );
/* Decode the payload as required */
sMemConnect( &stream, decryptedSignature, length );
switch( type )
{
case SIGN_PKCS1:
/* Decode the payload using the PKCS #1 format:
[ 0 ][ 1 ][ 0xFF padding ][ 0 ][ payload ]
Note that some implementations may have bignum code that
zero-truncates the result, which would produce a
CRYPT_ERROR_BADDATA error, it's the responsibility of the
lower-level crypto layer to reformat the data to return a
correctly-formatted result if necessary */
if( sgetc( &stream ) != 0 || sgetc( &stream ) != 1 )
{
status = CRYPT_ERROR_BADDATA;
break;
}
for( i = 0; i < length - 3; i++ )
if( ( ch = sgetc( &stream ) ) != 0xFF )
break;
if( ch != 0 )
{
status = CRYPT_ERROR_BADDATA;
break;
}
status = readMessageDigest( &stream, &hashAlgo, hash, &hashSize );
if( cryptStatusOK( status ) && contextHashAlgo != hashAlgo )
status = CRYPT_ERROR_SIGNATURE;
break;
case SIGN_SSL:
assert( contextHashAlgo == CRYPT_ALGO_MD5 );
/* Decode the payload using the PKCS #1 SSL format:
[ 0 ][ 1 ][ 0xFF padding ][ 0 ][ MD5 hash ][ SHA1 hash ] */
hashSize = 16; hashSize2 = 20;
if( sgetc( &stream ) != 0 || sgetc( &stream ) != 1 )
{
status = CRYPT_ERROR_BADDATA;
break;
}
for( i = 0; i < ( hashSize + hashSize2 - 3 ); i++ )
if( ( ch = sgetc( &stream ) ) != 0xFF )
break;
if( ch != 0 )
{
status = CRYPT_ERROR_BADDATA;
break;
}
status = sread( &stream, hash, hashSize );
if( cryptStatusOK( status ) )
status = sread( &stream, hash2, hashSize2 );
break;
default:
assert( NOTREACHED );
return( CRYPT_ERROR_NOTAVAIL );
}
sMemDisconnect( &stream );
zeroise( decryptedSignature, CRYPT_MAX_PKCSIZE );
if( cryptStatusError( status ) )
return( status );
/* Finally, make sure that the two hash values match */
setMessageData( &msgData, hash, hashSize );
status = krnlSendMessage( mechanismInfo->hashContext, IMESSAGE_COMPARE,
&msgData, MESSAGE_COMPARE_HASH );
if( cryptStatusOK( status ) && hashSize2 > 0 )
{
setMessageData( &msgData, hash2, hashSize2 );
status = krnlSendMessage( mechanismInfo->hashContext2,
IMESSAGE_COMPARE, &msgData,
MESSAGE_COMPARE_HASH );
}
/* Clean up */
zeroise( hash, CRYPT_MAX_HASHSIZE );
zeroise( hash2, CRYPT_MAX_HASHSIZE );
return( cryptStatusError( status ) ? CRYPT_ERROR_SIGNATURE : status );
}
int signPKCS1( void *dummy, MECHANISM_SIGN_INFO *mechanismInfo )
{
UNUSED( dummy );
return( sign( mechanismInfo, SIGN_PKCS1 ) );
}
int sigcheckPKCS1( void *dummy, MECHANISM_SIGN_INFO *mechanismInfo )
{
UNUSED( dummy );
return( sigcheck( mechanismInfo, SIGN_PKCS1 ) );
}
#ifdef USE_SSL
int signSSL( void *dummy, MECHANISM_SIGN_INFO *mechanismInfo )
{
UNUSED( dummy );
return( sign( mechanismInfo, SIGN_SSL ) );
}
int sigcheckSSL( void *dummy, MECHANISM_SIGN_INFO *mechanismInfo )
{
UNUSED( dummy );
return( sigcheck( mechanismInfo, SIGN_SSL ) );
}
#endif /* USE_SSL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -