natfw/natfwunsaf_protocols/unsaf_codec/src/natfwunsafmessageintegrityattribute.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/natfw/natfwunsaf_protocols/unsaf_codec/src/natfwunsafmessageintegrityattribute.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,337 @@
+/*
+* Copyright (c) 2006-2007 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:   
+*
+*/
+
+
+
+
+#include "natfwunsafmessageintegrityattribute.h"
+#include "natfwunsafmessage.h"
+#include "natfwunsaflog.h"
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::DecodeL
+// -----------------------------------------------------------------------------
+//
+CNATFWUNSAFMessageIntegrityAttribute*
+CNATFWUNSAFMessageIntegrityAttribute::DecodeL(const TDesC8& aValue)
+    {
+    CNATFWUNSAFMessageIntegrityAttribute* self =
+        new (ELeave) CNATFWUNSAFMessageIntegrityAttribute();
+    CleanupStack::PushL(self);
+    self->DecodeValueL(aValue);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::NewL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CNATFWUNSAFMessageIntegrityAttribute*
+CNATFWUNSAFMessageIntegrityAttribute::NewL(const TDesC8& aSharedSecret,
+                                        CBufBase& aNATFWUNSAFMessage,
+                                        TBool aLongTerm)
+    {
+    CNATFWUNSAFMessageIntegrityAttribute* self =
+        CNATFWUNSAFMessageIntegrityAttribute::NewLC(aSharedSecret,
+            aNATFWUNSAFMessage, aLongTerm);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::NewLC
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CNATFWUNSAFMessageIntegrityAttribute*
+CNATFWUNSAFMessageIntegrityAttribute::NewLC(const TDesC8& aSharedSecret,
+                                         CBufBase& aNATFWUNSAFMessage,
+                                         TBool aLongTerm)
+    {
+    CNATFWUNSAFMessageIntegrityAttribute* self =
+        new (ELeave) CNATFWUNSAFMessageIntegrityAttribute();
+    CleanupStack::PushL(self);
+    self->ConstructL(aSharedSecret,aNATFWUNSAFMessage,aLongTerm);
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::DecodeAttributeL
+// -----------------------------------------------------------------------------
+//
+CNATFWUNSAFAttribute*
+CNATFWUNSAFMessageIntegrityAttribute::DecodeAttributeL(
+    const TDesC8& aByteStream)
+    {
+    CheckLengthL(aByteStream);
+
+    return DecodeL(aByteStream.Mid(EValueOffset));
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::CNATFWUNSAFMessageIntegrityAttribute
+// -----------------------------------------------------------------------------
+//
+CNATFWUNSAFMessageIntegrityAttribute::CNATFWUNSAFMessageIntegrityAttribute()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::ConstructL
+// Update message header's length field to include the MESSAGE-INTEGRITY before
+// computing the HMAC.
+// -----------------------------------------------------------------------------
+//
+void CNATFWUNSAFMessageIntegrityAttribute::ConstructL(
+    const TDesC8& aSharedSecret, CBufBase& aNATFWUNSAFMessage, TBool aLongTerm)
+    {
+    iLongTerm = aLongTerm;
+    TInt length = CNATFWUNSAFMessage::MessageLength(aNATFWUNSAFMessage.Ptr(0));
+    CNATFWUNSAFMessage::SetMessageLength(aNATFWUNSAFMessage,
+                                    length + EValueOffset + SHA1_HASH);
+    iLongTerm ? ComputeLongTermHMACL(aSharedSecret, aNATFWUNSAFMessage, iHash)
+              : ComputeShortTermHMACL(aSharedSecret, aNATFWUNSAFMessage, iHash);
+
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::~CNATFWUNSAFMessageIntegrityAttribute
+// -----------------------------------------------------------------------------
+//
+CNATFWUNSAFMessageIntegrityAttribute::~CNATFWUNSAFMessageIntegrityAttribute()
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::Type
+// -----------------------------------------------------------------------------
+//
+CNATFWUNSAFAttribute::TType CNATFWUNSAFMessageIntegrityAttribute::Type() const
+    {
+    return EMessageIntegrity;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::EncodeValueL
+// -----------------------------------------------------------------------------
+//
+HBufC8* CNATFWUNSAFMessageIntegrityAttribute::EncodeValueL() const
+    {
+    HBufC8* encodedValue = HBufC8::NewL(SHA1_HASH);
+    *encodedValue = iHash;
+    return encodedValue;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::CheckMessageIntegrityL
+// Exclude MESSAGE-INTEGRITY attribute from HMAC computing. It is located at the
+// end of the message.
+// If computed hash doesn't match, retry by excluding a possible FINGERPRINT
+// attribute.
+// If computed hash still doesn't match, retry so that the message header's
+// length field doesn't include the MESSAGE-INTEGRITY.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CNATFWUNSAFMessageIntegrityAttribute::CheckMessageIntegrityL(
+    const TDesC8& aNATFWUNSAFMessage,
+    const TDesC8& aSharedSecret) const
+    {
+    const TInt KMessageIntegritySize = EValueOffset + SHA1_HASH;
+    //Check there is enough data
+    __ASSERT_ALWAYS(aNATFWUNSAFMessage.Length() >= KMessageIntegritySize,
+                    User::Leave(KErrArgument));
+
+    CBufBase* message = CBufFlat::NewL(EInputBlockSize);
+    CleanupStack::PushL(message);
+
+    message->InsertL(0,
+                     aNATFWUNSAFMessage,
+                     aNATFWUNSAFMessage.Length() - KMessageIntegritySize);
+
+    //This buffer is for possible FINGERPRINT removal
+    CBufBase* message2 = CBufFlat::NewL(EInputBlockSize);
+    CleanupStack::PushL(message2);
+    const TInt KFingerprintSize = EValueOffset + 4;
+    message2->InsertL(0,
+                     aNATFWUNSAFMessage,
+                     aNATFWUNSAFMessage.Length() - KMessageIntegritySize -
+                        KFingerprintSize);
+
+    TSHA1_Hash hash;
+    iLongTerm ? ComputeLongTermHMACL(aSharedSecret, *message, hash)
+              : ComputeShortTermHMACL(aSharedSecret, *message, hash);
+
+    TBool match = (hash == iHash);
+    NATFWUNSAF_INTLOG("Checking MSG-INT, match", match)
+
+    if (!match)
+        {
+        // Try excluding a possible FINGERPRINT attribute
+        NATFWUNSAF_LOG("MSG-INT didn't match, try removing FINGERPRINT")
+
+        //Message length changed since calculating the HMAC, decrease it
+        TInt newLength = aNATFWUNSAFMessage.Length() -
+            CNATFWUNSAFMessage::EHeaderSize - KFingerprintSize;
+
+        CNATFWUNSAFMessage::SetMessageLength(*message2, newLength);
+
+        iLongTerm ? ComputeLongTermHMACL(aSharedSecret, *message2, hash)
+                  : ComputeShortTermHMACL(aSharedSecret, *message2, hash);
+
+        match = (hash == iHash);
+
+        NATFWUNSAF_INTLOG("Checking MSG-INT 2nd try, match", match)
+        }
+
+    if (!match)
+        {
+        TInt newLength = aNATFWUNSAFMessage.Length() -
+            (KMessageIntegritySize + CNATFWUNSAFMessage::EHeaderSize);
+        NATFWUNSAF_INTLOG("MSG-INT didn't match, try with header length",
+            newLength)
+        CNATFWUNSAFMessage::SetMessageLength(*message, newLength);
+
+        iLongTerm ? ComputeLongTermHMACL(aSharedSecret, *message, hash)
+                  : ComputeShortTermHMACL(aSharedSecret, *message, hash);
+
+        match = (hash == iHash);
+        NATFWUNSAF_INTLOG("Checking MSG-INT 3rd try, match", match)
+        }
+    CleanupStack::PopAndDestroy(message2);
+    CleanupStack::PopAndDestroy(message);
+    return hash == iHash;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::UseLongTermCredentials
+// Sets credential lifetime.
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CNATFWUNSAFMessageIntegrityAttribute::UseLongTermCredentials(
+    TBool aLongTerm)
+    {
+    iLongTerm = aLongTerm;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::CheckLengthL
+// This attribute has a fixed length
+// -----------------------------------------------------------------------------
+//
+void CNATFWUNSAFMessageIntegrityAttribute::CheckLengthL(
+    const TDesC8& aByteStream)
+    {
+    __ASSERT_ALWAYS(ParseLengthL(aByteStream) == SHA1_HASH,
+                    User::Leave(KErrCorrupt));
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::DecodeValueL
+// -----------------------------------------------------------------------------
+//
+void CNATFWUNSAFMessageIntegrityAttribute::DecodeValueL(const TDesC8& aValue)
+    {
+    __ASSERT_ALWAYS(aValue.Length() >= static_cast<TInt>(SHA1_HASH),
+                    User::Leave(KErrArgument));
+
+    TPtrC8 ptrToHash = aValue.Left(SHA1_HASH);
+    iHash = ptrToHash;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::ComputeShortTermHMACL
+// Pad the aNATFWUNSAFMessage with zeroes to make its length a multiple of
+// EInputBlockSize bytes.
+// -----------------------------------------------------------------------------
+//
+void CNATFWUNSAFMessageIntegrityAttribute::ComputeShortTermHMACL(
+    const TDesC8& aSharedSecret,
+    CBufBase& aNATFWUNSAFMessage,
+    TSHA1_Hash& aHash) const
+    {
+    CSHA1* sha1 = CSHA1::NewL();
+    CleanupStack::PushL(sha1);
+    CHMAC* hmac = CHMAC::NewL(aSharedSecret, sha1);
+    CleanupStack::Pop(sha1);
+    CleanupStack::PushL(hmac);
+
+    DoComputeSHA1L(aHash, hmac, aNATFWUNSAFMessage);
+
+    CleanupStack::PopAndDestroy(hmac);
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::ComputeLongTermHMACL
+// Pad the aNATFWUNSAFMessage with zeroes to make its length a multiple of
+// EInputBlockSize bytes.
+// -----------------------------------------------------------------------------
+//
+void CNATFWUNSAFMessageIntegrityAttribute::ComputeLongTermHMACL(
+    const TDesC8& aSharedSecret,
+    CBufBase& aNATFWUNSAFMessage,
+    TSHA1_Hash& aHash) const
+    {
+    CMD5* md5 = CMD5::NewL();
+    CleanupStack::PushL(md5);
+    CSHA1* sha1 = CSHA1::NewL();
+    CleanupStack::PushL(sha1);
+
+    // Pass the 16 byte MD5-hash as key for HMAC
+    CHMAC* hmac = CHMAC::NewL(md5->Hash(aSharedSecret), sha1);
+    CleanupStack::Pop(sha1);
+    CleanupStack::PopAndDestroy(md5);
+    CleanupStack::PushL(hmac);
+
+    DoComputeSHA1L(aHash, hmac, aNATFWUNSAFMessage);
+
+    CleanupStack::PopAndDestroy(hmac);
+    }
+
+// -----------------------------------------------------------------------------
+// CNATFWUNSAFMessageIntegrityAttribute::DoComputeSHA1L
+// -----------------------------------------------------------------------------
+//
+void CNATFWUNSAFMessageIntegrityAttribute::DoComputeSHA1L(TSHA1_Hash& aHash,
+    CHMAC* aHmac, CBufBase& aNATFWUNSAFMessage) const
+    {
+    __ASSERT_ALWAYS( aHmac, User::Leave( KErrArgument ) );
+    
+    // Pad msg with zeroes
+    TInt bytesInLastBlock = aNATFWUNSAFMessage.Size() % EInputBlockSize;
+    TInt bytesToAppend = 0;
+
+    if (bytesInLastBlock > 0)
+        {
+        bytesToAppend = EInputBlockSize - bytesInLastBlock;
+        const TUint8 KZero = 0;
+        for (TInt i = 0; i < bytesToAppend; ++i)
+            {
+            aNATFWUNSAFMessage.InsertL(aNATFWUNSAFMessage.Size(), &KZero, 1);
+            }
+        }
+
+    TPtrC8 hash = aHmac->Hash(aNATFWUNSAFMessage.Ptr(0));
+
+    //Remove appended zeros
+    aNATFWUNSAFMessage.Delete(aNATFWUNSAFMessage.Size() - bytesToAppend,
+        bytesToAppend);
+
+    //SHA-1 hash is a fixed length
+    __ASSERT_ALWAYS(aHmac->HashSize() == SHA1_HASH, User::Leave(KErrGeneral));
+
+    aHash = hash;
+    }