/****************************************************************************
*																			*
*					cryptlib ECDSA Encryption Routines						*
*			Copyright Matthias Bruestle and Peter Gutmann 2006-2007			*
*																			*
****************************************************************************/

#define PKC_CONTEXT		/* Indicate that we're working with PKC context */
#if defined( INC_ALL )
  #include "crypt.h"
  #include "context.h"
#else
  #include "crypt.h"
  #include "context/context.h"
#endif /* Compiler-specific includes */

#ifdef USE_ECC

/****************************************************************************
*																			*
*								Algorithm Self-test							*
*																			*
****************************************************************************/

/* Test the ECDSA implementation using the test vectors from ??? */

static BOOLEAN pairwiseConsistencyTest( CONTEXT_INFO *contextInfoPtr )
	{
	return( CRYPT_ERROR_NOTAVAIL );
	}

static int selfTest( void )
	{
	pairwiseConsistencyTest( NULL );	/* Keep compiler happy */
	return( CRYPT_ERROR_NOTAVAIL );
	}

/****************************************************************************
*																			*
*							Create/Check a Signature						*
*																			*
****************************************************************************/

/* Since ECDSA signature generation produces two values and the 
   cryptEncrypt() model only provides for passing a byte string in and out 
   (or, more specifically, the internal bignum data can't be exported to the 
   outside world), we need to encode the resulting data into a flat format.  
   This is done by encoding the output as an X9.31 Dss-Sig record, which is
   also used for ECDSA:

	Dss-Sig ::= SEQUENCE {
		r	INTEGER,
		s	INTEGER
		} */

/* Sign a single block of data  */

static int sign( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int noBytes )
	{
	return( CRYPT_ERROR_NOTAVAIL );
	}

/* Signature check a single block of data */

static int sigCheck( CONTEXT_INFO *contextInfoPtr, BYTE *buffer, int noBytes )
	{
	return( CRYPT_ERROR_NOTAVAIL );
	}

/****************************************************************************
*																			*
*								Key Management								*
*																			*
****************************************************************************/

/* Load key components into an encryption context */

static int initKey( CONTEXT_INFO *contextInfoPtr, const void *key,
					const int keyLength )
	{
	int status;

#ifndef USE_FIPS140
	/* Load the key component from the external representation into the
	   internal bignums unless we're doing an internal load */
	if( key != NULL )
		{
		PKC_INFO *pkcInfo = contextInfoPtr->ctxPKC;
		const CRYPT_PKCINFO_ECC *eccKey = ( CRYPT_PKCINFO_ECC * ) key;
		int bnStatus = BN_STATUS;

		contextInfoPtr->flags |= ( eccKey->isPublicKey ) ? \
							CONTEXT_ISPUBLICKEY : CONTEXT_ISPRIVATEKEY;
		CKPTR( BN_bin2bn( eccKey->p, bitsToBytes( eccKey->pLen ),
						  &pkcInfo->eccParam_p ) );
		CKPTR( BN_bin2bn( eccKey->a, bitsToBytes( eccKey->aLen ),
						  &pkcInfo->eccParam_a ) );
		CKPTR( BN_bin2bn( eccKey->b, bitsToBytes( eccKey->bLen ),
						  &pkcInfo->eccParam_b ) );
		CKPTR( BN_bin2bn( eccKey->gx, bitsToBytes( eccKey->gxLen ),
						  &pkcInfo->eccParam_gx ) );
		CKPTR( BN_bin2bn( eccKey->gy, bitsToBytes( eccKey->gyLen ),
						  &pkcInfo->eccParam_gy ) );
		CKPTR( BN_bin2bn( eccKey->r, bitsToBytes( eccKey->rLen ),
						  &pkcInfo->eccParam_r ) );
		CKPTR( BN_bin2bn( eccKey->qx, bitsToBytes( eccKey->qxLen ),
						  &pkcInfo->eccParam_qx ) );
		CKPTR( BN_bin2bn( eccKey->qy, bitsToBytes( eccKey->qyLen ),
						  &pkcInfo->eccParam_qy ) );
		if( !eccKey->isPublicKey )
			CKPTR( BN_bin2bn( eccKey->d, bitsToBytes( eccKey->dLen ),
							  &pkcInfo->eccParam_d ) );
		contextInfoPtr->flags |= CONTEXT_PBO;
		if( bnStatusError( bnStatus ) )
			return( getBnStatus( bnStatus ) );
		}
#endif /* USE_FIPS140 */

	/* Complete the key checking and setup */
	status = initECCkey( contextInfoPtr );
	if( cryptStatusOK( status ) )
		status = checkECCkey( contextInfoPtr );
	if( cryptStatusOK( status ) )
		status = contextInfoPtr->ctxPKC->calculateKeyIDFunction( contextInfoPtr );
	return( status );
	}

/* Generate a key into an encryption context */

static int generateKey( CONTEXT_INFO *contextInfoPtr, const int keySizeBits )
	{
	int status;

	status = generateECCkey( contextInfoPtr, keySizeBits );
	if( cryptStatusOK( status ) &&
#ifndef USE_FIPS140
		( contextInfoPtr->flags & CONTEXT_SIDECHANNELPROTECTION ) &&
#endif /* USE_FIPS140 */
		!pairwiseConsistencyTest( contextInfoPtr ) )
		{
		assert( NOTREACHED );
		status = CRYPT_ERROR_FAILED;
		}
	if( cryptStatusOK( status ) )
		status = contextInfoPtr->ctxPKC->calculateKeyIDFunction( contextInfoPtr );
	return( status );
	}

/****************************************************************************
*																			*
*						Capability Access Routines							*
*																			*
****************************************************************************/

static const CAPABILITY_INFO FAR_BSS capabilityInfo = {
	CRYPT_ALGO_ECDSA, bitsToBytes( 0 ), "ECDSA",
	MIN_PKCSIZE_ECC, bitsToBytes( 256 ), CRYPT_MAX_PKCSIZE_ECC,
	selfTest, getDefaultInfo, NULL, NULL, initKey, generateKey,
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, sign, sigCheck
	};

const CAPABILITY_INFO *getECDSACapability( void )
	{
	return( &capabilityInfo );
	}

#endif /* USE_ECC */
