omadrm/drmengine/ro/src/DrmProtectedRoParser.cpp
changeset 0 95b198f216e5
child 12 8a03a285ab14
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omadrm/drmengine/ro/src/DrmProtectedRoParser.cpp	Thu Dec 17 08:52:27 2009 +0200
@@ -0,0 +1,1297 @@
+/*
+* Copyright (c) 2005 - 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:  Implementation of a parser for protected OMA DRM rights
+ *
+*/
+
+
+// INCLUDE FILES
+#include <e32base.h>
+#include <e32math.h>
+#include <apmstd.h>
+#include <utf.h>
+#include <stringpool.h>
+#include <xml/ParserFeature.h>
+
+#ifdef _DEBUG
+#include <flogger.h>
+#endif // _DEBUG
+#include "base64.h"
+#include "DcfCommon.h"
+#include "DrmRightsParser.h"
+#include "DrmProtectedRoParser.h"
+#include "DrmRightsClient.h"
+#include "hash.h"
+#include "DRMCommon.h"
+#include "OmaCrypto.h"
+#include "CmlaCrypto.h"
+#include "DrmPermission.h"
+#include "RoapMessage.h"
+#include "DcfRep.h"
+#include "DcfEntry.h"
+#include "Oma2Dcf.h"
+
+using namespace Roap;
+using namespace Xml;
+
+// MODULE DATA STRUCTURES
+NONSHARABLE_CLASS(CDrmProtectedRoParser::CParsedProtectedRo): public CBase
+    {
+public:
+    static CParsedProtectedRo* NewL();
+    ~CParsedProtectedRo();
+
+protected:
+    CParsedProtectedRo();
+
+public:
+    TKeyTransportScheme iTransportScheme;
+    HBufC8* iKey;
+    TBool iDomainRo;
+    HBufC8* iId;
+    HBufC8* iRiUrl;
+    HBufC8* iDomainId;
+    HBufC8* iRightsIssuerId;
+    TTime iTimeStamp;
+    HBufC8* iMac;
+    HBufC8* iMacDigest;
+    };
+
+enum TElementEnum
+    {
+    EProtectedRo = 0,
+    ERo,
+    EDomainRo,
+    EId,
+    EStateful,
+    EVersion,
+    ERiId,
+    EKeyIdentifier,
+    EHash,
+    ETimeStamp,
+    EEncKey,
+    EEncryptionMethod,
+    EKeyInfo,
+    EX509SPKIHash,
+    ECipherData,
+    ECipherValue,
+    EMac,
+    ESignedInfo,
+    ECanonicalizationMethod,
+    ESignatureMethod,
+    EReference,
+    EDigestMethod,
+    EDigestValue,
+    ESignatureValue,
+    ERetreivalMethod,
+    ERoapDomainId,
+    EDomainIdentifier,
+    ERoapDomainIdentifier,
+    ERoResponse,
+    ELast,
+    };
+
+enum TParserStackState
+    {
+    ERoState,
+    ECipherValueState,
+    EDomainIdentifierState,
+    EEncryptionMethodState,
+    ERightsIssuerIdState,
+    ETimeStampState,
+    EMacValueState,
+    EMacDigestValueState,
+    EUnknownState = -1,
+    };
+
+struct TElements
+    {
+    const TText8* iString;
+    TInt iNumber;
+    };
+
+// MACROS
+#define ELEMENT_COUNT(x) static_cast<TInt>((sizeof(x) / sizeof (x[0])))
+
+#ifdef _DEBUG
+_LIT(KParseLogDir, "DRM");
+_LIT(KParseLogFile, "Parse.log");
+#define DEBUGLOG( a ) { _LIT(KDebugString, a); RFileLogger::Write( KParseLogDir(), KParseLogFile(), EFileLoggingModeAppend, KDebugString() ); }
+#define DEBUGLOGHEX( ptr, len ) RFileLogger::HexDump( KParseLogDir(), KParseLogFile(), EFileLoggingModeAppend, _S(""), _S(""), ptr, len );
+#else
+#define DEBUGLOG( a )
+#define DEBUGLOGHEX( ptr, len )
+#endif // _DEBUG
+
+// LOCAL CONSTANTS AND MACROS
+const TInt KParserChunkSize = 512;
+const TInt KMaxElementNesting = 24;
+const TInt KMaxElementLen = 80;
+
+_LIT8(KXmlParserMimeType, "text/xml");
+_LIT8(KIdAttr, "id");
+_LIT8(KDomainRoAttr, "domainRO");
+_LIT8(KRiUrlAttr, "riURL");
+_LIT8(KAlgorithmAttr, "Algorithm");
+_LIT8(KProtectedRoElement, "protectedRO");
+_LIT8(KRoapPrefix, "roap:");
+_LIT8(KStartElementStart, "<");
+_LIT8(KEndElementStart, "</");
+_LIT8(KRoElement, "roap:ro");
+_LIT8( KElementEnd, ">" );
+_LIT8(KQualifiedProtectedRo, "roap:protectedRO");
+_LIT8(KSignedInfoElement, "ds:SignedInfo");
+_LIT8(KRoapXmlNs, " xmlns:roap=\"urn:oma:bac:dldrm:roap-1.0\"");
+_LIT8(KRoapXmlNsUri, "urn:oma:bac:dldrm:roap-1.0");
+_LIT8(KMacStart, "<mac");
+
+static const TElements KElements[] =
+    {
+        {
+        _S8("roResponse"), ERoResponse
+        },
+        {
+        _S8("protectedRo"), EProtectedRo
+        },
+        {
+        _S8("ro"), ERo
+        },
+        {
+        _S8("domainRo"), EDomainRo
+        },
+        {
+        _S8("id"), EId
+        },
+        {
+        _S8("stateful"), EStateful
+        },
+        {
+        _S8("version"), EVersion
+        },
+        {
+        _S8("riID"), ERiId
+        },
+        {
+        _S8("keyIdentifier"), EKeyIdentifier
+        },
+        {
+        _S8("hash"), EHash
+        },
+        {
+        _S8("timeStamp"), ETimeStamp
+        },
+        {
+        _S8("encKey"), EEncKey
+        },
+        {
+        _S8("EncryptionMethod"), EEncryptionMethod
+        },
+        {
+        _S8("KeyInfo"), EKeyInfo
+        },
+        {
+        _S8("roap:X509SPKIHash"), EX509SPKIHash
+        },
+        {
+        _S8("CipherData"), ECipherData
+        },
+        {
+        _S8("CipherValue"), ECipherValue
+        },
+        {
+        _S8("mac"), EMac
+        },
+        {
+        _S8("SignedInfo"), ESignedInfo
+        },
+        {
+        _S8("CanonicalizationMethod"), ECanonicalizationMethod
+        },
+        {
+        _S8("SignatureMethod"), ESignatureMethod
+        },
+        {
+        _S8("Reference"), EReference
+        },
+        {
+        _S8("DigestMethod"), EDigestMethod
+        },
+        {
+        _S8("DigestValue"), EDigestValue
+        },
+        {
+        _S8("SignatureValue"), ESignatureValue
+        },
+        {
+        _S8("RetreivalMethod"), ERetreivalMethod
+        },
+        {
+        _S8("domainID"), ERoapDomainId
+        },
+        {
+        _S8("DomainIdentifier"), EDomainIdentifier
+        },
+        {
+        _S8("roap:DomainIdentifier"), ERoapDomainIdentifier
+        }
+    };
+
+struct TStackState
+    {
+    TParserStackState iState;
+    TElementEnum iStack[KMaxElementNesting];
+    };
+
+static const TStackState KParserStackStates[] =
+    {
+        {
+        ERightsIssuerIdState,
+            {
+            EHash, EKeyIdentifier, ERiId, ERo, ELast
+            }
+        },
+        {
+        EDomainIdentifierState,
+            {
+            ERoapDomainId, EKeyInfo, EEncKey, ERo, ELast
+            }
+        },
+        {
+        EDomainIdentifierState,
+            {
+            EDomainIdentifier, EKeyInfo, EEncKey, ERo, ELast
+            }
+        },
+        {
+        EDomainIdentifierState,
+            {
+            ERoapDomainIdentifier, EKeyInfo, EEncKey, ERo, ELast
+            }
+        },
+        {
+        ECipherValueState,
+            {
+            ECipherValue, ECipherData, EEncKey, ERo, ELast
+            }
+        },
+        {
+        EEncryptionMethodState,
+            {
+            EEncryptionMethod, EEncKey, ERo, ELast
+            }
+        },
+        {
+        ETimeStampState,
+            {
+            ETimeStamp, ERo, ELast
+            }
+        },
+        {
+        EMacValueState,
+            {
+            ESignatureValue, EMac, ELast
+            }
+        },
+        {
+        EMacDigestValueState,
+            {
+            EDigestValue, EReference, ESignedInfo, EMac, ELast
+            }
+        },
+        {
+        ERoState,
+            {
+            ERo, ELast
+            }
+        }
+    };
+
+// LOCAL FUNCTION PROTOTYPES
+TTime Iso8601ToTime(TDesC8& aTimeString);
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// Iso8601ToTime
+// -----------------------------------------------------------------------------
+//
+TTime Iso8601ToTime(TDesC8& aTimeString)
+    {
+    TLex8 lex;
+    TInt year = 0;
+    TInt month = 0;
+    TInt day = 0;
+    TInt hour = 0;
+    TInt minute = 0;
+    TInt second = 0;
+    TTime r = Time::NullTTime();
+    TLocale l;
+    TTimeIntervalSeconds offset(l.UniversalTimeOffset());
+
+    if (aTimeString.Length() > 0)
+        {
+        lex = aTimeString;
+        lex.Val(year);
+        lex.Inc();
+        lex.Val(month);
+        lex.Inc();
+        lex.Val(day);
+        lex.Inc();
+        lex.Val(hour);
+        lex.Inc();
+        lex.Val(minute);
+        lex.Inc();
+        lex.Val(second);
+        r = TTime(TDateTime(year, static_cast<TMonth>(month - 1), day - 1,
+                hour, minute, second, 0));
+        if (lex.Get() != 'Z')
+            {
+            r += offset;
+            }
+        }
+    return r;
+    }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRo::NewL
+// Allocate a new protected RO object
+// -----------------------------------------------------------------------------
+//
+CDrmProtectedRoParser::CParsedProtectedRo* CDrmProtectedRoParser::CParsedProtectedRo::NewL()
+    {
+    CParsedProtectedRo* self = new(ELeave) CParsedProtectedRo;
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CParsedProtectedRo::~CParsedProtectedRo
+// Release all data
+// -----------------------------------------------------------------------------
+//
+CDrmProtectedRoParser::CParsedProtectedRo::~CParsedProtectedRo()
+    {
+    delete iKey;
+    delete iId;
+    delete iRiUrl;
+    delete iDomainId;
+    delete iRightsIssuerId;
+    delete iMac;
+    delete iMacDigest;
+    }
+
+// -----------------------------------------------------------------------------
+// CParsedProtectedRo::CParsedProtectedRo
+// Initialize all member data
+// -----------------------------------------------------------------------------
+//
+CDrmProtectedRoParser::CParsedProtectedRo::CParsedProtectedRo() :
+    iTransportScheme(EOma), iKey(NULL), iDomainRo(EFalse), iId(NULL),
+            iRiUrl(NULL), iDomainId(NULL), iRightsIssuerId(NULL), iMac(NULL)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::CDrmProtectedRoParser
+// Reset all member variables
+// -----------------------------------------------------------------------------
+//
+CDrmProtectedRoParser::CDrmProtectedRoParser() :
+    iParser(NULL), iRights(NULL), iContent(NULL)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::ConstructL
+// Initialize the string pool elements
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::ConstructL()
+    {
+    iParser = CParser::NewL(KXmlParserMimeType, *this);
+    for (TInt i = 0; i < ELEMENT_COUNT(KElements); i++)
+        {
+        TPtrC8 ptr(KElements[i].iString,
+                User::StringLength(KElements[i].iString));
+        iElements[KElements[i].iNumber] = iParser->StringPool().OpenStringL(ptr);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CDrmProtectedRoParser* CDrmProtectedRoParser::NewL()
+    {
+    CDrmProtectedRoParser* self = new(ELeave) CDrmProtectedRoParser;
+
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::~CDrmProtectedRoParser
+// Release the allocated strings
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CDrmProtectedRoParser::~CDrmProtectedRoParser()
+    {
+    for (TInt i = 0; i < ELEMENT_COUNT(KElements); i++)
+        {
+        iElements[KElements[i].iNumber].Close();
+        }
+    delete iParser;
+    delete iRights;
+    delete iContent;
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::ParseL
+// Parses one <protectedRo> element
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::ParseL(const TDesC8& aProtectedRo,
+        CParsedProtectedRo*& aResultRights)
+    {
+    TInt i( 0 );
+
+    iElementStackDepth = 0;
+    delete iRights;
+    delete iContent;
+    iContent = NULL;
+    iRights = NULL;
+    iRights = CParsedProtectedRo::NewL();
+    iParser->ParseBeginL();
+
+    i = aProtectedRo.Find( KRoapXmlNsUri );
+
+    if ( i == KErrNotFound )
+        {
+        // Feed in the ROAP XML namespace declaration
+        i = aProtectedRo.Find(KProtectedRoElement);
+        if ( i == KErrNotFound )
+            {
+            User::Leave(KErrCorrupt);
+            }
+        i += KProtectedRoElement().Length();
+        iParser->ParseL( aProtectedRo.Left( i ) );
+        iParser->ParseL( KRoapXmlNs() );
+        }
+    else
+        {
+        i = 0;
+        }
+
+    while ( i < aProtectedRo.Length() )
+        {
+        TInt n( Min( aProtectedRo.Length() - i, KParserChunkSize ) );
+        iParser->ParseL( aProtectedRo.Mid( i, n ) );
+        i += n;
+        }
+    iParser->ParseEndL();
+    aResultRights = iRights;
+    iRights = NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::GetRiUrlL
+// Parse the RO and return the RI URL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C HBufC8* CDrmProtectedRoParser::GetRiUrlL(
+        const TDesC8& aProtectedRo)
+    {
+    TInt i( 0 );
+    HBufC8* r( NULL );
+
+    iElementStackDepth = 0;
+    delete iRights;
+    delete iContent;
+    iRights = NULL;
+    iContent = NULL;
+    iRights = CParsedProtectedRo::NewL();
+    iParser->ParseBeginL();
+    while (i < aProtectedRo.Length())
+        {
+        TInt n( Min( aProtectedRo.Length() - i, KParserChunkSize ) );
+        iParser->ParseL( aProtectedRo.Mid( i, n ) );
+        i += n;
+        }
+    iParser->ParseEndL();
+    if ( iRights->iRiUrl )
+        {
+        r = iRights->iRiUrl->AllocL();
+        }
+    delete iRights;
+    iRights = NULL;
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::GetRiUrlL
+// Parse the RO and return the RI ID
+// -----------------------------------------------------------------------------
+//
+EXPORT_C HBufC8* CDrmProtectedRoParser::GetRiIdL(
+        const TDesC8& aProtectedRo)
+    {
+    HBufC8* r = NULL;
+
+    iElementStackDepth = 0;
+    delete iRights;
+    delete iContent;
+    iRights = NULL;
+    iContent = NULL;
+    iRights = CParsedProtectedRo::NewL();
+    iParser->ParseBeginL();
+    TInt i( 0 );
+    while (i < aProtectedRo.Length())
+        {
+        TInt n( Min( aProtectedRo.Length() - i, KParserChunkSize ) );
+        iParser->ParseL(aProtectedRo.Mid(i, n));
+        i += n;
+        }
+    iParser->ParseEndL();
+    if ( iRights->iRightsIssuerId )
+        {
+        r = iRights->iRightsIssuerId->AllocL();
+        }
+    delete iRights;
+    iRights = NULL;
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::GetDomainIdL
+// Parse the RO and return the domain ID
+// -----------------------------------------------------------------------------
+//
+EXPORT_C HBufC8* CDrmProtectedRoParser::GetDomainIdL(
+        const TDesC8& aProtectedRo)
+    {
+    HBufC8* r = NULL;
+
+    iElementStackDepth = 0;
+    delete iRights;
+    iRights = NULL;
+    delete iContent;
+    iContent = NULL;
+    iRights = CParsedProtectedRo::NewL();
+    iParser->ParseBeginL();
+    TInt i( 0 );
+    while (i < aProtectedRo.Length())
+        {
+        TInt n( Min(aProtectedRo.Length() - i, KParserChunkSize) );
+        iParser->ParseL(aProtectedRo.Mid(i, n));
+        i += n;
+        }
+    iParser->ParseEndL();
+    if ( iRights->iDomainId )
+        {
+        r = iRights->iDomainId->AllocL();
+        }
+    delete iRights;
+    iRights = NULL;
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::ParseAndStoreL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CDrmProtectedRoParser::ParseAndStoreL(
+        const TDesC8& aRightsObject,
+        RPointerArray<CDRMRights>& aResultRights)
+    {
+    RDRMRightsClient client;
+    CDrmRightsParser* parser = NULL;
+    CDRMRights* rights = NULL;
+    CParsedProtectedRo* parsedRo = NULL;
+    TDRMUniqueID id = 0;
+    HBufC8 *cid = NULL;
+    TPtr8 ptr(0, 0);
+    TBool domain = EFalse;
+    TPtrC8 riId(0, 0);
+    TInt start = 0;
+    TInt end = 0;
+    TInt roStart = 0;
+    TInt roEnd = 0;
+    TInt signedInfoStart = 0;
+    TInt signedInfoEnd = 0;
+    TInt n( 0 );
+    TInt r( 0 );
+    TBool inCache = EFalse;
+    CSHA1* sha1 = NULL;
+    TBool integrityCheck = ETrue;
+    HBufC8* roWithNs = NULL;
+    TPtr8 roWithNsPtr(NULL, NULL);
+
+    User::LeaveIfError(client.Connect());
+    CleanupClosePushL(client);
+
+    // Loop through the complete roResponse and find all embedded protected
+    // rights objects
+    while (GetElementStartEnd(KProtectedRoElement, aRightsObject, start, end))
+        {
+        TPtrC8 protectedRo = aRightsObject.Mid(start, end - start);
+        if (GetElementStartEnd(KRoElement, protectedRo, roStart, roEnd) == EFalse)
+            {
+            User::Leave(KErrCorrupt);
+            }
+        TPtrC8 ro = protectedRo.Mid(roStart, roEnd - roStart);
+
+        ParseL(protectedRo, parsedRo);
+        User::LeaveIfNull(parsedRo);
+        CleanupStack::PushL(parsedRo);
+
+        parser = CDrmRightsParser::NewL();
+        CleanupStack::PushL(parser);
+        parser->ParseL(protectedRo, aResultRights);
+        CleanupStack::PopAndDestroy( parser );
+
+        //////////////////////////
+        // Replay protection
+        //////////////////////////
+
+        if (parsedRo->iTimeStamp == Time::NullTTime())
+            {
+            User::LeaveIfError(client.IsInCache(*parsedRo->iId, inCache));
+            if (inCache)
+                {
+                User::Leave(KErrAlreadyExists);
+                }
+            }
+        else
+            {
+            User::LeaveIfError(client.IsInCache(*parsedRo->iId, parsedRo->iTimeStamp, inCache));
+            if (inCache)
+                {
+                User::Leave(KErrAlreadyExists);
+                }
+            }
+
+        ///////////////////////////////////////////////////////
+        // Unwrap MAC and REK
+        // The plain keys are stored on the server side session
+        ///////////////////////////////////////////////////////
+        if (parsedRo->iDomainRo)
+            {
+            User::LeaveIfError( client.UnwrapMacAndRek(*parsedRo->iKey,
+                            parsedRo->iTransportScheme,
+                            *parsedRo->iRightsIssuerId,
+                            *parsedRo->iDomainId) );
+            }
+        else
+            {
+            User::LeaveIfError( client.UnwrapMacAndRek(*parsedRo->iKey,
+                            parsedRo->iTransportScheme,
+                            *parsedRo->iRightsIssuerId,
+                            KNullDesC8) );
+            }
+
+        //////////////////////////
+        // Validate digest and MAC
+        //////////////////////////
+        roWithNs = AddRoapNamespaceL(ro);
+        if (roWithNs)
+            {
+            CleanupStack::PushL(roWithNs);
+            roWithNsPtr.Set(roWithNs->Des());
+            }
+
+        // Validate RO digest
+        sha1 = CSHA1::NewL();
+        if (roWithNs)
+            {
+            DEBUGLOGHEX( roWithNsPtr.Ptr(), roWithNsPtr.Length() );
+            sha1->Update(roWithNsPtr);
+            CleanupStack::PopAndDestroy(roWithNs);
+            }
+        else
+            {
+            DEBUGLOGHEX( ro.Ptr(), ro.Length() );
+            sha1->Update(ro);
+            }
+
+        CleanupStack::PushL(sha1);
+        HBufC8* calculatedHash( sha1->Final().AllocL() );
+        CleanupStack::PopAndDestroy( sha1 );
+        sha1 = NULL;
+        CleanupStack::PushL( calculatedHash );
+
+        if (calculatedHash->Compare(*parsedRo->iMacDigest) == KErrNone)
+            {
+            // Digest OK -> now verify the MAC
+            signedInfoStart = protectedRo.Find(KMacStart());
+
+            if (signedInfoStart < KErrNone)
+                {
+                integrityCheck = EFalse;
+                r = KErrCorrupt;
+                }
+
+            if (integrityCheck && GetElementStartEnd(KSignedInfoElement, protectedRo, signedInfoStart, signedInfoEnd) == EFalse)
+                {
+                integrityCheck = EFalse;
+                r = KErrCorrupt;
+                }
+
+            if(integrityCheck)
+                {
+                TPtrC8 signedInfo = protectedRo.Mid(signedInfoStart, signedInfoEnd - signedInfoStart);
+                r = client.VerifyMacL(signedInfo, *parsedRo->iMac);
+
+                if (r == KErrNone)
+                    {
+                    // MAC validation OK
+                    // If we parsed a domain RO, store it in its original form as well
+                    if (parsedRo->iDomainRo)
+                        {
+                        HBufC8* protRoWithNs = NULL;
+                        protRoWithNs = AddRoapNamespaceL(protectedRo);
+                        if(protRoWithNs)
+                            {
+                            client.AddDomainRO(*parsedRo->iId, *protRoWithNs);
+                            delete protRoWithNs;
+                            protRoWithNs = NULL;
+                            }
+                        else
+                            {
+                            client.AddDomainRO(*parsedRo->iId, protectedRo);
+                            }
+                        }
+
+                    // Add RO to replay cache
+                    if (parsedRo->iTimeStamp == Time::NullTTime())
+                        {
+                        User::LeaveIfError(client.AddToCache(*parsedRo->iId));
+                        }
+                    else
+                        {
+                        User::LeaveIfError(client.AddToCache(*parsedRo->iId, parsedRo->iTimeStamp));
+                        }
+                    }
+                else
+                    {
+                    integrityCheck = EFalse;
+                    }
+                }
+            }
+        else
+            {
+            integrityCheck = EFalse;
+            r = KErrCorrupt;
+            }
+        CleanupStack::PopAndDestroy( calculatedHash );
+        calculatedHash = NULL;
+
+        if ( integrityCheck && !r )
+            {
+            // Only add the rigths which were parsed in this loop
+    
+            for ( TInt i( n ); i < aResultRights.Count(); i++)
+                {
+                cid = NULL;
+                rights = aResultRights[i];
+                rights->GetContentURI(cid);
+                CleanupStack::PushL(cid);
+                rights->GetPermission().iOriginalInsertTime =
+                parsedRo->iTimeStamp;
+                rights->GetPermission().iRoID = (*parsedRo->iId).AllocL();
+                rights->GetPermission().iRiId.Copy(*parsedRo->iRightsIssuerId);
+                if (parsedRo->iDomainRo)
+                    {
+                    domain = ETrue;
+                    rights->GetPermission().iDomainID =
+                    parsedRo->iDomainId->AllocL();
+                    }
+                if (parsedRo->iRightsIssuerId)
+                    {
+                    riId.Set(*parsedRo->iRightsIssuerId);
+                    }
+                if (parsedRo->iTransportScheme == EOma)
+                    {
+                    rights->GetPermission().iRightsObjectVersion.iVersionMain =
+                    EOma2Rights;
+                    }
+                else
+                    {
+                    rights->GetPermission().iRightsObjectVersion.iVersionMain =
+                    ECmlaRights;
+                    }
+                r = client.AddProtectedRecord( rights->GetAsset().iProtectedKey,
+                        domain, rights->GetPermission(),
+                        *cid, id );
+                if (!r)
+                    {
+                    if (rights->GetAsset().iProtectedAuthSeed.Length()> 0)
+                        {
+                        r = client.SetAuthenticationSeed(*cid,
+                                rights->GetAsset().iProtectedAuthSeed);
+                        }
+                    }
+
+                User::LeaveIfError(r);
+                rights->SetLocalID(id);
+                CleanupStack::PopAndDestroy(cid);
+                }
+            }
+        else
+            {
+            User::Leave(KErrCorrupt);
+            }
+
+        start = end;
+        n = aResultRights.Count();
+        CleanupStack::PopAndDestroy(parsedRo);
+        parsedRo = NULL;
+        }
+    CleanupStack::PopAndDestroy( &client );
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnStartDocumentL
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnStartDocumentL(
+        const RDocumentParameters& /*aDocParam*/, TInt /*aErrorCode*/)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnEndDocumentL
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnEndDocumentL(TInt /*aErrorCode*/)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnStartElementL
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnStartElementL(const RTagInfo& aElement,
+        const RAttributeArray& aAttributes, TInt /*aErrorCode*/)
+    {
+    HBufC8* b= NULL;
+
+    if (iContent)
+        {
+        delete iContent;
+        iContent = NULL;
+        iContent = HBufC8::NewL(0);
+        }
+
+    for (TInt i = 0; i < KMaxElementCount; i++)
+        {
+        if (aElement.LocalName() == iElements[i])
+            {
+            iElementStack[iElementStackDepth] = static_cast<TElementEnum>(i);
+            iElementStackDepth++;
+            if (iElementStackDepth == KMaxElementNesting)
+                {
+                User::Leave(EXmlUnexpectedState);
+                }
+            TInt state( MatchStackState() );
+            if (state == ERoState)
+                {
+                _LIT8( KTrue, "true" );
+                iRights->iId = GetAttributeValueL(aAttributes, KIdAttr);
+                iRights->iRiUrl = GetAttributeValueL(aAttributes, KRiUrlAttr);
+                b = GetAttributeValueL(aAttributes, KDomainRoAttr);
+                if ( b && b->Compare( KTrue() ) == 0 )
+                    {
+                    iRights->iDomainRo = ETrue;
+                    }
+                else
+                    {
+                    iRights->iDomainRo = EFalse;
+                    }
+                delete b;
+                }
+            else
+                if (state == EEncryptionMethodState)
+                    {
+                    b = GetAttributeValueL(aAttributes, KAlgorithmAttr);
+                    if ( b )
+                        {
+                        iRights->iTransportScheme
+                                = CmlaCrypto::AlgorithmIdToTransportScheme(*b);
+                        delete b;
+                        }
+                    }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnEndElementL
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnEndElementL(const RTagInfo& aElement, TInt /*aErrorCode*/)
+    {
+    for (TInt i = 0; i < KMaxElementCount; i++)
+        {
+        if (aElement.LocalName() == iElements[i])
+            {
+            switch (MatchStackState())
+                {
+                case ECipherValueState:
+                    iRights->iKey = Base64DecodeL(iContent->Des());
+                    break;
+                case EDomainIdentifierState:
+                    iRights->iDomainId = iContent->AllocL();
+                    break;
+                case ERightsIssuerIdState:
+                    iRights->iRightsIssuerId = Base64DecodeL(iContent->Des());
+                    break;
+                case ETimeStampState:
+                    iRights->iTimeStamp = Iso8601ToTime(*iContent);
+                    break;
+                case EMacValueState:
+                    iRights->iMac = Base64DecodeL(iContent->Des());
+                    break;
+                case EMacDigestValueState:
+                    iRights->iMacDigest = Base64DecodeL(iContent->Des());
+                    break;
+                }
+            iElementStackDepth--;
+            if (iElementStackDepth < 0)
+                {
+                User::Leave(EXmlUnexpectedState);
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnContentL
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnContentL(const TDesC8& aBytes, TInt /*aErrorCode*/)
+    {
+    if ( !iContent )
+        {
+        iContent = HBufC8::NewL(aBytes.Size());
+        *iContent = aBytes;
+        }
+    else
+        {
+        iContent = iContent->ReAllocL(iContent->Size() + aBytes.Size());
+        TPtr8 c(iContent->Des());
+        c.Append(aBytes);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnStartPrefixMappingL
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnStartPrefixMappingL(const RString& /*aPrefix*/,
+        const RString& /*aUri*/, TInt /*aErrorCode*/)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnEndPrefixMappingL
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnEndPrefixMappingL(const RString& /*aPrefix*/,
+        TInt /*aErrorCode*/)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnIgnorableWhiteSpaceL
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnIgnorableWhiteSpaceL(const TDesC8& /*aBytes*/,
+        TInt /*aErrorCode*/)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnSkippedEntityL
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnSkippedEntityL(const RString& /*aName*/, TInt /*aErrorCode*/)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnProcessingInstructionL
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnProcessingInstructionL(
+        const TDesC8& /*aTarget*/, const TDesC8& /*aData*/, TInt /*aErrorCode*/)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnOutOfData
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnOutOfData()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::OnError
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::OnError(TInt /*aErrorCode*/)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::GetExtendedInterface
+// -----------------------------------------------------------------------------
+//
+TAny* CDrmProtectedRoParser::GetExtendedInterface(const TInt32 /*aUid*/)
+    {
+    return NULL;
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::MatchStackState
+// -----------------------------------------------------------------------------
+//
+TInt CDrmProtectedRoParser::MatchStackState()
+    {
+    TInt i( 0 );
+    TInt j( 0 );
+    TInt k( 0 );
+    TParserStackState r = EUnknownState;
+
+    for (i = 0; r == EUnknownState && i < ELEMENT_COUNT(KParserStackStates); i++)
+        {
+        for (j = iElementStackDepth - 1, k = 0; j > 0
+                && KParserStackStates[i].iStack[k] != ELast; j--, k++)
+            {
+            if (iElementStack[j] != KParserStackStates[i].iStack[k])
+                {
+                break;
+                }
+            }
+        if ((j == 0 && iElementStack[j] == KParserStackStates[i].iStack[k])
+                || KParserStackStates[i].iStack[k] == ELast)
+            {
+            r = KParserStackStates[i].iState;
+            }
+        }
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::GetAttributeValueL
+// Allocate the attribute value as a buffer if it is found, otherwise it's NULL
+// -----------------------------------------------------------------------------
+//
+HBufC8* CDrmProtectedRoParser::GetAttributeValueL(
+        const RAttributeArray& aAttrList, const TDesC8& aAttrName)
+    {
+    HBufC8* r( NULL );
+
+    for ( TInt i(0); !r && i < aAttrList.Count(); i++ )
+        {
+        const RAttribute& a( aAttrList[i] );
+        if ( a.Attribute().LocalName().DesC().Compare( aAttrName ) == 0 )
+            {
+            r = a.Value().DesC().AllocL();
+            }
+        }
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::GetElementStartEnd
+// Search for the element as a string
+// -----------------------------------------------------------------------------
+//
+TBool CDrmProtectedRoParser::GetElementStartEnd(const TDesC8& aElement,
+        const TDesC8& aData, TInt& aStart, TInt& aEnd)
+    {
+    TInt i( 0 );
+    TInt j( 0 );
+    TBool r( EFalse );
+    TBuf8<KMaxElementLen> element;
+
+    DEBUGLOG( "CDrmProtectedRoParser::GetElementStartEnd ->" );
+
+    DEBUGLOG( "aElement" );
+    DEBUGLOGHEX( aElement.Ptr(), aElement.Length() );
+    DEBUGLOG( "aData" );
+    DEBUGLOGHEX( aData.Ptr(), aData.Length() );
+    element.Copy(KStartElementStart);
+    element.Append(aElement);
+    // Find the start tag, which has to end with a "<" or whitespace
+    i = aData.Mid(aStart).Find(element);
+
+    if (i == KErrNotFound)
+        {
+        // try the same thing with ROAP prefix
+        element.Copy(KStartElementStart);
+        element.Append(KRoapPrefix);
+        element.Append(aElement);
+        i = aData.Mid(aStart).Find(element);
+        }
+
+    while (i != KErrNotFound && !(aData[aStart + i + element.Length()] == '>' || aData[aStart + i + element.Length()] <= ' '))
+        {
+        aStart += i;
+        i = aData.Mid(aStart + element.Length() + 1).Find(element);
+        }
+
+    if (i != KErrNotFound)
+        {
+        aStart += i;
+        i = aStart;
+        element.Copy(KEndElementStart);
+        element.Append(aElement);
+        element.Append(KElementEnd);
+        j = aData.Mid(i + 1).Find(element);
+        if (j == KErrNotFound)
+            {
+            // try the same thing with ROAP prefix
+            element.Copy(KEndElementStart);
+            element.Append(KRoapPrefix);
+            element.Append(aElement);
+            element.Append(KElementEnd);
+            j = aData.Mid(i + 1).Find(element);
+            }
+        if (j != KErrNotFound)
+            {
+            aEnd = i + 1 + j + element.Length();
+            r = ETrue;
+            }
+        }
+#ifdef _DEBUG
+    if ( r )
+        {
+        TPtrC8 extracted( aData.Mid( aStart, aEnd - aStart ) );
+        DEBUGLOG( "got element: " );
+        DEBUGLOGHEX( extracted.Ptr(), extracted.Length() );
+        }
+#endif
+    DEBUGLOG( "-> CDrmProtectedRoParser::GetElementStartEnd" );
+    return r;
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::HandleUnregisteredDomainRoL
+// Embed the domain RO into all matching DCF files
+// -----------------------------------------------------------------------------
+//
+void CDrmProtectedRoParser::HandleUnregisteredDomainRoL(
+        const TDesC8& aContentId, const TDesC8& aDomainRoData,
+        CParsedProtectedRo* /*aDomainRo*/)
+    {
+    CDcfRep* rep( NULL );
+    COma2Dcf* dcf( NULL );
+    CDcfEntry* entry( NULL );
+    RFile file;
+    RFs fs;
+    TBool exists( EFalse );
+    TInt r( KErrNone );
+
+    User::LeaveIfError( fs.Connect() );
+    CleanupClosePushL( fs );
+    rep = CDcfRep::NewL();
+    CleanupStack::PushL( rep );
+    TRAP( r, rep->OrderListL( aContentId ) );
+    if ( r == KErrNone )
+        {
+        entry = rep->NextL();
+        }
+    while ( r == KErrNone && entry )
+        {
+        CleanupStack::PushL( entry );
+
+        r = file.Open( fs, entry->FileName(), EFileWrite
+                | EFileShareReadersOrWriters );
+        if ( r == KErrInUse )
+            {
+            r = file.Open(fs, entry->FileName(), EFileWrite | EFileShareAny);
+            }
+
+        if ( r == KErrNone )
+            {
+            CleanupClosePushL( file );
+            dcf = COma2Dcf::NewL( file );
+            CleanupStack::PushL( dcf );
+            for ( TInt i = 0; !exists && i < dcf->iRightsObjects.Count(); i++ )
+                {
+                if ( dcf->iRightsObjects[i]->Compare(aDomainRoData) == 0 )
+                    {
+                    exists = ETrue;
+                    }
+                }
+            if ( !exists )
+                {
+                dcf->iRightsObjects.Append( aDomainRoData.AllocL() );
+                dcf->SetRightsObjectsL( dcf->iRightsObjects );
+                }
+            CleanupStack::PopAndDestroy( dcf );
+            CleanupStack::PopAndDestroy( &file );
+            }
+        CleanupStack::PopAndDestroy( entry );
+        entry = rep->NextL();
+        }
+    CleanupStack::PopAndDestroy( rep );
+    CleanupStack::PopAndDestroy( &fs );
+    }
+
+// -----------------------------------------------------------------------------
+// CDrmProtectedRoParser::AddRoapNamespaceL
+// Add ROAP namespace declaration if needed
+// -----------------------------------------------------------------------------
+//
+HBufC8* CDrmProtectedRoParser::AddRoapNamespaceL(TDesC8& aProtectedRo) const
+    {
+    TInt index = 0;
+    HBufC8* roWithNs= NULL;
+    TPtr8 roWithNsPtr(NULL, NULL);
+
+    if (aProtectedRo.Find(KRoapXmlNsUri) == KErrNotFound)
+        {
+        roWithNs = HBufC8::NewLC(aProtectedRo.Length() + KRoapXmlNs().Length());
+        roWithNsPtr.Set(roWithNs->Des());
+        index = aProtectedRo.Find(KQualifiedProtectedRo);
+        if (index == KErrNotFound)
+            {
+            index = aProtectedRo.Find(KRoElement);
+            if (index == KErrNotFound)
+                {
+                User::Leave(KErrCorrupt);
+                }
+            index += KRoElement().Length();
+            }
+        else
+            {
+            index += KQualifiedProtectedRo().Length();
+            }
+        roWithNsPtr.Copy(aProtectedRo.Left(index));
+        roWithNsPtr.Append(KRoapXmlNs());
+        roWithNsPtr.Append(aProtectedRo.Right(aProtectedRo.Length() - index));
+        CleanupStack::Pop(roWithNs);
+        }
+    return roWithNs;
+    }
+
+//  End of File