pkiutilities/ocsp/src/ocsputils.cpp
changeset 0 164170e6151a
equal deleted inserted replaced
-1:000000000000 0:164170e6151a
       
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Define generic methods which can be used accross the ocsp component.
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <asymmetrickeys.h>
       
    19 #include <ocsp.h>
       
    20 #include "oids.h"
       
    21 #include <x509certext.h>
       
    22 #include "ocsprequestandresponse.h"
       
    23 
       
    24 namespace OCSPUtils
       
    25 	{
       
    26 	/**
       
    27 		Checks whether the supplied certificate matches the responder
       
    28 		ID in the supplied response.  This implements S3.2.3 of RFC2560.
       
    29 		Note this does <em>not</em> mean the response is signed by the
       
    30 		certificate's subject.  It just checks that the certificate's
       
    31 		name, or a hash of its key, is present in the response's plaintext.
       
    32 		
       
    33 		@param	aResponse		Response whose responder ID should describe
       
    34 								<var>aCert</var>.
       
    35 		@param	aCert			Certificate whose name or key should be
       
    36 								in the response.
       
    37 		@return ETrue if the response's responder ID matches <var>aCert</var>,
       
    38 			EFalse otherwise.
       
    39 	 */
       
    40 	TBool DoesResponderIdMatchCertL( const COCSPResponse& aResponse, 
       
    41 												const CX509Certificate& aResponderCert)
       
    42 		{	
       
    43 		return (DoesIssuerKeyMatchL(aResponse,aResponderCert) || DoesDNNameMatchL(aResponse,aResponderCert));
       
    44 		}
       
    45 	
       
    46 	TBool DoesDNNameMatchL( 	const COCSPResponse& aResponse, const CX509Certificate& aCert)
       
    47 		{
       
    48 		TBool result = EFalse;
       
    49 		const TPtrC8* nameData = aResponse.DataElementEncoding(COCSPResponse::EResponderIDName);
       
    50 		if (nameData)
       
    51 			{
       
    52 			CX500DistinguishedName* name = CX500DistinguishedName::NewLC(*nameData);
       
    53 			if (aCert.SubjectName().ExactMatchL(*name))
       
    54 				{
       
    55 				result = ETrue;
       
    56 				}
       
    57 			CleanupStack::PopAndDestroy(name);
       
    58 			}
       
    59 		return result;
       
    60 		}
       
    61 	
       
    62 	TBool DoesIssuerKeyMatchL(const COCSPResponse& aResponse, const CX509Certificate& aCert)
       
    63 		{
       
    64 		TBool result = EFalse;
       
    65 		// check the responder's issuer key and verify that it is the same as the issuer cert
       
    66 		const TPtrC8* keyHash = aResponse.DataElementEncoding(COCSPResponse::EResponderIDKeyHash);
       
    67 		const TPtrC8* keyEncoding = aCert.DataElementEncoding(CX509Certificate::ESubjectPublicKeyInfo);
       
    68 		if (!keyHash || !keyEncoding)
       
    69 			{
       
    70 			return result;
       
    71 			}
       
    72 		
       
    73 		TASN1DecSequence decSeq;
       
    74 		TInt pos = 0;
       
    75 		CArrayPtrFlat<TASN1DecGeneric>* seq = decSeq.DecodeDERLC(*keyEncoding, pos, 2, KMaxTInt);
       
    76 	
       
    77 		TASN1DecBitString decBitStr;
       
    78 		HBufC8* toHashData = decBitStr.ExtractOctetStringL(*seq->At(1));
       
    79 		CleanupStack::PushL(toHashData);
       
    80 		
       
    81 		CSHA1* hashAlg = CSHA1::NewL();
       
    82 		CleanupStack::PushL(hashAlg);
       
    83 		TPtrC8 certKeyHash = hashAlg->Hash(*toHashData);
       
    84 		
       
    85 		if (certKeyHash == *keyHash)
       
    86 			{
       
    87 			// Public key hashes match
       
    88 			result = ETrue;
       
    89 			}
       
    90 		CleanupStack::PopAndDestroy(3, seq); // hashAlg, toHashData, seq
       
    91 			
       
    92 		return result;
       
    93 		}
       
    94 	
       
    95 	TBool IsResponseSignedByCertL(
       
    96 		COCSPResponse* aResponse, const CX509Certificate& aCert)
       
    97 	/**
       
    98 		Checks whether the supplied response is signed by the supplied
       
    99 		certificate.
       
   100 		
       
   101 		@param	aResponse		Response which should be signed by aCert.
       
   102 		@param	aCert			Candidate certificate which may have been
       
   103 								used to sign <var>aResponse</var>.
       
   104 		@return ETrue if <var>aCert</var> is used to sign <var>aResponse</var>,
       
   105 			EFalse otherwise.  Note <code>COCSPResponse</code> derives
       
   106 			from <code>CSignedObject</code>.
       
   107 	 */
       
   108 		{
       
   109 		if (aCert.PublicKey().AlgorithmId() == EDSA)
       
   110 			{
       
   111 			TX509KeyFactory factory;
       
   112 			CDSAParameters* theDSAParams = factory.DSAParametersL(aCert.PublicKey().EncodedParams());
       
   113 			CleanupStack::PushL(theDSAParams);
       
   114 			
       
   115 			CSigningKeyParameters* params = CSigningKeyParameters::NewLC();
       
   116 			params->SetDSAParamsL(*theDSAParams);
       
   117 					
       
   118 			aResponse->SetParametersL(*params);
       
   119 			CleanupStack::PopAndDestroy(2, theDSAParams);
       
   120 			}
       
   121 		
       
   122 		return aResponse->VerifySignatureL(aCert.PublicKey().KeyData());
       
   123 		}
       
   124 	
       
   125 	TBool DoesCertHaveOCSPNoCheckExt(const CX509Certificate& aCert)
       
   126 	/**
       
   127 		Test whether the supplied certificate has id-pkix-ocsp-nocheck
       
   128 		in an extendedKeyUsage extension.  
       
   129 		
       
   130 		@param	aCert		Certificate to test for id-kp-OCSPSigning.
       
   131 								
       
   132 		@return				ETrue if the supplied certificate has an
       
   133 							extendedKeyUsage extension which contains
       
   134 							id-pkix-ocsp-nocheck.
       
   135 	 */
       
   136 		{
       
   137 		return aCert.Extension(KOCSPOidNoCheck) != NULL;
       
   138 		}
       
   139 	
       
   140 	/**
       
   141 	 * Determine the URI of the OCSP server to use for a certificate.  Checks to see
       
   142 	 * if there is an authority info access extension containing an access
       
   143 	 * description with method oid id-ad-ocsp. If so, it copies the access
       
   144 	 * description into a new descriptor which it stores in iURI.  Otherwise it
       
   145 	 * returns iDefaultURI, which may be null.
       
   146 	 */
       
   147 	
       
   148 	TDesC8* ServerUriL(const CX509Certificate& aCert, const COCSPParameters* aParameters )
       
   149 		{
       
   150 		
       
   151 		TDesC8* uri = NULL;
       
   152 		
       
   153 		// check whether AIA is present or not:
       
   154 		// if present and UseAIA is enabled the get the AIA extension.
       
   155 		// if AIA is absent the else if part will handle it
       
   156 		// if present and UseAIA is disabled, means that iUseGlobalOCSPUri is enabled,
       
   157 		// do not leave with an error in this case the next case will handle this condition.
       
   158 		if( aParameters->UseAIA() && OCSPUtils::IsAIAForOCSPPresentL(aCert) )
       
   159 			{
       
   160 			uri = OCSPUtils::GetAIAL(aCert);
       
   161 			}
       
   162 		else if( aParameters->DefaultURI() != KNullDesC8())
       
   163 			{
       
   164 			uri = aParameters->DefaultURI().AllocL();
       
   165 			}
       
   166 		// the extension is absent and iUseGlobalOCSPUri is disabled, it has reached this case
       
   167 		// where neither is there an AIA in the cert nor is the global ocsp responder available,
       
   168 		// this should leave with EInvalidURI but this has been done to maintain backward compatibility.
       
   169 		else
       
   170 			{
       
   171 			User::Leave(KErrArgument);
       
   172 			}
       
   173 		return uri;
       
   174 		}
       
   175 	
       
   176 	// check whether AIA is present or not:
       
   177 	// if present and UseAIA is enabled then return true.
       
   178 	// if default uri is not null return true.
       
   179 	TBool IsUriAvailableL(const CX509Certificate& aCert, const COCSPParameters* aParameters )
       
   180 		{
       
   181 		return  ( aParameters->UseAIA() && OCSPUtils::IsAIAForOCSPPresentL(aCert) ) || 
       
   182 				 ( aParameters->DefaultURI() != KNullDesC8() ) ;
       
   183 		}
       
   184 	
       
   185 	TBool IsAIAForOCSPPresentL(const CX509Certificate& aCert)
       
   186 		{
       
   187 		TBool found = EFalse;
       
   188 		const CX509CertExtension* ext = aCert.Extension(KAuthorityInfoAccess);
       
   189 		
       
   190 		if(ext)
       
   191 			{
       
   192 			CX509AuthInfoAccessExt* auth = CX509AuthInfoAccessExt::NewLC(ext->Data());
       
   193 			for (TInt i = 0 ; i < auth->AccessDescriptions().Count() ; ++i)
       
   194 				{
       
   195 				const CX509AccessDescription* desc = auth->AccessDescriptions()[i];
       
   196 				if (desc->Method() == KAccessMethodOCSP && desc->Location().Tag() == EX509URI )
       
   197 					{
       
   198 					found = ETrue;
       
   199 					break;
       
   200 					}
       
   201 				} // end of for
       
   202 			CleanupStack::PopAndDestroy(auth);
       
   203 			}
       
   204 		return found;
       
   205 		}
       
   206 	
       
   207 	TDesC8* GetAIAL(const CX509Certificate& aCert)
       
   208 		{
       
   209 		TDesC8*	uri = NULL;
       
   210 		
       
   211 		const CX509CertExtension* ext = aCert.Extension(KAuthorityInfoAccess);
       
   212 		
       
   213 		if (ext)
       
   214 			{
       
   215 			CX509AuthInfoAccessExt* auth = CX509AuthInfoAccessExt::NewLC(ext->Data());
       
   216 			for (TInt i = 0 ; i < auth->AccessDescriptions().Count() ; ++i)
       
   217 				{
       
   218 				const CX509AccessDescription* desc = auth->AccessDescriptions()[i];
       
   219 				if (desc->Method() == KAccessMethodOCSP)
       
   220 					{
       
   221 					const CX509GeneralName& gn = desc->Location();
       
   222 					if (gn.Tag() == EX509URI)
       
   223 						{
       
   224 						// Decode the general name rather than using CX509IPBaseURI, 
       
   225 						// as this currently rejects some URIs
       
   226 						TASN1DecIA5String encStr;
       
   227 						TInt pos = 0;
       
   228 						HBufC* suri = encStr.DecodeDERL(gn.Data(), pos);
       
   229 						CleanupStack::PushL(suri);
       
   230 						HBufC8* buf = HBufC8::NewL(suri->Length());
       
   231 						uri = buf;
       
   232 						buf->Des().Copy(*suri);
       
   233 						CleanupStack::PopAndDestroy(suri);
       
   234 						break;
       
   235 						}
       
   236 					}
       
   237 				}
       
   238 			CleanupStack::PopAndDestroy(auth);
       
   239 			}
       
   240 		return uri;
       
   241 		}
       
   242 	
       
   243 	/**
       
   244 		Test whether the supplied certificate has id-kp-OCSPSigning
       
   245 		in an extendedKeyUsage extension.  This tests whether the
       
   246 		certificate is a trusted responder, as defined in RFC 2560 S4.2.2.2.
       
   247 			
       
   248 		@param	aCert			Certificate to test for id-kp-OCSPSigning.
       
   249 								This should be the certificate which was
       
   250 								immediately signed by the CA which issued
       
   251 								the certificate in question.
       
   252 		@return					ETrue iff the supplied certificate has an
       
   253 								extendedKeyUsage extension which contains
       
   254 								id-kp-OCSPSigning.
       
   255 	*/
       
   256 		
       
   257 	TBool DoesCertHaveOCSPSigningExtL(const CX509Certificate& aCert)
       
   258 		{
       
   259 		TBool found = EFalse;
       
   260 		// check has extended key usage
       
   261 		const CX509CertExtension* ekuExt = aCert.Extension(KExtendedKeyUsage);
       
   262 		if (ekuExt != NULL)
       
   263 			{	
       
   264 			// get set of extended key usages
       
   265 			const TDesC8& extData = ekuExt->Data();
       
   266 			CX509ExtendedKeyUsageExt* extUses = CX509ExtendedKeyUsageExt::NewLC(extData);
       
   267 			
       
   268 			// check if id-kp-OCSPSigning is one of the uses
       
   269 			const CArrayPtrFlat<HBufC>& usages = extUses->KeyUsages();
       
   270 			TInt usageCount = usages.Count();
       
   271 			for (TInt i = 0; i < usageCount; ++i)
       
   272 				{
       
   273 				if (*usages[i] == KOCSPOidOCSPSigning)
       
   274 					{
       
   275 					found = ETrue;
       
   276 					break;
       
   277 					}
       
   278 				}
       
   279 			CleanupStack::PopAndDestroy(extUses);
       
   280 			}
       
   281 		return found;
       
   282 		}
       
   283 	
       
   284 	
       
   285 	CX509Certificate* GetResponderCertLC(const TDesC8& aEncodedCerts)
       
   286 		{
       
   287 		// This specifies the position of the certificate which is to be retrieved from
       
   288 		// the encoded certificate chain. As responder certificate would always be the 
       
   289 		// end entity certificate, here we are retrieving the first one from the chain.
       
   290 		TInt pos = 0;
       
   291 		return CX509Certificate::NewLC(aEncodedCerts, pos);
       
   292 		}
       
   293 	} // OCSPUtils namespace