pkiutilities/ocsp/test/engine.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 26 Jan 2010 15:20:08 +0200
changeset 0 164170e6151a
permissions -rw-r--r--
Revision: 201004

// 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:
//

#include "engine.h"
#include "transport.h"
#include "panic.h"
#include "logger.h"
#include "main.h"
#include "requestlogger.h"
#include "testfilterparameters.h"
#include <miscutil.h>

#include <ocsp.h>
#include <x509cert.h>

#include <ocsptransport.h>

#include "ocspsupporttransport.h"

// Log file created by the transport filter
_LIT(KFilterLogFileName, "\\tocsphttpfilter.log");

const TInt KTimeMilliToMicro = 1000;

CTOCSPEngine* CTOCSPEngine::NewL(CTOCSPLogger& aLog)
	{
	CTOCSPEngine* self = new (ELeave) CTOCSPEngine(aLog);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}


CTOCSPEngine::CTOCSPEngine(CTOCSPLogger& aLog) :
	CActive(EPriorityNormal),
	iLog(aLog)
	{
	CActiveScheduler::Add(this);
	}


void CTOCSPEngine::ConstructL()
	{
	// Open file server session
	User::LeaveIfError(iFs.Connect());
	iCertUtils = CCertUtils::NewL(iFs);

	// Create cancellation timer
	iTimer = CCallbackTimer::NewL(*this);
	}

CTOCSPEngine::~CTOCSPEngine()
	{
    Cancel(); // Calls Reset along the way
	Destroy();
	delete iTimer;
	delete iCertUtils;
	delete iUnifiedCertStore;
	iFs.Close();
	}

// Common code between destructor and ResetL()
void CTOCSPEngine::Destroy()
	{
	delete iParams;
	iParams = NULL;
	
	delete iClient;
	iClient = NULL;
	
	iSubjectCerts.ResetAndDestroy();
	iIssuerCerts.ResetAndDestroy();
	iSigningCerts.ResetAndDestroy();
	iTransportLog.Close();

	delete iRequestLog;
	iRequestLog = NULL;

	// Not owned
	iTransport = NULL;
	}

void CTOCSPEngine::Reset()
	{
	Destroy();

	// Delete and reset all the filter parameters
	DeleteFilterParameters();

	iUseDirectAuthorisation = EFalse;
	iUseCADelegateAuthorisation = EFalse;
	iUseCADirectAuthorisation = EFalse;
	iUseAllSchemes = EFalse;

	iCancelTime = 0;
	}


void CTOCSPEngine::StartL(TRequestStatus& aStatus)
	{	
	iParams = COCSPParameters::NewL();	
	InitDirectAuthL();

	// Delete the transport filter log file
	TInt err = iFs.Delete(KFilterLogFileName);
	if ((err != KErrNone) && (err != KErrNotFound))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Failed to delete transport filter log file ("), ETrue);
			iLog.LogL(KFilterLogFileName);
			iLog.LogL(_L("). Error: "), ETrue);
			iLog.LogL(err);
			}
		User::Leave(err);
		}

	iState = EInitCertStore;
	aStatus = KRequestPending;
	iOriginalRequestStatus = &aStatus;
	SetActive();
		
	// Initialise unified cert store here if it doesn't already exist
	if (!iUnifiedCertStore)
		{
		iUnifiedCertStore = CUnifiedCertStore::NewL(iFs, ETrue);
		iUnifiedCertStore->Initialize(iStatus);
		}
	else
		{
		TRequestStatus* status = &iStatus;
		User::RequestComplete(status, KErrNone);
		}
	}

void CTOCSPEngine::EndL(TRequestStatus& aStatus)
	{
	Reset();
	CleanUpDirectAuthL(aStatus);
	}


void CTOCSPEngine::SetURIL(const TDesC8& aURI, TBool aUseAIA)
	{
	iParams->SetURIL(aURI, aUseAIA);
	}


void CTOCSPEngine::SetDefaultTransportL()
	{
	iIap = 0;
	MOCSPTransport* trans = COCSPTransportDefault::NewL(iIap);
	CleanupStack::PushL(trans);
	SetTransportL(trans);
	CleanupStack::Pop(trans);
	}


void CTOCSPEngine::SetTestTransportL(const TDesC& aResponseFile, const TDesC* aRequestFile)
	{
	CTOCSPTransport* trans = CTOCSPTransport::NewL(aResponseFile, aRequestFile);
	CleanupStack::PushL(trans);
	SetTransportL(trans);
	CleanupStack::Pop(trans);
	}

void CTOCSPEngine::SetOcspSupportTransportL()
	{
	iIap = 0;
	Swi::COcspSupportTransport* trans = Swi::COcspSupportTransport::NewL(iIap);

	CleanupStack::PushL(trans);
	SetTransportL(trans);
	CleanupStack::Pop(trans);
	}

