/*
* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/


#include "keyhelper.h"
#include <asn1enc.h>
#include <asymmetric.h>
#include <x509cert.h>

// CPKCS10KeyHelper ////////////////////////////////////////////////////////////

CPKCS10KeyHelper* CPKCS10KeyHelper::CreateKeyHelperL(MCTKeyStore& aKeyStore,
													 const CCTKeyInfo& aKeyInfo,
													 const TDesC8& aExportedKey,
													 const TAlgorithmId aDigestId)
	{
	CPKCS10KeyHelper* result = NULL;
	
	switch (aKeyInfo.Algorithm())
		{
		case CCTKeyInfo::ERSA:
			result = new (ELeave) CPKCS10RSAKeyHelper(aKeyStore, aKeyInfo);
			break;

		case CCTKeyInfo::EDSA:
			result = new (ELeave) CPKCS10DSAKeyHelper(aKeyStore, aKeyInfo);
			break;

		default:
			User::Leave(KErrArgument);
		}

	CleanupStack::PushL(result);
	result->CreateKeyEncoderL(aExportedKey, aDigestId);
	CleanupStack::Pop(result);

	return result;
	}

CPKCS10KeyHelper::CPKCS10KeyHelper(MCTKeyStore& aKeyStore, const CCTKeyInfo& aKeyInfo) :
	iKeyStore(aKeyStore),
	iKeyInfo(aKeyInfo)
	{
	}

CPKCS10KeyHelper::~CPKCS10KeyHelper()
	{
	delete iKeyEncoder;
	}

CASN1EncBase* CPKCS10KeyHelper::EncodeKeyLC()
	{
	return iKeyEncoder->EncodeKeyLC();
	}

CASN1EncBase* CPKCS10KeyHelper::DigestInfoLC(const TDesC8& digest)
	{
	CASN1EncSequence* seq = CASN1EncSequence::NewLC();
	
	// DigestAlgorithmIdentifier
	CASN1EncSequence* digestAlgID =iKeyEncoder-> EncodeDigestAlgorithmLC();

	seq->AddAndPopChildL(digestAlgID); 
	
	// Actual message digest	
	CASN1EncOctetString* octet = CASN1EncOctetString::NewLC(digest);
	seq->AddAndPopChildL(octet);
	
	return seq;
	}


CASN1EncSequence* CPKCS10KeyHelper::EncodeSignatureAlgorithmLC()
	{
	return iKeyEncoder->EncodeSignatureAlgorithmLC();
	}

// CPKCS10RSAKeyHelper /////////////////////////////////////////////////////////

CPKCS10RSAKeyHelper::CPKCS10RSAKeyHelper(MCTKeyStore& aKeyStore, const CCTKeyInfo& aKeyInfo) :
	CPKCS10KeyHelper(aKeyStore, aKeyInfo)
	{
	}

CPKCS10RSAKeyHelper::~CPKCS10RSAKeyHelper()
	{
	if (iRSASigner)
		{
		iRSASigner->Release();		
		}
	if (iDigestBuf) 
		{
		delete iDigestBuf;
		}
	delete iRSASignature;
	delete iPublicKey;	
	}

void CPKCS10RSAKeyHelper::OpenSigner(TRequestStatus& aStatus)
	{
	iKeyStore.Open(iKeyInfo, iRSASigner, aStatus);
	}

void CPKCS10RSAKeyHelper::CancelOpenSigner()
	{
	iKeyStore.CancelOpen();
	}

void CPKCS10RSAKeyHelper::SignDigestL(const TDesC8& aDigest, TRequestStatus& aStatus)
	{
	CASN1EncBase* digestInfo = DigestInfoLC(aDigest);
	
	// DER encode it!
	iDigestBuf = HBufC8::NewMaxL(digestInfo->LengthDER());
	TPtr8 oct(iDigestBuf->Des());
	oct.FillZ();

	TUint writePos = 0;
	digestInfo->WriteDERL(oct, writePos);
	
	// Sign the DER encoded digest info
	iRSASigner->Sign(*iDigestBuf, iRSASignature, aStatus);

	//CleanupStack::PopAndDestroy(octetData);	
	CleanupStack::PopAndDestroy(digestInfo);		
	}

void CPKCS10RSAKeyHelper::CancelSignDigest()
	{
	iRSASigner->CancelSign();
	}

void CPKCS10RSAKeyHelper::CreateKeyEncoderL(const TDesC8& aExportedKey, TAlgorithmId aDigestId)
	{
	CX509SubjectPublicKeyInfo* ki = CX509SubjectPublicKeyInfo::NewLC(aExportedKey);
	TX509KeyFactory factory; 
	iPublicKey = factory.RSAPublicKeyL(ki->KeyData());
	CleanupStack::PopAndDestroy(ki);
	iKeyEncoder = new (ELeave) TX509RSAKeyEncoder(*iPublicKey, aDigestId);
	}


CASN1EncBitString* CPKCS10RSAKeyHelper::EncodeSignatureLC()
	{
	// Get raw signature data
	HBufC8* sigData = iRSASignature->S().BufferLC();

	// Create ASN.1 bit string from the signature and return it.
	CASN1EncBitString* encSig = CASN1EncBitString::NewL(*sigData);
	CleanupStack::PopAndDestroy(sigData);
	CleanupStack::PushL(encSig);

	return encSig;
	}

// CPKCS10DSAKeyHelper /////////////////////////////////////////////////////////

CPKCS10DSAKeyHelper::CPKCS10DSAKeyHelper(MCTKeyStore& aKeyStore, const CCTKeyInfo& aKeyInfo) :
	CPKCS10KeyHelper(aKeyStore, aKeyInfo)
	{
	}

CPKCS10DSAKeyHelper::~CPKCS10DSAKeyHelper()
	{
	if (iDSASigner)
		iDSASigner->Release();
	delete iDSASignature;
	delete iPublicKey;
	}

void CPKCS10DSAKeyHelper::OpenSigner(TRequestStatus& aStatus)
	{
	iKeyStore.Open(iKeyInfo, iDSASigner, aStatus);
	}

void CPKCS10DSAKeyHelper::CancelOpenSigner()
	{
	iKeyStore.CancelOpen();
	}

void CPKCS10DSAKeyHelper::SignDigestL(const TDesC8& aDigest, TRequestStatus& aStatus)
	{
	iDSASigner->Sign(aDigest, iDSASignature, aStatus);
	}

void CPKCS10DSAKeyHelper::CancelSignDigest()
	{
	iDSASigner->CancelSign();
	}

void CPKCS10DSAKeyHelper::CreateKeyEncoderL(const TDesC8& aExportedKey, TAlgorithmId aDigestId)
	{
	CX509SubjectPublicKeyInfo* ki = CX509SubjectPublicKeyInfo::NewLC(aExportedKey);
	TX509KeyFactory factory; 
	iPublicKey = factory.DSAPublicKeyL(ki->EncodedParams(), ki->KeyData());
	CleanupStack::PopAndDestroy(ki);
	iKeyEncoder = new (ELeave) TX509DSAKeyEncoder(*iPublicKey, aDigestId);
	}

/**
 * Override default implementation - leave DSA parameters out of the
 * AlgorithmIdentifier when it appears outside of SubjectPublicKeyInfo.  
 */
