networksecurity/tls/protocol/handshaketransmitevents.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/networksecurity/tls/protocol/handshaketransmitevents.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,716 @@
+// Copyright (c) 2003-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:
+// Implementation file for transmitted handshake events - ClientHello, 
+// ClientKeyExchange, ClientCertificate, CertificateVerify, and Client Finished
+// messages.
+// 
+//
+
+/**
+ @file
+*/
+
+#include "tlshandshakeitem.h"
+#include "handshaketransmitevents.h"
+#include "recordprotocolevents.h"
+#include "tlshandshake.h"
+#include <tlstypedef_internal.h>
+#include <ssl_internal.h>
+
+CHandshakeTransmit::~CHandshakeTransmit()
+{
+	LOG(Log::Printf(_L("CHandshakeTransmit::~CHandshakeTransmit()"));)
+   
+	iRecordComposer.SetUserData( NULL );
+	iRecordComposer.ResetCurrentPos();
+	delete iHandshakeMessage;
+	iHandshakeMessage = NULL;
+}
+
+void CHandshakeTransmit::ComposeHandshakeHeader( TInt aHistoryUpdate, ETlsHandshakeMessage aHandshakeMessage, TDesC8& aDesComposeMsg )
+/**
+ * This method updates the State Machine's history, composes a header for the 
+ * handshake message and sets the Record protocol content type.
+ */
+{
+	LOG(Log::Printf(_L("CHandshakeTransmit::ComposeHandshakeHeader()"));)
+
+	iStateMachine->UpdateHistory( aHistoryUpdate );
+	HandshakeMessage()->ComposeHeader( aHandshakeMessage, aDesComposeMsg.Length() - KTlsHandshakeHeaderSize );
+	iRecordComposer.SetRecordType( ETlsHandshakeContentType );
+
+	Handshake().UpdateVerify( aDesComposeMsg );
+
+	// Set the protocol version in the Record to the negotiated protocol, set the 
+	// data buffer in the Record composer to the data in the handshake message, 
+	// set up the next asynchronous event.
+	iRecordComposer.SetUserData( &aDesComposeMsg );
+}
+
+CClientCertificate::~CClientCertificate()
+/**
+ * Destructor.
+ */
+{
+	LOG(Log::Printf(_L("CClientCertificate::~CClientCertificate()"));)
+	iCertArray.ResetAndDestroy();
+}
+
+CClientKeyExch::~CClientKeyExch()
+/**
+ * Destructor.
+ */
+{
+	LOG(Log::Printf(_L("CClientKeyExch::~CClientKeyExch()"));)
+	delete iKeyExchBuf;
+}
+
+CCertificateVerify::~CCertificateVerify()
+/**
+ * Destructor.
+ */
+{
+	LOG(Log::Printf(_L("CCertificateVerify::~CCertificateVerify()"));)
+	delete iSignature;
+}
+
+
+CSendFinished::~CSendFinished()
+/**
+ * Destructor.
+ */
+{
+	LOG(Log::Printf(_L("CSendFinished::~CSendFinished()"));)
+	delete iFinishedMsg;
+	delete iShaHashPtr;
+	delete iMd5HashPtr;
+}
+
+//
+//
+CClientHello::~CClientHello()
+{
+	iCipherList.Close();
+}
+
+CAsynchEvent* CClientHello::ProcessL( TRequestStatus& aStatus )
+/**
+ * This asynchronous method processes a ClientHello message. This message 
+ * initiates Handshake negotiation.
+ *
+ * It creates a CClientHelloMsg object which contains the items needed for a ClientHello 
+ * message. The CClientHelloMsg constructor initialises the object with some basic values. 
+ * Other message items will need to be retrieved via the TLS Provider and will
+ * be used to complete construction of this object.
+ * 
+ * The required items are a session id (if one currently exists), client random  
+ * value, proposed protocol version, cipher suites and compression algorithm.
+ * 
+ * @param aStatus TRequestStatus object
+ * @return CAsynchEvent* Pointer to the next asynchronous event to be processed
+ */
+{
+	LOG(Log::Printf(_L("CClientHello::ProcessL()"));)
+
+	// Get a reference to CHandshake::iComposeMsg (TPtr8 descriptor). This 
+	// pointer descriptor is used to access the CStateMachine::iFragment heap
+	// descriptor and contains the message to be transmitted.
+	TPtr8& ptrComposeMsg = Handshake().ComposeMsg();
+
+	switch ( iClientHelloStates )
+	{
+		case ETlsGetSessionInfo:
+		{
+			LOG(Log::Printf(_L("CClientHello::ProcessL() - ETlsGetSessionInfo"));)
+
+			iClientHelloStates = ETlsGetCiphers;
+			__ASSERT_DEBUG( !iHandshakeMessage, TlsPanic(ETlsPanicHandshakeMsgAlreadyExists));
+			CTlsCryptoAttributes& cryptoAttributes = *iTlsProvider->Attributes();
+
+			if(!cryptoAttributes.iServerNames)
+				{
+				// If this type is changed be very careful to check all the code which uses iHandshakeMessage...
+				iHandshakeMessage = new(ELeave)CClientHelloMsg;
+				}
+			else
+				{
+				// If this type is changed be very careful to check all the code which uses iHandshakeMessage...
+				iHandshakeMessage = new(ELeave)CClientHelloWithExtensionsMsg;
+				}
+			LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CClientHelloMsg ));)
+
+			Handshake().GetServerAddrInfo( cryptoAttributes.iSessionNameAndID.iServerName );
+
+			cryptoAttributes.iSessionNameAndID.iSessionId.Zero();		// Reset the length.
+			iTlsProvider->GetSessionL(cryptoAttributes.iSessionNameAndID.iServerName, 
+			cryptoAttributes.iSessionNameAndID.iSessionId, aStatus);
+
+			break;
+		}
+		case ETlsGetCiphers:
+		{
+			LOG(Log::Printf(_L("CClientHello::ProcessL() - ETlsGetCiphers"));)
+			
+			iClientHelloStates = ETlsComposeHello;
+			__ASSERT_DEBUG( iHandshakeMessage, TlsPanic(ETlsPanicNullHandshakeMsg) );
+      
+			// Get the list of available ciphers the Provider.
+			iTlsProvider->CipherSuitesL(iCipherList, aStatus); 
+			break;
+		}
+		case ETlsComposeHello:
+		{
+			LOG(Log::Printf(_L("CClientHello::ProcessL() - ETlsComposeHello"));)
+			
+			iClientHelloStates = ETlsGetSessionInfo;
+			__ASSERT_DEBUG( iHandshakeMessage, TlsPanic(ETlsPanicNullHandshakeMsg));
+
+			CTlsCryptoAttributes &cryptoAttributes = *iTlsProvider->Attributes();
+      
+			// Get and set the variable length (CVariableItem) parameters.
+			// Cipher suites
+			TDes8& desCipherSuites = iTlsProvider->Attributes()->iProposedCiphers;
+			if ( desCipherSuites.Length() == 0 )
+			{
+				// The user has not already setup the ciphersuite list via CSecureSocket::SetAvailableCipherSuites
+				// so we set it to all the ciphersuites which are supported and configured.
+				for ( TInt loop = 0; loop < iCipherList.Count(); ++loop )
+				{
+					const TTLSCipherSuite &cipherSuite = iCipherList[loop];
+						
+					desCipherSuites.Append( cipherSuite.iHiByte );
+					desCipherSuites.Append( cipherSuite.iLoByte );
+				}
+			}
+			iCipherList.Close();
+					
+			// Get the Compression and session id
+			// Compute and set the length of the Variable length items.
+			const TDesC8& desCompression = iRecordComposer.SupportedCompression();
+			TDes8& desSessionId = iTlsProvider->Attributes()->iSessionNameAndID.iSessionId;
+
+			CClientHelloMsg* pHelloMsg = (CClientHelloMsg*)iHandshakeMessage;
+			pHelloMsg->iCipherSuite.Header().SetInitialValue( desCipherSuites.Length() );
+			pHelloMsg->iCompression.Header().SetInitialValue( desCompression.Length() );
+			pHelloMsg->iSessionId.Header().SetInitialValue( desSessionId.Length() );
+
+			CClientServerNameExtension *serverNameExtension = 0;
+			if(cryptoAttributes.iServerNames)
+				{
+				CClientHelloWithExtensionsMsg* pHelloExtMsg = static_cast<CClientHelloWithExtensionsMsg*>(pHelloMsg);
+
+				serverNameExtension = CClientServerNameExtension::NewLC();
+				pHelloExtMsg->AddExtensionL(serverNameExtension);
+				CleanupStack::Pop(serverNameExtension);
+
+				TInt serverNameCount = cryptoAttributes.iServerNames->Count();
+				for(TInt i=0; i<serverNameCount; ++i)
+					{
+					const TPtrC8 &serverName = (*cryptoAttributes.iServerNames)[i];
+					CClientServerNameEntry *serverNameEntry = CClientServerNameEntry::NewLC(serverName.Length());
+					serverNameExtension->AddServerNameEntryL(serverNameEntry);
+					CleanupStack::Pop(serverNameEntry);
+					}
+				}
+      
+			// Compute the length of the Client Hello message and allocate an 
+			// appropriate-sized buffer.
+			HBufC8* pFragment = iStateMachine->ReAllocL( pHelloMsg->iRecord.CalcTotalInitialiseLength() );
+			ptrComposeMsg.Set( pFragment->Des() );
+			ptrComposeMsg.Zero();
+		
+			// Initialise each item's pointer to point to the start of its part of 
+			// the buffer and set each items' value.
+			pHelloMsg->iRecord.InitialiseL( ptrComposeMsg ); 
+      
+			pHelloMsg->iCipherSuite.SetBody( desCipherSuites ); 
+			pHelloMsg->iCompression.SetBody( desCompression );
+			pHelloMsg->iSessionId.SetBody( desSessionId );
+
+			iBody.Set( pHelloMsg->iVersion.GetBodyDes() );
+			iBody[0] = iTlsProvider->Attributes()->iProposedProtocol.iMajor;
+			iBody[1] = iTlsProvider->Attributes()->iProposedProtocol.iMinor;
+
+			// Generate random directly into message buffer and set the value in the
+			// Provider also.
+			iBody.Set( pHelloMsg->iRandom.GetBodyDes() );
+			iTlsProvider->GenerateRandom( iBody );
+			iTlsProvider->Attributes()->iMasterSecretInput.iClientRandom = iBody;
+
+			if(serverNameExtension)
+				{
+				// Set type field
+				serverNameExtension->SetBigEndian( CExtensionNode::KExtServerName );
+
+				TInt serverNameCount = cryptoAttributes.iServerNames->Count();
+				for(TInt i=0; i<serverNameCount; ++i)
+					{
+					// Get server name
+					const TPtrC8 &serverName = (*cryptoAttributes.iServerNames)[i];
+
+					// Create the server name entry
+					CClientServerNameEntry *entry = serverNameExtension->Node(i);
+					// Set type to DNS
+					entry->SetBigEndian( CClientServerNameEntry::KExtServerNameTypeDns );
+
+					TPtr8 serverNameDes(0,0);
+					serverNameDes.Set( entry->iName.GetBodyDes() );
+
+					serverNameDes = serverName;
+					}
+				}
+		
+			// Create handshake header, update the history, and set the record protocol
+			// content type. Hard-coded start using SSL3.0 framing to support TLS->SSL fall
+			// back. Set the Record composer's data buffer to the handshake message and set
+			// up the next asynchronous event.
+			ComposeHandshakeHeader( ETlsClientHelloSent, ETlsClientHelloMsg, ptrComposeMsg );
+			CRecordComposer& recordComposer = iRecordComposer; //'this' will be deleted
+            if ( !recordComposer.TlsVersion() )
+                {
+                // Always default to the newest version, if the server doesn't
+                // support it we will get an SSL3.0 server hello and we will
+                // rollback to that
+                recordComposer.SetVersion( &KTLS1_0 );
+                }
+            else
+                {
+                recordComposer.SetVersion( &iTlsProvider->Attributes()->iProposedProtocol );
+                }
+
+
+			LOG(Log::Printf(_L("CClientHello message"));)
+#ifdef _DEBUG
+      	LOG(iHandshakeMessage->iRecord.Dump( KSSLLogDir,KSSLLogFileName);)
+#endif
+			recordComposer.SetNext( Handshake().InitiateReceiveL() );
+			// !'this' is now deleted !
+			return recordComposer.ProcessL( aStatus );
+		}
+		default:
+		{
+			LOG(Log::Printf(_L("CClientHello::ProcessL() - Default case statement - ERROR"));)
+			__ASSERT_ALWAYS( EFalse, TlsPanic(ETlsPanicInvalidProcessState));
+			break;
+		}
+	}
+	return this;
+}
+
+//
+//
+CAsynchEvent* CClientKeyExch::ProcessL( TRequestStatus& aStatus )
+/**
+ * This method processes a Client Key exchange message. The content of the message is 
+ * passed to the Protocol via the TLS Provider API.
+ * 
+ * For the RSA key exchange algorithm, this message will consist of an encrypted premaster secret.
+ * For the DH key exchange algorithm, it will consist of the DH parameters.
+ * For the PSK key exchange algorithm, it will consist of the PSK identity.
+ * For the DHE_PSK Key Exchange Algorithm it will consist of the PSK identity followed
+ * by the ClientDiffieHellmanPublic params.
+ * For the RSA_PSK Key Exchange Algorithm it will consist of the PSK identity followed
+ * by the EncryptedPreMasterSecret.
+ *
+ * @param aStatus TRequestStatus object
+ * @return CAsynchEvent* Pointer to the next event to be processed
+ */
+{
+	LOG(Log::Printf(_L("CClientKeyExch::ProcessL()"));)
+	
+	// Get a pointer to the handshake message buffer and get the Key exchange algorithm.
+	TPtr8& ptrComposeMsg = Handshake().ComposeMsg();
+
+	switch ( iClientKeyExcStates )
+	{
+		case ETlsGetKeyExchangeMsg:
+			{
+				LOG(Log::Printf(_L("CClientKeyExch::ProcessL() - ETlsGetKeyExchangeMsg"));)
+//	__UHEAP_MARK; 
+//	__UHEAP_MARKEND;
+
+			const CTlsCryptoAttributes *cryptoAttributes = iTlsProvider->Attributes();
+
+			switch(cryptoAttributes->iPublicKeyParams->iKeyType)
+				{
+				case EPsk:
+				case EDhePsk:
+				case ERsaPsk:
+					if(!cryptoAttributes->iPskConfigured)
+						{
+						// Server asked for a ciphersuite with a PSK key exchange algorithm, but PSK is not configured.
+						// This can happen if the client forces the ciphersuite, without configuring the PSK callback info.
+						User::Leave(KErrSSLAlertIllegalParameter);
+						return 0;
+						}
+					// Callback is set so call it
+					delete cryptoAttributes->iPublicKeyParams->iValue4; // Make sure we do not leak a PSK identity
+					cryptoAttributes->iPublicKeyParams->iValue4 = 0;
+					delete cryptoAttributes->iPublicKeyParams->iValue5; // Make sure we do not leak a PSK value
+					cryptoAttributes->iPublicKeyParams->iValue5 = 0;
+					cryptoAttributes->iPskKeyHandler->GetPskL(cryptoAttributes->iPskIdentityHint,
+															  cryptoAttributes->iPublicKeyParams->iValue4,
+															  cryptoAttributes->iPublicKeyParams->iValue5);
+					if((cryptoAttributes->iPublicKeyParams->iValue4==0) || (cryptoAttributes->iPublicKeyParams->iValue5==0))
+						{
+						User::Leave(KErrSSLAlertIllegalParameter);
+						}
+					break;
+				default:
+					break;
+				}
+
+
+				iClientKeyExcStates = ETlsComposeKeyExchange;
+				iTlsProvider->TlsSessionPtr()->ClientKeyExchange( iKeyExchBuf, aStatus);
+				break;
+			}
+		case ETlsComposeKeyExchange:
+			{
+				LOG(Log::Printf(_L("CClientKeyExch::ProcessL() - ETlsComposeKeyExchange"));)
+				
+				iClientKeyExcStates = ETlsGetKeyExchangeMsg;
+				TTLSKeyExchangeAlgorithm keyExcAlg = iTlsProvider->Attributes()->iCurrentCipherSuite.CipherDetails()->iKeyExAlg;
+				__ASSERT_DEBUG( !iHandshakeMessage, TlsPanic(ETlsPanicHandshakeMsgAlreadyExists));
+
+				iBody.Set( iKeyExchBuf->Des() );	// Get a TPtr to the message contents
+            CClientKeyExchMsg* pKeyExchMsg = NULL; //to make compiler happy
+				if ( keyExcAlg == ERsa )
+				{
+               if ( iTlsProvider->Attributes()->iNegotiatedProtocol.iMinor )
+               {
+					   iHandshakeMessage = pKeyExchMsg = new(ELeave)CRsaClientKeyExchMsg31( iBody.Length() );	
+LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CRsaClientKeyExchMsg31 ));)
+               }
+               else
+               {
+					   iHandshakeMessage = pKeyExchMsg = new(ELeave)CRsaClientKeyExchMsg30( iBody.Length() );	
+LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CRsaClientKeyExchMsg30 ));)
+               }
+				}
+				else if ( keyExcAlg == EDHE )
+				{
+					iHandshakeMessage = pKeyExchMsg = new(ELeave)CDhExplicitClientKeyExchMsg( iBody.Length() );
+LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CDhExplicitClientKeyExchMsg ));)
+				}
+				else if (keyExcAlg == EPsk)
+				{
+					iHandshakeMessage = pKeyExchMsg = new(ELeave)CPskClientKeyExchMsg( iBody.Length() );
+LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CPskClientKeyExchMsg ));)
+				}
+				else 
+				{
+					LOG(Log::Printf(_L("CClientKeyExch::ProcessL() - Unsupported key exchange"));)
+					User::Leave(KErrSSLAlertIllegalParameter);
+				}
+				// Allocate memory in the state machine's buffer for the message
+				HBufC8* pFragment = iStateMachine->ReAllocL( pKeyExchMsg->iRecord.CalcTotalInitialiseLength() );
+				ptrComposeMsg.Set( pFragment->Des() );
+				ptrComposeMsg.Zero();
+
+				// Initialise the item's pointer to point to the start of its part of 
+				// the buffer and set its value.
+				pKeyExchMsg->iRecord.InitialiseL( ptrComposeMsg ); 
+	  			pKeyExchMsg->SetKeyExchnage( iBody );
+
+				// Create handshake header, update the handshake messages hash and history, set the 
+				// record protocol content type
+				ComposeHandshakeHeader( ETlsClientKeyExchSent, ETlsClientKeyExchMsg, ptrComposeMsg );
+
+#ifdef _DEBUG
+         	LOG(iHandshakeMessage->iRecord.Dump( KSSLLogDir,KSSLLogFileName);)
+#endif
+				CRecordComposer& recordComposer = iRecordComposer; //'this' will be deleted
+				recordComposer.SetNext( Handshake().InitiateTransmitL() );
+				return recordComposer.ProcessL( aStatus );			
+			}
+		default:
+			{
+				LOG(Log::Printf(_L("CClientKeyExch::ProcessL() - Default case statement - ERROR"));)
+				__ASSERT_DEBUG( EFalse, TlsPanic(ETlsPanicInvalidProcessState));
+				break;
+			}
+	} // switch
+
+	return this;
+}
+
+//
+//
+CAsynchEvent* CClientCertificate::ProcessL( TRequestStatus& aStatus )
+/**
+ * This asynchronous method processes a Client certificate message.
+ * This message is only sent if a Server certificate has been received (always true for
+ * this implementation as only authenticated servers are supported) and if a Certificate
+ * Request has been received by the Server.
+ *
+ * @param aStatus TRequestStatus object
+ * @return CAsynchEvent* Pointer to the next event to be processed
+ */
+{
+	TPtr8& ptrComposeMsg = Handshake().ComposeMsg();
+
+	switch ( iClientCertStates )
+	{
+		case ETlsGetCertInfo:
+			{
+				LOG(Log::Printf(_L("CClientCertificate::ProcessL() - ETlsGetCertInfo"));)
+
+				iClientCertStates = ETlsComposeClientCert;
+				__ASSERT_DEBUG( !iHandshakeMessage, TlsPanic(ETlsPanicHandshakeMsgAlreadyExists));
+				iHandshakeMessage = new(ELeave)CCertificateMsg;
+LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CCertificateMsg ));)
+
+				if( iTlsProvider->TlsSessionPtr() == NULL )
+ 				{
+ 					User::Leave(KErrSSLNullTlsSession);
+ 				}
+
+				iTlsProvider->TlsSessionPtr()->ClientCertificate( &iCertArray, aStatus );
+				break;
+			}
+		case ETlsComposeClientCert:
+			{
+				LOG(Log::Printf(_L("CClientCertificate::ProcessL() - ETlsGetCertInfo"));)
+
+				iClientCertStates = ETlsGetCertInfo;
+
+				// Compose Client certificate message - Allocate memory in the state machine's 
+				// buffer for the message; initialise the record object and set its value.
+				CCertificateMsg* pClientCertMsg = (CCertificateMsg*)iHandshakeMessage;
+
+				// If the Client Certificate message is NULL, there is no need to send a Certificate
+				// Verify message. A certificate message will be sent with an empty body.
+				TInt certCount = iCertArray.Count();
+ 				if (certCount != 0)
+				{
+					Handshake().SetCertificateVerifyReqd( ETrue );
+					for(TInt i=0; i<certCount; i++)
+ 						{
+ 						pClientCertMsg->iCertificateList.AddNodeL( iCertArray[i]->Length() );
+ 						}
+				}
+				HBufC8* pFragment = iStateMachine->ReAllocL( pClientCertMsg->iRecord.CalcTotalInitialiseLength() );
+				ptrComposeMsg.Set( pFragment->Des() ); 
+				ptrComposeMsg.Zero();
+				pClientCertMsg->iRecord.InitialiseL( ptrComposeMsg ); 
+				if(certCount != 0)
+ 					{
+ 					CListNode* currentNode = pClientCertMsg->iCertificateList.First();
+ 					for(TInt i=0; i<certCount; i++)
+ 						{
+ 						TPtrC8 cert = iCertArray[i]->Des();
+ 						currentNode->SetBody(cert);
+ 						currentNode = currentNode->Next();
+ 						}
+					}
+		
+				// Create handshake header, update the history, and set the record protocol,
+				// content type, Update the handshake messages hash
+				ComposeHandshakeHeader( ETlsClientCertificateSent, ETlsClientCertificateMsg, ptrComposeMsg );   
+				CRecordComposer& recordComposer = iRecordComposer; //'this' will be deleted
+#ifdef _DEBUG
+         	LOG(iHandshakeMessage->iRecord.Dump( KSSLLogDir,KSSLLogFileName);)
+#endif
+
+				recordComposer.SetNext( Handshake().NextTxEvent() );
+				return recordComposer.ProcessL( aStatus );
+			}
+		default:
+			{
+				// This should never happen
+				LOG(Log::Printf(_L("CClientCertificate::ProcessL() - 'Default' statement - unknown state"));)
+				__ASSERT_DEBUG( EFalse, TlsPanic(ETlsPanicInvalidProcessState));
+				break;
+			}
+	} // switch
+
+	return this;
+}
+
+//
+//
+CAsynchEvent* CCertificateVerify::ProcessL( TRequestStatus& aStatus )
+/**
+ * This asynchronous method processes a Certificate Verify message.
+ * The message is computed differently for the SSL3.0 and TLS1.0 protocols. However,
+ * the input passed to the Provider is the same and the differences are handled in the
+ * Security components.
+ * This message is sent only if the Client certificate is NOT NULL and if the Client 
+ * Certificate has signing capability. This is always true for this implementation as 
+ * static/fixed DH is NOT supported.
+ *
+ * @param aStatus TRequestStatus object
+ * @return CAsynchEvent* Pointer to the next event to be processed
+ */
+{
+	LOG(Log::Printf(_L("CCertificateVerify::ProcessL"));)
+
+	TPtr8& ptrComposeMsg = Handshake().ComposeMsg();
+	
+	TAlgorithmId& signatureAlg = Handshake().SignatureAlg();
+
+	CSHA1* sha1HashPtr = Handshake().SHA1Verify();
+	CMD5* md5HashPtr = Handshake().MD5Verify();
+
+	switch ( iCertVerifyStates )
+	{
+		case ETlsGetSignature:
+			{
+				LOG(Log::Printf(_L("CCertificateVerify::ProcessL() - ETlsGetSignature"));)
+
+				iCertVerifyStates = ETlsComposeCertVerify;
+				__ASSERT_DEBUG( !iHandshakeMessage, TlsPanic(ETlsPanicHandshakeMsgAlreadyExists));
+
+				if ( signatureAlg == ERSA)
+				{
+					LOG(Log::Printf(_L("CCertificateVerify::ProcessL - RSA signature"));)
+					iHandshakeMessage = new(ELeave)CRsaCertificateVerifyMsg;
+LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CRsaCertificateVerifyMsg ));)
+
+//					signatureLength = KTlsMd5Length + KTlsShaLength;
+				}
+				else if ( signatureAlg == EDSA )
+				{
+					LOG(Log::Printf(_L("CCertificateVerify::ProcessL - DSA signature"));)
+					iHandshakeMessage = new(ELeave)CDsaCertificateVerifyMsg;
+LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CDsaCertificateVerifyMsg ));)
+
+//					signatureLength = KTlsShaLength;
+				}
+				else
+				{
+					LOG(Log::Printf(_L("CCertificateVerify::ProcessL() - Unsupported signing algorithm"));)
+					User::Leave(KErrSSLAlertIllegalParameter);
+				}
+
+				// Allocate a buffer of the right size for the signature and call the Provider.
+				__ASSERT_DEBUG( !iSignature, TlsPanic(ETlsPanicSignatureAlreadyExists) );
+				//iSignature = HBufC8::NewL( signatureLength ); signature allocated by token
+         	//LOG(Log::Printf(_L("iSignature %x - %x"), iSignature, iSignature + signatureLength + sizeof( HBufC8 ));)
+				iTlsProvider->TlsSessionPtr()->CertificateVerifySignatureL( md5HashPtr, sha1HashPtr, iSignature, aStatus );
+
+				break;
+			}
+		case ETlsComposeCertVerify:
+			{
+				// Compose Certificate Verify message - Allocate memory in the state 
+				// machine's buffer for the message; initialise the record object and set 
+				// its value.
+				LOG(Log::Printf(_L("CCertificateVerify::ProcessL() - ETlsComposeCertVerify"));)
+
+				iCertVerifyStates = ETlsGetSignature;
+            TPtrC8 sigDes = iSignature->Des();
+            CCertificateVerifyMsg* pCertVerifyMsg = static_cast<CCertificateVerifyMsg*>(iHandshakeMessage);
+            pCertVerifyMsg->SetSignatureLength( sigDes );
+				HBufC8* pFragment = iStateMachine->ReAllocL( pCertVerifyMsg->iRecord.CalcTotalInitialiseLength() );
+				ptrComposeMsg.Set( pFragment->Des() ); 
+				ptrComposeMsg.Zero();
+				pCertVerifyMsg->iRecord.InitialiseL( ptrComposeMsg ); 
+            pCertVerifyMsg->SetSignature( sigDes );
+
+				// Create handshake header, update the history, and set the record protocol,
+				// content type, Update the handshake messages hash
+				ComposeHandshakeHeader( ETlsCertificateVerifySent, ETlsCertificateVerifyMsg, ptrComposeMsg );
+      
+#ifdef _DEBUG
+         	LOG(iHandshakeMessage->iRecord.Dump( KSSLLogDir,KSSLLogFileName);)
+#endif
+            iRecordComposer.SetNext( Handshake().NextTxEvent() );
+				return iRecordComposer.ProcessL( aStatus );
+
+			}	// case ETlsComposeCertVerify
+		default:
+			{	// This should never happen
+				LOG(Log::Printf(_L("CCertificateVerify::ProcessL() - 'Default' statement - unknown state"));)
+				__ASSERT_DEBUG( EFalse, TlsPanic(ETlsPanicInvalidProcessState));
+				break;
+			}
+	}// switch
+
+	return this;
+}
+
+//
+//
+CAsynchEvent* CSendFinished::ProcessL( TRequestStatus& aStatus )
+/** 
+ * This asynchronous method processes a transmitted Finished message.
+ * The input to the Finished message is the same for both SSL3.0 and TLS1.0. However
+ * the calculations for the end result (and thus the output) are different.
+ *
+ * @param aStatus TRequestStatus object
+ * @return CAsynchEvent* Pointer to the next event to be processed
+ */
+{
+	LOG(Log::Printf(_L("CSendFinished::ProcessL()"));)
+
+	switch( iFinishedStates)
+	{
+		case ETlsGetFinishedMsg:
+			{
+				LOG(Log::Printf(_L("CSendFinished::ProcessL() - ETlsGetFinishedMsg"));)
+			
+				iFinishedStates = ETlsComposeFinished;
+				__ASSERT_DEBUG( !iHandshakeMessage, TlsPanic(ETlsPanicHandshakeMsgAlreadyExists));
+
+				// Send the information to the Provider to calculate the message body
+				iShaHashPtr = static_cast<CSHA1*>( Handshake().SHA1Verify()->CopyL() ); 
+				iMd5HashPtr = static_cast<CMD5*>( Handshake().MD5Verify()->CopyL() );
+				iTlsProvider->TlsSessionPtr()->ClientFinishedMsgL( iMd5HashPtr, iShaHashPtr, iFinishedMsg, aStatus);				
+				break;
+			}
+		case ETlsComposeFinished:
+			{
+				LOG(Log::Printf(_L("CSendFinished::ProcessL() - ETlsComposeFinished"));)
+
+				iFinishedStates = ETlsGetFinishedMsg;
+				TPtr8& ptrComposeMsg = Handshake().ComposeMsg();
+
+				iBody.Set( iFinishedMsg->Des() );	// Get a TPtr to the message contents
+   			__ASSERT_DEBUG( !iHandshakeMessage,  TlsPanic(ETlsPanicHandshakeMsgAlreadyExists));
+				iHandshakeMessage = new(ELeave)CFinishedMsg( iBody.Length() );
+LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CFinishedMsg ));)
+				CFinishedMsg* pFinishedMsg = (CFinishedMsg*)iHandshakeMessage;
+
+				HBufC8* pFragment = iStateMachine->ReAllocL( pFinishedMsg->iRecord.CalcTotalInitialiseLength() );
+				ptrComposeMsg.Set( pFragment->Des() ); 
+				ptrComposeMsg.Zero();
+
+				pFinishedMsg->iRecord.InitialiseL( ptrComposeMsg ); 
+				pFinishedMsg->iFinishedData.SetBody ( iBody );			
+
+				// Create handshake header, update the history, and set the record protocol,
+				// content type, Update the handshake messages hash
+				ComposeHandshakeHeader( ETlsFinishedSent, ETlsFinishedMsg, ptrComposeMsg );      
+#ifdef _DEBUG
+         	LOG(iHandshakeMessage->iRecord.Dump( KSSLLogDir,KSSLLogFileName);)
+#endif
+			
+				// Set up next event.
+				CRecordComposer& recordComposer = iRecordComposer; //'this' will be deleted		
+				recordComposer.SetNext( Handshake().InitiateReceiveL() );
+				return recordComposer.ProcessL( aStatus );
+			}
+		default:
+			{	// This should never happen
+				LOG(Log::Printf(_L("CSendFinished::ProcessL() - 'Default' statement - unknown state"));)
+				__ASSERT_DEBUG( EFalse, TlsPanic(ETlsPanicInvalidProcessState) );
+				break;
+			}
+	} // switch
+	
+	return this;
+}
+