void CTOCSPEngine::SetTransportRetryCount(TUint aRetryCount)
	{
	__ASSERT_DEBUG(iTransport != NULL, Panic(KErrTOCSPScriptParameterError));
	iParams->SetRetryCount(aRetryCount);
	}

void CTOCSPEngine::SetTransportTimeout(TInt aTimeout)
	{
	__ASSERT_DEBUG(iTransport != NULL, Panic(KErrTOCSPScriptParameterError));
	iParams->SetTimeout(aTimeout);
	}

void CTOCSPEngine::SetTransportL(MOCSPTransport* aTransport)
	{
	// To log the request, we wrap the transport in our request logger transport
	if (iRequestLog)
		{
		aTransport = CTOCSPRequestLogger::NewL(*iRequestLog, aTransport);
		}
	iTransport = aTransport;
	iParams->SetTransport(aTransport);
	}

void CTOCSPEngine::SetFilterParameters(TInt aNumDelayResp, TInt aCountDropResp,
			TInt countCorruptHTTPDataHeader, TInt countCorruptHTTPDataBodySizeLarge, TInt countCorruptHTTPDataBodySizeSmall, 
			TInt aCountCorruptOCSPData, 
			TInt aCountInternalErrorResp, TInt aCountTryLaterResp,
			TInt aCountSigValidateFailure)
	{
	iNumDelayResp = aNumDelayResp;
	iCountDropResp = aCountDropResp;
	iCountCorruptHTTPDataHeader = countCorruptHTTPDataHeader;
	iCountCorruptHTTPDataBodySizeLarge = countCorruptHTTPDataBodySizeLarge;
	iCountCorruptHTTPDataBodySizeSmall = countCorruptHTTPDataBodySizeSmall;
	iCountCorruptOCSPData = aCountCorruptOCSPData;
	iCountInternalErrorResp = aCountInternalErrorResp;
	iCountTryLaterResp = aCountTryLaterResp;
	iCountSigValidateFailure = aCountSigValidateFailure;
	}

void CTOCSPEngine::AddCertL(const TDesC8& aSubject, const TDesC8& aIssuer)
	{
	// Create certificate objects and keep hold of them - these are added
	// to the client later

	CX509Certificate* subject = CX509Certificate::NewLC(aSubject);
	User::LeaveIfError(iSubjectCerts.Append(subject));
	CleanupStack::Pop(subject);  // Now owned through iCerts

	CX509Certificate* issuer = CX509Certificate::NewLC(aIssuer);
	User::LeaveIfError(iIssuerCerts.Append(issuer));
	CleanupStack::Pop(issuer);  // Now owned through iCerts
	
	// Add certificates to parameter
	iParams->AddCertificateL(*subject, *issuer);
	}

void CTOCSPEngine::ReadTransportLogL()
	{
	// Read and process the transport filter log (if it exists)
	RFile file;
	TInt size;
	if (file.Open(iFs, KFilterLogFileName, EFileShareAny | EFileRead) != KErrNone)
		{
		return;
		}

	CleanupClosePushL(file);
	file.Size(size);
	RFileReadStream fileStream(file);
	CleanupClosePushL(fileStream);
	RBuf8 logBuffer;
	logBuffer.CreateL(size);
	CleanupClosePushL(logBuffer);
	fileStream.ReadL(logBuffer, size);
	TInt readPos = 0;
	TPtrC8 currentLine;
	while (MiscUtil::ReadNonEmptyLineL(logBuffer, readPos, currentLine))
		{
		TLex8 lex(currentLine);
		TPtrC8 methodName = lex.NextToken();

		// Validate and store the entry
		TTransportLog logEntry;
		if (methodName.Length() <= 4)
			{
			logEntry.iHttpMethod.Copy(methodName);
			logEntry.iHttpMethod.UpperCase();
			}

		// Get the timestamps and calculate transaction duration
		TInt64 startTime = 0;
		TInt64 endTime = 0;
		lex.SkipSpaceAndMark(); User::LeaveIfError(lex.Val(startTime));
		lex.SkipSpaceAndMark(); User::LeaveIfError(lex.Val(endTime));
		logEntry.iTransDurationMs = static_cast<TInt64>((endTime - startTime) / KTimeMilliToMicro);

		iTransportLog.AppendL(logEntry);
		}
	CleanupStack::PopAndDestroy(3, &file); // fileStream, logBuffer
	}

