pkiutilities/ocsp/test/command.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) 2005-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 "command.h"
#include "engine.h"
#include "panic.h"
#include "logger.h"
#include "result.h"

#include "TEFparser.h"
#include <f32file.h>
#include <utf.h>

// Define the commands the user can use in the input script

// *****************  General  ************************

// Comment prefix for input file
_LIT(KTOCSPCommandComment,		"REM");

// Print remaining text to console
_LIT(KTOCSPCommandPrint,		"PRINT");

// Bail out at this point
_LIT(KTOCSPCommandAbort,		"ABORT");

// NOTE: Skips CAN be nested
// Skip everything unil KTOCSPCommandEndSkip
_LIT(KTOCSPCommandSkip,			"SKIP");

// Stop skipping - does nothing if not skipping
_LIT(KTOCSPCommandEndSkip,		"ENDSKIP");

// ************ Configuring the request ***************

// Start a new OCSP request/response transaction
// Has exactly one parameter - the name of the test (which must not include spaces)
_LIT(KTOCSPCommandStart,		"START");

// Set the URI of the server
_LIT(KTOCSPCommandSetURI,		"SETURI");


// Parameter is a file from which to read a cert
_LIT(KTOCSPCommandCert,			"REQUESTCERT");

// Parameter is ON or OFF
_LIT(KTOCSPCommandNonce,        "NONCE");

// ************ Handling the communication *************

// Set transport scheme for communication
// Parameter DEFAULT means let the OCSP module deal with the transport
// Parameter TEST means use the test harness server
_LIT(KTOCSPCommandSetTransport,	"TRANSPORT");

// ******* Configuring + performing the validation ********

// Set transport retry count
// Takes one parameter, the retry count (1 means no retry)
// NOTE: This command must appear after the TRANSPORT command
_LIT(KTOCSPCommandSetTransportRetry, "TRANSPORTRETRY");

// Set transport timeout
// Takes one parameter, the timeout value in milliseconds
// NOTE: This command must appear after the TRANSPORT command
_LIT(KTOCSPCommandSetTransportTimeout, "TRANSPORTTIMEOUT");

// Set validation date, parameters are YYYY MM DD HH MM - optional
_LIT(KTOCSPCommandValidationDate, "VALIDATIONDATE");

// Parameter is a file containing a cert to be set as valid for authorisation of
// the response.  Can call more than once.
_LIT(KTOCSPCommandDirectAuthorisation, "AUTHORISATIONCERT");

// No parameters - tells test client to use ca delegate authorisation.
// (See RFC2560 S2.2, S4.2.2.2)
_LIT(KTOCSPCommandCADelegateAuthorisation, "CADELEGATE");

// No parameters - tells test client to use direct signing by ca.
// see (RFC 2560 S2.2)
_LIT(KTOCSPCommandCADirectAuthorisation, "CADIRECT");

// No parameters - tells test client to use all schemes
// see (RFC 2560 S2.2)
_LIT(KTOCSPCommandAllAuthorisationSchemes, "ALLSCHEMES");

// Set the maximum allowable age of the status returned.  Parameter is in
// seconds, or "OFF" to disable checking.
_LIT(KTOCSPCommandSetMaxStatusAge, "SETMAXSTATUSAGE");

// Set http filter parameters
// The parameters to FILTERPARAMS command are:
// numDelayResp countDropResp countCorruptHTTPDataHeader countCorruptHTTPDataBodySizeLarge countCorruptHTTPDataBodySizeSmall countCorruptOCSPData countInternalErrorResp countTryLaterResp
// where:
// 		numDelayResp - Delays response by specified number of milliseconds
//		countDropResp - Drops specified number of responses
//		countCorruptHTTPDataHeader - Corrupts specified number of responses (content-type in header is corrupted)
//		countCorruptHTTPDataBodySizeLarge - Corrupts specified number of responses (body is of larger size than expected)
//		countCorruptHTTPDataBodySizeSmall - Corrupts specified number of responses (body is of smaller size than expected)
//		countCorruptOCSPData - Corrupts specified number of responses (OCSPResponse data is corrupted)
//		countInternalErrorResp - Returns an "internalError" response for specified number of requests
//		countTryLaterResp - Returns a "tryLater" response for specified number of requests
//		countSigValidateFailure - Causes a signature validation failure by corrupting the Responder ID
// NOTE: This command must appear after the TRANSPORT command
_LIT(KTOCSPCommandSetFilterParams, "FILTERPARAMS");


// Cancel the OCSP check after its issued
// The parameter is the time in milliseconds to wait before issuing the cancel
// Note that this command must appear before the CHECK command
_LIT(KTOCSPCommandCancel, "CANCEL");

// Run the OCSP check
_LIT(KTOCSPCommandCheck, "CHECK");

// Tests that the revocation check was cancelled
_LIT(KTOCSPCommandTestCancel, "TESTCANCEL");

// Tests that the summary result is as expected.  Takes one parameter, the
// expected result.
_LIT(KTOCSPCommandTestSummary, "TESTSUMMARY");

