--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pkiutilities/ocsp/src/client.cpp Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,360 @@
+// Copyright (c) 2002-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 "transaction.h"
+#include "validator.h"
+#include "panic.h"
+#include <ocsp.h>
+#include <x509certext.h>
+#include <x509certchain.h>
+#include <x509cert.h>
+#include <asn1dec.h>
+
+EXPORT_C COCSPClient* COCSPClient::NewL(const COCSPParameters* aParams)
+ {
+ COCSPClient* self = new (ELeave) COCSPClient();
+ CleanupStack::PushL(self);
+ self->ConstructL(aParams);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+COCSPClient::COCSPClient() :
+ CActive(EPriorityNormal)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+void COCSPClient::ConstructL(const COCSPParameters* aParams)
+ {
+ __ASSERT_ALWAYS(aParams, Panic(KErrArgument));
+
+ // Caller must supply transport
+ if (!aParams->Transport())
+ {
+ User::Leave(KErrArgument);
+ }
+
+ // Range check request timeout and retry values to avoid later panics
+ if (aParams->Timeout() < KTransportDefaultRequestTimeout)
+ {
+ User::Leave(KErrArgument);
+ }
+ if (aParams->RetryCount() < KTransportDefaultRequestRetryCount)
+ {
+ User::Leave(KErrArgument);
+ }
+
+ iParams = aParams; // Take ownership
+
+ // Make a request for every certificate
+ for (TUint i = 0 ; i < aParams->CertCount() ; ++i)
+ {
+ // Following are the condition in which the request would not be
+ // added for ocsp check:
+ // If CheckCertsWithAiaOnly is enabled and certificate does
+ // not contain AIA extension.
+ // Or
+ // CheckCertsWithAiaOnly is disabled and
+ // GenerateResponseFromMissingURI is disabled and
+ // AIA is absent and
+ // Global OCSP URL is absent
+
+ if (! ( ( aParams->CheckCertsWithAiaOnly() &&
+ !OCSPUtils::IsAIAForOCSPPresentL( aParams->SubjectCert(i) )
+ ) ||
+ ( !aParams->CheckCertsWithAiaOnly()
+ && !aParams->GenerateResponseForMissingUri()
+ && !OCSPUtils::IsAIAForOCSPPresentL(aParams->SubjectCert(i))
+ && aParams->DefaultURI() == KNullDesC8()
+ )
+ )
+ )
+ {
+ COCSPRequest* request = COCSPRequest::NewLC(aParams->UseNonce());
+ request->AddCertificateL(aParams->SubjectCert(i), aParams->IssuerCert(i));
+ User::LeaveIfError(iRequests.Append(request));
+ CleanupStack::Pop(request);
+ }
+
+ }
+ iValidator = COCSPValidator::NewL(*aParams);
+ }
+
+
+COCSPClient::~COCSPClient()
+ {
+ Cancel();
+ delete iParams;
+ delete iURI;
+ delete iTransport;
+ delete iTransaction;
+ delete iValidator;
+ iRequests.ResetAndDestroy();
+ iResponses.ResetAndDestroy();
+ iOutcomes.Close();
+ }
+
+EXPORT_C OCSP::TResult COCSPClient::SummaryResult(void) const
+ {
+ __ASSERT_ALWAYS(iState == EHaveResult, Panic(KErrNotReady));
+ return iSummaryResult;
+ }
+
+EXPORT_C TInt COCSPClient::TransactionCount(void) const
+ {
+ __ASSERT_ALWAYS(iState == EHaveResult, Panic(KErrNotReady));
+ return iResponses.Count();
+ }
+
+EXPORT_C const COCSPRequest& COCSPClient::Request(TInt aIndex) const
+ {
+ __ASSERT_ALWAYS(iState == EHaveResult, Panic(KErrNotReady));
+ __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iRequests.Count(), Panic(KErrNotFound));
+ return *(iRequests[aIndex]);
+ }
+
+EXPORT_C const TOCSPOutcome& COCSPClient::Outcome(TInt aIndex) const
+ {
+ __ASSERT_ALWAYS(iState == EHaveResult, Panic(KErrNotReady));
+ __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iOutcomes.Count(), Panic(KErrNotFound));
+ return iOutcomes[aIndex];
+ }
+
+EXPORT_C const COCSPResponse* COCSPClient::Response(TInt aIndex) const
+ {
+ __ASSERT_ALWAYS(iState == EHaveResult, Panic(KErrNotReady));
+ __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iResponses.Count(), Panic(KErrNotFound));
+ return iResponses[aIndex];
+ }
+
+EXPORT_C void COCSPClient::Check(TRequestStatus& aStatus)
+ {
+ __ASSERT_ALWAYS(iState == EInitial, Panic(KErrInUse));
+
+ iClientStatus = &aStatus;
+ TInt err = KErrNone;
+
+ if (iRequests.Count() == 0)
+ {
+ err = OCSP::KErrNoCertificates;
+ }
+
+ if (err == KErrNone)
+ {
+ aStatus = KRequestPending;
+ DoCheck();
+ }
+
+ if (err != KErrNone)
+ {
+ User::RequestComplete(iClientStatus, err);
+ iState = EError;
+ }
+ }
+
+EXPORT_C void COCSPClient::CancelCheck()
+ {
+ Cancel();
+ }
+
+EXPORT_C TBool COCSPClient::CertsAvailableForOCSPCheck()
+ {
+ return iRequests.Count();
+ }
+
+TInt COCSPClient::RunError(TInt aError)
+ {
+ User::RequestComplete(iClientStatus, aError);
+ iState = EError;
+ return KErrNone;
+ }
+
+void COCSPClient::DoCancel()
+ {
+ if (iTransaction)
+ {
+ iTransaction->CancelRequest();
+ }
+
+ iValidator->Cancel();
+ if (iClientStatus)
+ {
+ User::RequestComplete(iClientStatus, KErrCancel);
+ }
+ }
+
+void COCSPClient::DoCheck()
+ {
+ iSummaryResult = OCSP::EGood;
+ SendRequest();
+ }
+
+void COCSPClient::RunL()
+ {
+ switch (iState)
+ {
+ case ESendingRequest:
+ HandleResponseReceivedL();
+ break;
+
+ case EValidatingResponse:
+ User::LeaveIfError(iStatus.Int());
+ HandleResponseValidatedL();
+ break;
+
+ default:
+ Panic(KErrCorrupt);
+ break;
+ }
+ }
+
+/**
+ * Receive the response, if the response was received correctly,
+ * perform validation based on the scheme in use.
+ */
+void COCSPClient::HandleResponseReceivedL()
+ {
+ TInt status = iStatus.Int();
+
+ if (status == KErrNone)
+ {
+ COCSPResponse* response = iTransaction->TakeResponse();
+ CleanupStack::PushL(response);
+ User::LeaveIfError(iResponses.Append(response));
+ CleanupStack::Pop(response);
+ ValidateResponseL();
+ }
+ else if (status > 0)
+ {
+ HandleTransactionErrorL(static_cast<OCSP::TStatus>(status));
+ }
+ else if ((status == OCSP::KErrTransportFailure) || (status == OCSP::KErrServerNotFound))
+ {
+ HandleTransactionErrorL(OCSP::ETransportError);
+ }
+ else if (status == OCSP::KErrInvalidURI)
+ {
+ HandleTransactionErrorL(OCSP::EInvalidURI);
+ }
+ else if (status == OCSP::KErrTransportTimeout)
+ {
+ HandleTransactionErrorL(OCSP::ETimeOut);
+ }
+ else
+ {
+ User::Leave(status);
+ }
+ }
+
+/**
+ * Called when there's an error getting a response, and it's one of our non-fatal errors.
+ * We record the error and continue checking.
+ */
+
+void COCSPClient::HandleTransactionErrorL(OCSP::TStatus aStatus)
+ {
+ User::LeaveIfError(iOutcomes.Append(TOCSPOutcome(aStatus, OCSP::EUnknown)));
+ User::LeaveIfError(iResponses.Append(NULL));
+ HandleResponseValidatedL();
+ }
+
+/**
+ * Following is the sequence followed in this method:
+ * 1. Check the result for validation of the current response and update the Summary result accordingly.
+ * 2. If delegate certificate has to be checked further initiate the same.
+ * 3. if all request have not been processed then start validation for the next request.
+ * 4. If all request have been processed complete the original client request.
+ */
+void COCSPClient::HandleResponseValidatedL()
+ {
+ TInt index = iOutcomes.Count() - 1;
+ const TOCSPOutcome& outcome = iOutcomes[index];
+
+ if (outcome.iResult > iSummaryResult)
+ {
+ iSummaryResult = outcome.iResult;
+ }
+
+ if (iResponses.Count() < iRequests.Count())
+ {
+ SendRequest();
+ }
+ else
+ {
+ iState = EHaveResult;
+ User::RequestComplete(iClientStatus, KErrNone);
+ }
+ }
+
+void COCSPClient::SendRequest()
+ {
+ TRAPD(error, DoSendRequestL());
+
+ // Handle errors in RunL
+ if (error != KErrNone)
+ {
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, error);
+ }
+
+ iState = ESendingRequest;
+ SetActive();
+ }
+
+void COCSPClient::DoSendRequestL()
+ {
+ // Determine the next request to send by the number of responses received
+ TInt index = iResponses.Count();
+ COCSPRequest& request = *(iRequests[index]);
+
+ TDesC8* uri = NULL;
+ TRAPD(error, uri = OCSPUtils::ServerUriL(request.CertInfo(0).Subject(),iParams));
+
+ if(error == KErrArgument)
+ {
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, OCSP::ENoServerSpecified);
+ return;
+ }
+
+ User::LeaveIfError(error);
+ CleanupStack::PushL(uri);
+
+ // if state is valid it means that uri has been retrieved.
+ __ASSERT_ALWAYS(uri != NULL, Panic(OCSP::EInvalidURI));
+ MOCSPTransport& transport = *iParams->Transport();
+
+ delete iTransaction;
+ iTransaction = NULL;
+ iTransaction = COCSPTransaction::NewL(*uri, transport, iParams->RetryCount(), iParams->Timeout());
+ iTransaction->SendRequest(request, iStatus);
+ CleanupStack::PopAndDestroy(uri);
+ }
+
+/**
+ * Each response received has to undergo validation based on RFC 2560 guidelines.
+ */
+void COCSPClient::ValidateResponseL()
+ {
+ TInt index = iResponses.Count() - 1;
+
+ User::LeaveIfError(iOutcomes.Append(TOCSPOutcome()));
+ __ASSERT_ALWAYS(iOutcomes.Count() == iResponses.Count(), Panic(KErrCorrupt));
+
+ iState = EValidatingResponse;
+ iValidator->Validate(*(iRequests[index]), *(iResponses[index]), iOutcomes[index], iStatus);
+ SetActive();
+ }