How to use OSCP
===============

Note: The actual code snippets are indented.

Include ocsp.h in your header file.

	#include <ocsp.h>

Link your project with ocsp.lib: add the following string to your project's .mmp
file:

	LIBRARY ocsp.lib

Add the following to your class declaration, which should be derived from
CActive:

	COcspClient* iOcspClient;

You will need to know revocation server URI. It is possible to get it from
installer preferences. Most Software Install components accept the URI as a
construction parameter. This is because they are started by the UI which stores
preferences in its resource file. If you want to retrieve it yourself, you can
use the following code (taken from InstallEngineImpl.cpp):

	//	Open instapp's ini file
	static CDictionaryStore* OpenIniFileLC(RFs& aFs)
		{
		CApaAppFinder* appFinder=CApaScanningAppFinder::NewL(aFs);
		CleanupStack::PushL(appFinder);
		TUid instAppUid={KUidInstallAppValue};
		TFileName libName=appFinder->FindAppL(KInstallAppName,instAppUid);
		CleanupStack::PopAndDestroy(appFinder); 
		TParse parser;
		User::LeaveIfError(parser.SetNoWild(KIniFileExtension,&KInstAppDriveC(),
			&libName));
		aFs.MkDirAll(parser.FullName()); // ignore the error
		CDictionaryFileStore* dict = CDictionaryFileStore::OpenLC(aFs,
			parser.FullName(),instAppUid);
		return dict;
		}

	// get preferences from ini file
	{
	RFs fs;
	User::LeaveIfError(fs.Connect());
	CleanupClosePushL(fs);
	CDictionaryStore* iniFile=OpenIniFileLC(fs); // see above
	User::LeaveIfNull(iniFile);
	RDictionaryReadStream readStream;
	readStream.OpenLC(*iniFile,KUidInstallPrefs);
	TInstallPrefs prefs; // this is what you need
	TRAPD(ret,readStream >> prefs);   // will return KErrEof first time
	CleanupStack::PopAndDestroy(2); //readStream, iniFile
	CleanupStack::Pop(); // fs 
	fs.Close();
	}

If at any time you want to cancel OCSP check, call

	iOcspClient->CancelCheck();

When ready to perform the check (the certificate chain is built), use the
following code as a template (from JavaInstallerSecurityManager.cpp):

	COCSPParameters* params = COCSPParameters::NewLC();
	params->SetURIL(*iOCSPServerURI, ETrue);
	params->AddCertificatesL(*iCertChain);
	
	// Set up authorisation scheme - we've a special UID registered with the
	// certStore for the appropriate certificates
	COCSPDirectAuthorisationScheme* scheme = 
		COCSPDirectAuthorisationScheme::NewLC(
		TUid::Uid(KCertStoreUIDForSWInstallOCSPSigning));
	params->AddAuthorisationSchemeL(scheme);
	CleanupStack::Pop(scheme);
   		
	// Won't set validation time - this uses the response producedAt time
	// instead. This avoids us relying on an accurate time in the device.
	// Caching of old responses avoided by use of the nonce.

	iOcspClient = COcspClient::NewL(params);
	CleanupStack::Pop(params);
	iOcspClient->Check(iStatus);

When the request completes and your class's RunL() is called, use the following
function template to process the result:

	TBool accept = ETrue;
	switch (iStatus.Int())
		{
		case OCSP::KErrNoCertificates:
			// No certs in OCSP request - no proper cert chain formed.
			// Covered by check digital sig logic already, so we let it pass.
			break;
		case KErrNone:
		    {
			// Check the outcome of every transaction made
			for (TInt index = 0; 
				accept && index < iOcspClient->TransactionCount(); 
				++index)
				{
				const TOCSPOutcome& outcome = iOcspClient->Outcome(index);

				// We have the OCSP response.  Interpret it, asking the user
				// what questions we need to.  Return determines whether we
				// continue the install
				switch (outcome.iStatus)
					{
					case OCSP::ETransportError:
					case OCSP::EClientInternalError:
					case OCSP::EMalformedRequest:
					case OCSP::EServerInternalError:
					case OCSP::ETryLater:
					case OCSP::ESignatureRequired:
					case OCSP::EClientUnauthorised:
					case OCSP::EUnknownResponseType:
						// Error: unable to obtain certificate status
						break;
					case OCSP::ENoServerSpecified:
					case OCSP::EInvalidURI:
						// Error: invalid revocation server URI
						break;
					case OCSP::EResponseSignatureValidationFailure:
						// Error: response signature validation failed
						break;
					case OCSP::EThisUpdateTooLate:
					case OCSP::EThisUpdateTooEarly:
					case OCSP::ENextUpdateTooEarly:
					case OCSP::ENonceMismatch:
					case OCSP::EMalformedResponse:
					case OCSP::EUnknownCriticalExtension:
					case OCSP::EMissingCertificates:
						// Error: invalid server response
						break;
					case OCSP::EMissingNonce:
						// Error: missing nonce
						break;
					case OCSP::ECertificateNotValidAtValidationTime:
						// Error: invalid certificate status information
						break;
					case OCSP::EValid:
						switch(outcome.iResult)
							{
							case OCSP::EGood:
								accept = ETrue;
								break;
							case OCSP::EUnknown:
								// ask user
								break;
							case OCSP::ERevoked:
								// ask user
								break;
							default:
								ASSERT(EFalse);
							}
						break;
					default:
						ASSERT(EFalse);
						break;
					}
				}	
			break;
			}
		default:
			// Error: cannot obtain certificate status, ask user
			break;
		}

	delete iOcspClient;
	iOcspClient = NULL;

OCSP check can take a long time. Therefore it is a good thing to display a
status dialog for the user telling her that OCSP check is in progress and
allowing her to cancel it. Both SIS and Java installers delegate this function
to their respective UI handlers.