TBool CTOCSPEngine::ReadLineL(const TDesC8& aBuffer, TInt& aPos, TPtrC8& aLine) const
	{
	TBool endOfBuffer = EFalse;	
	aLine.Set(NULL, 0);

	TInt bufferLength = aBuffer.Length();	
	__ASSERT_ALWAYS(aPos >=0 && aPos <= bufferLength, User::Leave(KErrArgument));

	// Skip blank lines
	while (aPos < bufferLength) 
		{
		TChar  c = aBuffer[aPos];
		if (c != '\r' && c != '\n')
			{
			break;
			}
		aPos++;
		}

	// Find the position of the next delimter		
	TInt endPos = aPos;	
	while (endPos < bufferLength)
		{
		TChar c = aBuffer[endPos];
		if (c == '\n' || c == '\r') 
			{
			break;
			}	
		++endPos;
		}

	if (endPos != aPos)	
		{
		TInt tokenLen = endPos - aPos;
		aLine.Set(&aBuffer[aPos], tokenLen);
		}
	else 
		{
		return ETrue; // End of buffer
		}			

	aPos = endPos;
	return endOfBuffer;
	}

void CTOCSPEngine::LogResponseDetailsL()
	{
	if (iVerbose)
		{
		_LIT(KDateFormat, "%F%H:%T %D/%M/%Y");
		TBuf<32> timeString;

		iLog.LogL(_L("Response details:\n"));

		TTime timeNow;
		timeNow.UniversalTime();
		timeNow.FormatL(timeString, KDateFormat);
		iLog.LogL(_L("  Response generation time == "));
		iLog.LogL(timeString);
		iLog.LogL(_L("\n"));

		TBuf<10> indexText;

		for (int i = 0 ; i < iClient->TransactionCount() ; ++i)
			{
			const COCSPResponse* response = iClient->Response(i);

			iLog.LogL(_L("  Response "));
			indexText.Zero();
			indexText.Num(i);
			iLog.LogL(indexText);
			iLog.LogL(_L(":\n"));

			if (response)
				{
				response->ProducedAt().FormatL(timeString, KDateFormat);
				iLog.LogL(_L("    producedAt == "));
				iLog.LogL(timeString);
				iLog.NewLineL();
	
				TInt count = response->CertCount();
				for (TInt index = 0; index < count; ++index)
					{
					const COCSPResponseCertInfo& certInfo = response->CertInfo(index);

					iLog.LogL(_L("    Cert "));
					indexText.Zero();
					indexText.Num(index);
					iLog.LogL(indexText);
					iLog.LogL(_L(" Results:"));
			
					iLog.LogL(_L("\n      status == "));
					iLog.LogL(TranslateResultL(certInfo.Status()));

					certInfo.ThisUpdate().FormatL(timeString, KDateFormat);
					iLog.LogL(_L("\n      thisUpdate == "));
					iLog.LogL(timeString);
					iLog.NewLineL();

					if (certInfo.NextUpdate())
						{
						timeString.Zero();
						certInfo.NextUpdate()->FormatL(timeString, KDateFormat);
						iLog.LogL(_L("      nextUpdate == "));
						iLog.LogL(timeString);
						iLog.NewLineL();
						}

					if (certInfo.RevocationTime())
						{
						timeString.Zero();
						certInfo.RevocationTime()->FormatL(timeString, KDateFormat);
						iLog.LogL(_L("      revocationTime == "));
						iLog.LogL(timeString);
						iLog.NewLineL();
						}
					}
				}
			else
				{
				iLog.LogL(_L("    missing"));			
				iLog.NewLineL();
				}

			const TOCSPOutcome& outcome = iClient->Outcome(i);
			iLog.LogL(_L("    Validation outcome:"));
			iLog.NewLineL();
			iLog.LogL(_L("      status == "));
			iLog.LogL(TranslateStatusL(outcome.iStatus));
			iLog.NewLineL();
			iLog.LogL(_L("      result == "));
			iLog.LogL(TranslateResultL(outcome.iResult));
			iLog.NewLineL();
			}

		iLog.LogL(_L("  OCSP Summary result == "));
		iLog.LogL(TranslateResultL(iClient->SummaryResult()));
		iLog.NewLineL();
		}
	}


void CTOCSPEngine::RunL()
	{
	TInt err = iStatus.Int();
	if( KErrNotFound != err && KErrNone != err )
		{
		iLog.LogL(_L("Client request completed with code:"));  
		iLog.LogL(err);
		iLog.NewLineL();
		User::LeaveIfError(err);
		}

	if( KErrNotFound == err )
		{
		iLog.LogL(_L("Item not found leave code"));
		iLog.NewLineL();
		// Handle error
		User::Leave(err);
		}

	switch (iState)
		{
		case EInitCertStore:
			// Remove all certificates so we always start from the same state 
			iCertUtils->RemoveCertsL(*iUnifiedCertStore, iStatus);
			iState = ERemovingCerts;
			SetActive();
			break;
			
		case EAddingCert:
		case ERemovingCerts:
			User::RequestComplete(iOriginalRequestStatus, KErrNone);
			break;

		case EChecking:
			// Cancel the timer
			iTimer->Cancel();
			ReadTransportLogL();
			LogResponseDetailsL();
			User::RequestComplete(iOriginalRequestStatus, KErrNone);
			break;

		default:
            User::Panic(_L("TOCSP"), 1);
			break;
		}
	}