// Tests that the outcome for a certificate is as expected.  Takes three
// paramters, the certificate index, the expected status and the expected result
_LIT(KTOCSPCommandTestOutcome, "TESTOUTCOME");

// Tests that the outcome for the tranport is as expected. Takes four
// paramters, the retry count number (0 means first attempt), the expected HTTP method, 
// and the range of time in milliseconds (min max) within which each request should complete
// NOTE: The usage of this command assumes only one certificate is being
// checked for revocation per test case! (also means CHECKRESPONDERCERT command cannot be used with this)
_LIT(KTOCSPCommandTestTransport, "TESTTRANSPORT");

// Tests that the outcome for the retry attempts is as expected. 
// Takes one paramter, the retry count (1 means single attempt ie. no retry)
// NOTE: The usage of this command assumes only one certificate is being
// checked for revocation per test case! (also means CHECKRESPONDERCERT command cannot be used with this)
_LIT(KTOCSPCommandTestTransportRetry, "TESTTRANSPORTRETRY");

// Log the reponses to a file.  The filename is the only parameter.
// This command must be placed after the CHECK command
_LIT(KTOCSPCommandLogResponse, "LOGRESPONSE");

// Log the requests to a file.  The filename is the only parameter.
// This command must be placed before the TRANSPORT command
_LIT(KTOCSPCommandLogRequest, "LOGREQUEST");

// End a test
_LIT(KTOCSPCommandEnd, "END");

// parameter for setting whether the ocsp status check 
// for responder certificate should be done or not.
_LIT(KTOCSPCheckResponderCert, "CHECKRESPONDERCERT");

_LIT(KTOCSPAddCertToStore, "ADDCERTTOSTORE");

_LIT(KTOCSPUseAIA, "USEAIA");

_LIT(KTOCSPCheckCertsWithAiaOnly, "CHECKCERTSWITHAIAONLY");

_LIT(KTOCSPExpectedError, "EXPECTEDERROR");

// ************* Parameter definitions *****************

// Default transport (currently only HTTP)
_LIT(KTOCSPDefaultTransport,		"DEFAULT");

_LIT(KTOCSPTestTransport,			"TEST");

_LIT(KTOCSPOcspSupportTransport,	"OCSPSUPPORT");

// Generic parameter for toggle of settings.
_LIT(KTOCSPOn,  "ON");
_LIT(KTOCSPOff, "OFF");

_LIT(KTOCSPEnable,  "ENABLE");
_LIT(KTOCSPDisable, "DISABLE");
_LIT(KTOCSPEnableDisable,"ENABLE|DISABLE");


