diff -r 000000000000 -r 164170e6151a pkiutilities/ocsp/src/ocsputils.cpp --- /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 +#include +#include "oids.h" +#include +#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 not 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 + aCert. + @param aCert Certificate whose name or key should be + in the response. + @return ETrue if the response's responder ID matches aCert, + 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* 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 aResponse. + @return ETrue if aCert is used to sign aResponse, + EFalse otherwise. Note COCSPResponse derives + from CSignedObject. + */ + { + 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& 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