TInt CTOCSPEngine::RunError(TInt aError)
    {
    User::RequestComplete(iOriginalRequestStatus, aError);
    return KErrNone;
    }

void CTOCSPEngine::DoCancel()
	{
    switch (iState)
        {
		case EInitCertStore:
			if (iUnifiedCertStore)
				{
				iUnifiedCertStore->CancelInitialize();
				}
			break;
			
		case EAddingCert:
		case ERemovingCerts:
            iCertUtils->Cancel();
            break;

		case EChecking:
            iClient->CancelCheck();
            break;

		default:
            User::Panic(_L("TOCSP"), 1);
			break;
        }

	Reset();
    User::RequestComplete(iOriginalRequestStatus, KErrCancel);
	}

// Implementation of MTimerRun
void CTOCSPEngine::TimerRun(TInt /*aError*/)
	{
	// Cancellation timer expired
	this->Cancel();
	}

void CTOCSPEngine::SetValidationTimeL(const TTime& aWhen)
	{
	iParams->SetValidationTimeL(aWhen);
	}


void CTOCSPEngine::SetNonce(const TBool aNonce)
	{
	iParams->SetUseNonce(aNonce);
	}


void CTOCSPEngine::SetMaxStatusAgeL(TUint aMaxAge)
	{
	iParams->SetMaxStatusAgeL(aMaxAge);
	}

void CTOCSPEngine::InitDirectAuthL()
	{
	// Add OCSP test harness to cert store client list
	TName name(_L("TOCSP"));
	iCertUtils->AddApplicationL(name, TUid::Uid(KTOCSP_UID));
	}

void CTOCSPEngine::CleanUpDirectAuthL(TRequestStatus& aStatus)
	{
	iOriginalRequestStatus = &aStatus;
	aStatus = KRequestPending;

	// Should always succeed, as called after InitDirectAuthL
	iCertUtils->RemoveApplicationL(TUid::Uid(KTOCSP_UID));

	//This should remove the X509Certs, which is the only certificate type used by the test.
	iCertUtils->RemoveCertsL(*iUnifiedCertStore, iStatus);
	iState = ERemovingCerts;
	SetActive();
	}

void CTOCSPEngine::AddDirectAuthorisationCert(const TDesC& aCert,
                                              const TDesC& aLabel,
                                              TRequestStatus& aStatus)
	{
    TRAPD(err, DoAddDirectAuthorisationCertL(aCert, aLabel, aStatus));
    if (err != KErrNone)
        {
        Cancel();
        TRequestStatus* status = &aStatus;
        User::RequestComplete(status, err);
        }
    }

void CTOCSPEngine::DoAddDirectAuthorisationCertL(const TDesC& aCert,
												 const TDesC& aLabel,
												 TRequestStatus& aStatus)
	{
	TPtrC cert = aCert;
	HBufC8* certData = ReadDataL(iFs, cert);
	CleanupStack::PushL(certData);

	// Make and store the certificate
	CX509Certificate* cert2 = CX509Certificate::NewLC(*certData);
	User::LeaveIfError(iSigningCerts.Append(cert2));
	CleanupStack::Pop(cert2);  // Now owned through iCerts
	CleanupStack::PopAndDestroy(certData);
	
	iUseDirectAuthorisation = ETrue;

	iCert = aCert;
	iLabel = aLabel;	

	iOriginalRequestStatus = &aStatus;
	aStatus = KRequestPending;
	iState = EAddingCert;

	iCertUtils->AddCert(iLabel, EX509Certificate, ECACertificate, KTOCSP_UID,
						KNullDesC, iCert, *iUnifiedCertStore, iStatus);
	SetActive();
	}


/**
	Called when "AUTHORISATIONCERT AUTHCERTNONE" is parsed.
	Sets a flag so an instance of COCSPDirectAuthorisationScheme
	is allocated in PrepareAuthorisationSchemeL().
	
	This function should be used to test direct authorisation
	without supplying a cert.  When a cert is supplied, use
	AddDirectAuthorisationCert().
	
	@see AddDirectAuthorisationCert
	@see UseCADelegateAuthorisation
 */
void CTOCSPEngine::UseDirectAuthorisation()
	{
	iUseDirectAuthorisation = ETrue;	
	}