CTOCSPCommand* CTOCSPCommand::NewL(CTOCSPLogger& aLog,
								   CTOCSPResult& aResult,	
								   TInt aTransaction)
	{
	CTOCSPCommand* self = new (ELeave) CTOCSPCommand(aLog, aResult, aTransaction);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

 
CTOCSPCommand::CTOCSPCommand(CTOCSPLogger& aLog,
							 CTOCSPResult& aResult,
							 TInt aTransaction) :
	CActive(EPriorityNormal),
	iResult(aResult),
	iLog(aLog),
	iTestToProcess(aTransaction)
	{
	CActiveScheduler::Add(this);
	}


void CTOCSPCommand::ConstructL()
	{
	iEngine = CTOCSPEngine::NewL(iLog);
	}


CTOCSPCommand::~CTOCSPCommand()
	{
    Cancel();
	delete iEngine;
	iTokens.Close();
	}


void CTOCSPCommand::ResetL()
    {
	FinishedTestL();
    iTestIndex = 0;
    iTestToProcess = 0;
    }


TInt CTOCSPCommand::CurrentTransaction() const
    {
    return iTestIndex;
    }


TBool CTOCSPCommand::ProcessCommand(const TDesC& aLine, TRequestStatus& aStatus)
	{
	iOriginalRequestStatus = &aStatus;

    TBool result = ETrue;
    TRAPD(err, result = DoProcessCommandL(aLine));
    if (err != KErrNone)
        {
        Cancel();
        User::RequestComplete(iOriginalRequestStatus, err);
        }

    return result;
    }


TBool CTOCSPCommand::DoProcessCommandL(const TDesC& aLine)
	{
	*iOriginalRequestStatus = KRequestPending;

	if (!iVerbose)
		{
		iLog.LogL(_L("."), ETrue);
		}

	TLex lex(aLine);

    // Empty line
    if (lex.Eos())
        {
        User::RequestComplete(iOriginalRequestStatus, KErrNone);
        return ETrue;
        }

    TPtrC command = lex.NextToken();

    // Handle skipping commands
	if (command == KTOCSPCommandSkip)
		{
		++iSkipping;
		}
	else if (command == KTOCSPCommandEndSkip)
		{
        --iSkipping;
		if (iSkipping < 0)
			{
            User::RequestComplete(iOriginalRequestStatus, KErrCorrupt);
			return ETrue;
			}
		}

	LogCommandL(aLine);

	if (iSkipping)
		{
		User::RequestComplete(iOriginalRequestStatus, KErrNone);
        return ETrue;
		}

	if (command == KTOCSPCommandSkip || command == KTOCSPCommandEndSkip)
		{
		User::RequestComplete(iOriginalRequestStatus, KErrNone);
        return ETrue;
		}

	if (command == KTOCSPCommandStart)
		{
		++iTestIndex;
		}

    // Don't process any tests except the ones we're interested in
    if (iTestToProcess != 0 && iTestToProcess != iTestIndex)
        {   
		User::RequestComplete(iOriginalRequestStatus, KErrNone);
        return ETrue;
        }

	// Handle comment and print commands
	if (command == KTOCSPCommandComment)
		{
		// Remark - nothing to do except move on to next line
		User::RequestComplete(iOriginalRequestStatus, KErrNone);
        return ETrue;
		}
	else if (command == KTOCSPCommandPrint)
		{
		lex.SkipSpace();
		PrintCommandL(lex.Remainder());
        return ETrue;
		}

    // Now split the rest of the command into tokens
	iTokens.Reset();
	while (!lex.Eos())
		{
		User::LeaveIfError(iTokens.Append(lex.NextToken()));
		}
    
    // Check commands that don't have to occur in tests
	if (command == KTOCSPCommandAbort)
		{
		User::RequestComplete(iOriginalRequestStatus, KErrNone);
		return EFalse;
		}
	else if (command == KTOCSPCommandStart)
        {
		StartCommandL();
		}
	else if (command == KTOCSPCommandEnd)
        {
		EndCommandL();
		}
	else
		{
		return ProcessTestCommandL(command);
		}

	return ETrue;
	}


TBool CTOCSPCommand::ProcessTestCommandL(const TDesC& command)
	{
	if (!iInsideTest)
		{
		iLog.LogL(_L("Command cannot occur outside test: "));
		iLog.LogL(command);
		iLog.NewLineL();
		User::Leave(KErrCorrupt);
		}

    // Check the other commands that can only occur in tests
	if (command == KTOCSPCommandSetURI)
		{
		SetURICommandL();
		}
	else if (command == KTOCSPCommandSetTransport)
		{
		SetTransportCommandL();
		}
	else if (command == KTOCSPCommandSetTransportRetry)
		{
		SetTransportRetryCommandL();
		}
	else if (command == KTOCSPCommandSetTransportTimeout)
		{
		SetTransportTimeoutCommandL();
		}
	else if (command == KTOCSPCommandCert)
		{
		CertCommandL();
		}
	else if (command == KTOCSPCommandValidationDate)
		{
		ValidationDateCommandL();
		}
	else if (command == KTOCSPCommandDirectAuthorisation)
		{
		DirectAuthorisationCommandL();
		}
	else if (command == KTOCSPCommandCADelegateAuthorisation)
		{
		CADelegateAuthorisationCommandL();
		}
	else if (command == KTOCSPCommandCADirectAuthorisation)
		{
		CADirectAuthorisationCommandL();
		}
	else if (command == KTOCSPCommandAllAuthorisationSchemes)
		{
		AllAuthorisationSchemesCommandL();
		}
	else if (command == KTOCSPCommandSetMaxStatusAge)
		{
		SetMaxStatusAgeCommandL();
		}
	else if (command == KTOCSPCommandSetFilterParams)
		{
		SetFilterParamsCommandL();
		}
	else if (command == KTOCSPCommandCancel)
		{
		CancelCommandL();
		}
	else if (command == KTOCSPCommandCheck)
		{
		CheckCommand();
		}
	else if (command == KTOCSPCommandTestCancel)
		{
		TestCancelCommand();
		}
	else if (command == KTOCSPCommandTestSummary)
		{
		TestSummaryCommandL();
		}
	else if (command == KTOCSPCommandTestOutcome)
		{
		TestOutcomeCommandL();
		}
	else if (command == KTOCSPCommandTestTransport)
		{
		TestTransportCommandL();
		}
	else if (command == KTOCSPCommandTestTransportRetry)
		{
		TestTransportRetryCommandL();
		}
	else if (command == KTOCSPCommandNonce)
		{
		SetNonceCommandL();
		}
	else if (command == KTOCSPCommandLogResponse)
		{
		LogResponseCommandL();
		}
	else if (command == KTOCSPCommandLogRequest)
		{
		LogRequestCommandL();
		}
	else if (command == KTOCSPCheckResponderCert)
		{
		SetResponderCertCheck();
		}
	else if(command == KTOCSPAddCertToStore)
		{
		AddCertToStoreL();
		}
	else if(command ==  KTOCSPCheckCertsWithAiaOnly )
		{
		SetCheckCertsWithAiaOnly();
		}
	else if(command  == KTOCSPUseAIA)
		{
		SetUseAIAL();
		}
	else if(command == KTOCSPExpectedError)
		{
		LogErrorL();
		}
	else
		{
		UnknownCommandL(command);
		}

	return ETrue;
	}

void CTOCSPCommand::LogErrorL()
	{
	if (iTokens.Count() != 1)
		{
		WrongNumberOfArgumentsL();
		}

	TLex expectedErrorLex(iTokens[0]);
	TInt expectedError = 0;
	User::LeaveIfError(expectedErrorLex.Val(expectedError));

	iTestResult = (expectedError == iError)?ETrue:EFalse;

	User::RequestComplete(iOriginalRequestStatus, KErrNone);

	}

void CTOCSPCommand::RunL()
	{
	TInt err = iStatus.Int();

	// The engine does not get a chance to process the cancel notification so we handle it here
	if (err == KErrCancel)
		{
		// Cancel expected
		iCheckCancelled = ETrue;
		}
	else
		{
		User::LeaveIfError(err);
		}

	switch (iState)
		{
		case EEngineStart:
		case EEngineEnd:
		case EDirectAuthorisationCommand:
		case ECheckCommand:			
			User::RequestComplete(iOriginalRequestStatus, KErrNone);
			break;

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

TInt CTOCSPCommand::RunError(TInt aError)
    {
    iError = aError;
    User::RequestComplete(iOriginalRequestStatus, KErrNone);
    return KErrNone;
    }

void CTOCSPCommand::DoCancel()
	{
	switch (iState)
		{
		case EEngineStart:
		case EEngineEnd:
		case EDirectAuthorisationCommand:
		case ECheckCommand:
			iEngine->Cancel();
			break;
			
		default:
            User::Panic(_L("TOCSP"), 1);
			break;
		}
	}

void CTOCSPCommand::LogCommandL(const TDesC& aLine)
	{
	if (iVerbose)
		{
		// To file only
		if (iSkipping)
			{
			iLog.LogL(_L("Skipped: "), EFalse);
			}
		else
			{
			iLog.LogL(_L("Input: "), EFalse);
			}

		iLog.LogL(aLine, EFalse);		
		
		TInt match;
		_LIT(KMatch,"*START*");
		match = aLine.Match(KMatch);
		if (match==0)
			{
		iTmsId.Copy(TEFparser::ParseNthElement(aLine,2));
		
		TBuf<64> timeBuf;
		TTime time;
		time.UniversalTime();
		TDateTime dateTime = time.DateTime();
		_LIT(KDateFormat,"%02d:%02d:%02d:%03d "); 
		timeBuf.AppendFormat(KDateFormat,dateTime.Hour(),dateTime.Minute(),dateTime.Second(),(dateTime.MicroSecond()/1000));
		
		iLog.LogL(_L("\r\n"));
		iLog.LogL(timeBuf);	
		iLog.LogL(_L("Command = START_TESTCASE "));
		iLog.LogL(iTmsId);
			}	        
		iLog.LogL(_L("\n"));
		}
	}


void CTOCSPCommand::UnknownCommandL(const TDesC& aCommand)
	{
	// Log to screen and file
	iLog.LogL(_L("Unrecognised command \""), ETrue);
	iLog.LogL(aCommand);
	iLog.LogL(_L("\" - aborting\n"));
	
	User::RequestComplete(iOriginalRequestStatus, KErrCorrupt);
	}


void CTOCSPCommand::PrintCommandL(const TDesC& aMess)
	{
	if (iVerbose)
		{
		// To screen and file
		iLog.LogL(aMess, ETrue);
		iLog.LogL(_L("\n"), ETrue);
		}

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}


void CTOCSPCommand::StartCommandL()
	{
	if (iInsideTest)
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Misplaced START command: not inside test\n"));
			}
		User::Leave(KErrCorrupt);
		}

	if (iTokens.Count() != 1)
		{
		WrongNumberOfArgumentsL();
		}

	iInsideTest = ETrue;
	iTestResult = ETrue;
	iTransportSet = EFalse;

	iResult.NewTestL(iTokens[0]);

	if (iVerbose)
		{
		iLog.LogL(_L("Test: "));
		iLog.LogL(iTokens[0]);
		iLog.NewLineL();
		}

	iEngine->StartL(iStatus);
	iState = EEngineStart;
	SetActive();
	}


void CTOCSPCommand::EndCommandL()
	{
	if (!iInsideTest)
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Misplaced END command: not inside test\n"));
			}
		User::Leave(KErrCorrupt);
		}

	iInsideTest = EFalse;
	iCheckCancelled = EFalse;
	FinishedTestL();

	if (iVerbose)
		{
		iLog.NewLineL();
		}

	iEngine->EndL(iStatus);
	iState = EEngineEnd;
	SetActive();
	}


