networksecurity/tls/protocol/tlshandshake.cpp
changeset 0 af10295192d8
child 67 bb2423252ea3
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // SSL3.0 and TLS1.0 Handshake Negotiation source file.
       
    15 // Describes the implementation of a Handshake Negotiation state machine.
       
    16 // 
       
    17 //
       
    18 
       
    19 /**
       
    20  @file
       
    21 */
       
    22   
       
    23 #include "tlshandshakeitem.h"
       
    24 #include "AlertProtocolEvents.h"
       
    25 #include "handshakereceiveevents.h"
       
    26 #include "handshaketransmitevents.h"
       
    27 #include "recordprotocolevents.h"
       
    28 #include "changecipherevents.h"
       
    29 #include "tlsconnection.h"
       
    30 #include "tlshandshake.h"  
       
    31 
       
    32 void CHandshakeHeader::ComposeHeader( ETlsHandshakeMessage aHandshakeMessage, TInt aLength )
       
    33 /**
       
    34  * This method composes a handshake header.
       
    35  */ 
       
    36 {
       
    37 	LOG(Log::Printf(_L("CHandshakeHeader::ComposeHeader()"));)
       
    38 	
       
    39 	__ASSERT_DEBUG( iPtr8 != NULL, TlsPanic(ETlsPanicNullPointerToHandshakeHeaderBuffer) );
       
    40 	iPtr8[KTlsHandshakeTypeOffset] = static_cast<TUint8>(aHandshakeMessage);
       
    41    
       
    42 	TBigEndian value; 
       
    43 	value.SetValue( iPtr8 + KTlsHandshakeLengthOffset, KTlsHandshakeBodyLength, aLength );	
       
    44 }
       
    45 
       
    46 //
       
    47 CHandshake* CHandshake::NewL(CTlsConnection& aTlsConnection)
       
    48 /**
       
    49  * This method creates a Handshake negotiation object.
       
    50  */
       
    51 {
       
    52 	LOG(Log::Printf(_L("CHandshake::NewL()"));)
       
    53 
       
    54 	CHandshake* self = new(ELeave) CHandshake(aTlsConnection);
       
    55   	LOG(Log::Printf(_L("self %x - %x"), self, (TUint)self + sizeof( CHandshake ));)
       
    56 	CleanupStack::PushL(self);
       
    57 	self->ConstructL(aTlsConnection);
       
    58 	CleanupStack::Pop();
       
    59 	return self;
       
    60 }
       
    61 
       
    62 CHandshake::~CHandshake()
       
    63 /**
       
    64  * Destructor.
       
    65  * Destroys the list of handshake messages to transmit, the hash objects and the
       
    66  * 'Send Alert' object
       
    67  */
       
    68 {
       
    69 	LOG(Log::Printf(_L("CHandshake::~CHandshake()"));)
       
    70 
       
    71 	DestroyTxList();
       
    72 	delete iSHA1Verify;
       
    73 	delete iMD5Verify;
       
    74 	delete iSendAlert;
       
    75    delete iServerCert;
       
    76 }
       
    77 
       
    78 void CHandshake::DestroyTxList()
       
    79 {
       
    80 	LOG(Log::Printf(_L("CHandshake::DestroyTxList() of transmitted handshake messages"));)
       
    81 
       
    82 	CTlsEvent* listItem;
       
    83     
       
    84     iTxListIter.SetToFirst(); 
       
    85     while ( (listItem = iTxListIter++) != NULL )
       
    86         {
       
    87         iTransmitList.Remove(*listItem);
       
    88         delete listItem;
       
    89         };
       
    90 }
       
    91 void CHandshake::ConstructL(CTlsConnection& aTlsConnection)
       
    92 /**
       
    93  * Standard 2 phase construction.
       
    94  * This method creates and returns pointers to Hash objects; 
       
    95  * Re-constructs the record parser and composer objects (setting them up 
       
    96  * specifically for Handshake negotiation);
       
    97  * Creates an Alert object (for sending Alerts) and
       
    98  * Initiates transmission of the first asynchronous event, the Client Hello message.
       
    99  *
       
   100  * @param aTlsConnection The connection that initiated the handshake negotiation.
       
   101  */
       
   102 {
       
   103 	LOG(Log::Printf(_L("CHandshake::ConstructL()"));)
       
   104    
       
   105 	iSHA1Verify = CSHA1::NewL();
       
   106 	iMD5Verify = CMD5::NewL();
       
   107    
       
   108 	iSendAlert = new(ELeave)CSendAlert( *this, aTlsConnection.RecordComposer() );
       
   109   	LOG(Log::Printf(_L("iSendAlert %x - %x"), SendAlert(), (TUint)iSendAlert + sizeof( CSendAlert ));)
       
   110 	aTlsConnection.RecordParser().ReConstructL( this, TPtr8(NULL, 0), *iSendAlert );
       
   111 	aTlsConnection.RecordComposer().ReConstructL( this, 0 );
       
   112 	iActiveEvent = InitiateTransmitL(); // pointer to the 1st event/message to transmit
       
   113 }
       
   114 
       
   115 void CHandshake::StartL( TRequestStatus* aClientStatus, MStateMachineNotify* aStateMachineNotify )
       
   116 /**
       
   117  * This method starts the handshake negotiation state machine by calling the 
       
   118  * Start() method of the base state machine class (CStateMachine).
       
   119  *
       
   120  * @param aClientStatus Pointer to a TRequestStatus object that completes when  
       
   121  * handshake negotiation is completed.
       
   122  * @param aStateMachineNotify Pointer to a MStateMachineNotify interface object.
       
   123  */
       
   124 {
       
   125 	LOG(Log::Printf(_L("CHandshake::StartL()"));)
       
   126 
       
   127 	// Obtain a reference to a Record parser object and use its Handshake parser
       
   128 	// to set the user's data descriptor and its length (CRecordParser::iUserData 
       
   129 	// and iUserMaxLength).
       
   130 	CRecordParser& RecordParser = iTlsConnection.RecordParser();
       
   131 	CHandshakeParser* pParser = RecordParser.HandshakeParser();
       
   132 	pParser->SetMessageAsUserDataL( KTlsHandshakeHeaderSize );
       
   133 
       
   134 	CStateMachine::Start( aClientStatus, (CAsynchEvent*)iSendAlert, aStateMachineNotify );
       
   135 }
       
   136 
       
   137 CTlsEvent* CHandshake::InitiateReceiveL()
       
   138 /**
       
   139  * This method creates a list of Handshake messages that are expected from 
       
   140  * the Server.
       
   141  */
       
   142 {
       
   143 	LOG(Log::Printf(_L("CHandshake::InitiateReceiveL()"));)
       
   144 
       
   145 	CTLSProvider& tlsProvider = iTlsConnection.TlsProvider();
       
   146 
       
   147 	CRecordParser& recordParser = iTlsConnection.RecordParser();
       
   148 	CHandshakeParser* pParser = recordParser.HandshakeParser();
       
   149 	__ASSERT_DEBUG( pParser != 0, TlsPanic(ETlsPanicNullPointerToHandshakeRecordParser));
       
   150 	__ASSERT_DEBUG( History() != 0, TlsPanic(ETlsPanicNullStateMachineHistory));
       
   151 	
       
   152 	pParser->DestroyRxList();
       
   153 	CHandshakeReceive* rxItem;
       
   154 
       
   155 	if ( History() & ETlsFinishedRecv ) // Handshake negotiation is complete
       
   156 	{
       
   157 		return NULL;
       
   158 	}
       
   159 	
       
   160 	if ( History() == ETlsClientHelloSent ) // and nothing else has happened
       
   161 	{
       
   162 		rxItem = new(ELeave)CServerHello( tlsProvider, *this, recordParser );
       
   163 		//coverity[leave_without_push]
       
   164      	LOG(Log::Printf(_L("CServerHello %x - %x"), rxItem, (TUint)rxItem + sizeof( CServerHello ));)
       
   165 		pParser->AddToList( *rxItem );
       
   166 	}
       
   167 	else if ( History() & ETlsFullHandshake )			// Full handshake
       
   168 	{
       
   169 		if ( History() & ETlsServerHelloDoneRecv)		// Server hello done received
       
   170 		{
       
   171 			rxItem = new(ELeave)CRecvFinished( tlsProvider, *this, recordParser );
       
   172 			//coverity[leave_without_push]
       
   173      	LOG(Log::Printf(_L("CRecvFinished %x - %x"), rxItem, (TUint)rxItem + sizeof( CRecvFinished ));)
       
   174 			pParser->AddToList( *rxItem );
       
   175 		}
       
   176 		else											// Start of the handshake
       
   177 		{
       
   178 			if ( (History() & ETlsUsingPskKeyExchange) == 0)
       
   179 				{
       
   180 				rxItem = new(ELeave)CServerCertificate( tlsProvider, *this, recordParser );
       
   181 				//coverity[leave_without_push]
       
   182      			LOG(Log::Printf(_L("CServerCertificate %x - %x"), rxItem, (TUint)rxItem + sizeof( CServerCertificate ));)
       
   183 				pParser->AddToList( *rxItem );
       
   184 				}
       
   185 			
       
   186 			rxItem = new(ELeave)CServerKeyExch( tlsProvider, *this, recordParser );
       
   187 			//coverity[leave_without_push]
       
   188      		LOG(Log::Printf(_L("CServerKeyExch %x - %x"), rxItem, (TUint)rxItem + sizeof( CServerKeyExch ));)
       
   189 			pParser->AddToList( *rxItem );
       
   190 
       
   191 			if ( (History() & ETlsUsingPskKeyExchange) == 0)
       
   192 				{
       
   193 				rxItem = new(ELeave)CCertificateReq( tlsProvider, *this, recordParser );
       
   194 				//coverity[leave_without_push]
       
   195    	  			LOG(Log::Printf(_L("CCertificateReq %x - %x"), rxItem, (TUint)rxItem + sizeof( CCertificateReq ));)
       
   196 				pParser->AddToList( *rxItem );
       
   197 				}
       
   198 			
       
   199 			rxItem = new(ELeave)CServerHelloDone( tlsProvider, *this, recordParser );
       
   200 			//coverity[leave_without_push]
       
   201      		LOG(Log::Printf(_L("CServerHelloDone %x - %x"), rxItem, (TUint)rxItem + sizeof( CServerHelloDone ));)
       
   202 			pParser->AddToList( *rxItem );
       
   203 		}
       
   204 	}
       
   205 	else if ( History() & ETlsAbbreviatedHandshake )	// Abbreviated handshake	
       
   206 	{	
       
   207 		rxItem = new(ELeave)CRecvFinished( tlsProvider, *this, recordParser );
       
   208 		//coverity[leave_without_push]
       
   209      	LOG(Log::Printf(_L("CRecvFinished %x - %x"), rxItem, (TUint)rxItem + sizeof( CRecvFinished ));)
       
   210 		pParser->AddToList( *rxItem );
       
   211 	}
       
   212 	
       
   213 	return &recordParser;
       
   214 }
       
   215 
       
   216 CTlsEvent* CHandshake::InitiateTransmitL()
       
   217 /**
       
   218  * This method initiates transmission of SSL/TLS events.
       
   219  * It destroys the current list of events/messages and checks its current 
       
   220  * position in terms of the state machine's history. 
       
   221  * It also gets references to the TLS provider interface and the Record composer
       
   222  * object. (It needs access to cryptography services for the message items and it 
       
   223  * needs a record composer to build a TLS record to transmit)
       
   224  * 
       
   225  * This method is called whenever the protocol has to transmit messages/events, 
       
   226  * i.e., at the start of Handshake negotiations and the start of Client authentication. 
       
   227  */
       
   228 {
       
   229 	LOG(Log::Printf(_L("CHandshake::InitiateTransmitL()"));)
       
   230 
       
   231 	DestroyTxList();
       
   232 
       
   233 	// Handshake negotiation is complete
       
   234 	if ( History() & ETlsFinishedSent )
       
   235 		return NULL;
       
   236 
       
   237 	CTLSProvider& tlsProvider = iTlsConnection.TlsProvider();
       
   238 	CRecordComposer& recordComposer = iTlsConnection.RecordComposer();
       
   239 	CTlsEvent* txItem;
       
   240 
       
   241 	if ( History() == ETlsHandshakeStart )
       
   242 	{
       
   243 		// Create a ClientHello message, initialise it and add it to the Transmit list
       
   244 		txItem = new(ELeave)CClientHello( tlsProvider, *this, recordComposer );
       
   245 		//coverity[leave_without_push]
       
   246      	LOG(Log::Printf(_L("CClientHello %x - %x"), txItem, (TUint)txItem + sizeof( CClientHello ));)
       
   247 		AddToList( *txItem );
       
   248 	}
       
   249 	else if ( (History() & ETlsClientKeyExchSent) || (History() & ETlsAbbreviatedHandshake) )
       
   250 	{
       
   251 		// As fixed DH is not supported, the Certificate Verify message is always sent,
       
   252 		// providing a non-NULL Client Certificate message is sent.
       
   253 		if ( CertificateVerifyReqd() )
       
   254 		{	
       
   255 			txItem = new(ELeave)CCertificateVerify( tlsProvider, *this, recordComposer );
       
   256 			//coverity[leave_without_push]
       
   257      	LOG(Log::Printf(_L("CCertificateVerify %x - %x"), txItem, (TUint)txItem + sizeof( CClientHello ));)
       
   258 			AddToList( *txItem );
       
   259 		}
       
   260 
       
   261 		txItem = new(ELeave)CSendChangeCipherSpec( tlsProvider, *this, recordComposer );
       
   262 		//coverity[leave_without_push]
       
   263      	LOG(Log::Printf(_L("CSendChangeCipherSpec %x - %x"), txItem, (TUint)txItem + sizeof( CClientHello ));)
       
   264 		AddToList( *txItem );
       
   265 
       
   266 		txItem = new(ELeave)CSendFinished( tlsProvider, *this, recordComposer );
       
   267 		//coverity[leave_without_push]
       
   268      	LOG(Log::Printf(_L("CSendFinished %x - %x"), txItem, (TUint)txItem + sizeof( CClientHello ));)
       
   269 		AddToList( *txItem );
       
   270 	}
       
   271 	else
       
   272 	{
       
   273 		if ( History() & ETlsCertificateReqRecv )
       
   274 		{	
       
   275 			txItem = new(ELeave)CClientCertificate( tlsProvider, *this, recordComposer );
       
   276 			//coverity[leave_without_push]
       
   277      	LOG(Log::Printf(_L("CClientCertificate %x - %x"), txItem, (TUint)txItem + sizeof( CClientHello ));)
       
   278 			AddToList( *txItem );
       
   279 		}
       
   280 		txItem = new(ELeave)CClientKeyExch( tlsProvider, *this, recordComposer );
       
   281 		//coverity[leave_without_push]
       
   282      	LOG(Log::Printf(_L("CClientKeyExch %x - %x"), txItem, (TUint)txItem + sizeof( CClientHello ));)
       
   283 		AddToList( *txItem );
       
   284 	}
       
   285 
       
   286    iTxListIter.SetToFirst();
       
   287    return NextTxEvent();
       
   288 }
       
   289 
       
   290 void CHandshake::SetNegotiatedVersion( const TTLSProtocolVersion* aTlsVersion )
       
   291 {
       
   292 	iTlsConnection.RecordComposer().SetVersion( aTlsVersion );
       
   293 }
       
   294 
       
   295 void CHandshake::UpdateVerify( TDesC8& aMessage )
       
   296 /**
       
   297  * When the first Finished message is computed, it is necessary to copy the iMD5Verify
       
   298  * and iSHA1Verify to new CMD5 & CSHA1 to see all ::Final and be able to update the members 
       
   299  * to compute the second Finished message.
       
   300  */
       
   301 {
       
   302 	LOG(Log::Printf(_L("CHandshake::UpdateVerify()"));)	
       
   303 
       
   304 	iMD5Verify->Update( aMessage );
       
   305 	iSHA1Verify->Update( aMessage );
       
   306 }
       
   307 
       
   308 void CHandshake::DoCancel()
       
   309 	{
       
   310 	LOG(Log::Printf(_L("CHandshake::DoCancel()"));)
       
   311 
       
   312     if ( iTlsConnection.TlsSession() )
       
   313         {
       
   314         iTlsConnection.TlsSession()->CancelRequest();
       
   315         }
       
   316 
       
   317 	iTlsConnection.RecordComposer().CancelAll();
       
   318 	iTlsConnection.RecordParser().CancelAll();	
       
   319 	}
       
   320 
       
   321 void CHandshake::Cancel(TInt aLastError)
       
   322     {
       
   323 	LOG(Log::Printf(_L("CHandshake::Cancel(TInt)"));)
       
   324 	CStateMachine::Cancel(aLastError);
       
   325 	if (!iErrorEvent)
       
   326 		{
       
   327 		OnCompletion(); // This will cause the instance to be deleted
       
   328 		}
       
   329     }
       
   330 
       
   331 void CHandshake::AddToList( CTlsEvent& aMsgItem )
       
   332 {
       
   333 	LOG(Log::Printf(_L("CHandshake::AddToList()"));)
       
   334 
       
   335     TxMessageList().AddLast(aMsgItem);
       
   336 }
       
   337 
       
   338 void CHandshake::GetServerAddrInfo( TTLSServerAddr& serverInfo )
       
   339 {
       
   340    iTlsConnection.GetServerAddrInfo( serverInfo );
       
   341 }
       
   342 
       
   343 CTLSSession*& CHandshake::TlsSession()
       
   344 {
       
   345    return iTlsConnection.TlsSession();
       
   346 }
       
   347 
       
   348 void CHandshake::ResetCryptoAttributes()
       
   349 {
       
   350    iTlsConnection.ResetCryptoAttributes();
       
   351 }
       
   352 
       
   353 TBool CHandshake::SessionReUse() const
       
   354 /** 
       
   355  * This method returns a boolean which indicates whether a session should be reused.
       
   356  */
       
   357 {
       
   358 	LOG(Log::Printf(_L("CHandshake::SessionReUse()"));)
       
   359 	return iTlsConnection.SessionReUse();
       
   360 }
       
   361 
       
   362 CExtensionNode::CExtensionNode(CItemBase* aNext) :
       
   363 	CConstItem(aNext, KTlsExtensionTypeLength)
       
   364 {
       
   365 }
       
   366 
       
   367 CExtensionNode::~CExtensionNode()
       
   368 {
       
   369 }
       
   370 
       
   371 TInt CExtensionNode::ExtensionLength()
       
   372 	/**
       
   373 		For ParseL (internalisation) to work correctly this function must return the total extension length.
       
   374 		Any derived class must override this function by calling this one and then adding on its extra members.
       
   375 		Unfortunately we can not walk the record linked list to perform this calculation because GetItemLength
       
   376 		is not virtual (and not define in CItemBase).
       
   377 	*/
       
   378 {
       
   379 	return GetItemLength();
       
   380 }
       
   381 
       
   382 
       
   383 CKnownExtensionNode::CKnownExtensionNode() :
       
   384 	CExtensionNode(&iOpaqueData),
       
   385 	iOpaqueData(NULL, KTlsExtensionLength)
       
   386 {
       
   387 }
       
   388 
       
   389 void CKnownExtensionNode::ConstructOpaqueDataWrapperL(CItemBase* aNext)
       
   390 {
       
   391 	iOpaqueData.AddNodeL(aNext);
       
   392 }
       
   393 
       
   394 CKnownExtensionNode::~CKnownExtensionNode()
       
   395 {
       
   396 	// Must not delete the opaque data because it points to members of a class derived from this one...
       
   397 	iOpaqueData.DropNodes();
       
   398 }
       
   399 
       
   400 CCompoundList::~CCompoundList()
       
   401 	{
       
   402 	TInt nodeCount = iRecords.Count();
       
   403 	for(TInt i=0; i<nodeCount; ++i)
       
   404 		{
       
   405 		delete iRecords[i].First();
       
   406 		}
       
   407 	iRecords.Reset();
       
   408 	}
       
   409 
       
   410 void CCompoundList::AddNodeL( CItemBase* aNode )
       
   411 /** 
       
   412  * Adds the item to the tail of the compound list. 
       
   413  
       
   414  * Once added the item is owned by the iNodes pointer array
       
   415  *
       
   416  * @param aItemBase the item to be added
       
   417  */
       
   418 	{
       
   419 	// Add node to end of list. 
       
   420 	// Each node is managed by a TRecord object
       
   421 	TRecord record(aNode);
       
   422 	iRecords.AppendL(record);
       
   423 	}
       
   424 
       
   425 TInt CCompoundList::CalcTotalInitialiseLength() const
       
   426 /** 
       
   427  * Calculates the length of the data buffer to hold the data for all items in the 
       
   428    dynamic record.
       
   429  
       
   430  * An initial value must be assigned to the items' headers.
       
   431  *
       
   432  * @return the buffer length
       
   433  */
       
   434 	{
       
   435 	TInt n = CCompoundListHeader::CalcTotalInitialiseLength();
       
   436 	TInt nodeCount = iRecords.Count();
       
   437 	for(TInt i=0; i<nodeCount; ++i)
       
   438 		{
       
   439 		n += iRecords[i].CalcTotalInitialiseLength();
       
   440 		}
       
   441 	return n;
       
   442 	}
       
   443 
       
   444 void CCompoundList::InitialiseL( TPtr8& aBuf8 )
       
   445 /** 
       
   446  * Initialises the pointers and length for all the items in the dynamic record
       
   447  *
       
   448  * @param aBuf8  An 8 bit modifiable pointer descriptor to hold the item's data
       
   449  */
       
   450 	{
       
   451 	TInt tmp = aBuf8.Length();
       
   452 	CCompoundListHeader::InitialiseL( aBuf8 );
       
   453 	TInt n = aBuf8.Length();
       
   454 
       
   455 	TInt nodeCount = iRecords.Count();
       
   456 	for(TInt i=0; i<nodeCount; ++i)
       
   457 		{
       
   458 		iRecords[i].InitialiseL( aBuf8 );
       
   459 		}
       
   460 	CCompoundListHeader::SetBigEndian( aBuf8.Length() - n );
       
   461 	}
       
   462 
       
   463 void CCompoundList::ParseL( TPtr8& /*aDes8*/ )
       
   464 /** 
       
   465  * Checks the input and initialises the items' pointers to point to the beginning 
       
   466  * of theirs input buffers
       
   467  *
       
   468  * @param aDes8 An 8 bit modifiable pointer descriptor representing the descriptor to be checked
       
   469  */
       
   470 	{
       
   471 	ASSERT(false);
       
   472 	}
       
   473