/**
	Called when a "CADELEGATE" command is parsed.  It sets
	a flag so that an instance of COCSPDelegateAuthorisationScheme
	is allocated in PrepareAuthorisationSchemeL().

	@see AddDirectAuthorisationCert
	@see UseCADirectAuthorisation
 */
void CTOCSPEngine::UseCADelegateAuthorisation()
	{
	iUseCADelegateAuthorisation = ETrue;
	}

/**
	Called when "CADIRECT" command is parsed.  It sets
	a flag so that an instance of COCSPCaDirectAuthorisationScheme
	is allocated in PrepareAuthorisationSchemeL().

	@see AddDirectAuthorisationCert
	@see UseCADelegateAuthorisation
 	@see UseDirectAuthorisation
*/
void CTOCSPEngine::UseCADirectAuthorisation()
	{
	iUseCADirectAuthorisation = ETrue;
	}

/**
	Called when "ALLSCHEMES" command is parsed.  It sets
	a flag so that all schemes are allocated in 
	PrepareAuthorisationSchemeL().

	@see AddDirectAuthorisationCert
	@see UseCADelegateAuthorisation
	@see UseCADirectAuthorisation
*/
void CTOCSPEngine::UseAllAuthorisationSchemes()
	{
	iUseAllSchemes = ETrue;
	}

void CTOCSPEngine::PrepareAuthorisationL()
	{
	if (iUseAllSchemes)
		{
		// iUseDirectAuthorisation may also be set because
		// "AUTHORISATIONCERT" commands have been parsed.
		ASSERT(!(iUseCADelegateAuthorisation || iUseCADirectAuthorisation));

		// This assumes __SECURITY_PLATSEC_ARCH__ is defined.  This
		// is the case because AddAllAuthorisationSchemesL() is added
		// to 9.1 onwards.
		iParams->AddAllAuthorisationSchemesL(TUid::Uid(KTOCSP_UID), *iUnifiedCertStore);
		return;
		}

	if (iUseDirectAuthorisation)
		{
		// Register direct authorisation object with OCSP validator
		COCSPDirectAuthorisationScheme* scheme =  
			COCSPDirectAuthorisationScheme::NewLC(TUid::Uid(KTOCSP_UID), *iUnifiedCertStore);
		iParams->AddAuthorisationSchemeL(scheme);
		CleanupStack::Pop(); // scheme, now owned by client
		}
	
	if (iUseCADelegateAuthorisation)
		{
		COCSPDelegateAuthorisationScheme* schemeDel =
			COCSPDelegateAuthorisationScheme::NewLC(*iUnifiedCertStore);
		iParams->AddAuthorisationSchemeL(schemeDel);
		CleanupStack::Pop(schemeDel); // scheme, now owned by client		
		}
	
	if (iUseCADirectAuthorisation)
		{
		COCSPCaDirectAuthorisationScheme* schemeCad =
			COCSPCaDirectAuthorisationScheme::NewLC();
		iParams->AddAuthorisationSchemeL(schemeCad);
		CleanupStack::Pop(schemeCad); // scheme, now owned by client		
		}
	}

// Set filter parameters
void CTOCSPEngine::DefineAndSetFilterParametersL()
	{
	TUid categoryUid = TUid::Uid(KFilterParametersCategoryUID);

	// Define the parameters
	RProperty::Define(categoryUid, KFilterParameterNumDelayResp, RProperty::EInt);
	RProperty::Define(categoryUid, KFilterParameterCountDropResp, RProperty::EInt);
	RProperty::Define(categoryUid, KFilterParameterCountCorruptHTTPDataHeader, RProperty::EInt);
	RProperty::Define(categoryUid, KFilterParameterCountCorruptHTTPDataBodySizeLarge, RProperty::EInt);
	RProperty::Define(categoryUid, KFilterParameterCountCorruptHTTPDataBodySizeSmall, RProperty::EInt);
	RProperty::Define(categoryUid, KFilterParameterCountCorruptOCSPData, RProperty::EInt);
	RProperty::Define(categoryUid, KFilterParameterCountInternalErrorResp, RProperty::EInt);
	RProperty::Define(categoryUid, KFilterParameterCountTryLaterResp, RProperty::EInt);
	RProperty::Define(categoryUid, KFilterParameterCountSigValidateFailure, RProperty::EInt);

	// and Set them
	User::LeaveIfError(RProperty::Set(categoryUid, KFilterParameterNumDelayResp, iNumDelayResp));
	User::LeaveIfError(RProperty::Set(categoryUid, KFilterParameterCountDropResp, iCountDropResp));
	User::LeaveIfError(RProperty::Set(categoryUid, KFilterParameterCountCorruptHTTPDataHeader, iCountCorruptHTTPDataHeader));
	User::LeaveIfError(RProperty::Set(categoryUid, KFilterParameterCountCorruptHTTPDataBodySizeLarge, iCountCorruptHTTPDataBodySizeLarge));
	User::LeaveIfError(RProperty::Set(categoryUid, KFilterParameterCountCorruptHTTPDataBodySizeSmall, iCountCorruptHTTPDataBodySizeSmall));
	User::LeaveIfError(RProperty::Set(categoryUid, KFilterParameterCountCorruptOCSPData, iCountCorruptOCSPData));
	User::LeaveIfError(RProperty::Set(categoryUid, KFilterParameterCountInternalErrorResp, iCountInternalErrorResp));
	User::LeaveIfError(RProperty::Set(categoryUid, KFilterParameterCountTryLaterResp, iCountTryLaterResp));
	User::LeaveIfError(RProperty::Set(categoryUid, KFilterParameterCountSigValidateFailure, iCountSigValidateFailure));
	}