void CTOCSPCommand::SetURICommandL()
	{
	TInt tokenCount = iTokens.Count();
	
	if (tokenCount < 1 || tokenCount > 3) 
		{
		WrongNumberOfArgumentsL();
		}
	
	// Need to convert from unicode (as in file) to 8-bit (as used by OCSP)
	TBuf8<256> uri8;
	uri8.Copy(iTokens[0]);
	_LIT8(KNull,"NULL");
	if(uri8.Compare(KNull) == 0)
		{
		uri8.FillZ();
		}
	if(tokenCount == 3 )
		{
		if(iTokens[1].Compare(KTOCSPUseAIA) != 0 )
			{
			InvalidArgumentL(KTOCSPUseAIA);
			}
		if(iTokens[2].Compare(KTOCSPEnable) == 0)
			{
			iEngine->SetURIL(uri8, ETrue);
			}
		else if(iTokens[2].Compare(KTOCSPDisable) == 0)
			{
			iEngine->SetURIL(uri8, EFalse);
			}
		else
			{
			InvalidArgumentL(KTOCSPUseAIA,KTOCSPEnableDisable);
			}
		}
	else
		{
		// default value
		iEngine->SetURIL(uri8, ETrue);
		}
	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::SetTransportCommandL()
	{
	if (iTokens.Count() == 0)
		{
		WrongNumberOfArgumentsL();
		}

	TPtrC parameter = iTokens[0];
	if (parameter == KTOCSPDefaultTransport)
		{
		if (iTokens.Count() != 1)
			{
			WrongNumberOfArgumentsL();
			}
		iEngine->SetDefaultTransportL();
		}
	else if (parameter == KTOCSPTestTransport)
		{
		if (iTokens.Count() < 2 || iTokens.Count() > 3)
			{
			WrongNumberOfArgumentsL();
			}

		iEngine->SetTestTransportL(iTokens[1], iTokens.Count() == 3 ? &iTokens[2] : NULL);
		}
	else if (parameter == KTOCSPOcspSupportTransport)
		{
		if (iTokens.Count() != 1)
			{
			WrongNumberOfArgumentsL();
			}

		iEngine->SetOcspSupportTransportL();
		}
	iTransportSet = ETrue;
	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::SetTransportRetryCommandL()
	{
	if (!iTransportSet)
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Command sequence error: TRANSPORTRETRY must appear after TRANSPORT command\n"));
			}
		User::Leave(KErrCorrupt);
		}

	if (iTokens.Count() != 1)
		{
		WrongNumberOfArgumentsL();
		}

	TInt retryCount = 0;
	TLex lex(iTokens[0]);
	if ((lex.Val(retryCount) != KErrNone) || (retryCount < 0))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid retry count in TRANSPORTRETRY command\n"));
			}
		User::Leave(KErrArgument);
		}

	iEngine->SetTransportRetryCount(static_cast<TUint>(retryCount));

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::SetTransportTimeoutCommandL()
	{
	if (!iTransportSet)
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Command sequence error: TRANSPORTTIMEOUT must appear after TRANSPORT command\n"));
			}
		User::Leave(KErrCorrupt);
		}

	if (iTokens.Count() != 1)
		{
		WrongNumberOfArgumentsL();
		}

	TInt timeout = 0;
	TLex lex(iTokens[0]);
	if ((lex.Val(timeout) != KErrNone) || (timeout < -1))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid timeout in TRANSPORTTIMEOUT command\n"));
			}
		User::Leave(KErrArgument);
		}

	iEngine->SetTransportTimeout(timeout);

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::SetNonceCommandL()
	{
	if (iTokens.Count() != 1)
		{
		WrongNumberOfArgumentsL();
		}

	TPtrC param = iTokens[0];
	if (param == KTOCSPOn)
		{
		iEngine->SetNonce(ETrue);
		}
	else if (param == KTOCSPOff)
		{
		iEngine->SetNonce(EFalse);
		}
	else
		{
		User::Leave(KErrArgument);
		}

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}


