pkiutilities/ocsp/src/ocsputils.cpp
changeset 0 164170e6151a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkiutilities/ocsp/src/ocsputils.cpp	Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,293 @@
+// 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:
+// Define generic methods which can be used accross the ocsp component.
+// 
+//
+
+#include <asymmetrickeys.h>
+#include <ocsp.h>
+#include "oids.h"
+#include <x509certext.h>
+#include "ocsprequestandresponse.h"
+
+namespace OCSPUtils
+	{
+	/**
+		Checks whether the supplied certificate matches the responder
+		ID in the supplied response.  This implements S3.2.3 of RFC2560.
+		Note this does <em>not</em> mean the response is signed by the
+		certificate's subject.  It just checks that the certificate's
+		name, or a hash of its key, is present in the response's plaintext.
+		
+		@param	aResponse		Response whose responder ID should describe
+								<var>aCert</var>.
+		@param	aCert			Certificate whose name or key should be
+								in the response.
+		@return ETrue if the response's responder ID matches <var>aCert</var>,
+			EFalse otherwise.
+	 */
+	TBool DoesResponderIdMatchCertL( const COCSPResponse& aResponse, 
+												const CX509Certificate& aResponderCert)
+		{	
+		return (DoesIssuerKeyMatchL(aResponse,aResponderCert) || DoesDNNameMatchL(aResponse,aResponderCert));
+		}
+	
+	TBool DoesDNNameMatchL( 	const COCSPResponse& aResponse, const CX509Certificate& aCert)
+		{
+		TBool result = EFalse;
+		const TPtrC8* nameData = aResponse.DataElementEncoding(COCSPResponse::EResponderIDName);
+		if (nameData)
+			{
+			CX500DistinguishedName* name = CX500DistinguishedName::NewLC(*nameData);
+			if (aCert.SubjectName().ExactMatchL(*name))
+				{
+				result = ETrue;
+				}
+			CleanupStack::PopAndDestroy(name);
+			}
+		return result;
+		}
+	
+	TBool DoesIssuerKeyMatchL(const COCSPResponse& aResponse, const CX509Certificate& aCert)
+		{
+		TBool result = EFalse;
+		// check the responder's issuer key and verify that it is the same as the issuer cert
+		const TPtrC8* keyHash = aResponse.DataElementEncoding(COCSPResponse::EResponderIDKeyHash);
+		const TPtrC8* keyEncoding = aCert.DataElementEncoding(CX509Certificate::ESubjectPublicKeyInfo);
+		if (!keyHash || !keyEncoding)
+			{
+			return result;
+			}
+		
+		TASN1DecSequence decSeq;
+		TInt pos = 0;
+		CArrayPtrFlat<TASN1DecGeneric>* seq = decSeq.DecodeDERLC(*keyEncoding, pos, 2, KMaxTInt);
+	
+		TASN1DecBitString decBitStr;
+		HBufC8* toHashData = decBitStr.ExtractOctetStringL(*seq->At(1));
+		CleanupStack::PushL(toHashData);
+		
+		CSHA1* hashAlg = CSHA1::NewL();
+		CleanupStack::PushL(hashAlg);
+		TPtrC8 certKeyHash = hashAlg->Hash(*toHashData);
+		
+		if (certKeyHash == *keyHash)
+			{
+			// Public key hashes match
+			result = ETrue;
+			}
+		CleanupStack::PopAndDestroy(3, seq); // hashAlg, toHashData, seq
+			
+		return result;
+		}
+	
+	TBool IsResponseSignedByCertL(
+		COCSPResponse* aResponse, const CX509Certificate& aCert)
+	/**
+		Checks whether the supplied response is signed by the supplied
+		certificate.
+		
+		@param	aResponse		Response which should be signed by aCert.
+		@param	aCert			Candidate certificate which may have been
+								used to sign <var>aResponse</var>.
+		@return ETrue if <var>aCert</var> is used to sign <var>aResponse</var>,
+			EFalse otherwise.  Note <code>COCSPResponse</code> derives
+			from <code>CSignedObject</code>.
+	 */
+		{
+		if (aCert.PublicKey().AlgorithmId() == EDSA)
+			{
+			TX509KeyFactory factory;
+			CDSAParameters* theDSAParams = factory.DSAParametersL(aCert.PublicKey().EncodedParams());
+			CleanupStack::PushL(theDSAParams);
+			
+			CSigningKeyParameters* params = CSigningKeyParameters::NewLC();
+			params->SetDSAParamsL(*theDSAParams);
+					
+			aResponse->SetParametersL(*params);
+			CleanupStack::PopAndDestroy(2, theDSAParams);
+			}
+		
+		return aResponse->VerifySignatureL(aCert.PublicKey().KeyData());
+		}
+	
+	TBool DoesCertHaveOCSPNoCheckExt(const CX509Certificate& aCert)
+	/**
+		Test whether the supplied certificate has id-pkix-ocsp-nocheck
+		in an extendedKeyUsage extension.  
+		
+		@param	aCert		Certificate to test for id-kp-OCSPSigning.
+								
+		@return				ETrue if the supplied certificate has an
+							extendedKeyUsage extension which contains
+							id-pkix-ocsp-nocheck.
+	 */
+		{
+		return aCert.Extension(KOCSPOidNoCheck) != NULL;
+		}
+	
+	/**
+	 * Determine the URI of the OCSP server to use for a certificate.  Checks to see
+	 * if there is an authority info access extension containing an access
+	 * description with method oid id-ad-ocsp. If so, it copies the access
+	 * description into a new descriptor which it stores in iURI.  Otherwise it
+	 * returns iDefaultURI, which may be null.
+	 */
+	
+	TDesC8* ServerUriL(const CX509Certificate& aCert, const COCSPParameters* aParameters )
+		{
+		
+		TDesC8* uri = NULL;
+		
+		// check whether AIA is present or not:
+		// if present and UseAIA is enabled the get the AIA extension.
+		// if AIA is absent the else if part will handle it
+		// if present and UseAIA is disabled, means that iUseGlobalOCSPUri is enabled,
+		// do not leave with an error in this case the next case will handle this condition.
+		if( aParameters->UseAIA() && OCSPUtils::IsAIAForOCSPPresentL(aCert) )
+			{
+			uri = OCSPUtils::GetAIAL(aCert);
+			}
+		else if( aParameters->DefaultURI() != KNullDesC8())
+			{
+			uri = aParameters->DefaultURI().AllocL();
+			}
+		// the extension is absent and iUseGlobalOCSPUri is disabled, it has reached this case
+		// where neither is there an AIA in the cert nor is the global ocsp responder available,
+		// this should leave with EInvalidURI but this has been done to maintain backward compatibility.
+		else
+			{
+			User::Leave(KErrArgument);
+			}
+		return uri;
+		}
+	
+	// check whether AIA is present or not:
+	// if present and UseAIA is enabled then return true.
+	// if default uri is not null return true.
+	TBool IsUriAvailableL(const CX509Certificate& aCert, const COCSPParameters* aParameters )
+		{
+		return  ( aParameters->UseAIA() && OCSPUtils::IsAIAForOCSPPresentL(aCert) ) || 
+				 ( aParameters->DefaultURI() != KNullDesC8() ) ;
+		}
+	
+	TBool IsAIAForOCSPPresentL(const CX509Certificate& aCert)
+		{
+		TBool found = EFalse;
+		const CX509CertExtension* ext = aCert.Extension(KAuthorityInfoAccess);
+		
+		if(ext)
+			{
+			CX509AuthInfoAccessExt* auth = CX509AuthInfoAccessExt::NewLC(ext->Data());
+			for (TInt i = 0 ; i < auth->AccessDescriptions().Count() ; ++i)
+				{
+				const CX509AccessDescription* desc = auth->AccessDescriptions()[i];
+				if (desc->Method() == KAccessMethodOCSP && desc->Location().Tag() == EX509URI )
+					{
+					found = ETrue;
+					break;
+					}
+				} // end of for
+			CleanupStack::PopAndDestroy(auth);
+			}
+		return found;
+		}
+	
+	TDesC8* GetAIAL(const CX509Certificate& aCert)
+		{
+		TDesC8*	uri = NULL;
+		
+		const CX509CertExtension* ext = aCert.Extension(KAuthorityInfoAccess);
+		
+		if (ext)
+			{
+			CX509AuthInfoAccessExt* auth = CX509AuthInfoAccessExt::NewLC(ext->Data());
+			for (TInt i = 0 ; i < auth->AccessDescriptions().Count() ; ++i)
+				{
+				const CX509AccessDescription* desc = auth->AccessDescriptions()[i];
+				if (desc->Method() == KAccessMethodOCSP)
+					{
+					const CX509GeneralName& gn = desc->Location();
+					if (gn.Tag() == EX509URI)
+						{
+						// Decode the general name rather than using CX509IPBaseURI, 
+						// as this currently rejects some URIs
+						TASN1DecIA5String encStr;
+						TInt pos = 0;
+						HBufC* suri = encStr.DecodeDERL(gn.Data(), pos);
+						CleanupStack::PushL(suri);
+						HBufC8* buf = HBufC8::NewL(suri->Length());
+						uri = buf;
+						buf->Des().Copy(*suri);
+						CleanupStack::PopAndDestroy(suri);
+						break;
+						}
+					}
+				}
+			CleanupStack::PopAndDestroy(auth);
+			}
+		return uri;
+		}
+	
+	/**
+		Test whether the supplied certificate has id-kp-OCSPSigning
+		in an extendedKeyUsage extension.  This tests whether the
+		certificate is a trusted responder, as defined in RFC 2560 S4.2.2.2.
+			
+		@param	aCert			Certificate to test for id-kp-OCSPSigning.
+								This should be the certificate which was
+								immediately signed by the CA which issued
+								the certificate in question.
+		@return					ETrue iff the supplied certificate has an
+								extendedKeyUsage extension which contains
+								id-kp-OCSPSigning.
+	*/
+		
+	TBool DoesCertHaveOCSPSigningExtL(const CX509Certificate& aCert)
+		{
+		TBool found = EFalse;
+		// check has extended key usage
+		const CX509CertExtension* ekuExt = aCert.Extension(KExtendedKeyUsage);
+		if (ekuExt != NULL)
+			{	
+			// get set of extended key usages
+			const TDesC8& extData = ekuExt->Data();
+			CX509ExtendedKeyUsageExt* extUses = CX509ExtendedKeyUsageExt::NewLC(extData);
+			
+			// check if id-kp-OCSPSigning is one of the uses
+			const CArrayPtrFlat<HBufC>& usages = extUses->KeyUsages();
+			TInt usageCount = usages.Count();
+			for (TInt i = 0; i < usageCount; ++i)
+				{
+				if (*usages[i] == KOCSPOidOCSPSigning)
+					{
+					found = ETrue;
+					break;
+					}
+				}
+			CleanupStack::PopAndDestroy(extUses);
+			}
+		return found;
+		}
+	
+	
+	CX509Certificate* GetResponderCertLC(const TDesC8& aEncodedCerts)
+		{
+		// This specifies the position of the certificate which is to be retrieved from
+		// the encoded certificate chain. As responder certificate would always be the 
+		// end entity certificate, here we are retrieving the first one from the chain.
+		TInt pos = 0;
+		return CX509Certificate::NewLC(aEncodedCerts, pos);
+		}
+	} // OCSPUtils namespace