void CTOCSPEngine::DeleteFilterParameters()
	{
	TUid categoryUid = TUid::Uid(KFilterParametersCategoryUID);
	RProperty::Delete(categoryUid, KFilterParameterNumDelayResp);
	RProperty::Delete(categoryUid, KFilterParameterCountDropResp);
	RProperty::Delete(categoryUid, KFilterParameterCountCorruptHTTPDataHeader);
	RProperty::Delete(categoryUid, KFilterParameterCountCorruptHTTPDataBodySizeLarge);
	RProperty::Delete(categoryUid, KFilterParameterCountCorruptHTTPDataBodySizeSmall);
	RProperty::Delete(categoryUid, KFilterParameterCountCorruptOCSPData);
	RProperty::Delete(categoryUid, KFilterParameterCountInternalErrorResp);
	RProperty::Delete(categoryUid, KFilterParameterCountTryLaterResp);
	RProperty::Delete(categoryUid, KFilterParameterCountSigValidateFailure);
	// Reset the params
	iNumDelayResp = iCountDropResp = iCountCorruptHTTPDataHeader = iCountCorruptHTTPDataBodySizeLarge = 
		iCountCorruptHTTPDataBodySizeSmall = iCountCorruptOCSPData = iCountInternalErrorResp = 
		iCountTryLaterResp = iCountSigValidateFailure = 0;
	}

void CTOCSPEngine::SetCancelTime(TInt aTime)
	{
	iCancelTime = aTime;
	}

void CTOCSPEngine::Check(TRequestStatus& aStatus)
	{
    TRAPD(err, DoCheckL(aStatus));
    if (err != KErrNone)
        {
        Cancel();
        TRequestStatus* status = &aStatus;
        User::RequestComplete(status, err);
        }
    }

void CTOCSPEngine::DoCheckL(TRequestStatus& aStatus)
 	{
	iOriginalRequestStatus = &aStatus;
	aStatus = KRequestPending;
	iState = EChecking;

	PrepareAuthorisationL();

	// Set filter parameters
	DefineAndSetFilterParametersL();

	if (iVerbose)
		{
		iLog.LogL(_L("Checking...\n"), ETrue);
		}

	iClient = COCSPClient::NewL(iParams);
	iParams = NULL; // Client takes ownership

	// Setup cancellation timer
	if (iCancelTime)
		{
		iTimer->After(iCancelTime * KTimeMilliToMicro);
		}
	iClient->Check(iStatus);
	SetActive();
 	}

void CTOCSPEngine::LogValidationL(const TOCSPOutcome& aOutcome) const
	{
	if (iVerbose)
		{
		iLog.LogL(_L("Validation complete:\n  status == "));
		iLog.LogL(TranslateStatusL(aOutcome.iStatus));
	
		// Output summary result
		iLog.LogL(_L("\n  summary result == "));
		iLog.LogL(TranslateResultL(aOutcome.iResult));
		iLog.NewLineL();
		}
	}