void CTOCSPCommand::CertCommandL()
	{
	if (iTokens.Count() != 2)
		{
		WrongNumberOfArgumentsL();
		}

	TPtrC subjectCert = iTokens[0];
	TPtrC issuerCert = iTokens[1];

	// Open file server session
	RFs session;
	User::LeaveIfError(session.Connect());
	CleanupClosePushL(session);

	HBufC8* subjectData = 0;
	TRAPD(err, subjectData = Input::ReadFileL(subjectCert, session));
	CleanupStack::PushL(subjectData);
	if (err != KErrNone)
		{
		if (err != KErrNoMemory && iVerbose)
			{
			iLog.LogL(_L("Error opening "));
			iLog.LogL(subjectCert);
			}
		User::Leave(err);
		}

	HBufC8* issuerData = 0;
	TRAP(err, issuerData = Input::ReadFileL(issuerCert, session));
	CleanupStack::PushL(issuerData);
	if (err != KErrNone)
		{
		if (err != KErrNoMemory && iVerbose)
			{
			iLog.LogL(_L("Error opening "));
			iLog.LogL(issuerCert);
			}
		User::Leave(err);
		}

	// Engine will actually read + own the cert
	iEngine->AddCertL(*subjectData, *issuerData);

	CleanupStack::PopAndDestroy(3); // issuerData, subjectData, close session

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}


