pkiutilities/ocsp/test/resign/resign.cpp
changeset 0 164170e6151a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkiutilities/ocsp/test/resign/resign.cpp	Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,364 @@
+// Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "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:
+// App for resigning OCSP responses.
+// 
+//
+
+#include <e32cons.h>
+#include <f32file.h>
+#include <asn1dec.h>
+#include <asn1enc.h>
+#include <x509cert.h>
+#include <signed.h>
+#include <bigint.h>
+#include <asymmetric.h>
+#include <hash.h>
+#include <bacline.h>
+
+#include "resign.h"
+
+// CertTool command line parameters
+_LIT(KResign, "-resign");
+_LIT(KResignShort, "-r");
+
+_LIT(KCreate, "-create");
+_LIT(KCreateShort, "-c");
+
+_LIT(KExtractResponse, "-e");
+_LIT(KExtractResponseShort, "-extract");
+
+CResign* CResign::NewLC()
+	{
+	CResign* resign = new(ELeave) CResign();
+	CleanupStack::PushL(resign);
+	resign->ConstructL();
+	return resign;
+	}
+	
+CResign* CResign::NewL()
+	{
+	CResign* resign = CResign::NewLC();
+	CleanupStack::Pop(resign);
+	return resign;
+	}
+		
+CResign::CResign()
+	{}
+	
+void CResign::ConstructL()
+	{
+	User::LeaveIfError(iFs.Connect());
+	}
+
+CResign::~CResign()
+	{
+	delete iArguments;
+	iFs.Close();
+	}
+
+void CResign::ResignL(const TPtrC8& aSignedData,
+			 TPtr8& aSignature,
+			 RInteger& aModulus,
+			 const RInteger& /*aPublicExponent*/,
+			 RInteger& aPrivateExponent)
+	{
+	__UHEAP_MARK;
+	// Build message digest
+	CSHA1* hash = CSHA1::NewL();
+	CleanupStack::PushL(hash);
+	TPtrC8 digest = hash->Final(aSignedData);
+
+	// Build ASN1 encoding of digestAlgId and digest..
+	CASN1EncSequence* encAll = CASN1EncSequence::NewLC();
+
+	// Build AlgID encoder (for SHA1)
+	CASN1EncSequence* encAlgId = CASN1EncSequence::NewLC();
+
+	CASN1EncObjectIdentifier* encObjId = CASN1EncObjectIdentifier::NewLC(KSHA1);
+	encAlgId->AddChildL(encObjId);
+	CleanupStack::Pop(); // encObjId, now owned by endAlgId
+
+	CASN1EncNull* encNull = CASN1EncNull::NewLC();
+	encAlgId->AddChildL(encNull);
+	CleanupStack::Pop(); // encNull, now owned by endAlgId
+
+	encAll->AddChildL(encAlgId);
+	CleanupStack::Pop(); // endAlgId, now owned by encAll
+
+	CASN1EncOctetString* encDigest = CASN1EncOctetString::NewLC(digest);
+	encAll->AddChildL(encDigest);
+	CleanupStack::Pop(); // encDigest, now owned by encAll
+
+	HBufC8* digestInfo = HBufC8::NewMaxLC(encAll->LengthDER());
+	TUint pos = 0;
+	TPtr8 digestInfoPtr = digestInfo->Des();
+	encAll->WriteDERL(digestInfoPtr, pos);
+
+	__UHEAP_MARK;
+
+	CRSAPrivateKeyStandard* rsaPriv = CRSAPrivateKeyStandard::NewLC(aModulus, aPrivateExponent);
+
+	CRSAPKCS1v15Signer* signer = CRSAPKCS1v15Signer::NewLC(*rsaPriv);
+	
+	const CRSASignature* signature = signer->SignL(digestInfoPtr);
+	
+	HBufC8* theSignature = signature->S().BufferLC();
+	aSignature.Copy(*theSignature);
+	
+	CleanupStack::PopAndDestroy(4, rsaPriv);
+
+	__UHEAP_MARKEND;
+
+	CleanupStack::PopAndDestroy(3, hash);
+	
+	__UHEAP_MARKEND;
+	}
+
+void CResign::DecodeDataL(TDes8& aResponse, const TDesC8& aKey)
+	{
+	__UHEAP_MARK;
+	TASN1DecSequence seqDec;
+	TInt pos = 0;
+
+	// Get the signed data and signature portions of the response
+	CArrayPtr<TASN1DecGeneric>* ocspResponseSeq = seqDec.DecodeDERLC(aResponse, pos, 2, 2);
+	TPtrC8 responseBytes = ocspResponseSeq->At(1)->GetContentDER();
+	CleanupStack::PopAndDestroy(ocspResponseSeq);
+
+	pos = 0;
+	CArrayPtr<TASN1DecGeneric>* responseBytesSeq = seqDec.DecodeDERLC(responseBytes, pos, 2, 2);
+	TPtrC8 basicOCSPResponse = responseBytesSeq->At(1)->GetContentDER();
+	CleanupStack::PopAndDestroy(responseBytesSeq);
+
+	pos = 0;
+	CArrayPtr<TASN1DecGeneric>* basicOCSPResponseSeq = seqDec.DecodeDERLC(basicOCSPResponse, pos, 3, 4);
+	TPtrC8 responseData = basicOCSPResponseSeq->At(0)->Encoding();
+	TPtrC8 signatureAlgorithm = basicOCSPResponseSeq->At(1)->Encoding();
+	TPtrC8 signature = basicOCSPResponseSeq->At(2)->GetContentDER();
+	CleanupStack::PopAndDestroy(basicOCSPResponseSeq);
+
+	// Check that it's RSA with SHA1
+	CX509SigningAlgorithmIdentifier* algId = CX509SigningAlgorithmIdentifier::NewLC(signatureAlgorithm);
+	if (algId->DigestAlgorithm().Algorithm() != ESHA1
+		|| algId->AsymmetricAlgorithm().Algorithm() != ERSA)
+		{
+		User::Leave(KErrNotSupported);
+		}
+	CleanupStack::PopAndDestroy(algId);
+
+	// Get the modulus and private key portions of the key - only RSA supported
+
+	// ASN1 .key files have 9 parts: version, modulus, public exponent, private exponent,
+	// prime 1, prime2, exponent 1, exponent 2, coefficient
+	// This is defined in PKCS1 (RFC 2313), the RSAPrivateKey ASN1 data structure
+	pos = 0;
+	CArrayPtr<TASN1DecGeneric>* keySeq = seqDec.DecodeDERLC(aKey, pos, 9, 9);
+	TASN1DecInteger decInt;
+
+	RInteger modulus = decInt.DecodeDERLongL(*keySeq->At(1));
+	CleanupStack::PushL(modulus);
+
+	RInteger publicExponent = decInt.DecodeDERLongL(*keySeq->At(2));
+	CleanupStack::PushL(publicExponent);
+
+	RInteger privateExponent = decInt.DecodeDERLongL(*keySeq->At(3));
+	CleanupStack::PushL(privateExponent);
+
+	// Cast constness off the signature - and skip the 'number of unused bits' octet
+	TPtr8 sigEdit(CONST_CAST(TUint8*, signature.Ptr() + 1), signature.Length() - 1, signature.Length() - 1);
+
+	// Pass data on for re-signing
+	ResignL(responseData, sigEdit, modulus, publicExponent, privateExponent);
+
+	CleanupStack::PopAndDestroy(3, &modulus); // The RIntegers
+	CleanupStack::PopAndDestroy(keySeq);
+	__UHEAP_MARKEND;
+	}
+
+void CResign::ProcessCommandLineL()
+    {
+	iArguments = CCommandLineArguments::NewL();
+	
+	if(iArguments->Count() > 1)
+		{	
+		TCommand command = ENone; 
+		
+		TPtrC args = iArguments->Arg(1);
+		if ((args.Compare(KResign)==0) || (args.Compare(KResignShort)==0))
+			{
+			command = EResign;
+			}	
+		if ((args.Compare(KCreate)==0) || (args.Compare(KCreateShort)==0))
+			{
+			command = ECreate;
+			}
+		if ((args.Compare(KExtractResponse)==0) || (args.Compare(KExtractResponseShort)==0))
+			{
+			command = EExtract;
+			}
+		
+		if(command != ENone)
+			{
+			HandleCommandL(command);
+			}
+		}
+    }
+
+void CResign::HandleCommandL(TCommand aCommand)
+	{
+	switch(aCommand)
+		{
+		case EResign:
+			ResignFilesL();
+			break;
+			
+		case ECreate:
+			CreateDatFileL();
+			break;
+		
+		case EExtract:
+			ExtractResponseL();
+			break;
+		}
+	}
+
+void CResign::ResignFilesL()
+	{
+	__UHEAP_MARK;
+	
+	TPtrC responseFile(iArguments->Arg(2));
+	TPtrC keyFile(iArguments->Arg(3));
+	
+	// Load the key
+	RFile file;
+	User::LeaveIfError(file.Open(iFs, keyFile, EFileRead | EFileShareAny));
+	CleanupClosePushL(file);
+	
+	TInt keySize;
+	User::LeaveIfError(file.Size(keySize));
+	HBufC8* keyBuf = HBufC8::NewLC(keySize);
+	TPtr8 key = keyBuf->Des();
+
+	User::LeaveIfError(file.Read(key));
+	
+	// Open the logged response file
+
+	RFileReadStream readStream;
+	User::LeaveIfError(readStream.Open(iFs, responseFile, EFileRead | EFileShareAny));
+	CleanupClosePushL(readStream);
+	MStreamBuf* readBuf = readStream.Source();
+
+	RFileWriteStream writeStream;
+	User::LeaveIfError(writeStream.Open(iFs, responseFile, EFileWrite | EFileShareAny));
+	CleanupClosePushL(writeStream);
+	MStreamBuf* writeBuf = writeStream.Sink();
+
+	TInt totalResponses = readStream.ReadUint32L();
+
+	for (TInt i = 0 ; i < totalResponses ; ++i)
+		{
+		TInt responseSize = readStream.ReadUint32L();
+		TStreamPos pos = readBuf->TellL(MStreamBuf::ERead);
+
+		HBufC8* responseBuf = HBufC8::NewLC(responseSize);
+
+		TPtr8 response = responseBuf->Des();
+		readStream.ReadL(response);
+
+		// resigning response
+		DecodeDataL(response, key);
+
+		writeBuf->SeekL(MStreamBuf::EWrite, pos);
+		writeStream.WriteL(response);
+
+		CleanupStack::PopAndDestroy(responseBuf);
+		}
+	
+	CleanupStack::PopAndDestroy(4,&file); // close writeStream, readStream, keyBuf and file
+	
+	__UHEAP_MARKEND;
+	}
+
+void CResign::CreateDatFileL()
+	{
+	__UHEAP_MARK;
+	
+	
+	// this path will fail if the directories are not already present.
+	_LIT(KDatFile,"c:\\system\\tocsp\\responses\\response.dat");
+	RFileWriteStream writeStream;
+	User::LeaveIfError(writeStream.Replace(iFs, KDatFile, EFileWrite | EFileShareAny));
+	CleanupClosePushL(writeStream);
+	
+	TInt fileCount = iArguments->Count(); 
+	
+	// total no of responses in this dat file
+	writeStream.WriteInt32L(fileCount-2);
+	RFile file;
+	for(TInt i=2;i<fileCount;i++)
+		{
+		TPtrC responseFile(iArguments->Arg(i));
+		// Load the response file
+		User::LeaveIfError(file.Open(iFs, responseFile, EFileRead | EFileShareAny));
+		CleanupClosePushL(file);
+		
+		TInt respSize = 0;
+		User::LeaveIfError(file.Size(respSize));
+		HBufC8* respBuf = HBufC8::NewLC(respSize);
+		TPtr8 resp = respBuf->Des();
+		User::LeaveIfError(file.Read(resp));
+		
+		writeStream.WriteInt32L(respSize);
+		writeStream.WriteL(resp);
+		
+		CleanupStack::PopAndDestroy(2,&file); // respBuf and file
+		}
+	
+	CleanupStack::PopAndDestroy(&writeStream);
+	
+	__UHEAP_MARKEND;
+	}
+
+void CResign::ExtractResponseL()
+	{
+	__UHEAP_MARK;
+	
+	TPtrC responseFile(iArguments->Arg(2));
+	
+	// Load the response file
+	RFileReadStream respFile;
+	User::LeaveIfError(respFile.Open(iFs, responseFile, EFileRead | EFileShareAny));
+	CleanupClosePushL(respFile);
+	
+	// reading the transaction value.
+	respFile.ReadInt32L();
+	TInt respSize = respFile.ReadInt32L();
+	
+	HBufC8* respBuf = HBufC8::NewLC(respSize);
+	TPtr8 resp = respBuf->Des();
+
+	respFile.ReadL(resp, respSize);
+	
+	// this path will fail if the directories are not already present.
+	_LIT(KDerFile,"c:\\system\\tocsp\\responses\\response.der");
+	RFileWriteStream writeStream;
+	User::LeaveIfError(writeStream.Replace(iFs, KDerFile, EFileWrite | EFileShareAny));
+	CleanupClosePushL(writeStream);
+	writeStream.WriteL(resp);
+	
+	CleanupStack::PopAndDestroy(3,&respFile); // writeStream, respBuf and respFile
+	
+	__UHEAP_MARKEND;
+
+	}