--- /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;
+
+ }