void CTOCSPCommand::ValidationDateCommandL()
	{
	if (iTokens.Count() != 5)
		{
		WrongNumberOfArgumentsL();
		}

	iEngine->SetValidationTimeL(ParseTimeL(0));

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

/**
 * Parse a series of input tokens representing a time - format is:
 * YEAR MONTH DAY HOUR MINUTE
 */

TTime CTOCSPCommand::ParseTimeL(TInt aStartToken)
	{
	TLex lexer;
	TInt year, month, day, hour, minute;

	lexer.Assign(iTokens[aStartToken++]);
	User::LeaveIfError(lexer.Val(year));

	lexer.Assign(iTokens[aStartToken++]);
	User::LeaveIfError(lexer.Val(month));

	lexer.Assign(iTokens[aStartToken++]);
	User::LeaveIfError(lexer.Val(day));

	lexer.Assign(iTokens[aStartToken++]);
	User::LeaveIfError(lexer.Val(hour));

	lexer.Assign(iTokens[aStartToken]);
	User::LeaveIfError(lexer.Val(minute));

	// Internal month and day are 0-based
	TDateTime dateTime(year, TMonth(--month), --day, hour, minute, 0, 0);

	return dateTime;
	}


void CTOCSPCommand::SetMaxStatusAgeCommandL()
	{
	if (iTokens.Count() != 1)
		{
		WrongNumberOfArgumentsL();
		}

	if (iTokens[0] == KTOCSPOff)
		{
		iEngine->SetMaxStatusAgeL(0);
		}
	else
		{
		TLex lexer;
		lexer.Assign(iTokens[0]);
		TUint seconds;
		User::LeaveIfError(lexer.Val(seconds));
		iEngine->SetMaxStatusAgeL(seconds);
		}

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::SetFilterParamsCommandL()
	{
	if (iTokens.Count() != 9)
		{
		WrongNumberOfArgumentsL();
		}
	TInt numDelayResp = 0, countDropResp = 0;
	TInt countCorruptHTTPDataHeader = 0, countCorruptHTTPDataBodySizeLarge = 0, countCorruptHTTPDataBodySizeSmall = 0;
	TInt countCorruptOCSPData = 0;
	TInt countInternalErrorResp = 0, countTryLaterResp = 0;
	TInt countSigValidateFailure = 0;

	TLex lex(iTokens[0]);
	if ((lex.Val(numDelayResp) != KErrNone) || (numDelayResp < -1))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid numDelayResp in FILTERPARAMS command\n"));
			}
		User::Leave(KErrArgument);
		}

	lex = iTokens[1];
	if ((lex.Val(countDropResp) != KErrNone) || (countDropResp < -1))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid countDropResp in FILTERPARAMS command\n"));
			}
		User::Leave(KErrArgument);
		}

	lex = iTokens[2];
	if ((lex.Val(countCorruptHTTPDataHeader) != KErrNone) || (countCorruptHTTPDataHeader < -1))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid countCorruptHTTPDataHeader in FILTERPARAMS command\n"));
			}
		User::Leave(KErrArgument);
		}

	lex = iTokens[3];
	if ((lex.Val(countCorruptHTTPDataBodySizeLarge) != KErrNone) || (countCorruptHTTPDataBodySizeLarge < -1))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid countCorruptHTTPDataBodySizeLarge in FILTERPARAMS command\n"));
			}
		User::Leave(KErrArgument);
		}

	lex = iTokens[4];
	if ((lex.Val(countCorruptHTTPDataBodySizeSmall) != KErrNone) || (countCorruptHTTPDataBodySizeSmall < -1))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid countCorruptHTTPDataBodySizeSmall in FILTERPARAMS command\n"));
			}
		User::Leave(KErrArgument);
		}

	lex = iTokens[5];
	if ((lex.Val(countCorruptOCSPData) != KErrNone) || (countCorruptOCSPData < -1))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid countCorruptOCSPData in FILTERPARAMS command\n"));
			}
		User::Leave(KErrArgument);
		}

	lex = iTokens[6];
	if ((lex.Val(countInternalErrorResp) != KErrNone) || (countInternalErrorResp < -1))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid countInternalErrorResp in FILTERPARAMS command\n"));
			}
		User::Leave(KErrArgument);
		}

	lex = iTokens[7];
	if ((lex.Val(countTryLaterResp) != KErrNone) || (countTryLaterResp < -1))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid countTryLaterResp in FILTERPARAMS command\n"));
			}
		User::Leave(KErrArgument);
		}

	lex = iTokens[8];
	if ((lex.Val(countSigValidateFailure) != KErrNone) || (countSigValidateFailure < -1))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid countSigValidateFailure in FILTERPARAMS command\n"));
			}
		User::Leave(KErrArgument);
		}

	iEngine->SetFilterParameters(numDelayResp, countDropResp,
			countCorruptHTTPDataHeader, countCorruptHTTPDataBodySizeLarge, countCorruptHTTPDataBodySizeSmall,
			countCorruptOCSPData, 
			countInternalErrorResp, countTryLaterResp, countSigValidateFailure);

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

