diff -r 000000000000 -r 95b198f216e5 omadrm/drmengine/roapstorage/src/RoapStorageSession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omadrm/drmengine/roapstorage/src/RoapStorageSession.cpp Thu Dec 17 08:52:27 2009 +0200 @@ -0,0 +1,2506 @@ +/* +* Copyright (c) 2004-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: Session class for handling roap storage client requests +* +*/ + + +// INCLUDE FILES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef RD_DRM_METERING +#include +#include +#endif //RD_DRM_METERING +#ifdef RD_MULTIPLE_DRIVE +#include +#endif +#include // CleanupResetAndDestroyPushL dependencies +#include "drmaescrypto.h" +#include "RoapStorageSession.h" +#include "DRMContextDB.h" +#include "DRMRIContext.h" +#include "DRMDomainContext.h" +#include "RoapStorageServer.h" +#include "CmlaCrypto.h" +#include "DrmAesCrypto.h" +#include "DrmKeyStorage.h" +#include "RoapDef.h" +#include "RoapLog.h" +#include "drmroapclientserver.h" +#include "drmclockclient.h" +#include "DrmTypes.h" +#include "drmpointerarray.h" +//OCSP classes +#include "roapocsp.h" +#include "responsedecoder.h" +#include "certid.h" +//drm clock +#include "drmclockclient.h" + +#include "base64.h" + +#include "cleanupresetanddestroy.h" // CleanupResetAndDestroyPushL +// NAMESPACES +using namespace Roap; + +// EXTERNAL DATA STRUCTURES +// EXTERNAL FUNCTION PROTOTYPES + +// CONSTANTS +const TInt KMaxElementLength = 327680; +const TInt KMinDomainIdLength = 4; +// DEBUG PRINT MACROS +#ifdef _DEBUG +#include +_LIT(KMacLogDir, "DRM"); +_LIT(KMacLogFile, "MAC.log"); +#define MACLOG( a ) RFileLogger::Write( KMacLogDir(), KMacLogFile(), EFileLoggingModeAppend, a ); +#define MACLOGHEX( ptr, len ) RFileLogger::HexDump( KMacLogDir(), KMacLogFile(), EFileLoggingModeAppend, _S(""), _S(""), ptr, len ); +#define MACLOGLIT( a ) MACLOG( _L ( a ) ) +#define _DRM_DETAILED_DEBUG // uncomment if want detailed debugs to log file +#else +#undef _DRM_DETAILED_DEBUG +#define MACLOG( a ) +#define MACLOGHEX( ptr, len ) +#define MACLOGLIT( a ) +#endif +#ifdef _DRM_DETAILED_DEBUG +#define MACLOGDETAIL( a ) MACLOG( a ) +#define MACLOGHEXDETAIL( ptr, len ) MACLOGHEX( ptr, len ) +#define MACLOGLITDETAIL( a ) MACLOGLIT( a ) +#define MACLOGLDETAIL( a ) MACLOGLIT( a ) +#define CERTDETAIL( c ) \ +{ \ +const TPtrC8* n( c->DataElementEncoding( CX509Certificate::ESerialNumber ) ); \ +const TPtrC8* a( c->DataElementEncoding( CX509Certificate::EAlgorithmId ) ); \ +const TPtrC8* s( c->DataElementEncoding( CX509Certificate::ESubjectName ) ); \ +const TPtrC8* i( c->DataElementEncoding( CX509Certificate::EIssuerName ) ); \ +const TPtrC8* p( c->DataElementEncoding( CX509Certificate::ESubjectPublicKeyInfo ) ); \ +MACLOGLDETAIL( "certificate (subject issuer serial algorithm key)" ) \ +MACLOGHEXDETAIL( s->Ptr(), s->Length() ) \ +MACLOGHEXDETAIL( i->Ptr(), i->Length() ) \ +MACLOGHEXDETAIL( n->Ptr(), n->Length() ) \ +MACLOGHEXDETAIL( a->Ptr(), a->Length() ) \ +MACLOGHEXDETAIL( p->Ptr(), p->Length() ) \ +} +#else +#define MACLOGDETAIL( a ) +#define MACLOGHEXDETAIL( ptr, len ) +#define MACLOGLITDETAIL( a ) +#define MACLOGLDETAIL( a ) +#define CERTDETAIL( a ) +#endif +// END OF DEBUG PRINT MACROS +// LOCAL CONSTANTS AND MACROS +_LIT8( KRoapDomainKey, "roap:domainKey"); +_LIT8( KRoapX509SPKIHash, "roap:X509SPKIHash"); +_LIT8( KRoapXmlNs, " xmlns:roap=\"urn:oma:bac:dldrm:roap-1.0\""); +#ifdef RD_DRM_METERING +_LIT8( KCmlaIp1, "http://www.cm-la.com/tech/cmlaip/cmlaip#cmlaip-1"); +#endif + +static const TUid KCRUidRoapHandler = + { + 0x10205CBF + }; +static const TInt KRoapHandlerRegistrationWhitelist = 1; +static const TInt KMaxWhiteListLen = 1024; + +static const TInt KTzZulu( 0 ); //UTC time zone +#ifdef RD_MULTIPLE_DRIVE +_LIT( KRIContextFileName, "_:\\private\\101F51F2\\ricontexts.dat" ); +_LIT( KDomainContextFileName, "_:\\private\\101F51F2\\domaincontexts.dat" ); +#endif + +#define ROAPDB ( ( CRoapStorageServer* )( Server() ) )->ContextDB() + +static const TInt KP3( 3 ); +#define IPCREAD0L( a ) aMessage.ReadL( 0, a ) +#define IPCREAD1L( a ) aMessage.ReadL( 1, a ) +#define IPCREAD2L( a ) aMessage.ReadL( 2, a ) +#define IPCREAD3L( a ) aMessage.ReadL( KP3, a ) +#define IPCWRITE0L( a ) aMessage.WriteL( 0, a ) +#define IPCWRITE1L( a ) aMessage.WriteL( 1, a ) +#define IPCWRITE2L( a ) aMessage.WriteL( 2, a ) +#define IPCWRITE3L( a ) aMessage.WriteL( KP3, a ) +#define IPCGETDESLEN0 aMessage.GetDesLength( 0 ) +#define IPCGETDESLEN1 aMessage.GetDesLength( 1 ) +#define IPCGETDESLEN2 aMessage.GetDesLength( 2 ) +#define IPCGETDESLEN3 aMessage.GetDesLength( KP3 ) +#define IPCGETDESMAXLEN0 aMessage.GetDesMaxLength( 0 ) +#define IPCGETDESMAXLEN1 aMessage.GetDesMaxLength( 1 ) +#define IPCGETDESMAXLEN2 aMessage.GetDesMaxLength( 2 ) +#define IPCGETDESMAXLEN3 aMessage.GetDesMaxLength( KP3 ) + +const TInt KSanityDataLengthLow = 0; +const TInt KSanityDataLengthHigh = 32768; +// DATA TYPES +// LOCAL FUNCTION PROTOTYPES +LOCAL_C RPointerArray BufferToArrayL( TDesC8& aBuffer ); +LOCAL_C HBufC8* ArrayToBufferLC( const RPointerArray& aArray ); + +LOCAL_C void UnwrapDomainKeyL( MDrmKeyStorage* aKeyStorage, + const TDesC8& aProtectedDomainKey, HBufC8*& aDomainKey, HBufC8*& aMacKey, + TKeyTransportScheme& aTransportScheme ); +LOCAL_C TBool VerifyMacL( TDesC8& aDomainElements, TDesC8& aMacs, + RPointerArray& aMacKeys ); + +// --------------------------------------------------------------------------- +// DeleteAndSetNull +// --------------------------------------------------------------------------- +// +template Taa*& DeleteAndSetNull( Taa*& aArg ) + { + if ( aArg ) + { + delete aArg; + aArg = NULL; + } + return aArg; + } + +// --------------------------------------------------------------------------- +// SanitizeL +// Performs a sanity check on length parameters +// --------------------------------------------------------------------------- +// +LOCAL_C void SanitizeL( TInt aParam ) + { + User::LeaveIfError( aParam ); + if ( aParam <= KSanityDataLengthLow || aParam > KSanityDataLengthHigh ) + { + User::Leave( KErrArgument ); + } + } + +// --------------------------------------------------------------------------- +// Swap elements +// --------------------------------------------------------------------------- +// +template +LOCAL_C void SwapElement( RPointerArray& aArray, TInt aFirst, TInt aSecond ) + { + if ( aFirst != aSecond ) + { + T* temp( NULL); + temp = aArray[aFirst]; + aArray[aFirst] = aArray[aSecond]; + aArray[aSecond] = temp; + } + } +// --------------------------------------------------------------------------- +// Sort Ocsp responses for certChain validation +// --------------------------------------------------------------------------- +// +LOCAL_C TBool SortOcspCertsL( RPointerArray& aOcspCerts, + const CX509Certificate* aRootCert ) + { + MACLOGLITDETAIL( "::SortOcspCertsL -->" ) + const TInt last( aOcspCerts.Count() - 1 ); + TBool sortable( EFalse ); + + // Find first find cert issued by root cert + // There can be only one cert issued by Root on valid cert chain + for ( TInt i( 0 ); !sortable && i <= last; i++ ) + { + if ( aRootCert->SubjectName().ExactMatchL( + aOcspCerts[i]->IssuerName() ) ) + { + SwapElement ( aOcspCerts, i, last ); + sortable = ETrue; + } + } + + for ( TInt s(last); sortable && s > 0; s-- ) + { + sortable = EFalse; + for ( TInt i( s - 1 ); !sortable && i >= 0; i-- ) + { + // compare cert s subject to issuer i + if ( aOcspCerts[s]->SubjectName().ExactMatchL( + aOcspCerts[i]->IssuerName() ) ) + { + SwapElement ( aOcspCerts, i, s-1 ); + sortable = ETrue; + } + } + } + MACLOGLITDETAIL( "--> ::SortOcspCertsL" ) + return sortable; + } + +// --------------------------------------------------------------------------- +// VerifyOcspCertChainL() +// --------------------------------------------------------------------------- +// +LOCAL_C TBool VerifyOcspCertChainL( const COCSPResponse& aResponse, + const CX509Certificate* aRootCert, CX509Certificate*& aOcspCert ) + { + MACLOGLITDETAIL( "::VerifyOcspCertChainL -->" ) + + + + CX509Certificate* cert = NULL; + const CX509Certificate* signingCert = NULL; + TInt pos = 0; + TBool result = ETrue; + + RPointerArray certArray; + CleanupResetAndDestroyPushL( certArray ); + + const TPtrC8* ocspCerts( aResponse.SigningCerts() ); + + if ( !ocspCerts ) + { + MACLOGLIT( "No OCSP certs present" ) +#ifdef _DISABLE_OCSP_CHECK + CleanupStack::PopAndDestroy( &certArray ); + return ETrue; +#endif + User::Leave( KErrRoapServerFatal ); + } + + MACLOGLITDETAIL( "getting certs in OCSP response" ) + while ( pos < ocspCerts->Length() ) + { + cert = CX509Certificate::NewLC( *ocspCerts, pos ); + certArray.AppendL( cert ); + CleanupStack::Pop( cert ); + CERTDETAIL( cert ) + } + + result = SortOcspCertsL( certArray, aRootCert ); + + // validate the OCSP cert chain up till root cert (root cert is already validated) + for ( TInt i = 0; i < certArray.Count() && result; i++ ) + { + cert = certArray[i]; + if ( certArray.Count() - 1 == i ) + { + signingCert = aRootCert; + } + else + { + signingCert = certArray[i + 1]; + } + MACLOGLDETAIL( "OCSP verify, using certificate" ) + CERTDETAIL( cert ) + result = cert->VerifySignatureL( signingCert->PublicKey().KeyData() ); +#ifdef _DEBUG + if ( result ) + { + MACLOGLIT( "Verify succeeded." ) + } + else + { + MACLOGLIT( "Verify failed." ) + } +#endif + } + + // Copy OCSP cert and return it + aOcspCert = CX509Certificate::NewL( *certArray[0] ); + + CleanupStack::PopAndDestroy( &certArray ); + MACLOGLITDETAIL( "--> ::VerifyOcspCertChainL" ) + return result; + } + + +#ifdef _DISABLE_DRM_TIME_UPDATE_CHECK +LOCAL_C TBool IsCmlaRootL( + const RPointerArray& /*aTrustedRoots*/, + const CX509Certificate* /* aRootCert */) + { + MACLOGLITDETAIL( "IsCmlaRootL -->\n--> IsCmlaRootL" ) + return ETrue; + } +#else +LOCAL_C TBool IsCmlaRootL( const RPointerArray& aTrustedRoots, + const CX509Certificate* aRootCert ) + { + MACLOGLITDETAIL( "IsCmlaRootL -->" ) + TBool isCmlaRoot( EFalse ); + // Check are we running on a CMLA device + for ( TInt i = 0; i < aTrustedRoots.Count() && !isCmlaRoot; i++ ) + { + HBufC8* encodedRoot( Base64EncodeL( *aTrustedRoots[i] ) ); + CleanupStack::PushL( encodedRoot ); + if ( encodedRoot->CompareF( KRoapCmlaRootHash() ) == 0 + || encodedRoot->CompareF( KRoapCmlaRnDRootHash() ) == 0 + || encodedRoot->CompareF( KRoapCmlaRnDRootHashOld() ) == 0 ) + { + isCmlaRoot = ETrue; + } + CleanupStack::PopAndDestroy( encodedRoot ); + encodedRoot = NULL; + } + if ( isCmlaRoot ) + { + __UHEAP_MARK; + // The root cert found, check that it's the CMLA (production or R&D) root + CSHA1* hash( CSHA1::NewL() ); + CleanupStack::PushL( hash ); + hash->Hash( *aRootCert->DataElementEncoding( + CX509Certificate::ESubjectPublicKeyInfo ) ); + MACLOGLDETAIL( "Inputs for SHA1" ) + MACLOGHEXDETAIL( + aRootCert->DataElementEncoding( + CX509Certificate::ESubjectPublicKeyInfo )->Ptr(), + aRootCert->DataElementEncoding( + CX509Certificate::ESubjectPublicKeyInfo )->Length() ) + + HBufC8* encodedRoot( Base64EncodeL( hash->Final() ) ); + CleanupStack::PushL( encodedRoot ); + + MACLOGLDETAIL( "Encoded root (base64 encoded SHA1 of public key)" ) + MACLOGDETAIL( *encodedRoot ) + MACLOGLDETAIL( "CMLA root" ) + MACLOGDETAIL( KRoapCmlaRootHash() ) + MACLOGLDETAIL( "CMLA RD root" ) + MACLOGDETAIL( KRoapCmlaRnDRootHash() ) + MACLOGLDETAIL( "old CMLA RD root" ) + MACLOGDETAIL( KRoapCmlaRnDRootHashOld() ) + + if ( encodedRoot->CompareF( KRoapCmlaRootHash() ) != 0 + && encodedRoot->CompareF( KRoapCmlaRnDRootHash() ) != 0 + && encodedRoot->CompareF( KRoapCmlaRnDRootHashOld() ) != 0 ) + { + // The RI CA cert is not signed by CMLA root + MACLOGLIT( "The RI CA cert is not signed by CMLA (production or R&D) root" ) + isCmlaRoot = EFalse; + } + else + { + // We are running on a CMLA device and + // RI certificate is signed by the CMLA (production or R&D) root + // -> Verify still that the OCSP chain is signed by CMLA + MACLOGLIT( "RI certificate is signed by the CMLA root" ) + } + CleanupStack::PopAndDestroy( encodedRoot ); + CleanupStack::PopAndDestroy( hash ); + __UHEAP_MARKEND; + } + MACLOGLITDETAIL( "--> IsCmlaRootL" ) + return isCmlaRoot; + } +#endif + + +// --------------------------------------------------------------------------- +// ValidateNonceL +// --------------------------------------------------------------------------- +// +LOCAL_C TBool ValidateNonceL( const COCSPResponse& aResponse, + const TDesC8& aRegReqNonce ) + { + // check that nonce in OCSP response equals to the nonce sent in Reg Request + TBool ret( EFalse ); + const TPtrC8 * nonce( aResponse.DataElementEncoding( + COCSPResponse::ENonce ) ); + + if ( !nonce ) + { + // no nonce found -> don't update DRM Time + MACLOGLIT( "No nonce in the OCSP response!" ) + ret = EFalse; + } + else if ( nonce->CompareF( aRegReqNonce ) != 0 ) + { + // Maybe the nonce is in ASN.1 format? + // -> Remove the first two bytes (type and size), and try again + TASN1DecGeneric asn1Dec( *nonce ); + asn1Dec.InitL(); + TPtrC8 ptr( asn1Dec.GetContentDER() ); + if ( ptr.CompareF( aRegReqNonce ) != 0 ) + { + MACLOGLIT( "Fatal server error: OCSP nonce != RegRequest nonce!" ) + User::Leave( KErrRoapServerFatal ); + } + else + { + MACLOGLIT( "OCSP nonce == RegRequest nonce." ) + ret = ETrue; + } + MACLOGLDETAIL( "values ( OCSP nonce, request nonce )" ) + MACLOGHEXDETAIL( nonce->Ptr(), nonce->Length() ) + MACLOGHEXDETAIL( aRegReqNonce.Ptr(), aRegReqNonce.Length() ) + } + else + { + ret = ETrue; + MACLOGLDETAIL( "values ( OCSP nonce, request nonce )" ) + MACLOGHEXDETAIL( nonce->Ptr(), nonce->Length() ) + MACLOGHEXDETAIL( aRegReqNonce.Ptr(), aRegReqNonce.Length() ) + } + return ret; + } +// --------------------------------------------------------------------------- +// IsTimeUpdateAllowedL() +// --------------------------------------------------------------------------- +// +LOCAL_C TBool IsTimeUpdateAllowedL( + const RPointerArray& aTrustedRoots, + const RPointerArray& aRootCertificates, + const RPointerArray& aCertChain, + const COCSPResponse& aOcspResponse, + const TDesC8& aRegReqNonce ) + { + MACLOGLITDETAIL( "::IsTimeUpdateAllowedL -->" ) + + + // check that nonce in OCSP response equals to the nonce sent in Reg Request + TBool bIsAllowed( ValidateNonceL( aOcspResponse, aRegReqNonce ) ); + + if ( !bIsAllowed ) + { + MACLOGLIT( "No nonce. Not possible to update DRM time" ) + return bIsAllowed; + } + + + if ( !aCertChain.Count() ) + { + MACLOGLIT( "Wrong input data - No certificates or OCSP responses" ) + bIsAllowed = EFalse; + return bIsAllowed; + } + + CX509Certificate* riCa = NULL; + CX509Certificate* rootCert = NULL; + // Get the last cert from the chain. + // It should be signed by some of our trusted anchor + riCa = CX509Certificate::NewLC( *( aCertChain[aCertChain.Count() - 1] ) ); + MACLOGLITDETAIL( "Selected as RI CA" ) // (last of given cert chain) + CERTDETAIL( riCa ) + + // iterate over root certificates and check, whether given + // RI CA issuer matches name of the selected root + for ( TInt i = 0; i < aRootCertificates.Count() && !rootCert; i++ ) + { + rootCert = CX509Certificate::NewL( *aRootCertificates[i] ); + if ( !rootCert->SubjectName().ExactMatchL( riCa->IssuerName() ) ) + { + delete rootCert; + rootCert = NULL; + } + } + + if ( rootCert ) + { + MACLOGLDETAIL( "Selected root CERT" ) + CERTDETAIL( rootCert ) + CleanupStack::PushL( rootCert ); + + if ( IsCmlaRootL( aTrustedRoots, rootCert ) ) + { + CX509Certificate* ocspCert = NULL; + __UHEAP_MARK; + // Try to verify OCSP cert chain with the root cert + if ( VerifyOcspCertChainL( aOcspResponse, rootCert, + DeleteAndSetNull ( ocspCert ) ) ) + { + MACLOGLITDETAIL( "OCSP cert chain verified with root cert" ) + MACLOGLIT( "DRM Time update allowed!" ) + bIsAllowed = ETrue; + } + // Try to verify OCSP cert chain with the RI CA cert + + else if ( VerifyOcspCertChainL( aOcspResponse, riCa, + DeleteAndSetNull ( ocspCert ) ) ) + { + MACLOGLITDETAIL( "OCSP cert chain verified with RI CA cert" ) + // Check signing of RiCa + bIsAllowed = riCa->VerifySignatureL( + rootCert->PublicKey().KeyData() ); + if ( !bIsAllowed ) + { + MACLOGLITDETAIL( "RI CA cert verify failed" ) + MACLOGLIT( "DRM time update not allowed!" ) + } + else + { + MACLOGLITDETAIL( "RI CA verified with root cert" ) + MACLOGLIT( "DRM time update allowed" ) + } + } + else + { + MACLOGLITDETAIL( "OCSP cert chain verify failed" ) + MACLOGLIT( "DRM Time update is not allowed!" ) + bIsAllowed = EFalse; + } + + if ( ocspCert ) + { + if ( !aOcspResponse.VerifySignatureL( + ocspCert->PublicKey().KeyData() ) ) + { + MACLOGLIT( "OCSP response signature verification failed" ) + bIsAllowed = EFalse; + } + if ( bIsAllowed ) + { + const TTime timeCandidate( aOcspResponse.ProducedAt() ); + if ( !ocspCert->ValidityPeriod().Valid( timeCandidate ) ) + { + MACLOGLIT( "OCSP responder cert expired in respect to proposed new time" ) + bIsAllowed = EFalse; + } + } + } + DeleteAndSetNull ( ocspCert ); + __UHEAP_MARKEND; + } + CleanupStack::PopAndDestroy( rootCert ); + rootCert = NULL; + } + CleanupStack::PopAndDestroy( riCa ); + riCa = NULL; + MACLOGLITDETAIL( "--> ::IsTimeUpdateAllowedL" ) + return bIsAllowed; + } + +//LOCAL CLASS DECLARATION +// Used for lazy connecting to clock server (only connected if needed) +class LazyClockClient + { +public: + inline LazyClockClient(); + inline virtual ~LazyClockClient(); + inline void GetSecureTimeL( TTime& aTime, TInt& aZone, + DRMClock::ESecurityLevel& aLevel ); + inline void UpdateSecureTimeL( const TTime& aTime, const TInt aZone ); + inline void Close(); +private: + inline void ConnectL(); + TBool iConnected; + RDRMClockClient iClock; + }; + +// ============================ MEMBER FUNCTIONS =============================== + +// --------------------------------------------------------------------------- +inline LazyClockClient::LazyClockClient() : + iConnected( EFalse ) + { + } + +// --------------------------------------------------------------------------- +inline LazyClockClient::~LazyClockClient() + { + Close(); + } + +// --------------------------------------------------------------------------- +inline void LazyClockClient::Close() + { + iClock.Close(); + iConnected = EFalse; + } + +// --------------------------------------------------------------------------- +inline void LazyClockClient::ConnectL() + { + if ( !iConnected ) + { + User::LeaveIfError( iClock.Connect() ); + iConnected = ETrue; + } + } + +// --------------------------------------------------------------------------- +inline void LazyClockClient::GetSecureTimeL( TTime& aTime, TInt& aZone, + DRMClock::ESecurityLevel& aLevel ) + { + ConnectL(); + User::LeaveIfError( iClock.GetSecureTime( aTime, aZone, aLevel ) ); + } + +// --------------------------------------------------------------------------- +inline void LazyClockClient::UpdateSecureTimeL( const TTime& aTime, + const TInt aZone ) + { + ConnectL(); + User::LeaveIfError( iClock.UpdateSecureTime( aTime, aZone ) ); + } + + +// CRoapStorageSession methods + +// --------------------------------------------------------------------------- +// CRoapStorageSession::NewLC +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CRoapStorageSession* CRoapStorageSession::NewL() + { + CRoapStorageSession* self = new ( ELeave ) CRoapStorageSession(); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::~CRoapStorageSession +// Destructor. +// --------------------------------------------------------------------------- +// +CRoapStorageSession::~CRoapStorageSession() + { + delete iPreparedData; + delete iKeyStorage; + delete iLazyClock; + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::ServiceL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::ServiceL( const RMessage2& aMessage ) + { + DispatchL( aMessage ); + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::DispatchL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::DispatchL( const RMessage2& aMessage ) + { + switch ( aMessage.Function() ) + { + case EAddRiContext: + { + AddRiContextL( aMessage ); + break; + } + case EAddDomainContext: + { + AddDomainContextL( aMessage ); + break; + } + case EGetRiContext: + { + GetRiContextL( aMessage ); + break; + } + case EGetDomainContext: + { + GetDomainContextL( aMessage ); + break; + } + case EGetData: + { + GetDataL( aMessage ); + break; + } + case EDeleteRiContext: + { + DeleteRiContextL( aMessage ); + break; + } + case EDeleteDomainContext: + { + DeleteDomainContextL( aMessage ); + break; + } + case EDeleteExpiredRIs: + { + DeleteExpiredRIsL( aMessage ); + break; + } + case EDeleteExpiredDomains: + { + DeleteExpiredDomainsL( aMessage ); + break; + } + case EWhiteListCheck: + { + WhiteListUrlExistsL( aMessage ); + break; + } + case EGetPublicKey: + { + GetDevicePublicKeyDerL( aMessage ); + break; + } + case EGetCertificates: + { + GetDeviceCertificateChainL( aMessage ); + break; + } + case ESignMessage: + { + SignL( aMessage ); + break; + } + case ESelectRoot: + { + SelectTrustedRootL( aMessage ); + break; + } + case EActivateRoot: + { + ActivateTrustedRootL( aMessage ); + break; + } + case EGetTrustedRoots: + { + GetTrustedRootsL( aMessage ); + break; + } + case EGetRootCert: + { + GetRootCertificateL( aMessage ); + break; + } + case EDeleteExpired: + { + DeleteExpiredContextsL( aMessage ); + break; + } + case EDeleteAll: + { + DeleteAllL( aMessage ); + break; + } + case ERsaSign: + { + RsaSignL( aMessage ); + break; + } +#ifdef RD_DRM_METERING + case EGetMeteringData: + { + GetMeteringDataL( aMessage ); + break; + } + case EDeleteMeteringData: + { + DeleteMeteringDataL( aMessage ); + break; + } + case ERetrieveAllRIContexts: + { + GetAllRIContextsL( aMessage ); + break; + } + case EUpdateRIContext: + { + UpdateRIContextL( aMessage ); + break; + } +#endif // RD_DRM_METERING + case EUpdateDrmTime: + { + UpdateDrmTimeL( aMessage ); + break; + } + case EVerifyOcspResponses: + { + VerifyOcspResponsesL( aMessage ); + break; + } + case EGetOcspResponderId: + { + GetOcspResponderIdL( aMessage ); + break; + } + default: + MACLOGLIT( "CRoapStorageSession::ServiceL: Invalid command" ) + PanicClient( aMessage, EPanicBadFunction ); + } + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::PanicClient +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::PanicClient( + const RMessage2& aMessage, + TPanic aReason ) + { + _LIT( KPanicCategory, "RoapStorageSession" ); + if ( !aMessage.IsNull() ) + { + aMessage.Panic( KPanicCategory, aReason ); + } + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::ServiceError +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::ServiceError( + const RMessage2& aMessage, + TInt aError ) + { + MACLOGLITDETAIL( "CRoapStorageSession::ServiceError -->" ) + + if ( aError == KErrBadDescriptor ) + { + PanicClient( aMessage, EPanicBadDescriptor ); + } + else + { + CSession2::ServiceError( aMessage, aError ); + } + MACLOGLITDETAIL( "--> CRoapStorageSession::ServiceError" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::CRoapStorageSession +// Default constructor. +// --------------------------------------------------------------------------- +// +CRoapStorageSession::CRoapStorageSession() + { + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::ConstructL +// Second phase constructor. Initializes the log tool in DRM internal testing. +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::ConstructL() + { + iKeyStorage = DrmKeyStorageNewL(); + iKeyStorage->SelectDefaultRootL(); + iDeleteExpired = ETrue; + iLazyClock = new ( ELeave ) LazyClockClient(); + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::AddRiContextL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::AddRiContextL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::AddRiContextL -->" ) + CDRMRIContext* context = NULL; + HBufC8* contextData = NULL; + TPtr8 data( NULL, 0 ); + TInt size = 0; + + if ( iDeleteExpired ) + { + TTime drmTime; + DRMClock::ESecurityLevel level; + TInt zone = KTzZulu; + iLazyClock->GetSecureTimeL( drmTime, zone, level ); + + if ( level == DRMClock::KSecure ) + { + ROAPDB->DeleteExpiredRightsIssuerContextsL( drmTime ); + ROAPDB->DeleteExpiredDomainContextsL( drmTime ); + iDeleteExpired = EFalse; + } + } + + size = User::LeaveIfError( IPCGETDESLEN0 ); + contextData = HBufC8::NewMaxLC( size ); + data.Set( const_cast ( contextData->Ptr() ), 0, size ); + IPCREAD0L( data ); + MACLOGLITDETAIL( "Serialized RI context" ) + MACLOGHEXDETAIL( contextData->Ptr(), contextData->Length() ) + + context = CDRMRIContext::NewLC(); + context->ImportL( data ); + ROAPDB->StoreRightsIssuerContextL( *context ); + + CleanupStack::PopAndDestroy( context ); + CleanupStack::PopAndDestroy( contextData ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::AddRiContextL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::AddDomainContextL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::AddDomainContextL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::AddDomainContextL -->" ) + CDRMDomainContext* context = NULL; + HBufC8* contextData = NULL; + HBufC8* domainElements = NULL; + HBufC8* macs = NULL; + TPtr8 data( NULL, 0 ); + TInt size = 0; + TKeyTransportScheme transScheme; + TPckg package( transScheme ); + + HBufC8* plainDomainKey = NULL; + HBufC8* plainMacKey = NULL; + + if ( iDeleteExpired ) + { + TTime drmTime; + DRMClock::ESecurityLevel level; + TInt zone = KTzZulu; + iLazyClock->GetSecureTimeL( drmTime, zone, level ); + + if ( level == DRMClock::KSecure ) + { + ROAPDB->DeleteExpiredRightsIssuerContextsL( drmTime ); + ROAPDB->DeleteExpiredDomainContextsL( drmTime ); + iDeleteExpired = EFalse; + } + } + + RPointerArray plainDomainKeys; + CleanupResetAndDestroyPushL( plainDomainKeys ); + + RPointerArray plainMacKeys; + CleanupResetAndDestroyPushL( plainMacKeys ); + + size = IPCGETDESLEN0; + + if ( size <= 0 ) + { + User::Leave( KErrArgument ); + } + + contextData = HBufC8::NewMaxLC( size ); + data.Set( const_cast ( contextData->Ptr() ), 0, size ); + IPCREAD0L( data ); + MACLOGLITDETAIL( "Serialized domain context" ) + MACLOGHEXDETAIL( contextData->Ptr(), contextData->Length() ) + + context = CDRMDomainContext::NewLC(); + context->ImportL( data ); + + TPtrC8 domainId = context->DomainID(); + + if ( domainId.Length() <= 0 ) + { + User::Leave( KErrArgument ); + } + + IPCREAD1L( package ); + + size = IPCGETDESLEN2; + + if ( size <= 0 ) + { + User::Leave( KErrArgument ); + } + + macs = HBufC8::NewLC( size ); + data.Set( macs->Des() ); + IPCREAD2L( data ); + + size = IPCGETDESLEN3; + + if ( size <= 0 ) + { + User::Leave( KErrArgument ); + } + + domainElements = HBufC8::NewLC( size ); + data.Set( domainElements->Des() ); + IPCREAD3L( data ); + + const RPointerArray& domainKeys( context->DomainKeys() ); + + for ( TInt i = 0; i < domainKeys.Count(); i++ ) + { + UnwrapDomainKeyL( iKeyStorage, *domainKeys[i], plainDomainKey, + plainMacKey, transScheme ); + TInt ret( plainDomainKeys.Append( plainDomainKey ) ); + if ( ret ) + { + // Append did not succeed, + // delete buffers not in CleanupStack and leave. + delete plainDomainKey; + plainDomainKey = NULL; + delete plainMacKey; + plainMacKey = NULL; + User::LeaveIfError( ret ); + } + CleanupStack::PushL( plainMacKey ); + plainMacKeys.AppendL( plainMacKey ); + CleanupStack::Pop( plainMacKey ); + } + + if ( !VerifyMacL( *domainElements, *macs, plainMacKeys ) ) + { + User::Leave( KErrRoapServerFatal ); + } + + context->SetDomainKeysL( plainDomainKeys ); + + ROAPDB->StoreDomainContextL( *context ); + + CleanupStack::PopAndDestroy( domainElements ); + CleanupStack::PopAndDestroy( macs ); + CleanupStack::PopAndDestroy( context ); + CleanupStack::PopAndDestroy( contextData ); + CleanupStack::PopAndDestroy( &plainMacKeys ); + CleanupStack::PopAndDestroy( &plainDomainKeys ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::AddDomainContextL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::GetRiContextL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::GetRiContextL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::GetRiContextL -->" ) + CDRMRIContext* context = CDRMRIContext::NewLC(); + HBufC8* riId = NULL; + TInt size = 0; + TPtr8 data( NULL, 0 ); + + TPckg package( size ); + riId = HBufC8::NewLC( User::LeaveIfError( IPCGETDESLEN1 ) ); + data.Set( riId->Des() ); + IPCREAD1L( data ); + if ( riId->Length() != SHA1_HASH ) + { + User::Leave( KErrArgument ); + } + context->SetRIIDL( *riId ); + ROAPDB->FetchRightsIssuerContextL( *context ); + size = context->Size(); + IPCWRITE0L( package ); + delete iPreparedData; + iPreparedData = NULL; + iPreparedData = context->ExportL(); + + CleanupStack::PopAndDestroy( riId ); // riId, context + CleanupStack::PopAndDestroy( context ); // riId, context + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( " --> CRoapStorageSession::GetRiContextL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::GetDomainContextL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::GetDomainContextL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::GetDomainContextL -->" ) + RThread thread; + aMessage.ClientL( thread ); + CleanupClosePushL( thread ); + + CDRMDomainContext* context = CDRMDomainContext::NewLC(); + HBufC8* domainId = NULL; + TInt size = 0; + TPtr8 data( NULL, 0 ); + _LIT_SECURITY_POLICY_V0(vidCheck, VID_DEFAULT); + // Check Default VID + + TPckg package( size ); + domainId = HBufC8::NewLC( User::LeaveIfError( IPCGETDESLEN1 ) ); + data.Set( domainId->Des() ); + IPCREAD1L( data ); + if ( domainId->Length() < KMinDomainIdLength || domainId->Length() + > SHA1_HASH ) + { + User::Leave( KErrArgument ); + } + + context->SetDomainIDL( *domainId ); + ROAPDB->FetchDomainContextL( *context ); + if ( !vidCheck.CheckPolicy( thread ) ) + { + // Remove sensitive data since trusted vendor id not present + RPointerArray emptyDomainKeys; + CleanupResetAndDestroyPushL( emptyDomainKeys ); + emptyDomainKeys.Reset(); + context->SetDomainKeysL( emptyDomainKeys ); + CleanupStack::PopAndDestroy( &emptyDomainKeys ); + } + size = context->Size(); + IPCWRITE0L( package ); + delete iPreparedData; + iPreparedData = NULL; + iPreparedData = context->ExportL(); + + CleanupStack::PopAndDestroy( domainId ); + CleanupStack::PopAndDestroy( context ); + CleanupStack::PopAndDestroy( &thread ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( " --> CRoapStorageSession::GetDomainContextL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::GetDataL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::GetDataL( const RMessage2& aMessage ) + { + if ( !iPreparedData ) + { + User::Leave( KErrNotReady ); + } + + IPCWRITE0L( iPreparedData->Des() ); + + delete iPreparedData; + iPreparedData = NULL; + + aMessage.Complete( KErrNone ); + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::DeleteRiContextL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::DeleteRiContextL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::DeleteRiContextL -->" ) + HBufC8* riId = NULL; + TPtr8 data( NULL, 0 ); + + SanitizeL( aMessage.GetDesLength( 0 ) ); + + riId = HBufC8::NewLC( IPCGETDESLEN0 ); + data.Set( riId->Des() ); + IPCREAD0L( data ); + + if ( riId->Length() != SHA1_HASH ) + { + User::Leave( KErrArgument ); + } + + ROAPDB->DeleteRightsIssuerContextL( *riId ); + + CleanupStack::PopAndDestroy( riId ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::DeleteRiContextL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::DeleteDomainContextL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::DeleteDomainContextL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::DeleteDomainContextL -->" ) + HBufC8* domainId = NULL; + TPtr8 data( NULL, 0 ); + + SanitizeL( aMessage.GetDesLength( 0 ) ); + + domainId = HBufC8::NewLC( IPCGETDESLEN0 ); + data.Set( domainId->Des() ); + IPCREAD0L( data ); + + if ( domainId->Length() < KMinDomainIdLength || domainId->Length() + > SHA1_HASH ) + { + User::Leave( KErrArgument ); + } + + ROAPDB->DeleteDomainContextL( *domainId ); + + CleanupStack::PopAndDestroy( domainId ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::DeleteDomainContextL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::DeleteExpiredRIsL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::DeleteExpiredRIsL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::DeleteExpiredRIsL -->" ) + TTime time; + TPckg package( time ); + + IPCREAD0L( package ); + ROAPDB->DeleteExpiredRightsIssuerContextsL( time ); + + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::DeleteExpiredRIsL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::DeleteExpiredDomainsL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::DeleteExpiredDomainsL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::DeleteExpiredDomainsL -->" ) + TTime time; + TPckg package( time ); + + IPCREAD0L( package ); + ROAPDB->DeleteExpiredDomainContextsL( time ); + + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::DeleteExpiredDomainsL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::WhiteListUrlExistsL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::WhiteListUrlExistsL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::WhiteListURLExistsL -->" ) + HBufC8* url = NULL; + TPtr8 data( NULL, 0 ); + TBool exists = EFalse; + + __UHEAP_MARK; + SanitizeL( aMessage.GetDesLength( 0 ) ); + User::LeaveIfError( IPCGETDESLEN1 ); + TBool fromPreConfiguredWhiteList( EFalse ); + TPckg preConfiguredInOutParam( fromPreConfiguredWhiteList ); + + url = HBufC8::NewLC( IPCGETDESLEN0 ); + data.Set( url->Des() ); + IPCREAD0L( data ); + IPCREAD1L( preConfiguredInOutParam ); + exists = ROAPDB->WhiteListURLExistsL( *url ); + + if ( exists ) + { + fromPreConfiguredWhiteList = EFalse; + } + else if ( fromPreConfiguredWhiteList ) + { + TPtrC8 whitelistElement( NULL, 0 ); + HBufC* buffer = HBufC::NewLC( KMaxWhiteListLen ); + HBufC8* whitelist = HBufC8::NewLC( KMaxWhiteListLen ); + + TPtr ptr( NULL, 0 ); + ptr.Set( buffer->Des() ); + CRepository* repository = CRepository::NewLC( KCRUidRoapHandler ); + repository->Get( KRoapHandlerRegistrationWhitelist, ptr ); + data.Set( whitelist->Des() ); + data.Copy( ptr ); + TLex8 lex( *whitelist ); + + TUriParser8 uri; + uri.Parse( *url ); + + const TDesC8& host = uri.Extract( EUriHost ); + while ( !exists && !lex.Eos() ) + { + whitelistElement.Set( lex.NextToken() ); + if ( host.Right( whitelistElement.Length() ).CompareF( + whitelistElement ) == 0 ) + { + exists = ETrue; + } + } + fromPreConfiguredWhiteList = exists; + CleanupStack::PopAndDestroy( repository ); + CleanupStack::PopAndDestroy( whitelist ); + CleanupStack::PopAndDestroy( buffer ); + } + + CleanupStack::PopAndDestroy( url ); + IPCWRITE1L( preConfiguredInOutParam ); + exists ? aMessage.Complete( KErrNone ) : aMessage.Complete( KErrNotFound ); + __UHEAP_MARKEND; + MACLOGLITDETAIL( "--> CRoapStorageSession::WhiteListURLExistsL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::GetDevicePublicKeyDerL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::GetDevicePublicKeyDerL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::GetDevicePublicKeyDerL -->" ) + HBufC8* publicKey = NULL; + TInt size = 0; + TPtr8 data( NULL, 0 ); + TPckg package( size ); + CX509Certificate* cert = NULL; + RPointerArray certChain; + + CleanupResetAndDestroyPushL( certChain ); + + iKeyStorage->GetCertificateChainL( certChain ); + if ( certChain.Count() > 0 ) + cert = CX509Certificate::NewL( *certChain[0] ); + else + User::Leave( KErrNotFound ); + CleanupStack::PopAndDestroy( &certChain ); + CleanupStack::PushL( cert ); + publicKey = cert->DataElementEncoding( + CX509Certificate::ESubjectPublicKeyInfo )->AllocLC(); + size = publicKey->Size(); + IPCWRITE0L( package ); + delete iPreparedData; + iPreparedData = NULL; + iPreparedData = publicKey; + CleanupStack::Pop( publicKey ); + CleanupStack::PopAndDestroy( cert ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::GetDevicePublicKeyDerL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::GetDeviceCertificateChainL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::GetDeviceCertificateChainL( + const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::GetCertificateChainL -->" ) + RPointerArray certChain; + HBufC8* certChainBuf = NULL; + TInt bufferSize = 0; + TPckg package( bufferSize ); + + CleanupResetAndDestroyPushL( certChain ); + + iKeyStorage->GetCertificateChainL( certChain ); + certChainBuf = ArrayToBufferLC( certChain ); + CleanupStack::Pop( certChainBuf ); + CleanupStack::PopAndDestroy( &certChain ); + CleanupStack::PushL( certChainBuf ); + bufferSize = certChainBuf->Size(); + IPCWRITE0L( package ); + delete iPreparedData; + iPreparedData = certChainBuf; + CleanupStack::Pop( certChainBuf ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::GetCertificateChainL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::SignL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::SignL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::SignL -->" ) + HBufC8* hash = NULL; + HBufC8* signature = NULL; + TInt size = 0; + TPtr8 data( NULL, 0 ); + TPckg package( size ); + + if ( IPCGETDESLEN1 <= 0 || IPCGETDESLEN1 >= KMaxTInt / 2 ) + { + User::Leave( KErrArgument ); + } + + hash = HBufC8::NewLC( IPCGETDESLEN1 ); + + data.Set( hash->Des() ); + IPCREAD1L( data ); + signature = OmaCrypto::RsaPssSignHashL( iKeyStorage, *hash ); + CleanupStack::PushL( signature ); + size = signature->Size(); + IPCWRITE0L( package ); + delete iPreparedData; + iPreparedData = signature; + CleanupStack::Pop( signature ); + CleanupStack::PopAndDestroy( hash ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::SignL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::RsaSignL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::RsaSignL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::RsaSignL -->" ) + HBufC8* hash = NULL; + HBufC8* signature = NULL; + TInt size = 0; + TPtr8 data( NULL, 0 ); + TPckg package( size ); + + if ( IPCGETDESLEN1 <= 0 || IPCGETDESLEN1 >= KMaxTInt / 2 ) + { + User::Leave( KErrArgument ); + } + + hash = HBufC8::NewLC( IPCGETDESLEN1 ); + + data.Set( hash->Des() ); + IPCREAD1L( data ); + signature = iKeyStorage->RsaSignL( data ); + CleanupStack::PushL( signature ); + size = signature->Size(); + IPCWRITE0L( package ); + delete iPreparedData; + iPreparedData = signature; + CleanupStack::Pop( signature ); + CleanupStack::PopAndDestroy( hash ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::RsaSignL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::SelectTrustedRootL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::SelectTrustedRootL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::SelectTrustedRootL -->" ) + RPointerArray riRoots; + RPointerArray deviceRoots; + HBufC8* rootsBuf = NULL; + TPtr8 data( NULL, 0 ); + TBool commonRootFound = EFalse; + TInt i = 0; + TInt j = 0; + + CleanupResetAndDestroyPushL( riRoots ); + CleanupResetAndDestroyPushL( deviceRoots ); + + SanitizeL( aMessage.GetDesLength( 0 ) ); + rootsBuf = HBufC8::NewLC( IPCGETDESLEN0 ); + + data.Set( rootsBuf->Des() ); + IPCREAD0L( data ); + riRoots = BufferToArrayL( *rootsBuf ); + iKeyStorage->GetTrustedRootsL( deviceRoots ); + + while ( i < deviceRoots.Count() && !commonRootFound ) + { + j = 0; + while ( j < riRoots.Count() && !commonRootFound ) + { + if ( deviceRoots[i]->CompareF( *riRoots[j] ) == KErrNone ) + { + commonRootFound = ETrue; + } + ++j; + } + ++i; + } + if ( !commonRootFound ) + { + User::Leave( KErrNotFound ); + } + + const TPtrC8 selectedRoot( *( deviceRoots[i - 1] ) ); + iKeyStorage->SelectTrustedRootL( selectedRoot ); + IPCWRITE1L( selectedRoot ); + MACLOGLITDETAIL( "Selected trusted root" ) + MACLOGHEXDETAIL( selectedRoot.Ptr(), selectedRoot.Length() ) + + CleanupStack::PopAndDestroy( rootsBuf ); + CleanupStack::PopAndDestroy( &deviceRoots ); + CleanupStack::PopAndDestroy( &riRoots ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::SelectTrustedRootL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::ActivateTrustedRootL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::ActivateTrustedRootL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::ActivateTrustedRootL -->" ) + TBuf8 trustedRoot; + + if ( IPCGETDESLEN0 <= 0 ) + { + // select default root + iKeyStorage->SelectTrustedRootL( KNullDesC8 ); + } + else + { + // select the root indicated by the client + IPCREAD0L( trustedRoot ); + if ( trustedRoot.Length() != SHA1_HASH ) + { + User::Leave( KErrArgument ); + } + iKeyStorage->SelectTrustedRootL( trustedRoot ); + } + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::ActivateTrustedRootL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::GetTrustedRootsL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::GetTrustedRootsL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::GetTrustedRootsL -->" ) + RPointerArray deviceRoots; + TInt size = 0; + HBufC8* rootsData = NULL; + + CleanupResetAndDestroyPushL( deviceRoots ); + + TPckg package( size ); + iKeyStorage->GetTrustedRootsL( deviceRoots ); + rootsData = ArrayToBufferLC( deviceRoots ); + size = rootsData->Size(); + IPCWRITE0L( package ); + delete iPreparedData; + iPreparedData = NULL; + iPreparedData = rootsData; + + CleanupStack::Pop( rootsData ); + CleanupStack::PopAndDestroy( &deviceRoots ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::GetTrustedRootsL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::GetRootCertificateL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::GetRootCertificateL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::GetRootCertificateL -->" ) + HBufC8* rootCertBuf( NULL ); + HBufC* subject( NULL ); + TInt size( 0 ); + TPtr data( NULL, 0 ); + RPointerArray rootCerts; + TPckg package( size ); + CX509Certificate* rootCert( NULL ); + HBufC* rootName( NULL ); + TInt i = 0; + + SanitizeL( IPCGETDESLEN1 ); + subject = HBufC::NewLC( User::LeaveIfError( IPCGETDESLEN1 ) ); + data.Set( subject->Des() ); + IPCREAD1L( data ); + + iKeyStorage->GetRootCertificatesL( rootCerts ); + + CleanupResetAndDestroyPushL( rootCerts ); + + for ( i = 0; i < rootCerts.Count() && !rootCertBuf; i++ ) + { + rootCert = CX509Certificate::NewLC( *( rootCerts[i] ) ); + rootName = rootCert->IssuerName().DisplayNameL(); + CleanupStack::PushL( rootName ); + const TInt compareResult( rootName->CompareF( *subject ) ); + CleanupStack::PopAndDestroy( rootName ); + CleanupStack::PopAndDestroy( rootCert ); + if ( compareResult == KErrNone ) + { + rootCertBuf = rootCerts[i]->AllocLC(); + } + } + + if ( !rootCertBuf ) + { + User::Leave( KErrNotFound ); + } + + size = rootCertBuf->Size(); + IPCWRITE0L( package ); + delete iPreparedData; + iPreparedData = NULL; + iPreparedData = rootCertBuf; + + CleanupStack::Pop( rootCertBuf ); + CleanupStack::PopAndDestroy( &rootCerts ); + CleanupStack::PopAndDestroy( subject ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::GetRootCertificateL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::DeleteExpiredContextsL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::DeleteExpiredContextsL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::DeleteExpiredContextsL -->" ) + TTime time; + TPckg package( time ); + + IPCREAD0L( package ); + ROAPDB->DeleteExpiredRightsIssuerContextsL( time ); + ROAPDB->DeleteExpiredDomainContextsL( time ); + + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::DeleteExpiredContextsL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::DeleteAllL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::DeleteAllL( const RMessage2& aMessage ) + { + + MACLOGLITDETAIL( "CRoapStorageSession::DeleteAllL -->" ) +#ifndef RD_MULTIPLE_DRIVE + + ROAPDB->DeleteAllL( KRIContextFile(), KDomainContextFile() ); + +#else //RD_MULTIPLE_DRIVE + RFs fs; + TInt driveNumber( -1 ); + TChar driveLetter; + DriveInfo::GetDefaultDrive( DriveInfo::EDefaultSystem, driveNumber ); + + User::LeaveIfError( fs.Connect() ); + CleanupClosePushL( fs ); + fs.DriveToChar( driveNumber, driveLetter ); + CleanupStack::PopAndDestroy( &fs ); + + TFileName riContextFile; + riContextFile.Copy( KRIContextFileName ); + __ASSERT_ALWAYS( riContextFile.Length()>0, User::Invariant() ); + riContextFile[0] = ( TUint )driveLetter; + + TFileName domainContextFile; + domainContextFile.Copy( KDomainContextFileName ); + __ASSERT_ALWAYS( domainContextFile.Length()>0, User::Invariant() ); + domainContextFile[0] = ( TUint )driveLetter; + + ROAPDB->DeleteAllL( riContextFile, domainContextFile ); + +#endif + + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::DeleteAllL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::GetMeteringDataL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::GetMeteringDataL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::GetMeteringDataL -->" ) +#ifndef RD_DRM_METERING + aMessage.Complete( KErrNotSupported ); +#else + HBufC8* riId = NULL; + HBufC8* meteringData = NULL; + HBufC8* encryptedMeteringData = NULL; + RDRMRightsClient client; + TInt mekAndMakSize = 0; + TInt meteringDataSize = 0; + TPtr8 data( NULL, 0 ); + TPtr8 ptr( NULL, 0 ); + TPckg MakMek( mekAndMakSize ); + TPckg dataSize( meteringDataSize ); + TBuf8 mac; + TBuf8 mek; + TBuf8 initializingVector; + CRSAPublicKey* riPublicKey = NULL; + CX509Certificate* cert = NULL; + CSHA1* hasher = NULL; + TBuf8 encKeyHash; + TX509KeyFactory factory; + TKeyTransportScheme selectedAlgorithm = EOma; + HBufC8* encryptedMekAndMak = NULL; + CDRMRIContext* context = NULL; + + User::LeaveIfError( client.Connect() ); + CleanupClosePushL( client ); + + SanitizeL( aMessage.GetDesLength( 0 ) ); + + riId = HBufC8::NewLC( IPCGETDESLEN0 ); + data.Set( riId->Des() ); + IPCREAD0L( data ); + + // generate mek + mek.SetLength( OmaCrypto::KKeySize ); + TRandom::Random( mek ); + + // generate mac + mac.SetLength( OmaCrypto::KMacSize ); + TRandom::Random( mac ); + + initializingVector.SetLength( KDCFKeySize ); + TRandom::Random( initializingVector ); + + context = CDRMRIContext::NewLC(); + context->SetRIIDL( *riId ); + ROAPDB->FetchRightsIssuerContextL( *context ); + + cert = CX509Certificate::NewLC( *( context->CertificateChain() )[0] ); + + hasher = CSHA1::NewL(); + CleanupStack::PushL( hasher ); + // Calculate SHA1_HASH for RI public key + hasher->Hash( *cert->DataElementEncoding( + CX509Certificate::ESubjectPublicKeyInfo ) ); + encKeyHash.Append( hasher->Final() ); + CleanupStack::PopAndDestroy( hasher ); + + riPublicKey = factory.RSAPublicKeyL( cert->PublicKey().KeyData() ); + CleanupStack::PopAndDestroy( cert ); + cert = NULL; + CleanupStack::PushL( riPublicKey ); + + // check if we are not using OMA algorithms + for ( TInt i = 0; i < context->Algorithms().Count(); i++ ) + { + if ( context->Algorithms()[i]->CompareF( KCmlaIp1() ) == KErrNone ) + { + selectedAlgorithm = ECmlaIp1; + break; + } + } + + // Wrap Mek and Mac with RI's public key + if ( selectedAlgorithm == EOma ) + { + encryptedMekAndMak = OmaCrypto::RsaKemKwsEncryptL( riPublicKey, mek, + mac ); + } + else + { // CMLA + encryptedMekAndMak = CmlaCrypto::CmlaIpEncryptL( selectedAlgorithm, + riPublicKey, mek, mac ); + } + CleanupStack::PopAndDestroy( riPublicKey ); + riPublicKey = NULL; + CleanupStack::PopAndDestroy( context ); + context = NULL; + + CleanupStack::PushL( encryptedMekAndMak ); + + mekAndMakSize = encryptedMekAndMak->Size(); + // Get the actual metering data!!! + meteringData = client.GetMeteringDataL( *riId ); + + if ( !meteringData ) + { + MACLOGLIT( "No metering Data found from DB!:" ) + } + else + { + MACLOGLIT( "Raw meteringData:" ) + MACLOGHEX( meteringData->Ptr(), meteringData->Length() ) + CleanupStack::PushL( meteringData ); + + encryptedMeteringData = DrmAesCrypto::DrmAesEncryptL( mek, + initializingVector, ETrue, meteringData->Des() ); + + CleanupStack::PopAndDestroy( meteringData ); + meteringData = NULL; + + CleanupStack::PushL( encryptedMeteringData ); + + MACLOGLIT( "Ciphered meteringData with 128-bit AESCBC:" ) + MACLOGHEX( encryptedMeteringData->Ptr(), encryptedMeteringData->Length()) + meteringDataSize = encryptedMeteringData->Size(); + } + + IPCWRITE1L( MakMek ); + IPCWRITE2L( dataSize ); + if ( iPreparedData ) + { + delete iPreparedData; + iPreparedData = NULL; + } + iPreparedData = HBufC8::NewL( OmaCrypto::KMacSize + SHA1_HASH + + mekAndMakSize + meteringDataSize ); + ptr.Set( iPreparedData->Des() ); + ptr.Copy( mac ); + ptr.Append( encKeyHash ); + ptr.Append( *encryptedMekAndMak ); + if ( encryptedMeteringData ) + { + ptr.Append( *encryptedMeteringData ); + CleanupStack::PopAndDestroy( encryptedMeteringData ); + } + + MACLOGLIT( "Final iPreparedData:" ) + MACLOGHEX( iPreparedData->Ptr(), iPreparedData->Length() ) + + CleanupStack::PopAndDestroy( encryptedMekAndMak ); + CleanupStack::PopAndDestroy( riId ); + CleanupStack::PopAndDestroy( &client ); + // riId, client + aMessage.Complete( KErrNone ); +#endif //RD_DRM_METERING + MACLOGLITDETAIL( "--> CRoapStorageSession::GetMeteringDataL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::DeleteMeteringDataL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::DeleteMeteringDataL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::DeleteMeteringDataL -->" ) +#ifndef RD_DRM_METERING + aMessage.Complete( KErrNotSupported ); +#else + HBufC8* riId = NULL; + TPtr8 data( NULL, 0 ); + RDRMRightsClient client; + + User::LeaveIfError( client.Connect() ); + CleanupClosePushL( client ); + riId = HBufC8::NewLC( User::LeaveIfError( IPCGETDESLEN0 ) ); + data.Set( riId->Des() ); + IPCREAD0L( data ); + client.DeleteMeteringDataL( *riId ); + + CleanupStack::PopAndDestroy( riId ); + CleanupStack::PopAndDestroy( &client ); + + aMessage.Complete( KErrNone ); +#endif // RD_DRM_METERING + MACLOGLITDETAIL( "--> CRoapStorageSession::DeleteMeteringDataL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::GetAllRIContextsL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::GetAllRIContextsL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::GetAllRIContextsL -->" ) +#ifndef RD_DRM_METERING + aMessage.Complete( KErrNotSupported ); +#else + TInt size = 0; + TPtr8 data( NULL, 0 ); + CDRMPointerArray* contexts = CDRMPointerArray< + CDRMRIContext>::NewLC(); + contexts->SetAutoCleanup( ETrue ); + + TPckg package( size ); + + ROAPDB->FetchAllRightsIssuerContextsL( *contexts ); + + // Calculate the size of the output buffer: + if ( contexts->Count() ) + { + size = contexts->Count() * sizeof(TInt) + sizeof(TInt); + for ( TInt i = 0; i < contexts->Count(); i++ ) + { + size += ( *contexts )[i]->Size(); + } + } + else + { + User::Leave( KErrNotFound ); + } + + IPCWRITE0L( package ); + + // Create a buffer of the proper size and export the data to the buffer: + if ( iPreparedData ) + { + delete iPreparedData; + iPreparedData = NULL; + } + iPreparedData = HBufC8::NewMaxL( size ); + + if ( !iPreparedData ) + { + User::Leave( KErrNoMemory ); + } + + RMemWriteStream stream( ( TAny* )( iPreparedData->Ptr() ), size ); + CleanupClosePushL( stream ); + TInt value = 0; + + for ( TInt i = 0; i < contexts->Count(); i++ ) + { + // Size: + value = ( *contexts )[i]->Size(); + stream.WriteInt32L( value ); + + // Data: + ( *contexts )[i]->ExternalizeL( stream ); + } + // Finishing size: + value = 0; + stream.WriteInt32L( value ); + + CleanupStack::PopAndDestroy( 2, contexts ); // stream, contexts + + aMessage.Complete( KErrNone ); +#endif // RD_DRM_METERING + MACLOGLITDETAIL( "--> CRoapStorageSession::GetAllRIContextsL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::UpdateRIContextL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::UpdateRIContextL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::UpdateRIContextL -->" ) +#ifndef RD_DRM_METERING + aMessage.Complete( KErrNotSupported ); +#else + CDRMRIContext* context = NULL; + HBufC8* contextData = NULL; + TPtr8 data( NULL, 0 ); + TInt size = 0; + + size = User::LeaveIfError( IPCGETDESLEN0 ); + contextData = HBufC8::NewMaxLC( size ); + data.Set( const_cast ( contextData->Ptr() ), 0, size ); + IPCREAD0L( data ); + context = CDRMRIContext::NewLC(); + context->ImportL( data ); + + // Update RI context: + ROAPDB->UpdateRightsIssuerContextL( *context ); + + CleanupStack::PopAndDestroy( context ); + CleanupStack::PopAndDestroy( contextData ); + aMessage.Complete( KErrNone ); +#endif // RD_DRM_METERING + MACLOGLITDETAIL( "--> CRoapStorageSession::UpdateRIContextL" ) + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::UpdateDrmTimeL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::UpdateDrmTimeL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::UpdateDrmTimeL -->" ) + COCSPResponseDecoder* responseDecoder = NULL; + COCSPResponse* response = NULL; + RPointerArray ocspResponses; + + RPointerArray riCertChain; + + TBool clockUpdated( EFalse ); + TPckg retBuf( clockUpdated ); + + // Some sanity checks + const TInt argLen0( IPCGETDESLEN0 ); + const TInt argLen1( IPCGETDESLEN1 ); + const TInt argLen2( IPCGETDESLEN2 ); + SanitizeL( argLen0 ); + SanitizeL( argLen1 ); + SanitizeL( argLen2 ); + User::LeaveIfError( IPCGETDESLEN3 ); + + RBuf8 readBuf; + CleanupClosePushL( readBuf ); + readBuf.CreateL( Max( argLen0, Max( argLen1, argLen2 ) ) ); + + readBuf.Zero(); + IPCREAD0L( readBuf ); + MACLOGLDETAIL( "---- read Ri Cert Chain ----" ) + MACLOGHEXDETAIL( readBuf.Ptr(), readBuf.Length() ) + riCertChain = BufferToArrayL( readBuf ); + CleanupResetAndDestroyPushL( riCertChain ); + + readBuf.Zero(); + IPCREAD1L( readBuf ); + MACLOGLDETAIL( "---- read serialized OCSP responses ----" ) + MACLOGHEXDETAIL( readBuf.Ptr(), readBuf.Length() ) + ocspResponses = BufferToArrayL( readBuf ); + CleanupResetAndDestroyPushL( ocspResponses ); + + readBuf.Zero(); + IPCREAD2L( readBuf ); + MACLOGLDETAIL( "---- read request nonce ----" ) + MACLOGHEXDETAIL( readBuf.Ptr(), readBuf.Length() ) + const TPtrC8 regReqNonce( readBuf ); // Do not modify readBuf after this. + + // Get trusted roots and root certificates. + RPointerArray trustedRoots; + CleanupResetAndDestroyPushL( trustedRoots ); + iKeyStorage->GetTrustedRootsL( trustedRoots ); + RPointerArray rootCertificates; + CleanupResetAndDestroyPushL( rootCertificates ); + iKeyStorage->GetRootCertificatesL( rootCertificates ); + + //First, check, if update is allowed + if ( ocspResponses.Count() ) + { + responseDecoder = COCSPResponseDecoder::NewL( *ocspResponses[0] ); + CleanupStack::PushL( responseDecoder ); + response = responseDecoder->TakeResponse(); // CRoapEng owns the response now + User::LeaveIfNull( response ); + CleanupStack::PopAndDestroy( responseDecoder ); + responseDecoder = NULL; + CleanupStack::PushL( response ); + if ( ::IsTimeUpdateAllowedL( trustedRoots, rootCertificates, + riCertChain, *response, regReqNonce ) ) + { + iLazyClock->UpdateSecureTimeL( response->ProducedAt(), KTzZulu ); + clockUpdated = ETrue; + MACLOGLIT( "DRM time updated" ) + } + + CleanupStack::PopAndDestroy( response ); + } + else + { + MACLOGLIT( "No OCSP responses present!" ) + // So wrong argument got + } + CleanupStack::PopAndDestroy( &rootCertificates ); + CleanupStack::PopAndDestroy( &trustedRoots ); + CleanupStack::PopAndDestroy( &ocspResponses ); + CleanupStack::PopAndDestroy( &riCertChain ); + CleanupStack::PopAndDestroy( &readBuf ); + IPCWRITE3L( retBuf ); + + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::UpdateDrmTimeL" ) + } + +// --------------------------------------------------------------------------- +// BufferToArrayL +// Created buffer will contain +// +// --------------------------------------------------------------------------- +// +LOCAL_C RPointerArray BufferToArrayL( TDesC8& aBuffer ) + { + TInt32 count = 0; + HBufC8* element = NULL; + RPointerArray array; + CleanupResetAndDestroyPushL( array ); + TInt size = aBuffer.Size(); + RMemReadStream stream( ( TAny* )( aBuffer.Ptr() ), size ); + CleanupClosePushL( stream ); + + // amount of elements + count = stream.ReadInt32L(); + + // for each element in RPointerArray + for ( TInt i = 0; i < count; i++ ) + { + // Read the element and append it to array + element = HBufC8::NewLC( stream, KMaxElementLength ); + array.AppendL( element ); + CleanupStack::Pop( element ); + } + + CleanupStack::PopAndDestroy( &stream ); + CleanupStack::Pop( &array ); + return array; + } + +// --------------------------------------------------------------------------- +// ArrayToBuffer +// Created buffer will contain +// --------------------------------------------------------------------------- +// +LOCAL_C HBufC8* ArrayToBufferLC( const RPointerArray& aArray ) + { + HBufC8* buffer = NULL; + TInt32 sizeOfElements = 0; + + for ( TInt i = 0; i < aArray.Count(); i++ ) + { + sizeOfElements += aArray[i]->Length() + sizeof(TInt); // sizeof(TInt) is for + // element length info + } + // length of elements + amount of elements + sizeOfElements += sizeof(TInt32); + + buffer = HBufC8::NewMaxLC( sizeOfElements ); + + RMemWriteStream stream( ( TAny* )( buffer->Ptr() ), sizeOfElements ); + CleanupClosePushL( stream ); + + stream.WriteInt32L( aArray.Count() ); + + for ( TInt i = 0; i < aArray.Count(); i++ ) + { + stream << *( aArray[i] ); + } + + CleanupStack::PopAndDestroy( &stream ); + + return buffer; + } + +// --------------------------------------------------------------------------- +// UnwrapDomainKeyL +// --------------------------------------------------------------------------- +// +LOCAL_C void UnwrapDomainKeyL( + MDrmKeyStorage* aKeyStorage, + const TDesC8& aProtectedDomainKey, + HBufC8*& aDomainKey, + HBufC8*& aMacKey, + TKeyTransportScheme& aTransportScheme ) + { + MACLOGLITDETAIL( "::UnwrapDomainKeyL -->" ) + TBuf8 mac; + TBuf8 dk; + TPtrC8 macAndRek( 0, 0 ); + TPtrC8 wrappedCek( 0, 0 ); + + if ( aTransportScheme == EOma ) + { + OmaCrypto::RsaKemKwsDecryptL( aKeyStorage, aProtectedDomainKey, dk, + mac ); + } + else + { + CmlaCrypto::CmlaIpDecryptL( aTransportScheme, aKeyStorage, + aProtectedDomainKey, dk, mac ); + } + + HBufC8* domainKey( dk.AllocLC() ); + aMacKey = mac.AllocL(); + CleanupStack::Pop( domainKey ); + aDomainKey = domainKey; + MACLOGLITDETAIL( "--> ::UnwrapDomainKeyL" ) + } + +// --------------------------------------------------------------------------- +// VerifyMac +// --------------------------------------------------------------------------- +// +LOCAL_C TBool VerifyMacL( + TDesC8& aDomainElements, + TDesC8& aMacs, + RPointerArray& aMacKeys ) + { + MACLOGLITDETAIL( "::VerifyMacL -->" ) + __UHEAP_MARK; + RPointerArray domainArray; + RPointerArray macArray; + CMessageDigest* hMac = NULL; + HBufC8* domainKeyWithNs = NULL; + TPtr8 domainKeyWithNsPtr( NULL, NULL ); + TPtrC8 hmac_value( KNullDesC8 ); + TInt index = 0; + + CleanupResetAndDestroyPushL( domainArray ); + CleanupResetAndDestroyPushL( macArray ); + + domainArray = BufferToArrayL( aDomainElements ); + macArray = BufferToArrayL( aMacs ); + + if ( domainArray.Count() != macArray.Count() || macArray.Count() + != aMacKeys.Count() ) + { + User::Leave( KErrRoapServerFatal ); + } + + //Verify macs + for ( TInt i = 0; i < aMacKeys.Count(); i++ ) + { + // Add ROAP namespaces + domainKeyWithNs = HBufC8::NewLC( domainArray[i]->Length() + 2 + * KRoapXmlNs().Length() ); + domainKeyWithNsPtr.Set( domainKeyWithNs->Des() ); + index = domainArray[i]->Find( KRoapDomainKey() ); + if ( index == KErrNotFound ) + { + index = domainArray[i]->Find( KRoapX509SPKIHash() ); + if ( index == KErrNotFound ) + { + User::Leave( KErrCorrupt ); + } + index += KRoapX509SPKIHash().Length(); + } + else + { + index += KRoapDomainKey().Length(); + } + domainKeyWithNsPtr.Copy( domainArray[i]->Left( index ) ); + domainKeyWithNsPtr.Append( KRoapXmlNs() ); + domainKeyWithNsPtr.Append( domainArray[i]->Right( + domainArray[i]->Length() - index ) ); + + hMac = CMessageDigestFactory::NewHMACLC( CMessageDigest::ESHA1, + *aMacKeys[i] ); + hMac->Update( domainKeyWithNsPtr ); + + hmac_value.Set( hMac->Final() ); + + MACLOGLIT( "DomainKeyElement:" ) + MACLOGHEX( domainKeyWithNsPtr.Ptr(), domainKeyWithNsPtr.Length() ) + MACLOGLIT( "Calculated HMAC_value:" ) + MACLOGHEX( hmac_value.Ptr(), hmac_value.Length() ) + MACLOGLIT( "HMAC_value:" ) + MACLOGHEX( macArray[i]->Ptr(), macArray[i]->Length() ) + + if ( hmac_value.CompareF( *macArray[i] ) != 0 ) + { + // MAC validation failed + User::Leave( KErrRightsServerMacFailed ); + } + CleanupStack::PopAndDestroy( 2, domainKeyWithNs ); // hMac, domainKeyWithNs + } + + CleanupStack::PopAndDestroy( &macArray ); + CleanupStack::PopAndDestroy( &domainArray ); + __UHEAP_MARKEND; + MACLOGLITDETAIL( "--> ::VerifyMacL" ) + return ETrue; + } + +// --------------------------------------------------------------------------- +// CRoapStorageSession::VerifyOcspResponsesL() +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::VerifyOcspResponsesL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::VerifyOcspResponsesL -->" ) + + const TInt argLen0( IPCGETDESLEN0 ); + const TInt argLen1( IPCGETDESLEN1 ); + const TInt argLen2( IPCGETDESLEN2 ); + SanitizeL( argLen0 ); + SanitizeL( argLen1 ); + SanitizeL( argLen2 ); + User::LeaveIfError( IPCGETDESLEN3 ); + + COCSPResponseDecoder* responseDecoder = NULL; + COCSPResponse* response = NULL; + COCSPResponseCertInfo* certInfo = NULL; + COCSPCertID* certID = NULL; + CX509Certificate* ocspCert = NULL; + TBool result = EFalse; + TInt certInfoCount = 0; + TInt found = KErrNone; + CX509Certificate* riCaCert( NULL ); + + TPckg package( result ); + + RBuf8 readBuf; + CleanupClosePushL( readBuf ); + readBuf.CreateL( Max( argLen0, Max( argLen1, argLen2 ) ) ); + + // read arguments + IPCREAD0L( readBuf ); + RPointerArray ocspResponses( BufferToArrayL( readBuf ) ); + CleanupResetAndDestroyPushL( ocspResponses ); + readBuf.Zero(); + + IPCREAD1L( readBuf ); + riCaCert = CX509Certificate::NewLC( readBuf ); + readBuf.Zero(); + + IPCREAD2L( readBuf ); + RPointerArray certSerialNums( BufferToArrayL( readBuf ) ); + CleanupResetAndDestroyPushL( certSerialNums ); + readBuf.Zero(); + + // Check OcspResponses. Only the very first response is checked. + if ( ocspResponses.Count() ) + { + responseDecoder = COCSPResponseDecoder::NewL( *ocspResponses[0] ); + CleanupStack::PushL( responseDecoder ); + response = responseDecoder->TakeResponse(); + CleanupStack::PopAndDestroy( responseDecoder ); + User::LeaveIfNull( response ); + CleanupStack::PushL( response ); + + if ( !response ) + { + MACLOGLIT( "No OCSP certificate!" ) + User::Leave( KErrArgument ); + } + + result = VerifyOcspCertChainL( *response, riCaCert, ocspCert ); + + CleanupStack::PushL( ocspCert ); + + // validate OCSP response signature and + // that all the RI cert in the chain is valid (status == good) + if ( result ) + { + result = response->VerifySignatureL( + ocspCert->PublicKey().KeyData() ); + } + + if ( result ) + { + certInfoCount = response->CertCount(); + if ( certSerialNums.Count() && result ) + { + TBool isCertStatusFound = EFalse; + for ( TInt i = 0; i < certInfoCount && result; i++ ) + { + certInfo = response->CertInfo( i ); // certInfo is owned by response + certID = certInfo->CertID(); // certID is owned by certInfo + found = certSerialNums[0]->Compare( + certID->SerialNumber() ); + if ( found == KErrNone ) + { + isCertStatusFound = ETrue; + if ( certInfo->Status() != OCSP::EGood ) + { + result = EFalse; + } + } + } + if ( !isCertStatusFound ) + { + result = EFalse; + } + } + } + + CleanupStack::PopAndDestroy( ocspCert ); + CleanupStack::PopAndDestroy( response ); + } + CleanupStack::PopAndDestroy( &certSerialNums ); + CleanupStack::PopAndDestroy( riCaCert ); + CleanupStack::PopAndDestroy( &ocspResponses ); + CleanupStack::PopAndDestroy( &readBuf ); + +#ifdef _ROAP_TESTING + if ( result ) + { + MACLOGLIT( "OCSP response verification ok." ) + } + else + { + MACLOGLIT( "OCSP response verification failed." ) + } +#endif + +#ifdef _DISABLE_OCSP_CHECK + result = ETrue; +#endif + IPCWRITE3L( package ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::VerifyOcspResponsesL" ) + } +// --------------------------------------------------------------------------- +// CRoapStorageSession::GetOcspResponderIdL +// --------------------------------------------------------------------------- +// +void CRoapStorageSession::GetOcspResponderIdL( const RMessage2& aMessage ) + { + MACLOGLITDETAIL( "CRoapStorageSession::GetOCSPResponderIdL -->" ) + COCSPResponseDecoder* rd( NULL ); + COCSPResponse* response( NULL ); + + RPointerArray certArray; + CX509Certificate* cert( NULL ); + CSHA1* hash( NULL ); + TInt pos( 0 ); + TInt size( 0 ); + TPckg sizeArg( size ); + + SanitizeL( IPCGETDESLEN0 ); + User::LeaveIfError( IPCGETDESLEN1 ); + CleanupResetAndDestroyPushL( certArray ); + + HBufC8* riId( HBufC8::NewLC( IPCGETDESLEN0 ) ); + TPtr8 data( riId->Des() ); + IPCREAD0L( data ); + if ( riId->Length() != SHA1_HASH ) + { + User::Leave( KErrArgument ); + } + CDRMRIContext* context( CDRMRIContext::NewLC() ); + context->SetRIIDL( *riId ); + CleanupStack::Pop( context ); + CleanupStack::PopAndDestroy( riId ); + riId = NULL; + CleanupStack::PushL( context ); + ROAPDB->FetchRightsIssuerContextL( *context ); + + const RPointerArray& ocspResponses( context->OCSPResponse() ); + // Fetch OCSP response from given RiId + + if ( !ocspResponses.Count() ) + { + User::Leave( KErrRoapDevice ); + } + + rd = COCSPResponseDecoder::NewL( *ocspResponses[0] ); + CleanupStack::PushL( rd ); + response = rd->TakeResponse(); // CRoapEng owns the response now + CleanupStack::PopAndDestroy( rd ); + rd = NULL; + CleanupStack::PopAndDestroy( context ); + context = NULL; + User::LeaveIfNull( response ); + + CleanupStack::PushL( response ); + const TPtrC8* ocspCerts( response->SigningCerts() ); + + TBool ocspResponseUsable( EFalse ); + // Get SecureTime from ClockServer + TTime secureTime; + TInt zone( KTzZulu ); + DRMClock::ESecurityLevel securityLevel( DRMClock::KInsecure ); + iLazyClock->GetSecureTimeL( secureTime, zone, securityLevel ); + + if ( securityLevel == DRMClock::KSecure ) + { + ocspResponseUsable = ETrue; + } + // Verify that OCSP responses are not expired + for ( TInt i( 0 ); ocspResponseUsable && i < response->CertCount(); ++i ) + { + const TTime* nextUpdate( response->CertInfo( i )->NextUpdate() ); + if ( !nextUpdate || *nextUpdate <= secureTime || response->CertInfo( + i )->RevocationTime() ) + { + ocspResponseUsable = EFalse; + } + } + + if ( ocspResponseUsable ) + { + while ( ocspCerts && pos < ocspCerts->Length() ) + { + cert = CX509Certificate::NewLC( *ocspCerts, pos ); + certArray.AppendL( cert ); + CleanupStack::Pop( cert ); + } + ocspCerts = NULL; + } + CleanupStack::PopAndDestroy( response ); + response = NULL; + + if ( cert ) + { + // hash the SubjectPublicKeyInfo element + hash = CSHA1::NewL(); + CleanupStack::PushL( hash ); + hash->Hash( *cert->DataElementEncoding( + CX509Certificate::ESubjectPublicKeyInfo ) ); + + delete iPreparedData; + iPreparedData = NULL; + iPreparedData = hash->Final().AllocL(); + CleanupStack::PopAndDestroy( hash ); + size = iPreparedData->Length(); + MACLOGLIT( "Got OCSP responder" ) + MACLOGHEX( iPreparedData->Ptr(), iPreparedData->Length() ) + } + CleanupStack::PopAndDestroy( &certArray ); + IPCWRITE1L( sizeArg ); + aMessage.Complete( KErrNone ); + MACLOGLITDETAIL( "--> CRoapStorageSession::GetOCSPResponderIdL" ) + } + +// End of File