applayerprotocols/httpexamples/nwsswsptrhnd/CNwssWspSession.cpp
changeset 0 b16258d2340f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/applayerprotocols/httpexamples/nwsswsptrhnd/CNwssWspSession.cpp	Tue Feb 02 01:09:52 2010 +0200
@@ -0,0 +1,1164 @@
+// Copyright (c) 2002-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:
+//
+
+
+// System includes
+#include <wsp/mwspproxyinfoprovider.h>
+#include <http/framework/csecuritypolicy.h>
+#include <http/framework/securitypolicypluginstrings.h>
+#include <wsperror.h>
+#include <http/framework/logging.h>
+
+// Local includes
+#include "tnwsswsptrhndpanic.h"
+#include "mconnectioninfoprovider.h"
+#include "testoom.h"
+
+// Class signature
+#include "cnwsswspsession.h"
+
+const TInt KWtlsMaxFieldSize	= 256;
+
+CNwssWspSession::~CNwssWspSession()
+	{
+	}
+
+CNwssWspSession::CNwssWspSession(RStringPool& aStringPool,
+								 MNwssWapServer& aWapStackProvider,
+								 MConnectionInfoProvider& aConnInfoProvider,
+								 MSecurityPolicy& aSecurityPolicy): 
+	CActive(CActive::EPriorityStandard), iStringPool(aStringPool),
+	iWapStackProvider(aWapStackProvider), iConnInfoProvider(aConnInfoProvider),
+	iState(EDisconnected), iSecurityPolicy(aSecurityPolicy)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+void CNwssWspSession::BaseConstructL()
+	{
+	// Add the security policy plug-in string table to the string pool
+	__DEBUGTESTLEAVE
+	iStringPool.OpenL(SecurityPolicyProperties::Table);
+	}
+
+void CNwssWspSession::InitiateProxyConnection()
+	{
+	if (iState == EDisconnected)
+		CompleteSelf();
+	}
+
+CNwssWspSession::TState CNwssWspSession::State() const
+	{
+	return iState;
+	}
+
+
+TInt CNwssWspSession::SessionDisconnectedCallback()
+	{
+	TInt err = CloseWspSession();
+	if (err == KErrNone)
+		iState = EDisconnected;
+	return err;
+	}
+
+void CNwssWspSession::RunL()
+	{
+	switch (iState)
+		{
+	case EDisconnected:
+		{
+		__LOG("--Running in state EDisconnected")
+		// Make initial connection to the WAP Stack
+		__DEBUGTESTLEAVE
+		TBool useWtls = OpenWapProxyL();
+		if (useWtls)
+			iState = ESessionOpen;
+		else
+			iState = EReady;
+		CompleteSelf();
+		} break;
+	case ESessionOpen:
+		{
+		__LOG("--Running in state ESessionOpen")
+		// Do pre-handshake setup, followed by phase 1 of the connection
+		__DEBUGTESTLEAVE
+		DoWTLSConnectionPreHandshakeL();
+		DoWTLSConnectionPhaseOne(ETrue);
+		iHandshakeWasAnonymous = EFalse;
+		iState = EDoingWtlsPhase1;
+		} break;
+	case EDoingWtlsPhase1:
+		{
+		__LOG("--Running in state EDoingWtlsPhase1")
+		// Did phase 1 succeed?
+		TInt completionCode = iStatus.Int();
+		switch (completionCode)
+			{
+		case RWTLS::EHandshakeOk:
+			{
+			__LOG("--Phase 1 result is EHandshakeOK")
+			__LOG("--indicates that an anonymous handshake was performed.");
+			__LOG("--proceeding to check negotiated configuration")
+			// The handshake is fully complete after one phase.  Since we always initiate a 2-phase
+			// handshake, this indicates that anonymous key exchange suites were agreed.
+			// Note - it would seem sensible to do a phase 2 to complete the handshake, since we initiated
+			// it as 2 phase.  However doing so never works (ConnectPhase2() returns EErrGeneral). So we'll
+			// have to consider the handshake complete now.
+			
+			// Store 'was anonymous' flag for the next AO iteration, where we will check against the policy
+			// to ensure anonymous acceptable. 
+			iHandshakeWasAnonymous = ETrue;
+			iState = ECheckingNegotiated;
+			CompleteSelf();
+			} break;
+		case RWTLS::EServerCertificateValid:
+			{
+			__LOG("--Phase 1 result is EServerCertificateValid")
+			__LOG("--proceeding to do handshake phase 2")
+			// Note - this error code indicates that the server certificate is valid, and that it
+			// was verified by the WAP Stack against a root cert held on the device.  First get 
+			// the server certificate in case the client asks to see it and then move to phase 2.
+			__DEBUGTESTLEAVE
+			GetServerCertL();
+			DoWTLSConnectionPhaseTwo();
+			iState = EDoingWtlsPhase2;
+			} break;
+        case RWTLS::EServerCertificateNotValid:
+			{
+			__LOG("--Phase 1 result is EServerCertificateNotValid")
+			// Note - this error code indicates that although all fields of the server certificate
+			// were valid, the WAP Stack couldn't verify the server identity against a root cert.
+			// For a 2-phase (authenticating) handshake, this means we present the cert to the user
+			// for verification
+			__LOG("--proceeding to check untrusted server certificate")
+			// Check the server cert before phase 2 of the handshake
+			iState = ECheckingServerCert;
+			__DEBUGTESTLEAVE
+			GetServerCertL();
+			ValidateUntrustedServerCertL();
+			} break;
+		case RWTLS::EHandshakeError:
+		case RWTLS::EHandshakeUserAbort:
+		case RWTLS::ECertificateRequested:
+			{
+#ifdef _DEBUG
+			if (completionCode == RWTLS::EHandshakeError)
+				{
+				__LOG("--Phase 1 result is EHandshakeError")
+				}
+			else if (completionCode == RWTLS::EHandshakeUserAbort)
+				{
+				__LOG("--Phase 1 result is EHandshakeUserAbort")
+				}
+			else
+				{
+				// Presumably this refers to a client cert? Not supported by this client if that's the case.
+				__LOG("--Phase 1 result is ECertificateRequested")
+				}
+#endif
+			// Cancel phase 1 - the connect could not be established
+			CancelWTLSConnectionPhaseOne();
+			User::Leave(KWtlsErrPhase1HandshakeFailed);
+			} break;
+		default:
+			{
+			__LOG1("--Phase 1 result is unknown (%d)", completionCode)
+			// Other error codes from completion of phase 1 connect
+			if (completionCode >= 0)
+				completionCode = KWtlsErrPhase1HandshakeFailed;
+			User::Leave(completionCode);
+			} break;
+			}
+		} break;
+	case ECheckingServerCert:
+		{
+		__LOG("--Running in state ECheckingServerCert")
+		// Was the server cert accepted? If not, leave
+		TInt completionCode = iStatus.Int();
+		__DEBUGTESTLEAVE
+		User::LeaveIfError(completionCode);
+
+		// Enter second phase of handshake
+		DoWTLSConnectionPhaseTwo();
+		iState = EDoingWtlsPhase2;
+		} break;
+	case EDoingWtlsPhase2:
+		{
+		__LOG("--Running in state EDoingWtlsPhase2")
+		// Did phase 2 succeed? If not, leave
+		TInt completionCode = iStatus.Int();
+		__DEBUGTESTLEAVE
+		if ( (completionCode != RWTLS::EHandshakeOk) &&
+			 (iHandshakeWasAnonymous && (completionCode != RWTLS::EErrGeneral) ) )
+			User::Leave( (completionCode > 0)?KWtlsErrPhase2HandshakeFailed:completionCode );
+
+		// Move straight on to check the negotiated values
+		iState = ECheckingNegotiated;
+		CompleteSelf();
+		} break;
+	case ECheckingNegotiated:
+		{
+		__LOG("--Running in state ECheckingNegotiated")
+		// Finalise the handshake by checking the negotiated settings
+		__DEBUGTESTLEAVE
+		DoWTLSConnectionPostHandshakeL();
+
+		// Authenticating handshake has completed successfully
+		iState = EReady;
+		CompleteSelf();
+		} break;
+	case EReady:
+		{
+		__LOG("--Running in state EReady")
+		// Can now complete the WSP session connection to the proxy
+		__DEBUGTESTLEAVE
+		CompleteProxyConnectionL();
+		} break;
+	default:
+		{
+		TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInvalidState);
+		} break;
+		}
+	}
+
+TInt CNwssWspSession::RunError(TInt aError)
+	{
+	__LOG1("--Handling WAP stack error code %d", aError)
+	switch (iState)
+		{
+	case EDisconnected:
+		{
+		// Failed to open the WSP session
+		DoRunError(aError);
+		} break;
+	case ESessionOpen:
+		{
+		DoRunError(KWtlsErrConfigurationFailed);
+		} break;
+	case EDoingWtlsPhase1:
+		{
+		// If error is KErrNotSupported then this is usually an error of insufficient crypto strength
+		__ASSERT_DEBUG(aError != KErrNotSupported,
+						TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInsufficientCryptoStrength));
+
+		// Only expect an 'invalid server certificate' or 'phase 1 handshake failed' error in this state
+		__ASSERT_DEBUG(aError == KWtlsErrInvalidServerCert || aError == KWtlsErrPhase1HandshakeFailed,
+						TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInvalidState));
+		DoRunError(aError);
+		} break;
+	case ECheckingServerCert:
+		{
+		// Only expect an 'invalid/untrusted server certificate' error in this state
+		__ASSERT_DEBUG(aError == KWtlsErrInvalidServerCert || aError == KWtlsErrUntrustedServerCert,
+						TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInvalidState));
+		DoRunError(aError);
+		} break;
+	case EDoingWtlsPhase2:
+		{
+		DoRunError(KWtlsErrPhase2HandshakeFailed);
+		} break;
+	case ECheckingNegotiated:
+		{
+		DoRunError(KWtlsErrNegotiatedConfigRejected);
+		} break;
+	case EReady:
+		{
+		DoRunError(aError);
+		} break;
+	default:
+		{
+		// State machine screw-up!
+		__ASSERT_DEBUG(ETrue, TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EInvalidState));
+		} break;
+		}
+
+	// State after handling an error returns to 'disconnected'
+	iState = EDisconnected;
+	return KErrNone;
+	}
+
+void CNwssWspSession::DoCancel()
+	{
+	// Some cancellations will return the state machine to EDisconnected
+	switch (iState)
+		{
+	case EDoingWtlsPhase1:
+		{
+		// Outstanding request is the phase 1 connect
+		CancelWTLSConnectionPhaseOne();
+		iState = EDisconnected;
+		} break;
+	case ECheckingServerCert:
+		{
+		// Cancel the validation
+		CancelValidateUntrustedServerCert();
+		iState = EDisconnected;
+		} break;
+	case EDoingWtlsPhase2:
+		{
+		// Outstanding request is the phase 2 connect
+		CancelWTLSConnectionPhaseTwo();
+		iState = EDisconnected;
+		} break;
+	case EReady:
+		{
+		// Defer to sub-class.  The SubDoCancel() returns a flag if it wishes to move the state machine
+		// back to 'disconnected'.
+		if ( SubDoCancel() )
+			iState = EDisconnected;
+		} break;
+	default:
+		{
+		// Other states do not require asynch request cancellation
+		} break;
+		}
+	}
+
+TBool CNwssWspSession::OpenWapProxyL()
+	{
+	// Get details of the desired WAP proxy from the client's connection info provider
+	MWspProxyInfoProvider& prov = iConnInfoProvider.ProxyInfoProvider();
+	const TDesC8& addr = prov.ProxyAddress();
+	__LOG1("--Proxy Address is '%S'", &addr)
+	TUint16 remPort = prov.RemotePort();
+	__LOG1("--Remote Port is %d", remPort)
+	TUint16 locPort = prov.LocalPort();
+	__LOG1("--Local Port is %d", locPort)
+	TWspBearer bearer = prov.Bearer();
+	const TDesC8& svcCentNum = prov.ServiceCentreNumber();
+	TWspSession sessSvc = prov.WspSessionService();
+	__LOG1("--WSP Session Type is %d (0 = CO, 1 = CL)", sessSvc)
+	TBool isSecure = prov.SecureConnection();
+	__LOG1("--Security is %d (0 = off, 1 = on)", isSecure)
+
+	// It is an error for ConnectReq() to be used when the proxy specifies a CL session!
+	__ASSERT_ALWAYS(sessSvc == EWspConnectionOriented,
+					TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EWrongSessionType));
+
+	// Need to supply different parameters, according to whether the bearer is IP or
+	// SMS
+	TInt error = KErrNone;
+	switch (bearer)
+		{
+		// scope enumerations to the global namespace since that's where they were
+		// defined in <wapcli.h>  :(
+	case ::EIP:
+		{
+		__LOG("--Bearer is IP")
+
+		// Open the WSP CO connection with the WAP stack, using IP bearer
+		error = OpenWspSession(addr, remPort, locPort, (TBearer)bearer, isSecure);	  
+		} break;
+	case ::EWAPSMS7:
+	case ::EWAPSMS:
+		{
+		__LOG("--Bearer is SMS")
+		__LOG1("--Service Centre Number is '%S'", &svcCentNum)
+
+		// Open the WSP CO connection with the WAP stack, using SMS bearer
+		error = OpenWspSession(svcCentNum, remPort, locPort, (TBearer)bearer, isSecure);	  
+		} break;
+	case ::ESMS7:
+	case ::ESMS:
+	case ::EAll:
+	default:
+		__ASSERT_DEBUG(ETrue, 
+					   TNwssWspTrHndPanic::Panic(TNwssWspTrHndPanic::EWrongBearerType));
+		}
+
+	__LOG1("--RWSPCOConn::Open() returned with %d", error)
+	__DEBUGTESTLEAVE
+	User::LeaveIfError(error);
+
+	// Return the secure flag, so the state machine can go on to make the WTLS
+	// handshake if appropriate, for secure proxies
+	return isSecure;
+	}
+
+void CNwssWspSession::MapToPanic(TInt aErrorCode) const
+	{
+	// Error handling is severe, since all WSP state management is expected to be done
+	// in the client.
+	TNwssWspTrHndPanic::TNwssWspTrHndPanicCode panic;
+	switch (aErrorCode)
+		{
+		case RWAPConn::EBearerError:
+			panic = TNwssWspTrHndPanic::EBearerError;
+			break;
+		case RWAPConn::EPortAlreadyBound:
+			panic = TNwssWspTrHndPanic::EPortAlreadyBound;
+			break;
+		case RWAPConn::ECannotOpenPort:
+			panic = TNwssWspTrHndPanic::ECannotOpenPort;
+			break;
+		case RWAPConn::ETooManyConnections:
+			panic = TNwssWspTrHndPanic::ETooManyConnections;
+			break;
+		case RWAPConn::EBadConnection:
+			panic = TNwssWspTrHndPanic::EBadConnection;
+			break;
+		case RWAPConn::EBufferTooSmall:
+			panic = TNwssWspTrHndPanic::EBufferTooSmall;
+			break;
+		case RWSPCOConn::EBufferTooSmall:
+			panic = TNwssWspTrHndPanic::EBufferTooSmall;
+			break;
+		case RWSPCOConn::EInvalidSession:
+			panic = TNwssWspTrHndPanic::EInvalidSession;
+			break;
+		case RWSPCOConn::EInvalidTransaction:
+			panic = TNwssWspTrHndPanic::EInvalidTransaction;
+			break;
+		case RWSPCOConn::EParameterError:
+			panic = TNwssWspTrHndPanic::EParameterError;
+			break;
+		case RWSPCOConn::ESessionNotConnected:
+			panic = TNwssWspTrHndPanic::ESessionNotConnected;
+			break;
+		case RWSPCOConn::ENotSupported:
+			panic = TNwssWspTrHndPanic::ENotSupported;
+			break;
+		case RWSPCOConn::EInvalidState:
+			panic = TNwssWspTrHndPanic::EInvalidState;
+			break;
+		case RWSPCOConn::ESessionClosed:
+			panic = TNwssWspTrHndPanic::ESessionClosed;
+			break;
+		case RWSPCOConn::EMRUExceeded:
+			panic = TNwssWspTrHndPanic::EMRUExceeded;
+			break;
+		case RWSPCOConn::EInvalidBufferSize:
+			panic = TNwssWspTrHndPanic::EInvalidBufferSize;
+			break;
+		case RWSPCOConn::EDataNotAvailable:
+			panic = TNwssWspTrHndPanic::EDataNotAvailable;
+			break;
+		case RWSPCOConn::EErrorTimeout:
+			panic = TNwssWspTrHndPanic::EErrorTimeout;
+			break;
+
+
+	default:
+		panic = TNwssWspTrHndPanic::EUnknownPanic;
+		}
+	TNwssWspTrHndPanic::Panic(panic);
+	}
+
+void CNwssWspSession::CompleteSelf()
+	{
+	if (!IsActive())
+		{
+		TRequestStatus* pStat = &iStatus;
+		User::RequestComplete(pStat, KErrNone);
+		SetActive();
+		}
+	}
+
+
+void CNwssWspSession::DoWTLSConnectionPreHandshakeL()
+	{
+	// Set the Key Exchange Suites. There might be several desired cipher suites, so
+	// they are returned as an array
+	const RArray<TWtlsKeyExchangeSuite>& keyExchSuites = 
+		iSecurityPolicy.GetWtlsKeyExchangeSuites();
+	TInt idx = 0;
+	const TInt numKeyExchSuites = keyExchSuites.Count();
+	RWTLS::TKeyExchangeSuite stackSuite;
+	RWTLS::TIdType stackIdType;
+	for (idx = 0; idx < numKeyExchSuites; ++idx)
+		{
+		// Get the next suite, convert and set
+		TWtlsKeyExchangeSuite suite = keyExchSuites[idx];
+		stackSuite = (RWTLS::TKeyExchangeSuite)suite.iKeyExchangeSuite;
+		stackIdType = (RWTLS::TIdType)suite.iKeyIdType;
+#ifdef _DEBUG
+		DumpKeyExchangeSuite(stackSuite, stackIdType, ETrue);
+#endif
+		__TESTOOMD(stkErr, WtlsHnd().SetKeyExchangeSuite(stackSuite, stackIdType, suite.iKeyId));
+		if (stkErr < 0)
+			{
+			__LOG1("--RWTLS::SetKeyExchangeSuite returned %d", stkErr);
+			__LOG1("--Offensive key ex suite is %d", suite.iKeyExchangeSuite);
+			User::Leave(stkErr);
+			}
+		}
+
+	// Set the Cipher Suites. There might be several desired cipher suites, so
+	// they are returned as an array
+	const RArray<TWtlsCipherSuite>& cipherSuites =
+		iSecurityPolicy.GetWtlsCipherSuites();
+	const TInt numCipherSuites = cipherSuites.Count();
+	if(numCipherSuites>0)
+		{
+		// Make an array to pass in to RWTLS::SetCipherSuites
+		RWTLS::CipherSuiteArray* stackSuites =
+						new (ELeave) RWTLS::CipherSuiteArray(numCipherSuites);
+		CleanupStack::PushL(stackSuites);
+		for (idx = 0; idx < numCipherSuites; ++idx)
+			{
+			// Get the next suite, convert and append to the stack array
+			TWtlsCipherSuite suite = cipherSuites[idx];
+			RWTLS::TCipherSuite stackSuite;
+			stackSuite.iBulkEncryptionAlgorithm =
+				(RWTLS::TBulkEncryptionAlgorithm)suite.iBulkEncryptionAlgorithm;
+			stackSuite.iMacAlgorithm =
+				(RWTLS::TMacAlgorithm)suite.iMacAlgorithm;
+#ifdef _DEBUG
+			DumpCipherSuite(stackSuite, ETrue);
+#endif
+			stackSuites->AppendL(stackSuite);
+			}
+		__TESTOOMD(stkErr, WtlsHnd().SetCipherSuites(*stackSuites));
+		if (stkErr < 0)
+			{
+			__LOG1("--RWTLS::SetCipherSuites returned %d", stkErr);
+			User::Leave(stkErr);
+			}
+
+		CleanupStack::PopAndDestroy(stackSuites);
+		}
+
+	// Set the Sequence Number Mode.
+	RString  seqNumModeValStr;
+	RString seqNumModePropName =
+		iStringPool.String(SecurityPolicyProperties::ESequenceNumberMode,
+							SecurityPolicyProperties::Table);
+
+	RStringF seqNumName = iStringPool.OpenFStringL(seqNumModePropName.DesC());
+	CleanupClosePushL(seqNumName);
+
+	TInt policyErr = iSecurityPolicy.GetNamedPolicyProperty(seqNumName,
+															seqNumModeValStr);
+	CleanupClosePushL(seqNumModeValStr);
+
+	if (policyErr == KErrNone)
+		{
+		RWTLS::TSequenceNumberMode stackMode;
+		switch (seqNumModeValStr.Index(SecurityPolicyProperties::Table))
+			{
+			case SecurityPolicyProperties::EImplicit:
+				stackMode = RWTLS::EImplicit;
+				break;
+			case SecurityPolicyProperties::EExplicit:
+				stackMode = RWTLS::EExplicit;
+				break;
+			case SecurityPolicyProperties::ENotUsed:
+			default:
+				stackMode = RWTLS::ENotUsed;
+				break;
+			}		
+#ifdef _DEBUG
+			DumpSequenceNumberMode(stackMode, ETrue);
+#endif
+		__TESTOOMD(stkErr, WtlsHnd().SetSequenceNumberMode(stackMode));
+		if (stkErr < 0)
+			{
+			__LOG1("--RWTLS::SetSequenceNumberMode returned %d", stkErr);
+			User::Leave(stkErr);
+			}
+		}
+	CleanupStack::PopAndDestroy(2); // seqNumName, seqNumModeValStr
+
+
+	// Set the Key Refresh Rate.
+	RString  keyRefreshRateValStr;
+
+	RString keyRefreshRatePropName =
+		iStringPool.String(SecurityPolicyProperties::EKeyRefreshRate,
+							SecurityPolicyProperties::Table);
+
+	RStringF refreshRateName = iStringPool.OpenFStringL(keyRefreshRatePropName.DesC());
+	CleanupClosePushL(refreshRateName);
+
+	policyErr = iSecurityPolicy.GetNamedPolicyProperty(refreshRateName,
+													   keyRefreshRateValStr);
+	CleanupClosePushL(keyRefreshRateValStr);
+
+	if (policyErr == KErrNone)
+		{
+		TUint8 stackKRR = 0;
+		TLex8 lexer(keyRefreshRateValStr.DesC());
+		User::LeaveIfError( lexer.Val(stackKRR, EDecimal) );
+#ifdef _DEBUG
+		DumpKeyRefreshRate(stackKRR, ETrue);
+#endif
+		__TESTOOMD(stkErr, WtlsHnd().SetKeyRefreshRate(stackKRR));
+		if (stkErr < 0)
+			{
+			__LOG1("--RWTLS::SetKeyRefreshRate returned %d", stkErr);
+			User::Leave(stkErr);
+			}
+		}
+	CleanupStack::PopAndDestroy(2); // refreshRateName, keyRefreshRateValStr
+
+
+	// Set the Shared Secret
+	RString  sharedSecretValStr;
+
+	RString sharedSecretPropName =
+		iStringPool.String(SecurityPolicyProperties::ESharedSecret,
+							SecurityPolicyProperties::Table);
+
+	RStringF sharedSecretName = iStringPool.OpenFStringL(sharedSecretPropName.DesC());
+	CleanupClosePushL(sharedSecretName);
+
+	policyErr = iSecurityPolicy.GetNamedPolicyProperty(sharedSecretName,
+													   sharedSecretValStr);
+	CleanupClosePushL(sharedSecretValStr);
+
+	if (policyErr == KErrNone)
+		{
+		const TDesC8& stackSS = sharedSecretValStr.DesC();
+#ifdef _DEBUG
+		DumpSharedSecret(stackSS);
+#endif
+		__TESTOOMD(stkErr, WtlsHnd().SetSharedSecret(stackSS));
+		if (stkErr < 0)
+			{
+			__LOG1("--RWTLS::SetSharedSecret returned %d", stkErr);
+			User::Leave(stkErr);
+			}
+		}
+	CleanupStack::PopAndDestroy(2); // sharedSecretName, sharedSecretValStr
+
+
+	// Set the Record Length Usage.
+	RString  recordLengthUsageValStr;
+
+	RString recordLengthUsagePropName =
+		iStringPool.String(SecurityPolicyProperties::ERecordLengthUsage,
+							SecurityPolicyProperties::Table);
+
+	RStringF recLenUsageName = iStringPool.OpenFStringL(recordLengthUsagePropName.DesC());
+	CleanupClosePushL(recLenUsageName);
+
+	policyErr = iSecurityPolicy.GetNamedPolicyProperty(recLenUsageName,
+													   recordLengthUsageValStr);
+	CleanupClosePushL(recordLengthUsageValStr);
+
+	if (policyErr == KErrNone)
+		{
+		TBool stackRLU = EFalse;
+		switch (recordLengthUsageValStr.Index(SecurityPolicyProperties::Table))
+			{
+			case SecurityPolicyProperties::EUsed:
+				stackRLU = ETrue;
+				break;
+			case SecurityPolicyProperties::ENotUsed:
+			default:
+				stackRLU = EFalse;
+				break;
+			}
+#ifdef _DEBUG
+		DumpRecordLengthUsage(stackRLU, ETrue);
+#endif
+		__TESTOOMD(stkErr, WtlsHnd().SetRecordLengthUsage(stackRLU));
+		if (stkErr < 0)
+			{
+			__LOG1("--RWTLS::SetRecordLengthUsage returned %d", stkErr);
+			User::Leave(stkErr);
+			}
+		}
+	CleanupStack::PopAndDestroy(2); // recLenUsageName, recordLengthUsageValStr
+	}
+
+
+void CNwssWspSession::DoWTLSConnectionPhaseOne(TBool aTwoPhaseHandshake)
+	{
+	WtlsHnd().Connect(iStatus, aTwoPhaseHandshake);
+	SetActive();
+	__LOG1("--WTLS::Connect(phase 1 of %d)", (aTwoPhaseHandshake?2:1));
+	}
+
+
+void CNwssWspSession::CancelWTLSConnectionPhaseOne()
+	{
+	WtlsHnd().CancelConnect();
+	__LOG("--WTLS - CancelConnect() phase 1");
+	}
+
+
+void CNwssWspSession::ValidateUntrustedServerCertL()
+	{
+	// Make request of security policy plugin for validation
+	iSecurityPolicy.ValidateUntrustedServerCert(iServerCert, iStatus);
+	SetActive();
+	}
+
+void CNwssWspSession::GetServerCertL()
+	{
+	iServerCertValid = EFalse;
+	// Create space for subject, issuer and fingerprint fields in cert info
+	TBuf8<KWtlsMaxFieldSize> subject;
+	TBuf8<KWtlsMaxFieldSize> issuer;
+	TBuf8<KWtlsMaxFieldSize> fingerprint;
+
+	RCertificate::TInfo wtlsCertInfo;
+#ifdef _DEBUG
+	// shut up some WINS UDEB compiler warnings...
+	wtlsCertInfo.iValidNotBefore = 0;
+	wtlsCertInfo.iValidNotAfter = 0;
+	wtlsCertInfo.iSubjectCharacterSet = 0;
+	wtlsCertInfo.iIssuerCharacterSet = 0;
+	wtlsCertInfo.iServerCertificateStatus = RCertificate::EOk;
+#endif
+	wtlsCertInfo.iSubject		= &subject;
+	wtlsCertInfo.iIssuer		= &issuer;
+	wtlsCertInfo.iFingerPrint	= &fingerprint;
+
+	// Get the certificate from the WAP stack
+	RCertificate wtlsCert = WtlsHnd().ServerCert();
+	__TESTOOMD(stkErr, wtlsCert.Info(wtlsCertInfo));
+	if (stkErr != KErrNone)
+		User::Leave(KWtlsErrInvalidServerCert);
+
+	// Convert to a form accepted by the security policy plugin
+ 	_LIT(KUnixEpochStart,"19700000:000000.000000");
+
+	// Start date
+	TTime startTime(KUnixEpochStart);
+	TTimeIntervalSeconds addTime = wtlsCertInfo.iValidNotBefore;
+	iServerCert.iStartValDate = startTime + addTime;
+
+	// End date
+	TTime endTime(KUnixEpochStart);
+	addTime = wtlsCertInfo.iValidNotAfter;
+	iServerCert.iEndValDate = endTime + addTime;
+
+	// Subject. Ignore the character set from the WTLS cert - it should be UTF-8
+	TInt len = Min((wtlsCertInfo.iSubject)->Length(),
+				   iServerCert.iSubjectDNInfo.iCommonName.MaxLength());
+	iServerCert.iSubjectDNInfo.iCommonName.Copy((wtlsCertInfo.iSubject)->Left(len));
+
+	// Issuer. Ignore the character set from the WTLS cert - it should be UTF-8
+	len = Min((wtlsCertInfo.iIssuer)->Length(),
+				   iServerCert.iIssuerDNInfo.iCommonName.MaxLength());
+	iServerCert.iIssuerDNInfo.iCommonName.Copy((wtlsCertInfo.iIssuer)->Left(len));
+
+	// Ignore server certificate status - no field exists for it in TCertInfo
+
+	// Fingerprint
+	len = Min((wtlsCertInfo.iFingerPrint)->Length(), iServerCert.iFingerprint.MaxLength());
+	iServerCert.iFingerprint.Copy((wtlsCertInfo.iFingerPrint)->Left(len));
+
+	// We have a complete TCertInfo
+	iServerCertValid = ETrue;
+
+	// Log certificate data
+	__LOG("--Server Certificate:");
+	__LOG("-----------------------------------");
+	__LOG1("--Subject:     %S", wtlsCertInfo.iSubject);
+	__LOG1("--Issuer:      %S", wtlsCertInfo.iIssuer);
+	__LOG1("--Fingerprint: %S", wtlsCertInfo.iFingerPrint);
+#ifdef _DEBUG
+	_LIT(KDateFormat,"%D%M%Y%/0%1%/1%2%/2%3%/3 %:0%H%:1%T%:2%S.%C%:3");
+	TBuf<40> dateTimeString;
+	TBuf8<40> dateTimeString8;
+	__DEBUGTESTLEAVE
+	iServerCert.iStartValDate.FormatL(dateTimeString, KDateFormat);
+	dateTimeString8.Copy(dateTimeString);
+	__LOG1("--Start Date:  %S", &dateTimeString8);
+	__DEBUGTESTLEAVE
+	iServerCert.iEndValDate.FormatL(dateTimeString, KDateFormat);
+	dateTimeString8.Copy(dateTimeString);
+	__LOG1("--Start Date:  %S", &dateTimeString8);
+#endif
+	__LOG("-----------------------------------");
+	}
+
+void CNwssWspSession::CancelValidateUntrustedServerCert()
+	{
+	iSecurityPolicy.CancelValidateUntrustedServerCert();
+	}
+
+void CNwssWspSession::DoWTLSConnectionPhaseTwo()
+	{
+	WtlsHnd().ConnectPhaseTwo(iStatus);
+	SetActive();
+	__LOG("--WTLS::Connect(phase 2 of 2)");
+	}
+
+
+void CNwssWspSession::CancelWTLSConnectionPhaseTwo()
+	{
+	WtlsHnd().CancelConnectPhaseTwo();
+	__LOG("--WTLS - CancelConnect() phase 2");
+	}
+
+
+void CNwssWspSession::DoWTLSConnectionPostHandshakeL()
+	{
+	TInt stkErr = KErrNone;
+	// Dump the negotiated cipher suite and sequence number mode (debug only)
+#ifdef _DEBUG
+	// Find out which cipher suite was negotiated
+	RWTLS::TCipherSuite cipherSuite;
+
+	// shut up some WINS UDEB compiler warnings
+	cipherSuite.iBulkEncryptionAlgorithm = RWTLS::EBulkNull;
+	cipherSuite.iMacAlgorithm = RWTLS::ESha_0;
+	__TESTOOM(stkErr, WtlsHnd().GetCipherSuite(cipherSuite));
+	if (stkErr)
+		{
+		__LOG1("--RWTLS::GetCipherSuite() returned %d", stkErr);
+		}
+	else
+		DumpCipherSuite(cipherSuite, EFalse);
+
+	// Find out which sequence number mode was negotiated
+	RWTLS::TSequenceNumberMode mode = RWTLS::ENotUsed;
+	__TESTOOM(stkErr, WtlsHnd().GetSequenceNumberMode(mode));
+	if (stkErr)
+		{
+		__LOG1("--RWTLS::GetSequenceNumberMode() returned %d", stkErr);
+		}
+	else
+		DumpSequenceNumberMode(mode, EFalse);
+#endif
+
+	// Find out which key exchange suite was negotiated
+	RWTLS::TKeyExchangeSuite keyExchSuite(RWTLS::ESharedSecret);
+	__TESTOOM(stkErr, WtlsHnd().GetKeyExchangeSuite(keyExchSuite));
+	if (stkErr == KErrNone)
+		{
+#ifdef _DEBUG
+		// Dump the negotiated key exch suite (debug only)
+		DumpKeyExchangeSuite(keyExchSuite, (RWTLS::TIdType)KErrNotFound, EFalse);
+#endif
+
+		// Figure out if we got an anonymous one or not.  Note, this is
+		// authoritative, so overwrite any flag set earlier.
+		switch (keyExchSuite)
+			{
+			case RWTLS::EDHAnon:
+			case RWTLS::EDHAnon512:
+			case RWTLS::EDHAnon768:
+			case RWTLS::ERsaAnon:
+			case RWTLS::ERsaAnon512:
+			case RWTLS::ERsaAnon768:
+			case RWTLS::EEcdhAnon:
+			case RWTLS::EEcdhAnon113:
+			case RWTLS::EEcdhAnon131:
+				iHandshakeWasAnonymous = ETrue;
+			default:
+				iHandshakeWasAnonymous = EFalse;
+				break;
+			}
+		}
+#ifdef _DEBUG
+	else
+		{
+		__LOG1("--RWTLS::GetKeyExchangeSuite() returned %d", stkErr);
+		}
+#endif
+
+	// If it's anonymous, and anonymous is not allowed, then reject now.
+	__DEBUGTESTLEAVE
+	if (iHandshakeWasAnonymous && !AnonymousAuthenticationAllowedL())
+		User::Leave(KWtlsErrNegotiatedConfigRejected);
+	}
+
+
+TBool CNwssWspSession::AnonymousAuthenticationAllowedL()
+	{
+	RString  anonAllowedValStr;
+	RString anonAllowedPropName =
+		iStringPool.String(SecurityPolicyProperties::EAnonymousAllowed,
+							SecurityPolicyProperties::Table);
+
+	__DEBUGTESTLEAVE
+	RStringF anonAllowName = iStringPool.OpenFStringL(anonAllowedPropName.DesC());
+
+	TInt policyErr = iSecurityPolicy.GetNamedPolicyProperty(anonAllowName,
+															anonAllowedValStr);
+	TBool retVal = ( (policyErr == KErrNone) &&
+					 (anonAllowedValStr == iStringPool.String(SecurityPolicyProperties::EAllowed,
+							SecurityPolicyProperties::Table) ) );
+
+	anonAllowedValStr.Close();
+	anonAllowName.Close();
+	return retVal;
+	}
+
+TInt CNwssWspSession::ServerCert(TCertInfo& aCertInfo)
+	{
+	TInt retVal = KErrNotSupported;
+	switch(iState)
+		{
+		case EDisconnected:
+		case ESessionOpen:
+		case EDoingWtlsPhase1:
+			retVal = KErrNotReady;
+			break;
+		case ECheckingServerCert:
+		case EDoingWtlsPhase2:
+		case ECheckingNegotiated:
+		case EReady:
+			if(iServerCertValid)
+				{
+				retVal = KErrNone;
+				aCertInfo = iServerCert;
+				}
+			break;
+		default:
+			break;
+		}
+
+	return retVal;
+	}
+
+#ifdef _DEBUG
+
+void CNwssWspSession::DumpCipherSuite(RWTLS::TCipherSuite aCipherSuite, TBool aRequested)
+	{
+	TBuf8<100> msg;
+	if (aRequested)
+		{
+		_LIT8(KCipherSuiteMsg, "--Requested cipher suite is: (");
+		msg.Append(KCipherSuiteMsg());
+		}
+	else
+		{
+		_LIT8(KCipherSuiteMsg, "--Negotiated cipher suite is: (");
+		msg.Append(KCipherSuiteMsg());
+		}
+	switch (aCipherSuite.iBulkEncryptionAlgorithm)
+		{
+		case RWTLS::EBulkNull:
+			msg.Append(_L("EBulkNull,"));
+			break;
+		case RWTLS::ERc5_cbc_40:
+			msg.Append(_L("ERc5_cbc_40,"));
+			break;
+		case RWTLS::ERc5_cbc_56:
+			msg.Append(_L("ERc5_cbc_56,"));
+			break;
+		case RWTLS::ERc5_cbc:
+			msg.Append(_L("ERc5_cbc,"));
+			break;
+		case RWTLS::EDes_cbc_40:
+			msg.Append(_L("EDes_cbc_40,"));
+			break;
+		case RWTLS::EDes_cbc:
+			msg.Append(_L("EDes_cbc,"));
+			break;
+		case RWTLS::E3Des_cbc_ede:
+			msg.Append(_L("E3Des_cbc_ede,"));
+			break;
+		case RWTLS::EIdea_cbc_40:
+			msg.Append(_L("EIdea_cbc_40,"));
+			break;
+		case RWTLS::EIdea_cbc_56:
+			msg.Append(_L("EIdea_cbc_56,"));
+			break;
+		case RWTLS::EIdea_cbc:
+			msg.Append(_L("EIdea_cbc,"));
+			break;
+		default:
+			msg.Append(_L("<Unknown bulk alg>,"));
+			break;
+		}
+	switch (aCipherSuite.iMacAlgorithm)
+		{
+		case RWTLS::ESha_0:
+			msg.Append(_L("ESha_0)"));
+			break;
+		case RWTLS::ESha_40:
+			msg.Append(_L("ESha_40)"));
+			break;
+		case RWTLS::ESha_80:
+			msg.Append(_L("ESha_80)"));
+			break;
+		case RWTLS::ESha:
+			msg.Append(_L("ESha)"));
+			break;
+		case RWTLS::ESha_xor_40:
+			msg.Append(_L("ESha_xor_40)"));
+			break;
+		case RWTLS::EMd5_40:
+			msg.Append(_L("EMd5_40)"));
+			break;
+		case RWTLS::EMd5_80:
+			msg.Append(_L("EMd5_40)"));
+			break;
+		case RWTLS::EMd5:
+			msg.Append(_L("EMd5)"));
+			break;
+		default:
+			msg.Append(_L("<Unknown mac alg>)"));
+			break;
+		}
+	__LOG1("%S", &msg);
+	}
+
+void CNwssWspSession::DumpKeyExchangeSuite(RWTLS::TKeyExchangeSuite aKeyExchSuite, RWTLS::TIdType aStackIdType, TBool aRequested)
+	{
+	TBuf8<100> msg;
+	if (aRequested)
+		{
+		_LIT8(KKeyExchSuiteMsg, "--Requested key exchange suite is: ");
+		msg.Append(KKeyExchSuiteMsg());
+		}
+	else
+		{
+		_LIT8(KKeyExchSuiteMsg, "--Negotiated key exchange suite is: ");
+		msg.Append(KKeyExchSuiteMsg());
+		}
+	switch (aKeyExchSuite)
+		{
+		case RWTLS::ESharedSecret:
+			msg.Append(_L("(ESharedSecret,"));
+			break;
+		case RWTLS::EDHAnon:
+			msg.Append(_L("(EDHAnon,"));
+			break;
+		case RWTLS::EDHAnon512:
+			msg.Append(_L("(EDHAnon512,"));
+			break;
+		case RWTLS::EDHAnon768:
+			msg.Append(_L("(EDHAnon768,"));
+			break;
+		case RWTLS::ERsaAnon:
+			msg.Append(_L("(ERsaAnon,"));
+			break;
+		case RWTLS::ERsaAnon512:
+			msg.Append(_L("(ERsaAnon512,"));
+			break;
+		case RWTLS::ERsaAnon768:
+			msg.Append(_L("(ERsaAnon768,"));
+			break;
+		case RWTLS::ERsa:
+			msg.Append(_L("(ERsa,"));
+			break;
+		case RWTLS::ERsa512:
+			msg.Append(_L("(ERsa512,"));
+			break;
+		case RWTLS::ERsa768:
+			msg.Append(_L("(ERsa768,"));
+			break;
+		case RWTLS::EEcdhAnon:
+			msg.Append(_L("(EEcdhAnon,"));
+			break;
+		case RWTLS::EEcdhAnon113:
+			msg.Append(_L("(EEcdhAnon113,"));
+			break;
+		case RWTLS::EEcdhAnon131:
+			msg.Append(_L("(EEcdhAnon131,"));
+			break;
+		case RWTLS::EEcdhEcdsa:
+			msg.Append(_L("(EEcdhEcdsa,"));
+			break;
+		default:
+			msg.Append(_L("(<Unknown key exchange suite>,"));
+			break;
+		}
+		switch (aStackIdType)
+		{
+		case RWTLS::EIdNull:
+			msg.Append(_L("EIdNull)"));
+			break;
+		case RWTLS::EText:
+			msg.Append(_L("EText)"));
+			break;
+		case RWTLS::EBinary:
+			msg.Append(_L("EBinary)"));
+			break;
+		case RWTLS::EKeyHashSha:
+			msg.Append(_L("EKeyHashSha)"));
+			break;
+		case RWTLS::EX509Name:
+			msg.Append(_L("EX509Name)"));
+			break;
+		default:
+			msg.Append(_L("<Unknown ID type>)"));
+			break;
+		}
+	__LOG1("%S", &msg);
+	}
+
+
+void CNwssWspSession::DumpSequenceNumberMode(RWTLS::TSequenceNumberMode aSeqNumMode, TBool aRequested)
+	{
+	TBuf8<100> msg;
+	if (aRequested)
+		{
+		_LIT8(KSeqNumModeMsg, "--Requested sequence number mode is: ");
+		msg.Append(KSeqNumModeMsg());
+		}
+	else
+		{
+		_LIT8(KSeqNumModeMsg, "--Negotiated sequence number mode is: ");
+		msg.Append(KSeqNumModeMsg());
+		}
+	switch (aSeqNumMode)
+		{
+		case RWTLS::ENotUsed: 
+			msg.Append(_L("ENotUsed"));
+			break;
+		case RWTLS::EImplicit:
+			msg.Append(_L("EImplicit"));
+			break;
+		case RWTLS::EExplicit:
+			msg.Append(_L("EExplicit"));
+			break;
+		default:
+			msg.Append(_L("<Unknown>"));
+			break;
+		}
+	__LOG1("%S", &msg);
+	}
+
+void CNwssWspSession::DumpKeyRefreshRate(TUint8 aKeyRefreshRate, TBool aRequested)
+	{
+	_LIT8(KReqKeyRefRateMsg, "--Requested key refresh rate is: %d");
+	_LIT8(KNegKeyRefRateMsg, "--Negotiated key refresh rate is: %d");
+	TBuf8<100> msg;
+	if (aRequested)
+		{
+		msg.Format(KReqKeyRefRateMsg(), aKeyRefreshRate);
+		}
+	else
+		{
+		msg.Format(KNegKeyRefRateMsg(), aKeyRefreshRate);
+		}
+	__LOG1("%S", &msg);
+	}
+
+void CNwssWspSession::DumpSharedSecret(const TDesC8& aSharedSecret)
+	{
+	__LOG("--Shared secret is: ");
+	__DUMP("--", "--", aSharedSecret)
+	}
+
+void CNwssWspSession::DumpRecordLengthUsage(TBool aRecordLengthUsage, TBool aRequested)
+	{
+	_LIT8(KReqRecLenUsageMsg, "--Requested record length usage is: %S");
+	_LIT8(KNegRecLenUsageMsg, "--Negotiated record length usage is: %S");
+	_LIT8(KUsed, "Used");
+	_LIT8(KNotUsed, "Not Used");
+	TBuf8<100> msg;
+	if (aRequested)
+		{
+		msg.Format(KReqRecLenUsageMsg(), aRecordLengthUsage?&(KUsed()):&(KNotUsed()));
+		}
+	else
+		{
+		msg.Format(KNegRecLenUsageMsg(), aRecordLengthUsage?&(KUsed()):&(KNotUsed()));
+		}
+	__LOG1("%S", &msg);
+	}
+
+
+#endif