// Pass a certificate (file) to be used as a root cert for validation of the response
void CTOCSPCommand::DirectAuthorisationCommandL()
	{
	iState = EDirectAuthorisationCommand;
	
	switch (iTokens.Count())
		{
	case 1:
		// since CA Delegate support was added, the script
		// cannot assume that direct authorisation is always
		// used.  Therefore, the special case of
		// "AUTHORISATIONCERT AUTHCERTNONE" is used to indicate that
		// direct authorisation should be used, even if no
		// certs are supplied.
		if (iTokens[0] != KAuthCertNone)
			User::Leave(KErrArgument);
		
		iEngine->UseDirectAuthorisation();
		User::RequestComplete(iOriginalRequestStatus, KErrNone);
		return;
		
	case 2:
		iCert.Set(iTokens[0]);
		iLabel.Set(iTokens[1]);
		break;
		
	default:
		WrongNumberOfArgumentsL();
		}

	iEngine->AddDirectAuthorisationCert(iCert, iLabel, iStatus);
	SetActive();
	}

void CTOCSPCommand::CADelegateAuthorisationCommandL()
/**
	Instruct engine to use CA delegate authorisation.
 */
	{
	if (iTokens.Count() != 0)
		{
		WrongNumberOfArgumentsL();
		}

	iEngine->UseCADelegateAuthorisation();
	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::CADirectAuthorisationCommandL()
/**
	Instruct engine to expect the response is signed
	directly by the CA.
 */
	{
	if (iTokens.Count() != 0)
		{
		WrongNumberOfArgumentsL();
		}

	iEngine->UseCADirectAuthorisation();
	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::AllAuthorisationSchemesCommandL()
/**
	Instruct engine to expect allocate all supported
	authorisation schemes.

	The script will have to specify which authorisation certs
	are supported for direct authorisation with AUTHORISATIONCERT,
	later in the script.
 */
	{
	if (iTokens.Count() != 0)
		{
		WrongNumberOfArgumentsL();
		}

	iEngine->UseAllAuthorisationSchemes();
	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::CancelCommandL()
	{
	if (iTokens.Count() != 1)
		{
		WrongNumberOfArgumentsL();
		}

	TLex timeLex(iTokens[0]);
	TInt time = 0;
	User::LeaveIfError(timeLex.Val(time));

	iEngine->SetCancelTime(time);

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::CheckCommand()
	{
	iState = ECheckCommand;
	iEngine->Check(iStatus);
	SetActive();
	}

void CTOCSPCommand::TestCancelCommand()
	{
	iTestResult = iTestResult && iCheckCancelled;

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::TestSummaryCommandL()
	{
	if (iTokens.Count() != 1)
		{
		WrongNumberOfArgumentsL();
		}

	TLex expectedResultLex(iTokens[0]);
	TInt expectedResult = 0;
	User::LeaveIfError(expectedResultLex.Val(expectedResult));

	iTestResult = iTestResult && iEngine->TestSummaryL(STATIC_CAST(OCSP::TResult, expectedResult));

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}


void CTOCSPCommand::TestOutcomeCommandL()
	{
	if (iTokens.Count() != 3)
		{
		WrongNumberOfArgumentsL();
		}

	TLex certIndexLex(iTokens[0]);
	TInt certIndex = 0;
	User::LeaveIfError(certIndexLex.Val(certIndex));

	TLex expectedStatusLex(iTokens[1]);
	TInt expectedStatus = 0;
	User::LeaveIfError(expectedStatusLex.Val(expectedStatus));

	TLex expectedResultLex(iTokens[2]);
	TInt expectedResult = 0;
	User::LeaveIfError(expectedResultLex.Val(expectedResult));

	TOCSPOutcome expectedOutcome(STATIC_CAST(OCSP::TStatus, expectedStatus), STATIC_CAST(OCSP::TResult, expectedResult));

	iTestResult = iTestResult && iEngine->TestOutcomeL(certIndex, expectedOutcome);

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::TestTransportCommandL()
	{
	if (iTokens.Count() != 4)
		{
		WrongNumberOfArgumentsL();
		}

	TLex lex(iTokens[0]);
	TInt retryCountNum = 0;
	if ((lex.Val(retryCountNum) != KErrNone) || (retryCountNum < 0))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid request number in TESTTRANSPORT command"), ETrue);
			}
		User::Leave(KErrArgument);
		}

	// Check the method name supplied (do a case insensitive compare)
	TPtrC ptrHttpMethod = iTokens[1];
	if (ptrHttpMethod.CompareC(_L("GET"), 2, NULL) && 
			ptrHttpMethod.CompareC(_L("POST"), 2, NULL))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid HTTP method name in TESTTRANSPORT command"), ETrue);
			}
		User::Leave(KErrArgument);
		}

	// Get the response time range
	TInt expRespTimeRangeMin = 0;
	TInt expRespTimeRangeMax = 0;
	lex = iTokens[2];
	if (lex.Val(expRespTimeRangeMin) != KErrNone)
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid range (min) for response time in TESTTRANSPORT command"), ETrue);
			}
		User::Leave(KErrArgument);
		}

	lex = iTokens[3];
	if ((lex.Val(expRespTimeRangeMax) != KErrNone) || expRespTimeRangeMax < expRespTimeRangeMin)
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid range (max) for response time in TESTTRANSPORT command"), ETrue);
			}
		User::Leave(KErrArgument);
		}

	iTestResult = iTestResult && iEngine->TestTransportL(retryCountNum, ptrHttpMethod,  
															expRespTimeRangeMin, expRespTimeRangeMax);

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::TestTransportRetryCommandL()
	{
	if (iTokens.Count() != 1)
		{
		WrongNumberOfArgumentsL();
		}

	TLex lex(iTokens[0]);
	TInt retryCount = 0;
	if ((lex.Val(retryCount) != KErrNone) || (retryCount < 0))
		{
		if (iVerbose)
			{
			iLog.LogL(_L("Invalid request count in TESTTRANSPORTRETRY command"), ETrue);
			}
		User::Leave(KErrArgument);
		}

	iTestResult = iTestResult && iEngine->TestTransportRetryL(retryCount);

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::LogResponseCommandL()
	{
	if (iTokens.Count() != 1)
		{
		WrongNumberOfArgumentsL();
		}

    iEngine->LogResponseL(iTokens[0]);

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}


void CTOCSPCommand::LogRequestCommandL()
	{
	if (iTokens.Count() != 1)
		{
		WrongNumberOfArgumentsL();
		}

    iEngine->LogRequestL(iTokens[0]);

	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}


void CTOCSPCommand::SetVerbose(TBool aVerbose)
	{
	iVerbose = aVerbose;
	iEngine->SetVerbose(aVerbose);
	}


void CTOCSPCommand::FinishedTestL()
	{	
	TBuf<64> timeBuf;
	TTime time;
	time.UniversalTime();
	TDateTime dateTime = time.DateTime();
	_LIT(KDateFormat,"%02d:%02d:%02d:%03d "); 
	timeBuf.AppendFormat(KDateFormat,dateTime.Hour(),dateTime.Minute(),dateTime.Second(),(dateTime.MicroSecond()/1000));	
		
	iLog.LogL(_L("\r\n"));
	iLog.LogL(timeBuf);	
	iLog.LogL(_L("Command = END_TESTCASE "), EFalse);
	iLog.LogL(iTmsId, ETrue);
	iLog.LogL(_L(" ***TestCaseResult = "), ETrue);
	
	iResult.ResultL(iTestResult);
	if (iVerbose)
		{
		if (iTestResult)
			{
			iLog.LogL(_L("PASS\n"), ETrue);
			}
		else
			{
			iLog.LogL(_L("FAIL\n"), ETrue);
			}
		}
	}


void CTOCSPCommand::WrongNumberOfArgumentsL()
	{
	iLog.LogL(_L("Wrong number of arguments for command"), ETrue);
	User::Leave(KErrArgument);
	}

void CTOCSPCommand::InvalidArgumentL(const TDesC& aCommand, const TDesC& aCommandOptions )
	{
	iLog.LogL(_L("Invalid input for:"), ETrue);
	iLog.LogL(aCommand, ETrue);
	iLog.LogL(_L(", Expected:"), ETrue);
	iLog.LogL(aCommandOptions, ETrue);
	User::Leave(KErrArgument);
	}

void CTOCSPCommand::InvalidArgumentL(const TDesC& aCommand)
	{
	iLog.LogL(_L("Invalid input:"), ETrue);
	iLog.LogL(aCommand, ETrue);
	User::Leave(KErrArgument);
	}

void CTOCSPCommand::SetResponderCertCheck()
	{
	iEngine->SetReponderCertCheck();
	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::AddCertToStoreL()
{
	if(iTokens.Count()!= 2)
		{
		WrongNumberOfArgumentsL();
		}
	
	TPtrC certFileName = iTokens[0];
	TPtrC certLabel = iTokens[1];
	
	iEngine->AddCertToStore(certFileName, certLabel, ECACertificate, iStatus);
	
	iState = EEngineEnd;
	SetActive();
}

void CTOCSPCommand::SetCheckCertsWithAiaOnly()
	{
	iEngine->SetCheckCertsWithAiaOnly(ETrue);
	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}

void CTOCSPCommand::SetUseAIAL()
	{	
	if (iTokens.Count() != 1) 
		{
		WrongNumberOfArgumentsL();
		}
	
	if(iTokens[0].Compare(KTOCSPEnable) == 0)
		{
		iEngine->SetUseAIA(ETrue);
		}
	else if(iTokens[0].Compare(KTOCSPDisable) == 0)
		{
		iEngine->SetUseAIA(EFalse);
		}
	else
		{
		InvalidArgumentL(KTOCSPUseAIA,KTOCSPEnableDisable);
		}
	
	User::RequestComplete(iOriginalRequestStatus, KErrNone);
	}