CASN1EncSequence* CPKCS10DSAKeyHelper::EncodeSignatureAlgorithmLC()
	{
	CASN1EncSequence* seq = CASN1EncSequence::NewLC();
	// Assume only SHA1 with DSA
	CASN1EncObjectIdentifier* oid = CASN1EncObjectIdentifier::NewLC(KDSAWithSHA1);
	seq->AddAndPopChildL(oid);

	// Don't add parameters!

	return seq;	
	}

CASN1EncBitString* CPKCS10DSAKeyHelper::EncodeSignatureLC()
	{
	// Create sequence that will hold the two bit integers.
	CASN1EncSequence* sigSeq = CASN1EncSequence::NewLC();
	// Stuff two signature integers into the sequence.

	CASN1EncBigInt* r = CASN1EncBigInt::NewLC(iDSASignature->R());
	sigSeq->AddAndPopChildL(r);
	CASN1EncBigInt* s = CASN1EncBigInt::NewLC(iDSASignature->S());
	sigSeq->AddAndPopChildL(s);

	// Wrap the sequence into a bit string
	// Create ASN.1 encoding from the signature and return it.
	CASN1EncBitString* sigDer = CASN1EncBitString::NewL(*sigSeq);

	CleanupStack::PopAndDestroy(sigSeq);
	CleanupStack::PushL(sigDer);

	return sigDer;
	}
