networksecurity/ipsec/ipsec6/src/key_prt.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networksecurity/ipsec/ipsec6/src/key_prt.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,376 @@
+// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// key_prt.cpp - IPv6/IPv4 IPSEC PFKEY protocol
+//
+
+#include "ipsec.h"
+#include "sadb.h"
+#include "sa_crypt.h"
+#include <networking/pfkeyv2.h>
+#include "pfkey.h"
+#include "ipseclog.h"
+#include <networking/in6_ipsec.h>
+#include <es_prot_internal.h>
+
+
+CProtocolBase *IPSEC::NewPfkeyL()
+	/**
+	* Return new instance of PFKEY protocol object.
+	*
+	* @return The PFKEY protocol.
+	*/
+	{
+	return new (ELeave) CProtocolKey();
+	}
+
+void IPSEC::IdentifyPfkey(TServerProtocolDesc &aEntry)
+	/**
+	* Return PFKEY protocol description
+	*
+	* @retval aEntry The description
+	*/
+	{
+	_LIT(Kpfkey, "pfkey");
+
+	aEntry.iName = Kpfkey;
+	aEntry.iAddrFamily = KAfIpsec;
+	aEntry.iSockType = KSockRaw;
+	aEntry.iProtocol = KProtocolKey;
+	aEntry.iVersion = TVersion(1, 0, 0);
+	aEntry.iByteOrder = ELittleEndian;
+	aEntry.iServiceInfo = KSIConnectionLess | KSIMessageBased;
+	aEntry.iNamingServices = 0;
+	aEntry.iSecurity = KSocketNoSecurity;
+	aEntry.iMessageSize = 0xffff;
+	aEntry.iServiceTypeInfo = ESocketSupport | ENeedMBufs;
+	aEntry.iNumSockets = KUnlimitedSockets;
+	}
+
+MAssociationManager *IPSEC::FindAssociationManager(const CProtocolBase *aProtocol, TUint aId)
+	/**
+	* Return MAssociationManager, if aProtocol is CProtocolKey instance.
+	*
+	* @param aProtocol	The protocol instance
+		* @param aId The protocol Id
+	* @return NULL, if aProtocol is not CProtocolKey, otherwise return MAssociationManager
+	*/
+	{
+	if (aId == KProtocolKey)
+		return (CProtocolKey *)aProtocol;
+	return NULL;
+	}
+
+#pragma warning (disable:4355)
+CProtocolKey::CProtocolKey() : iEngineAH(this), iEngineESP(this), iEngineNATT(this)
+	/**
+	* Constructor.
+	*/
+	{
+	iSAPlist.SetOffset(_FOFF(CProviderKey,iSAPlink));
+	}
+#pragma warning (default:4355)
+
+
+void CProtocolKey::Open()
+	/**
+	* Increase reference count.
+	*
+	* The specific implementation exists only, because MAssociationManager::Open()
+	* must be mapped CProtocolBase::Open.
+	*/
+	{
+	CProtocolBase::Open();
+	}
+
+void CProtocolKey::Close()
+	/**
+	* Descrease reference count.
+	*
+	* The specific implementation exists only, because MAssociationManager::Close()
+	* must be mapped CProtocolBase::Close.
+	*/
+	{
+	CProtocolBase::Close();
+	}
+
+
+CServProviderBase* CProtocolKey::NewSAPL(TUint aSockType)
+	/**
+	* Create new PFKEY SAP.
+	*
+	* @param aSockType == KSockRaw
+	* @return CProviderKey instance
+	*/
+	{
+	if (aSockType!=KSockRaw)
+		User::Leave(KErrNotSupported);
+	CProviderKey *pSAP = new (ELeave) CProviderKey(*this);
+	iSAPlist.AddLast(*pSAP);
+	return pSAP;
+	}
+
+CProtocolKey::~CProtocolKey()
+	/**
+	* Destructor.
+	*/
+	{
+	// release End Points recorded by SetOpt
+	for (TInt i = iEndPoints.Count(); --i >= 0; )
+		{
+		iEndPoints[i].Close();
+		}
+	iEndPoints.Close();
+
+	delete iCrypto;		// Relese crypto libraries
+	delete iTimer;		// Disconnect Timer system.
+	//
+	// Release Security Associations
+	//
+	for (TInt j = 0; j < HashSize(); ++j)
+		while (iHash[j])
+			{
+			CSecurityAssoc *sa = iHash[j];
+			iHash[j] = sa->iNext;
+			delete sa;
+			}
+	// If assumptions are correct, iSAPlist should be empty!!
+	ASSERT(iSAPlist.IsEmpty());
+#if __WINS__
+	LOG(Log::Printf(_L("CProtocolKey::~CProtocolKey() done IPSEC_OBJECT_COUNT=%d"), IPSEC_OBJECT_COUNT));
+#endif
+	}
+
+void CProtocolKey::InitL(TDesC& /*aTag*/)
+	/**
+	* Initialize.
+	*
+	* Initialize the CProtocolKey. Create cryptographic library manager
+	* and timer handler.
+	*/
+	{
+	iCrypto = CIpsecCryptoManager::NewL();
+	MAssociationManager *const mgr = this;
+	iTimer = TimeoutFactory::NewL(1, mgr);
+	}
+
+// Unnecessary function, could use the default in CProtocolBase
+void CProtocolKey::StartL()
+	/**
+	* StartL has nothing to do.
+	*/
+	{
+	}
+
+void CProtocolKey::BindToL(CProtocolBase* aProtocol)
+	/**
+	* Bind requests protocols "below".
+	*
+	* The PFKEY allows here only cryptographic libraries, which are
+	* recognized from their protocol number #KProtocolCrypto .
+	*
+	* @param aProtocol The Cryptographic library.
+	*/
+	{
+	ASSERT(this != aProtocol);
+
+	// Find out the ID of given protocol object
+	TUint id;
+		{
+		TServerProtocolDesc info;
+		aProtocol->Identify(&info);
+		id = info.iProtocol;
+		}
+
+	if (id == STATIC_CAST(TUint, KProtocolCrypto))
+		iCrypto->AddLibraryL((CProtocolCrypto *)aProtocol);
+	else
+		User::Leave(KErrGeneral);	// Only Crypto libraries can be bound to PFKEY!
+	}
+
+
+void CProtocolKey::BindL(CProtocolBase * /*aProtocol*/, TUint /*id*/)
+	/**
+	* Bind request from a protocol "above".
+	*
+	* This is normally only used by the SECPOL protocol. The PFKEY
+	* does not keep track of these binds, and thus it accepts
+	* all BindL's as is (without any checks).
+	*
+	* @param aProtocol The protocol doing the bind.
+	* @param id The protocol number
+	*/
+	{
+	// This function is just to allow standard BindToL sequence
+	// to complete, currently PFKEY is not insterested in keeping
+	// track of who binds to it, thus nothing is done here.
+	}
+
+void CProtocolKey::Identify(TServerProtocolDesc *aInfo) const
+	/**
+	* Return PFKEY protocol description
+	*
+	* @retval aEntry The description
+	*/
+	{
+	IPSEC::IdentifyPfkey(*aInfo);
+	}
+	
+
+TInt CProtocolKey::GetOption(TUint aLevel, TUint aName, TDes8& aOption, CProtocolBase* /*aSourceProtocol*/)
+	/**
+	* Supported GetOpt's for the PFKEY socket
+	*
+	* PFKEY SAP GetOption calls this.
+	*
+	* @param aLevel The option level
+	* @param aName	The option name
+	* @param aOption The option argument
+	* @param aSourceProtocol Not used.
+	*
+	* Get Named EndPoint:
+	* @code aLevel = KSolIpsecControl, aName = KSoIpsecEndpoint, aOption = TNameRecord
+	* @endcode
+	*/
+	{
+	if (aLevel == KSolIpsecControl && aName == KSoIpsecEndpoint)
+		{
+		// A problematic option: the aOption is both input (iName) and output (iAddr)!
+
+
+		// Return the address (TNameRecord::iAddr) of a named end point (TNameRecord::iName)
+		// If the named endpoint does not exist, return KErrNotFound and set address to unspecified.
+
+		if (aOption.Length() != sizeof(TNameRecord))
+			return KErrArgument;
+		TNameRecord &record = (TNameRecord &)*aOption.Ptr();
+		// ** should check that TNameRecord::iName and iAddr are valid TBuf
+		// ** descriptors which do not cause a panic, when accessed! How?
+		RIpAddress ep;
+		const TInt res = ep.Open(iEndPointCollection, record.iName);
+		// (if Open fails, ep() return unspecified address)
+		TInetAddr::Cast(record.iAddr).SetAddress(ep());
+		TInetAddr::Cast(record.iAddr).SetScope(ep().iScope);
+		// ep is closed implicitly by destructor
+		return res;
+		}
+	return KErrNotSupported;
+	}
+
+TInt CProtocolKey::SetOption(TUint aLevel, TUint aName,const TDesC8& aOption, CProtocolBase* /*aSourceProtocol*/)
+	/**
+	* Supported SetOpt's for the PFKEY socket
+	*
+	* PFKEY SAP SetOption calls this.
+	*
+	* @param aLevel The option level
+	* @param aName	The option name
+	* @param aOption The option argument
+	* @param aSourceProtocol Not used.
+	*
+	* Set Named EndPoint.
+	* @code aLevel = KSolIpsecControl, aName = KSoIpsecEndpoint, aOption = TNameRecord
+	* @endcode
+	*/
+	{
+	if (aLevel == KSolIpsecControl && aName == KSoIpsecEndpoint)
+		{
+
+		// Set the named end point (TNameRecord::iName) to specified address (TNameRecord::iAddr).
+		if (aOption.Length() != sizeof(TNameRecord))
+			return KErrArgument;
+		const TNameRecord &record = (const TNameRecord &)*aOption.Ptr();
+		// ** should check that TNameRecord::iName and iAddr are valid TBuf
+		// ** descriptors which do not cause a panic, when accessed! How?
+
+		RIpAddress ep;
+		TInt res = ep.Open(iEndPointCollection, record.iName, TIpAddress(record.iAddr));
+		if (res != KErrNone)
+			return res;
+		// Need to look if this EP is already recorded
+		// If the EP reference is not stored any other place, it would
+		// get deleted automaticly. Thus, need to record the EP's that
+		// have been set with SetOpt, so that they stay around even if
+		// no other reference exist yet.
+		const TInt count = iEndPoints.Count();
+		for (TInt i = count; --i >= 0; )
+			{
+			if (&iEndPoints[i]() == &ep())	// (Compare TIpAddress pointers directly)
+				return KErrNone;			// Already recorded, nothing else to do.
+			}
+		// Unfortunately RArray Append does not execute RIpAddress copy
+		// constructor or assignment, need to do some arm twisting here...
+		RIpAddress dummy;
+		res = iEndPoints.Append(dummy);
+		if (res == KErrNone)
+			{
+			// Try with assigment...
+			iEndPoints[count] = ep;
+			}
+		return res;
+		// ep is closed implicitly by destructor
+		}
+	return KErrNotSupported;
+	}
+
+void CProtocolKey::SetAlgorithms(CAlgorithmList*& aList)
+	/**
+	* Receive Algorithm map from the policy.
+	*
+	* @param aList The algorithm mapping.
+	*/
+	{
+	ASSERT(iCrypto != NULL);	// Should never happen.
+	iCrypto->SetAlgorithms(aList);
+	}
+
+void CProtocolKey::Deliver(const TPfkeyMessage &aMsg)
+	/**
+	* Deliver PFKEY Messages to SAP's that are willing to receive them.
+	*
+	* @param aMsg	The PFKEY message
+	*/
+	{
+	CProviderKey* sap;
+	TDblQueIter<CProviderKey> iter(iSAPlist);
+
+	while (sap = iter++, sap != NULL)
+		{
+		sap->Deliver(aMsg);
+		}
+	LOG(aMsg.LogPrint(_L("---->"), iCrypto->Algorithms()));
+	}
+
+void CProtocolKey::DeliverRegistered(const TPfkeyMessage &aMsg)
+	/**
+	* Deliver PFKEY Messages selectively.
+	*
+	* Same as CProtocolKey::Deliver, but sends message only to SAP's that
+	* have REGISTERED for this type of Security Associtation.
+	*
+	* @param aMsg	The PFKEY message
+	*/
+	{
+	CProviderKey* sap;
+	TDblQueIter<CProviderKey> iter(iSAPlist);
+
+	TUint i = aMsg.iBase.iMsg->sadb_msg_satype;
+	TUint8 m = (TUint8)(1 << (i % 8));
+	i = i / 8;
+	while (sap = iter++, sap != NULL)
+		if (sap->iRegistered[i] & m)
+			{
+			sap->Deliver(aMsg);
+			}
+	LOG(aMsg.LogPrint(_L("---->"), iCrypto->Algorithms()));
+	}