TPtrC CTOCSPEngine::TranslateStatusL(OCSP::TStatus aStatus)
	{
	switch ((TInt) aStatus)
		{
		case OCSP::ETransportError:
			return _L("Transport error");
		case OCSP::ETimeOut:
			return _L("Request timedout");
		case OCSP::EClientInternalError:
			return _L("Client internal error");
		case OCSP::ENoServerSpecified:
			return _L("No server specified");
		case OCSP::EInvalidURI:
			return _L("Invalid URI");
		case OCSP::EMalformedResponse:
			return _L("Malformed response");
		case OCSP::EUnknownResponseType:
			return _L("Unknown response type");
		case OCSP::EUnknownCriticalExtension:
			return _L("Unknown critical extension");
		case OCSP::EMalformedRequest:
			return _L("Server: Malformed request");
		case OCSP::EServerInternalError:
			return _L("Server: Internal error");
		case OCSP::ETryLater:
			return _L("Server: Try later");
		case OCSP::ESignatureRequired:
			return _L("Server: Signature required");
		case OCSP::EClientUnauthorised:
			return _L("Server: Client unauthorised");
		case OCSP::EMissingCertificates:
			return _L("Missing certificates");
		case OCSP::EResponseSignatureValidationFailure:
			return _L("Response signature validation failure");
		case OCSP::EThisUpdateTooLate:
			return _L("Time error: This update too late");
		case OCSP::EThisUpdateTooEarly:
			return _L("Time error: This update too early");
		case OCSP::ENextUpdateTooEarly:
			return _L("Time error: Next update too early");
		case OCSP::ECertificateNotValidAtValidationTime:
			return _L("Time error: Not valid at validation time");
		case OCSP::ENonceMismatch:
			return _L("Nonce mismatch");			
		case OCSP::EMissingNonce:
			return _L("Missing nonce");
		case OCSP::EValid:
			return _L("Valid");
		case TOCSP::ETooManyTransactions:
			return _L("(test) Too many transactions");
		case TOCSP::EURIMismatch:
			return _L("(test) URI mismatch");
		case TOCSP::ERequestMismatch:
			return _L("(test) Request mismatch");
		default:
			return _L("Unknown");
		}
	}


TPtrC CTOCSPEngine::TranslateResultL(OCSP::TResult aResult)
	{
	switch (aResult)
		{
		case OCSP::EGood:
			return _L("Good");
		case OCSP::ERevoked:
			return _L("Revoked");
		case OCSP::EUnknown:
			return _L("Unknown");
		default:
			return _L("Unknown");
		}
	}


HBufC8* CTOCSPEngine::ReadDataL(RFs& session, const TDesC& aFileName) const
	{
	RFile file;
	User::LeaveIfError(file.Open(session, aFileName, EFileRead | EFileShareReadersOnly));
	CleanupClosePushL(file);

	TInt size = 0;
	User::LeaveIfError(file.Size(size));

	HBufC8* data = HBufC8::NewLC(size);
	TPtr8 dataPtr = data->Des();
	User::LeaveIfError(file.Read(dataPtr));

	CleanupStack::Pop(data);
	CleanupStack::PopAndDestroy(); // Close file;
	
	return data;
	}


void CTOCSPEngine::LogRequestL(const TDesC& aFilename)
    {
	delete iRequestLog;
	iRequestLog = NULL;

	iRequestLog = aFilename.AllocL();
	}


void CTOCSPEngine::LogResponseL(const TDesC& aFilename)
    {
	RFs fs;
	User::LeaveIfError(fs.Connect());
	CleanupClosePushL(fs);

	TInt err = fs.MkDirAll(aFilename);
	if (err != KErrAlreadyExists)
		{
		User::LeaveIfError(err);
		}

	RFile file;
	User::LeaveIfError(file.Replace(fs, aFilename, EFileWrite));
	CleanupClosePushL(file);

	RFileWriteStream writeStream(file);
	CleanupClosePushL(writeStream);

	writeStream.WriteUint32L(iClient->TransactionCount());

	for (int i = 0 ; i < iClient->TransactionCount() ; ++i)
		{
		const COCSPResponse* response = iClient->Response(i);
		if (response)
			{
			const TPtrC8 data = response->Encoding();
			writeStream.WriteUint32L(data.Length());
			writeStream.WriteL(data);
			}
		else
			{
			writeStream.WriteUint32L(0);
			}
		}

	CleanupStack::PopAndDestroy(3); // writeStream, file, fs
    }


void CTOCSPEngine::SetVerbose(TBool aVerbose)
	{
	iVerbose = aVerbose;
	}

TBool CTOCSPEngine::TestSummaryL(OCSP::TResult aExpected)
	{
	TBool result = iClient->SummaryResult() == aExpected;

	if (iVerbose && !result)
		{
		iLog.LogL(_L("Summary result fail: expected "));
		iLog.LogL(aExpected);
		iLog.NewLineL();
		}

	return result;
	}

TBool CTOCSPEngine::TestOutcomeL(TInt aIndex, const TOCSPOutcome& aExpected)
	{
	TBool result = EFalse;
	// This assumes one-transaction-per-certificate behaviour
	if(iClient)
		{
		result = iClient->Outcome(aIndex) == aExpected;
		}

	if (iVerbose && !result)
		{
		iLog.LogL(_L("Outcome result fail for cert "));
		iLog.LogL(aIndex);
		iLog.LogL(_L(":\n"));
		//iLog.LogL(_L("Expected Result:\n"));
		iLog.LogL(_L("Expected Status == "));
		iLog.LogL(TranslateStatusL(aExpected.iStatus));
		iLog.NewLineL();
		iLog.LogL(_L("Expected Result == "));
		iLog.LogL(TranslateResultL(aExpected.iResult));
		iLog.NewLineL();
		}

	return result;
	}

