diff -r 000000000000 -r 164170e6151a pkiutilities/ocsp/test/resign/resign.cpp --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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* ocspResponseSeq = seqDec.DecodeDERLC(aResponse, pos, 2, 2); + TPtrC8 responseBytes = ocspResponseSeq->At(1)->GetContentDER(); + CleanupStack::PopAndDestroy(ocspResponseSeq); + + pos = 0; + CArrayPtr* responseBytesSeq = seqDec.DecodeDERLC(responseBytes, pos, 2, 2); + TPtrC8 basicOCSPResponse = responseBytesSeq->At(1)->GetContentDER(); + CleanupStack::PopAndDestroy(responseBytesSeq); + + pos = 0; + CArrayPtr* 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* 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;iArg(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; + + }