diff -r 000000000000 -r 95b198f216e5 omadrm/drmengine/roapstorage/src/responsedecoder.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omadrm/drmengine/roapstorage/src/responsedecoder.cpp Thu Dec 17 08:52:27 2009 +0200 @@ -0,0 +1,428 @@ +/* +* Copyright (c) 2002-2008 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: OCSP response decoder for given response +* +*/ + + +#include "responsedecoder.h" +#include "oids.h" +#include "RoapOcsp.h" +#include +#include + +// Enum values in DER encoding of response status +enum + { + ESuccessfulEncoding = 0, + EMalformedRequestEncoding = 1, + EInternalErrorEncoding = 2, + ETryLaterEncoding = 3, + ESigRequiredEncoding = 5, + EUnauthorisedEncoding = 6 + }; + + +// Tag values in DER encoded response data +const TUint KResponseBytesTag = 0; +const TUint KCertificatesTag = 0; +const TUint KVersionTag = 0; +const TUint KResponderIDNameTag = 1; +const TUint KReponsderIDKeyHashTag = 2; +const TUint KResponseExtensionsTag = 1; + + +COCSPResponseDecoder* COCSPResponseDecoder::NewL(const TDesC8& aEncoding) + { + COCSPResponseDecoder* self = new (ELeave) COCSPResponseDecoder; + CleanupStack::PushL(self); + self->ConstructL(aEncoding); + CleanupStack::Pop(self); + return self; + } + + +COCSPResponseDecoder::COCSPResponseDecoder() + { + } + + +COCSPResponseDecoder::~COCSPResponseDecoder() + { + delete iResponse; + } + + +void COCSPResponseDecoder::ConstructL(const TDesC8& aEncoding) + { + iResponse = new (ELeave) COCSPResponse; + + // Populate CSignedObject data members + iResponse->iKeyFactory = new (ELeave) TX509KeyFactory; // Unconventional class name + iResponse->iEncoding = aEncoding.AllocL(); + + TRAPD(error, DecodeOCSPResponseL(*iResponse->iEncoding)); + if (error == KErrArgument || error == KErrNotSupported) + { + // These arise from problems parsing the data in X509 or ASN1 + error = OCSP::EMalformedResponse; + } + + if (error != KErrNone) + { + // Errors and our status codes go back to the client + delete iResponse; + iResponse = NULL; + User::Leave(error); + } + } + + +COCSPResponse* COCSPResponseDecoder::TakeResponse() + { + COCSPResponse* result = iResponse; + iResponse = NULL; + return result; + } + + +CArrayPtr* COCSPResponseDecoder::DecodeSequenceLC(const TDesC8& aEncoding) + { + CArrayPtr* items = NULL; + + // Check we've got a sequence + TASN1DecGeneric decGen(aEncoding); + decGen.InitL(); + if (decGen.Tag() != EASN1Sequence) + { + User::Leave(KErrArgument); + } + else + { + // Decode the sequence + TASN1DecSequence decSeq; + items = decSeq.DecodeDERLC(decGen); + } + return items; + } + + +CArrayPtr* COCSPResponseDecoder::DecodeSequenceLC(const TDesC8& aEncoding, + const TInt aMinTerms, + const TInt aMaxTerms) + { + CArrayPtr* items = DecodeSequenceLC(aEncoding); + TInt count = items->Count(); + if (count < aMinTerms || count > aMaxTerms) + { + // User::Leave(KErrArgument); + } + + return items; + } + + +void COCSPResponseDecoder::DecodeOCSPResponseL(const TDesC8& aEncoding) + { + CArrayPtr* items = DecodeSequenceLC(aEncoding, 1, 2); + + // Use integer decoding for enumerated + TASN1DecInteger decInt; + TInt status = decInt.DecodeDERShortL(*items->At(0)); + if (status == ESuccessfulEncoding) + { + if (items->Count() != 2) + { + User::Leave(OCSP::EMalformedResponse); + } + + // Check tag on second part is [0] + // We ignore any other parts in the sequence after that + TASN1DecGeneric& responseBytesDec = *items->At(1); + if (responseBytesDec.Tag() != KResponseBytesTag) + { + User::Leave(OCSP::EMalformedResponse); + } + + // It's OK, so decode the response bytes object therein + DecodeResponseBytesL(responseBytesDec.GetContentDER()); + } + else + { + if (items->Count() != 1) + { + User::Leave(KErrArgument); + } + + switch (status) + { + case EMalformedRequestEncoding: + User::Leave(OCSP::EMalformedRequest); + case EInternalErrorEncoding: + User::Leave(OCSP::EServerInternalError); + break; + case ETryLaterEncoding: + User::Leave(OCSP::ETryLater); + break; + case ESigRequiredEncoding: + User::Leave(OCSP::ESignatureRequired); + break; + case EUnauthorisedEncoding: + User::Leave(OCSP::EClientUnauthorised); + break; + default: + User::Leave(OCSP::EMalformedResponse); + } + } + CleanupStack::PopAndDestroy(items); + } + + +void COCSPResponseDecoder::DecodeResponseBytesL(const TDesC8& aEncoding) + { + CArrayPtr* items = DecodeSequenceLC(aEncoding, 2, 2); + + TASN1DecObjectIdentifier decOid; + HBufC* oid = decOid.DecodeDERL(*items->At(0)); + CleanupStack::PushL(oid); + if (*oid != KOCSPOidBasic) + { + User::Leave(OCSP::EUnknownResponseType); + } + + TASN1DecGeneric& response = *items->At(1); + if (response.Tag() != EASN1OctetString) + { + User::Leave(OCSP::EMalformedResponse); + } + + DecodeBasicOCSPResponseL(response.GetContentDER()); + + CleanupStack::PopAndDestroy(2, items); // oid, items + } + + +void COCSPResponseDecoder::DecodeBasicOCSPResponseL(const TDesC8& aEncoding) + { + CArrayPtr* items = DecodeSequenceLC(aEncoding, 3, 4); + + // First, the ResponseData object + DecodeResponseDataL(items->At(0)->Encoding()); + + // Continue, with the AlgorithmIdentifier + iResponse->iSigningAlgorithm = CX509SigningAlgorithmIdentifier::NewL(items->At(1)->Encoding()); + + // Now move on to the signature + TASN1DecBitString encBS; + iResponse->iSignature = encBS.ExtractOctetStringL(*items->At(2)); + + // And finally, the certs (if they're there) + if (items->Count() == 4) + { + // Check explicit tag [0] + TASN1DecGeneric& certsDec = *items->At(3); + if (certsDec.Tag() != KCertificatesTag) + { + User::Leave(OCSP::EMalformedResponse); + } + + // It's OK, so decode the response bytes object therein + DecodeCertificatesL(certsDec.GetContentDER()); + } + + CleanupStack::PopAndDestroy(items); + } + + +void COCSPResponseDecoder::DecodeCertificatesL(const TDesC8& aEncoding) + { + TASN1DecGeneric dec(aEncoding); + dec.InitL(); + if (dec.Tag() != EASN1Sequence) + { + User::Leave(OCSP::EMalformedResponse); + } + + // Just stores a reference to the encoding + iResponse->iSigningCerts.Set(dec.GetContentDER()); + } + + +void COCSPResponseDecoder::DecodeResponseDataL(const TDesC8& aEncoding) + { + TInt index = 0; + + // This is the signed data + iResponse->iSignedData.Set(aEncoding); + + // Exclude 5 items in sequence - defaulted version v1 shouldn't appear in DER + CArrayPtr* items = DecodeSequenceLC(aEncoding, 3, 4); + + // First item is responderID choice, or maybe version + TASN1DecGeneric& item0 = *items->At(index); // index = 0 + + ++index; + + switch (item0.Tag()) + { + case KResponderIDNameTag: + // Set to Name DER encoding + iResponse->iResponderIDName.Set(item0.GetContentDER()); + break; + case KReponsderIDKeyHashTag: + { + // Set to KeyHash to value within the octet string + TASN1DecGeneric decGen(item0.GetContentDER()); + decGen.InitL(); + iResponse->iResponderIDKeyHash.Set(decGen.GetContentDER()); + break; + } + case KVersionTag: + { + // skip the version, the next one should be responderID + TASN1DecGeneric item1 = *items->At(index); // index = 1 + ++index; + if (item1.Tag() == KResponderIDNameTag) + { + iResponse->iResponderIDName.Set(item1.GetContentDER()); + break; + } + else if (item1.Tag() == KReponsderIDKeyHashTag) + { + TASN1DecGeneric decGen(item1.GetContentDER()); + decGen.InitL(); + iResponse->iResponderIDKeyHash.Set(decGen.GetContentDER()); + break; + } + else + { + // falling through... + } + } + default: + User::Leave(OCSP::EMalformedResponse); + } + + + // ProducedAt is a GeneralizedTime + TASN1DecGeneralizedTime decGT; + iResponse->iProducedAt = decGT.DecodeDERL(*items->At(index)); // index = 1 | 2 + ++index; + + // Now the responses themselves + DecodeResponsesL(items->At(index)->Encoding()); // index = 2 | 3 + ++index; + + // Continue if extensions exist + if (items->Count() == index + 1) // index = 3 | 4 + { + // Check tag on responseExtensions + TASN1DecGeneric& item3 = *items->At(index); + if (item3.Tag() != KResponseExtensionsTag) + { + User::Leave(OCSP::EMalformedResponse); + } + + DecodeResponseExtensionsL(item3.GetContentDER()); + } + CleanupStack::PopAndDestroy(items); + } + + +void COCSPResponseDecoder::DecodeResponseExtensionsL(const TDesC8& aEncoding) + { + CArrayPtr* items = DecodeSequenceLC(aEncoding); + TInt count = items->Count(); + for (TInt index = 0; index < count; ++index) + { + DecodeResponseExtensionL(items->At(index)->Encoding()); + } + + CleanupStack::PopAndDestroy(items); + } + + +void COCSPResponseDecoder::DecodeResponseExtensionL(const TDesC8& aEncoding) + { + CArrayPtr* items = DecodeSequenceLC(aEncoding, 2, 3); + + // Get oid + TASN1DecGeneric& oid = *items->At(0); + if (oid.Tag() != EASN1ObjectIdentifier) + { + User::Leave(OCSP::EMalformedResponse); + } + + TASN1DecObjectIdentifier oidDec; + HBufC* oidVal = oidDec.DecodeDERL(oid); + CleanupStack::PushL(oidVal); + + TBool critical = EFalse; // Default value of critical flag + if (items->Count() == 3) + { + // The critical flag is specified - what does it say? + TASN1DecBoolean decBool; + critical = decBool.DecodeDERL(*items->At(1)); + } + + TASN1DecGeneric& extnVal = items->Count() == 3 ? *items->At(2) : *items->At(1); + if (extnVal.Tag() != EASN1OctetString) + { + User::Leave(OCSP::EMalformedResponse); + } + + // Check oid to decide what to do + if (*oidVal == KOCSPOidNonce) + { + iResponse->iNonce.Set(extnVal.GetContentDER()); + } + else if (*oidVal == KOCSPOidArchiveCutoff) + { + TASN1DecGeneralizedTime decGT; + TInt pos = 0; + iResponse->iArchiveCutoff = new (ELeave) TTime(decGT.DecodeDERL(extnVal.GetContentDER(), pos)); + } + else if (critical) + { + // Didn't understand extension, and it was critical! Erk! + User::Leave(OCSP::EUnknownCriticalExtension); + } + + CleanupStack::PopAndDestroy(2, items); // oidVal, items + } + + +void COCSPResponseDecoder::DecodeResponsesL(const TDesC8& aEncoding) + { + CArrayPtr* items = DecodeSequenceLC(aEncoding); + TInt count = items->Count(); + for (TInt index = 0; index < count; ++index) + { + DecodeSingleResponseL(items->At(index)->Encoding()); + } + + CleanupStack::PopAndDestroy(items); + } + + +void COCSPResponseDecoder::DecodeSingleResponseL(const TDesC8& aEncoding) + { + CArrayPtr* items = DecodeSequenceLC(aEncoding, 3, 5); + + COCSPResponseCertInfo* response = COCSPResponseCertInfo::NewLC(*items); + User::LeaveIfError(iResponse->iCertInfos.Append(response)); + CleanupStack::Pop(response); // Now owned through iSingleResponses + + CleanupStack::PopAndDestroy(items); + }