void CTOCSPEngine::SetReponderCertCheck()
	{
	iParams->SetOCSPCheckForResponderCert(ETrue);
	}

void CTOCSPEngine::AddCertToStore(const TDesC& aCertFileName, const TDesC& aLabel, TCertificateOwnerType aCertType, TRequestStatus& aStatus)
	{
	iOriginalRequestStatus = &aStatus;
	aStatus = KRequestPending;
	iState = EAddingCert;
	
	iCert = aCertFileName;
	iLabel = aLabel;	
	
	iCertUtils->AddCert(iLabel, EX509Certificate, aCertType, KTOCSP_UID,
						KNullDesC, iCert, *iUnifiedCertStore, iStatus);		
	
	SetActive();
	}

TBool CTOCSPEngine::TestTransportL(TInt aRetryCountNum, const TDesC& aExpectedHttpMethod, 
		TInt aExpectedRespTimeMin, TInt aExpectedRespTimeMax)
	{
	// This assumes one-tranaction-per-certificate behaviour
	// This also assumes test case includes only certificate revocation check request (which 
	// means CHECKRESPONDERCERT command cannot be used with this)
	// Ensure we have read the entry from the transport log
	TBool result = ETrue;
	if (iTransportLog.Count() < (aRetryCountNum + 1))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Transport filter log contains insufficient entries: "));
			iLog.LogL(_L("\n  Expected number of entries: "));
			iLog.LogL(aRetryCountNum + 1);
			iLog.LogL(_L("\n  Actual entries: "));
			iLog.LogL(iTransportLog.Count());
			iLog.NewLineL();
			}
		result = EFalse;
		}

	TTransportLog& logEntry = iTransportLog[aRetryCountNum];
	// Convert to 8-bit
	RBuf8 expectedMethod;
	expectedMethod.CreateL(aExpectedHttpMethod.Length());
	CleanupClosePushL(expectedMethod);
	expectedMethod.Copy(aExpectedHttpMethod);
	expectedMethod.UpperCase();
	if (expectedMethod != logEntry.iHttpMethod)
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Transport outcome result failed for send number: "));
			iLog.LogL(aRetryCountNum);
			iLog.LogL(_L("\n  Expected method: "));
			iLog.LogL(expectedMethod);
			iLog.LogL(_L("\n  Got method: "));
			iLog.LogL(logEntry.iHttpMethod);
			iLog.NewLineL();
			}
		result = EFalse;
		}
	CleanupStack::PopAndDestroy(&expectedMethod);

	// Test the range of response time
	if (aExpectedRespTimeMin > logEntry.iTransDurationMs || aExpectedRespTimeMax < logEntry.iTransDurationMs)
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Transport outcome result failed for send number: "));
			iLog.LogL(aRetryCountNum);
			iLog.LogL(_L("\n  Expected response time range (ms): "));
			iLog.LogL(aExpectedRespTimeMin);
			iLog.LogL(_L(" to "));
			iLog.LogL(aExpectedRespTimeMax);
			iLog.LogL(_L("\n  Actual response time (ms): "));
			iLog.LogL(logEntry.iTransDurationMs);
			iLog.NewLineL();
			}
		result = EFalse;
		}
	else if (iVerbose)
		{
		iLog.LogL(_L("Send number: "));
		iLog.LogL(aRetryCountNum);
		iLog.LogL(_L(" Response duration(ms): "));
		iLog.LogL(logEntry.iTransDurationMs);
		iLog.NewLineL();
		}

	return result;
	}

TBool CTOCSPEngine::TestTransportRetryL(TInt aRetryCount)
	{
	// This assumes one-tranaction-per-certificate behaviour
	// This also assumes test case includes only certificate revocation check request (which means 
	// CHECKRESPONDERCERT command cannot be used with this)
	// Check the number of retries
	TBool result = ETrue;
	if (iTransportLog.Count() != aRetryCount)
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Transport retry outcome result failed:"));
			iLog.LogL(_L("\n  Expected number of retries: "));
			iLog.LogL(aRetryCount);
			iLog.LogL(_L("\n  Actual retries: "));
			iLog.LogL(iTransportLog.Count());
			iLog.NewLineL();
			}
		result = EFalse;
		}

	return result;
	}

void CTOCSPEngine::SetCheckCertsWithAiaOnly(TBool aCheckCertsWithAiaOnly)
	{
	iParams->SetCheckCertsWithAiaOnly(aCheckCertsWithAiaOnly);
	}

void CTOCSPEngine::SetUseAIA(TBool aUseAIA)
	{
	iParams->SetUseAIA(aUseAIA);
	}