pkiutilities/ocsp/src/directauthorisation.cpp
changeset 0 164170e6151a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkiutilities/ocsp/src/directauthorisation.cpp	Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,321 @@
+// 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:
+// Define methods for authorisation scheme based on locally configured
+// authoritive root certs
+// 
+//
+
+#include "ocsp.h"
+#include "panic.h"
+#include <pkixcertchain.h>
+#include <asn1dec.h>
+#include <x509keys.h>
+#include <x509cert.h>
+#include <mcertstore.h>
+#include <ccertattributefilter.h>
+#include "ocsprequestandresponse.h"
+
+EXPORT_C COCSPDirectAuthorisationScheme* COCSPDirectAuthorisationScheme::NewLC(const TUid& aCertStoreUid, MCertStore& aCertStore)
+	{
+	COCSPDirectAuthorisationScheme* self = new(ELeave) COCSPDirectAuthorisationScheme(aCertStoreUid, aCertStore);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+COCSPDirectAuthorisationScheme::COCSPDirectAuthorisationScheme(const TUid& aCertStoreUid, MCertStore& aCertStore) :
+	CActive(CActive::EPriorityStandard),
+	iCertStoreUid(aCertStoreUid),
+	iCertStore(aCertStore)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+
+COCSPDirectAuthorisationScheme::~COCSPDirectAuthorisationScheme()
+	{
+	Cancel();
+	delete iCertChain;
+	delete iPKIXResult; 
+	delete iCertFilter;
+	delete iEncodedCertBuf;
+	delete iEncodedCertPtr;
+	iFs.Close();
+	iCertStoreEntries.Close();
+	delete iResponseCert;
+	}
+
+
+void COCSPDirectAuthorisationScheme::ConstructL()
+	{
+	iPKIXResult = CPKIXValidationResultBase::NewL();
+	
+	User::LeaveIfError(iFs.Connect());
+	
+	iCertFilter = CCertAttributeFilter::NewL();
+	iCertFilter->SetOwnerType(ECACertificate);
+	iCertFilter->SetUid(iCertStoreUid);
+	iCertFilter->SetFormat(EX509Certificate);
+	}
+
+/**
+ * Starts the process of validating the response.
+ * The initial value of the OCSP Status is set to signature validation failure.
+ */
+void COCSPDirectAuthorisationScheme::ValidateL(OCSP::TStatus& aOCSPStatus,
+	COCSPResponse& aResponse, const TTime aValidationTime, TRequestStatus& aStatus,
+	const COCSPRequest& aRequest)
+	{
+	iValidationTime = aValidationTime;
+
+	iClientStatus = &aStatus;
+	*iClientStatus = KRequestPending;
+
+	iResponse = &aResponse;
+	iRequest = &aRequest;
+	
+	iOCSPStatus = &aOCSPStatus;
+	*iOCSPStatus = OCSP::EResponseSignatureValidationFailure;
+	
+	// this object needs to be deleted if the same COCSPDirectAuthorisationScheme
+	// object is used for validating more than one certificate via COCSPValidator
+	delete iCertChain;
+	iCertChain = NULL;
+		
+	StartValidateL();
+	}
+
+
+void COCSPDirectAuthorisationScheme::ValidateFromRoots()
+//
+// Certs for the chain were not included in the response.
+// See if any of the root certs for the given Uid can do the job.
+//
+	{
+	iCertStore.List(iCertStoreEntries, *iCertFilter, iStatus);
+	iState = EListCertEntries;
+	}
+
+/**
+ * If response contains responder's certificate, chain validation would be done till the CA 
+ * certificate which should be located in the store.
+ */
+void COCSPDirectAuthorisationScheme::ValidateCertChainL()
+	{
+	__ASSERT_DEBUG(iCertChain, Panic(KErrCorrupt));
+
+	iCertChain->ValidateL(*iPKIXResult, iValidationTime, iStatus);
+	iState = EValidateCertChain;
+	}
+
+TBool COCSPDirectAuthorisationScheme::ValidateSignatureL()
+	{
+	__ASSERT_DEBUG(iCertChain, Panic(KErrCorrupt));
+
+	// Validate against first cert in chain - must exist
+	const CX509Certificate& eeCert = iCertChain->Cert(0);
+
+	return	OCSPUtils::DoesResponderIdMatchCertL(*iResponse, eeCert)
+		&&	OCSPUtils::IsResponseSignedByCertL(iResponse, eeCert);
+	}
+
+void COCSPDirectAuthorisationScheme::OnValidateCertChainL()
+// Called when cert chain validation completes
+	{
+	if (iPKIXResult->Error().iReason == EValidatedOK)
+		{
+		if (ValidateSignatureL())
+			{
+			delete iResponseCert;
+			iResponseCert = NULL;
+			iResponseCert = CX509Certificate::NewL(iCertChain->Cert(0));
+			*iOCSPStatus = OCSP::EValid;
+			}
+		}
+	User::RequestComplete(iClientStatus, KErrNone);
+	}
+		
+
+void COCSPDirectAuthorisationScheme::OnListCertEntries()
+// Called when listing cert store entries completes
+	{
+	// trigger transitory state to start getting entries
+	iCurEntry = -1;
+	iState = ERetrieveNext;
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrNone);
+	SetActive();
+	}
+
+
+void COCSPDirectAuthorisationScheme::OnRetrieveNextL()
+// Transitory state to retrieve next entry triggered
+	{
+	delete iEncodedCertBuf;
+	iEncodedCertBuf = 0;
+	delete iEncodedCertPtr;
+	iEncodedCertPtr = 0;
+	if (++iCurEntry < iCertStoreEntries.Count())
+	// still more entries, get next one
+		{
+		CCTCertInfo* certInfo = iCertStoreEntries[iCurEntry];
+		ASSERT(certInfo);
+
+		iEncodedCertBuf = HBufC8::NewL(certInfo->Size());
+		iEncodedCertPtr = new(ELeave) TPtr8(iEncodedCertBuf->Des());
+
+		iCertStore.Retrieve(*certInfo, *iEncodedCertPtr, iStatus);
+		
+		iState = ERetrievingEntry;
+		
+		SetActive();
+		}
+	else
+	// no more entries, bad news
+		{
+		User::RequestComplete(iClientStatus, KErrNone);
+		}
+	}
+
+void COCSPDirectAuthorisationScheme::OnRetrievingEntryL()
+// Called when retrieving an entry completes.
+	{
+	CX509Certificate* cert = CX509Certificate::NewLC(*iEncodedCertPtr);
+	
+	if (	OCSPUtils::DoesResponderIdMatchCertL(*iResponse, *cert)
+		&&	OCSPUtils::IsResponseSignedByCertL(iResponse, *cert)
+		&&	cert->ValidityPeriod().Valid(iValidationTime))
+	// found a good one, job finished
+		{
+		delete iResponseCert;
+		iResponseCert = NULL;
+		CleanupStack::Pop(cert);
+		iResponseCert = cert;
+		*iOCSPStatus = OCSP::EValid;
+		User::RequestComplete(iClientStatus, KErrNone);
+		}
+	else
+	// wasn't good, try next one
+		{
+		iState = ERetrieveNext;
+		TRequestStatus* status = &iStatus;
+		User::RequestComplete(status, KErrNone);
+		SetActive();
+		CleanupStack::PopAndDestroy(cert);
+		}
+	
+	}
+
+void COCSPDirectAuthorisationScheme::RunL()
+//
+// Handles transitions from one state to the next
+//
+	{
+	User::LeaveIfError(iStatus.Int());
+
+	switch (iState)
+		{
+	case EValidateCertChain:
+		OnValidateCertChainL();
+		break;
+	case EListCertEntries:
+		OnListCertEntries();
+		break;
+	case ERetrieveNext:
+		OnRetrieveNextL();
+		break;
+	case ERetrievingEntry:
+		OnRetrievingEntryL();
+		break;
+	
+	default:
+		ASSERT(FALSE);
+		}
+	}
+
+void COCSPDirectAuthorisationScheme::DoCancel()
+//
+// Cancel
+//
+	{
+	switch (iState)
+		{
+	case EValidateCertChain:
+		ASSERT(iCertChain);
+		iCertChain->CancelValidate();
+		break;
+	case EListCertEntries:
+		iCertStore.CancelList();
+		break;
+	case ERetrieveNext:
+		// nothing to do, this is a transitory state
+		break;
+	case ERetrievingEntry:
+		iCertStore.CancelRetrieve();
+		break;
+	default:
+		ASSERT(FALSE);
+		}
+	if (iClientStatus)
+		{
+		User::RequestComplete(iClientStatus, KErrCancel);
+		}
+	}
+
+
+TInt COCSPDirectAuthorisationScheme::RunError(TInt aError)
+	{
+	if(aError == KErrArgument)
+		{
+		User::RequestComplete(iClientStatus, KErrNone);
+		}
+	else
+		{
+		User::RequestComplete(iClientStatus, aError);
+		}
+	return KErrNone;
+	}
+
+/**
+ * If the response contains the certificate which signed the response, create the certificate chain
+ * till the responder certificate. Otherwise validate directly from root certificates contained 
+ * in the store initialized by the client.
+ */
+void COCSPDirectAuthorisationScheme::StartValidateL()
+	{
+	const TPtrC8* certChainData = iResponse->DataElementEncoding(COCSPResponse::ECertificateChain);
+	
+	// Cert chain data was included in response
+	if (certChainData)
+		{
+		iCertChain = CPKIXCertChainBase::NewL(iCertStore, *certChainData, iCertStoreUid);
+		ValidateCertChainL();
+		}
+	else
+		{
+		// No cert chain in response - validate directly from root certs
+		ValidateFromRoots();
+		}
+	SetActive();
+	}
+
+void COCSPDirectAuthorisationScheme::CancelValidate()
+	{
+	CActive::Cancel();
+	}
+
+const CX509Certificate* COCSPDirectAuthorisationScheme::ResponderCert() const	
+	{
+	return iResponseCert;
+	}