networksecurity/tls/protocol/handshakereceiveevents.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 // Implementation file for Received handshake events - ServerHello, 
       
    15 // Server Certificate, Server KeyExchange, ServerHelloDone and Server 
       
    16 // Finished messages. It also contains the implementation for the 
       
    17 // CHandshakeParser class (parses received handshake messages).
       
    18 // 
       
    19 //
       
    20 
       
    21 /**
       
    22  @file
       
    23 */
       
    24 
       
    25 #include "tlshandshakeitem.h"
       
    26 #include "handshakereceiveevents.h"
       
    27 #include "recordprotocolevents.h"
       
    28 #include "tlshandshake.h"
       
    29 #include "tlsconnection.h"
       
    30 #include <signed.h>
       
    31 
       
    32 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
       
    33 #include <tlstypedef_internal.h>
       
    34 #endif
       
    35 
       
    36 CHandshakeParser::~CHandshakeParser()
       
    37 /**
       
    38  * Destructor. 
       
    39  * Destroys the Received messages list, nulls and deletes its pointers
       
    40  * and descriptors.
       
    41  */
       
    42 {
       
    43 	LOG(Log::Printf(_L("CHandshakeParser::~CHandshakeParser()"));)
       
    44 
       
    45 	DestroyRxList();
       
    46 	iRecordParser.SetUserData( NULL );
       
    47 	iRecordParser.SetUserMaxLength( 0 );
       
    48 	delete iMessage;
       
    49 }
       
    50 
       
    51 void CHandshakeParser::DestroyRxList()
       
    52 {
       
    53 	LOG(Log::Printf(_L("CHandshakeParser::DestroyRxList() of expected handshake messages"));)
       
    54 
       
    55 	CHandshakeReceive* listItem;
       
    56     
       
    57     iRxListIter.SetToFirst(); 
       
    58     while ( (listItem = iRxListIter++) != NULL )
       
    59         {
       
    60         iMessageList.Remove(*listItem);
       
    61         delete listItem;
       
    62         };
       
    63 }
       
    64 
       
    65 void CHandshakeParser::AddToList( CHandshakeReceive& aRxMsgItem )
       
    66 {
       
    67 	LOG(Log::Printf(_L("CHandshakeParser::AddToList()"));)
       
    68 
       
    69     iMessageList.AddLast(aRxMsgItem);
       
    70 }
       
    71 
       
    72 CTlsEvent* CHandshakeParser::LookUpEventL( const TUint8 aHandshakeType )
       
    73 /**
       
    74  * This method is called from CHandshakeParser::ParseHeaderL(). It is used to determine
       
    75  * which handshake message (event) will process a received message.
       
    76  * 
       
    77  * @param aHandshakeType Constant TUint8 representing the Handshake message type.
       
    78  * @return CTlsEvent* A pointer to the event that will process the received message.
       
    79  */
       
    80 {
       
    81 	LOG(Log::Printf(_L("CHandshakeParser::LookUpEventL()"));)
       
    82 
       
    83    CHandshakeReceive* pEvent;
       
    84    iRxListIter.SetToFirst(); 
       
    85 
       
    86 	while ( (pEvent = iRxListIter) != 0 && !pEvent->AcceptMessage( aHandshakeType ) )
       
    87       {
       
    88 		iRxListIter++;
       
    89       }
       
    90 	if ( !pEvent )
       
    91       {
       
    92 		User::Leave( KErrSSLAlertUnexpectedMessage );
       
    93       }
       
    94   
       
    95    return pEvent;
       
    96 }
       
    97 
       
    98 TInt CHandshakeParser::ParseHeaderL()
       
    99 /**
       
   100  * This method parses a handshake message header and determines which event will
       
   101  * process a received message. It also extracts the message length (which is in
       
   102  * big endian format) from the message header.
       
   103  *
       
   104  * @return TInt An integer representing the handshake message length.
       
   105  */
       
   106 {
       
   107 	LOG(Log::Printf(_L("CHandshakeParser::ParseHeaderL()"));)
       
   108    
       
   109 	iNext = LookUpEventL( iMessageType = iMessagePtr[KTlsHandshakeTypeOffset] );
       
   110    
       
   111 	TBigEndian value; 
       
   112 	TInt nLength = value.GetValue( iMessagePtr.Ptr() + KTlsHandshakeLengthOffset, KTlsHandshakeBodyLength );
       
   113    if ( nLength > KTlsMaxHandshakeBodySize )
       
   114       {
       
   115       User::Leave( KErrSSLAlertIllegalParameter );
       
   116       }
       
   117 	LOG(RFileLogger::HexDump(KSSLLogDir,KSSLLogFileName,EFileLoggingModeAppend, NULL, NULL, iMessagePtr.Ptr(), iMessagePtr.Length() ));
       
   118    return nLength;
       
   119 }
       
   120 
       
   121 void CHandshakeParser::SetMessageAsUserDataL( TInt aWaitingFor )
       
   122 {
       
   123    if ( !iMessage )
       
   124       {
       
   125       iMessage = HBufC8::NewL( 128 );
       
   126    	iMessagePtr.Set( iMessage->Des() );
       
   127       }
       
   128 	iRecordParser.SetUserData( &iMessagePtr );
       
   129   	LOG(Log::Printf(_L("CHandshakeParser::SetMessageAsUserDataL() - aWaitingFor = %d, %d"), aWaitingFor, iMessagePtr.Length());)
       
   130 	iRecordParser.SetUserMaxLength( aWaitingFor );
       
   131    iWaitingFor = aWaitingFor;
       
   132 }
       
   133 
       
   134 TPtr8 CHandshakeParser::Message()
       
   135 /**
       
   136  * This method returns a pointer to a heap descriptor which contains (or
       
   137  * will contain) a received Handshake protocol message. We don't want to return a reference to HBuf
       
   138  * that's why thi akward TPtr construction. The caller MUST process the buffer before returning
       
   139  * to active scheduler.
       
   140  */
       
   141 {
       
   142    TPtr8 ptr( const_cast<TUint8*>(iMessagePtr.Ptr()), iMessagePtr.Length(), iMessagePtr.MaxLength() );
       
   143    iMessagePtr.SetLength( 0 );
       
   144   	LOG(Log::Printf(_L("CHandshakeParser::Message() - %d, %d"), iMessage->Length(), iMessagePtr.Length());)
       
   145 	return ptr; //we cannot return iMessagePtr since it's reset to zero
       
   146 }
       
   147 
       
   148 CAsynchEvent* CHandshakeParser::ProcessNextL( TRequestStatus& aStatus )
       
   149 {
       
   150 	// Note that a Finished message is treated differently (see CRecvFinished::ProcessL)
       
   151 	// update verify happens only whilst negotiating
       
   152 	if ( iMessageType != ETlsFinishedMsg && iStateMachine->History() != KTlsApplicationData )
       
   153 	{
       
   154 		Handshake().UpdateVerify( iMessagePtr );
       
   155 	}
       
   156 
       
   157 	SetMessageAsUserDataL( KTlsHandshakeHeaderSize );
       
   158 	return iNext->ProcessL( aStatus );
       
   159    }
       
   160 
       
   161 TBool CHandshakeParser::AcceptRecord( TInt aRecordType ) const
       
   162 /** 
       
   163  * This virtual method determines whether the first byte of a Record protocol header
       
   164  * (content type) can be accepted by an event (in iExpRecordTypes).
       
   165  *
       
   166  * @param aRecordType Integer specifying the Record protocol content type
       
   167  * @return TBool Boolean indicating whether or not the record should be accepted by  
       
   168  * this event.
       
   169  */
       
   170 {
       
   171 	LOG(Log::Printf(_L("CHandshakeParser::AcceptRecord()"));)
       
   172 	
       
   173 	return aRecordType == ETlsHandshakeContentType;
       
   174 }
       
   175 
       
   176 CAsynchEvent* CHandshakeParser::ProcessL( TRequestStatus& aStatus )
       
   177 /**
       
   178  * This asynchronous message parses a received handshake message. It first processes
       
   179  * the message header (extracts the message length) and then the message body.
       
   180  *
       
   181  * @param aStatus Request status for this event.
       
   182  * @return CAsynchEvent* A pointer to an asynchronous event which will process
       
   183  * the handshake message.
       
   184  */
       
   185 {
       
   186   
       
   187   	//********TODO: Remove this If condition when CR741 is submitted*******/
       
   188 	if(iMessage == NULL)
       
   189 		{
       
   190 		TRequestStatus* p=&aStatus;
       
   191   		User::RequestComplete( p, KErrNone );
       
   192   		return LookUpEventL(ETlsHelloRequestMsg);
       
   193 		/*			
       
   194 		Recordparser received a handshake message in application data mode which the
       
   195 		handshake parser framework isnt primed to do. hence this "null" message.
       
   196 		
       
   197 		The iMessage buffer is initialized when and during the initial or 
       
   198 		client renegotiation handshake and will not be initialized during APP data
       
   199 		transfer. Since we currently don't support renegotiations from server,
       
   200 		any handshake message about to be processed in app mode is stopped here, 
       
   201 		returning an alert.
       
   202 		*/
       
   203 		}
       
   204 	//*********************************************************************/
       
   205 	
       
   206 	__ASSERT_DEBUG( iMessage, TlsPanic(ETlsPanicNullHandshakeMsg) );
       
   207 	
       
   208 	// Do we have enough data?
       
   209 	if ( iMessagePtr.Length() == iWaitingFor )
       
   210 	{
       
   211 		if ( iMessagePtr.Length() == KTlsHandshakeHeaderSize )
       
   212 		{	// The handshake header has arrived
       
   213       	LOG(Log::Printf(_L("CHandshakeParser::ProcessL() - msg header received"));)
       
   214 			LOG(RFileLogger::HexDump(KSSLLogDir,KSSLLogFileName,EFileLoggingModeAppend, NULL, NULL, iMessagePtr.Ptr(), iMessagePtr.Length() ));
       
   215 			iWaitingFor += ParseHeaderL(); // Append message length
       
   216          
       
   217 			if ( iWaitingFor > iMessagePtr.MaxLength() )
       
   218 			{
       
   219 				iMessage = iMessage->ReAllocL( iWaitingFor );
       
   220          	iMessagePtr.Set( iMessage->Des() );
       
   221 			}
       
   222 			else if ( iWaitingFor == KTlsHandshakeHeaderSize )
       
   223 			{	// A zero length message was received => proceed at once
       
   224 				// The message length will be set to zero after the message has been processed
       
   225 				// see ParseHeaderL iNext must be != NULL => assert not necessary 
       
   226 				return ProcessNextL( aStatus );
       
   227 			}
       
   228 		}
       
   229 		else
       
   230 		{	// Must be the message body so process it. The message buffer length and 
       
   231 			// iUserMaxLength will be reset after the message has been processed.
       
   232       	LOG(Log::Printf(_L("CHandshakeParser::ProcessL() - msg body received"));)
       
   233 			iWaitingFor = KTlsHandshakeHeaderSize;	// reset  
       
   234 			__ASSERT_DEBUG( iNext, TlsPanic(ETlsPanicNoDataToProcess) ); //see ParseHeaderL
       
   235 		 
       
   236 			return ProcessNextL( aStatus );
       
   237 		}
       
   238 	}
       
   239 	
       
   240 	//read again
       
   241   	LOG(Log::Printf(_L("CHandshakeParser::ProcessL() - read again iWaitingFor = %d, %d, %d"), iWaitingFor, iMessage->Length(), iMessagePtr.Length());)
       
   242    SetMessageAsUserDataL( iWaitingFor );
       
   243 	return iRecordParser.ProcessL( aStatus );
       
   244 }
       
   245 
       
   246 //
       
   247 //
       
   248 CHandshakeReceive::~CHandshakeReceive()
       
   249 {
       
   250 	LOG(Log::Printf(_L("CHandshakeReceive::~CHandshakeReceive()"));)
       
   251 	delete iHandshakeMessage;
       
   252 	iHandshakeMessage = NULL;
       
   253 }
       
   254 
       
   255 //
       
   256 //
       
   257 CServerHello::~CServerHello()
       
   258 {
       
   259 	iCipherList.Close();
       
   260 }
       
   261 
       
   262 TBool CServerHello::AcceptMessage( const TUint8 aHandshakeType ) const
       
   263 /**
       
   264  * This method determines whether a Server Hello message (event) should be accepted.
       
   265  * It asserts that the Client Hello message has been sent. This is the only condition
       
   266  * that must be met before a Server Hello message can be received immediately afterwards.
       
   267  * @param aHandshakeType A handshake message type
       
   268  * @return TBool Boolean indicating whether a message should be accepted
       
   269  */
       
   270  {
       
   271 	LOG(Log::Printf(_L("CServerHello::AcceptMessage()"));)
       
   272 
       
   273 	__ASSERT_DEBUG( iStateMachine->History() & ETlsClientHelloSent, TlsPanic(ETlsPanicClientHelloMsgNotSent) );
       
   274 	return !iHandshakeMessage && aHandshakeType == ETlsServerHelloMsg;
       
   275 }
       
   276 
       
   277 CAsynchEvent* CServerHello::ProcessL( TRequestStatus& aStatus )
       
   278 /**
       
   279  * This method parses a received Server Hello message. It extracts the items in the 
       
   280  * message and passes the information on to Security for processing. 
       
   281  * For a Server Hello message, the only item of variable length is the Session Id
       
   282  * (hence this item is preceded by its length part).
       
   283  *
       
   284  * The next event to be processed depends on whether this is a full handshake or an
       
   285  * abbreviated handshake.
       
   286  *
       
   287  * @param aStatus Request status for this event.
       
   288  * @return CAsynchEvent* A pointer to the next asynchronous event to be processed.
       
   289  */ 
       
   290 {
       
   291 	LOG(Log::Printf(_L("CServerHello::ProcessL()"));)
       
   292    if ( iRecordParser.ReadActive() && !iCipherListRead )
       
   293    {//server's accepted renegotiation => close the old provider to reset token & attributes
       
   294    //we still keep the encryptor & decryptor for record level in CRecordParser::iActiveTlsSession
       
   295    //& CRecordComposer::iActiveTlsSession
       
   296       iTlsProvider->ReConnectL();
       
   297    //!!!need to find the session again to force token enumeration this is extremely silly!!!
       
   298    //!!!hoping to get the same session at least which should be implied
       
   299 	
       
   300 		iTlsProvider->CipherSuitesL(iCipherList, aStatus); 
       
   301       iCipherListRead = ETrue;
       
   302       return this;
       
   303    }
       
   304 	iCipherList.Close();
       
   305 	iHandshakeMessage = new(ELeave)CServerHelloMsgWithOptionalExtensions;
       
   306 	LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CServerHelloMsg ));)
       
   307 	
       
   308 	TPtr8 ptr( iRecordParser.HandshakeParser()->Message() );
       
   309 	iHandshakeMessage->iRecord.ParseL( ptr );	// Set each item's pointer to the correct part of the received message
       
   310 #ifdef _DEBUG
       
   311 	LOG(iHandshakeMessage->iRecord.Dump( KSSLLogDir,KSSLLogFileName);)
       
   312 #endif
       
   313 	
       
   314 	CServerHelloMsg* pHelloMsg = static_cast<CServerHelloMsg*>(iHandshakeMessage);
       
   315 	
       
   316 	// Extract the Server Hello data items and fill the TLSProvider's data structure
       
   317 
       
   318 	TPtr8 body = pHelloMsg->iVersion.GetBodyDes();
       
   319    CTlsCryptoAttributes& cryptoAttributes = *iTlsProvider->Attributes();
       
   320 	cryptoAttributes.iNegotiatedProtocol.iMajor = body[0];
       
   321 	cryptoAttributes.iNegotiatedProtocol.iMinor = body[1];
       
   322    
       
   323 	TDes8& desSessionId = cryptoAttributes.iSessionNameAndID.iSessionId;
       
   324 	TInt resumeSession = desSessionId.Compare( pHelloMsg->iSessionId.GetBodyDes() );
       
   325 
       
   326    Handshake().SetNegotiatedVersion( &cryptoAttributes.iNegotiatedProtocol ); 
       
   327 	
       
   328    cryptoAttributes.iMasterSecretInput.iServerRandom = pHelloMsg->iRandom.GetBodyDes();
       
   329 
       
   330 	User::LeaveIfError(pHelloMsg->iSessionId.GetBodyDes().Length() <= 32 ? KErrNone:KErrSSLAlertIllegalParameter);
       
   331 
       
   332 	desSessionId.Copy( pHelloMsg->iSessionId.GetBodyDes() );
       
   333 	LOG(RFileLogger::HexDump(KSSLLogDir,KSSLLogFileName,EFileLoggingModeAppend, NULL, NULL, desSessionId.Ptr(), desSessionId.Length() ));
       
   334 
       
   335 	body.Zero();
       
   336 	body = pHelloMsg->iCipherSuite.GetBodyDes();
       
   337    //we have to get back the cipher from our proposed list
       
   338    //current cipher suites start with 00 followed by something != 00 => the below test is sufficient
       
   339    //for the known ciphers. In case the server gives us something unknown the security will not be
       
   340    //able to find/use any token and should return an error further down the handshake.
       
   341    User::LeaveIfError( body.Length() == 2 && 
       
   342       cryptoAttributes.iProposedCiphers.Find( body ) != KErrNotFound ? KErrNone : KErrSSLAlertIllegalParameter );
       
   343 	cryptoAttributes.iCurrentCipherSuite.iLoByte = body[1];
       
   344 	cryptoAttributes.iCurrentCipherSuite.iHiByte = body[0];
       
   345 
       
   346 
       
   347 	body.Zero();
       
   348 	body = pHelloMsg->iCompression.GetBodyDes();
       
   349 	User::LeaveIfError( body[0] == NULL ? KErrNone : KErrSSLAlertUnexpectedMessage );
       
   350 	cryptoAttributes.iCompressionMethod = (TTLSCompressionMethod) body[0];
       
   351 		
       
   352 	// Update the history and decide on whether it's a full or abbreviated handshake.
       
   353 	// Abbreviated handshake is only when Client and Server Session Id match, AND the server's
       
   354 	// Session id is NOT zero (i.e. when it is a resumable session).
       
   355 	iStateMachine->UpdateHistory( ETlsServerHelloRecv );
       
   356 
       
   357 	if ( resumeSession == 0 && desSessionId.Length() ) 
       
   358       {//server hello done won't be sent => create security parameters here
       
   359    	LOG(Log::Printf(_L("Abbreviated Handshake"));)
       
   360 		iStateMachine->UpdateHistory( ETlsAbbreviatedHandshake ); // Abbreviated Handshake
       
   361    	iTlsProvider->CreateL( Handshake().TlsSession(), aStatus);
       
   362       }
       
   363 	else	   
       
   364       {
       
   365    	LOG(Log::Printf(_L("Full Handshake"));)
       
   366 		iStateMachine->UpdateHistory( ETlsFullHandshake ); // Full Handshake
       
   367 	   TRequestStatus* p=&aStatus;
       
   368 	   User::RequestComplete( p, KErrNone );
       
   369       }
       
   370 
       
   371       const TTLSCipherSuiteMapping *pCipherDetails = cryptoAttributes.iCurrentCipherSuite.CipherDetails();
       
   372       if(pCipherDetails)
       
   373       {
       
   374 	 	if(pCipherDetails->iKeyExAlg == EPsk)
       
   375 	 	{
       
   376 	    	// Using PSK for key exchange which impacts list of legal messages and ordering checks
       
   377 	    	iStateMachine->UpdateHistory( ETlsUsingPskKeyExchange );
       
   378 	 	}
       
   379 	 	// Set key exchange type in the CTLSPublicKeyParams structure which will be passed to the TLS token.
       
   380 	 	iTlsProvider->Attributes()->iPublicKeyParams->iKeyType = pCipherDetails->iKeyExAlg;
       
   381       }
       
   382 	
       
   383       // Call InitiateReceiveL() to set up the list of expected messages
       
   384       return Handshake().InitiateReceiveL();
       
   385 
       
   386 }
       
   387 
       
   388 //
       
   389 //
       
   390 TBool CCertificateReq::AcceptMessage( const TUint8 aHandshakeType ) const
       
   391 /**
       
   392  * This method determines whether a Certificate Request message (event) should 
       
   393  * be accepted. A server certificate must have been received before a certificate 
       
   394  * request can be made.
       
   395  *
       
   396  * @param aHandshakeType A handshake message type
       
   397  * @return TBool Boolean indicating whether a message should be accepted
       
   398  */
       
   399 {
       
   400 	LOG(Log::Printf(_L("CCertificateReq::AcceptMessage()"));)
       
   401 	return !iHandshakeMessage && iStateMachine->History() & ETlsServerCertificateRecv && aHandshakeType == ETlsCertificateReqMsg; 
       
   402 }
       
   403 
       
   404 CAsynchEvent* CCertificateReq::ProcessL( TRequestStatus& aStatus )
       
   405 /**
       
   406  * This asynchronous method processes a received Certificate Request message.
       
   407  *
       
   408  * @param aStatus Request status for this event.
       
   409  * @return CAsynchEvent* A pointer to the next asynchronous event to be processed.
       
   410  */
       
   411 {
       
   412 	LOG(Log::Printf(_L("CCertificateReq::ProcessL()"));)
       
   413 
       
   414 	__ASSERT_DEBUG( !iHandshakeMessage, TlsPanic( ETlsPanicHandshakeMsgAlreadyExists) );
       
   415 	iHandshakeMessage = new(ELeave) CCertificateReqMsg;
       
   416 	LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CCertificateReqMsg ));)
       
   417    TPtr8 ptr( iRecordParser.HandshakeParser()->Message() );
       
   418 	LOG(Log::Printf(_L("ptr.Length() %d"), ptr.Length() );)
       
   419     
       
   420 	iHandshakeMessage->iRecord.ParseL( ptr );
       
   421 #ifdef _DEBUG
       
   422 	LOG(iHandshakeMessage->iRecord.Dump( KSSLLogDir,KSSLLogFileName);)
       
   423 #endif
       
   424     
       
   425    // Update the Handshake history and set the Certificate Types
       
   426    iStateMachine->UpdateHistory( ETlsCertificateReqRecv );
       
   427    CCertificateReqMsg* pCertReqMsg = (CCertificateReqMsg*)iHandshakeMessage;
       
   428 	 
       
   429 	TPtr8 body = pCertReqMsg->iClientCertificateTypes.GetBodyDes();
       
   430    CTlsCryptoAttributes& cryptoAttributes = *iTlsProvider->Attributes();
       
   431 	
       
   432 	for (TInt loop = 0; loop < body.Length(); ++loop)
       
   433 	{
       
   434 		User::LeaveIfError( cryptoAttributes.iReqCertTypes.Append( (TTLSClientCertType) body[loop] ) );		
       
   435 	}
       
   436 
       
   437 	// Set the list of CA Distinguished Names
       
   438 	CListNode* listNode = pCertReqMsg->iDistinguishedNames.First();
       
   439 
       
   440 	__ASSERT_DEBUG( cryptoAttributes.iDistinguishedCANames.Count() == 0, TlsPanic(ETlsPanicNoCA ));
       
   441    while ( listNode )
       
   442 	{
       
   443 		TPtr8 listPtr = listNode->GetBodyDes();
       
   444    	LOG(Log::Printf(_L("DistinguishedCAName") );)
       
   445 		LOG(RFileLogger::HexDump(KSSLLogDir,KSSLLogFileName,EFileLoggingModeAppend, NULL, NULL, listPtr.Ptr(), listPtr.Length() ));
       
   446 		
       
   447 		// Append the item into the Distinguished Names array and get the next list item
       
   448       HBufC8* buf = listPtr.AllocL();
       
   449    	CleanupStack::PushL(buf);
       
   450 		User::LeaveIfError(cryptoAttributes.iDistinguishedCANames.Append(buf) );
       
   451    	CleanupStack::Pop();
       
   452 		listNode = listNode->Next();
       
   453 	}
       
   454    iTlsProvider->Attributes()->iClientAuthenticate = ETrue;
       
   455 
       
   456 	TRequestStatus* p=&aStatus;
       
   457 	User::RequestComplete( p, KErrNone );
       
   458     return &iRecordParser;
       
   459 }
       
   460 
       
   461 //
       
   462 //
       
   463 TBool CServerCertificate::AcceptMessage( const TUint8 aHandshakeType ) const
       
   464 /**
       
   465  * This method determines whether a Server Certificate message (event) should 
       
   466  * be accepted.
       
   467  *
       
   468  * @param aHandshakeType A handshake message type
       
   469  * @return TBool Boolean indicating whether a message should be accepted
       
   470  */
       
   471 {
       
   472 	LOG(Log::Printf(_L("CServerCertificate::AcceptMessage()"));)
       
   473 
       
   474 	// Assert that a Server Hello message has been received
       
   475 	__ASSERT_DEBUG( iStateMachine->History() & ETlsServerHelloRecv, TlsPanic(ETlsPanicServerHelloMsgNotReceived));
       
   476 	return !iHandshakeMessage && aHandshakeType == ETlsServerCertificateMsg;
       
   477 }
       
   478 
       
   479 CAsynchEvent* CServerCertificate::ProcessL( TRequestStatus& aStatus )
       
   480 /**
       
   481  * This asynchronous method processes a Server Certificate message. The contents of the
       
   482  * message are passed as an uninterpreted buffer to the Security subsystem.
       
   483  *
       
   484  * @param aStatus Request status for this event.
       
   485  * @return CAsynchEvent* A pointer to the next asynchronous event to be processed.
       
   486  */
       
   487 {
       
   488 	CX509Certificate*& serverCert = Handshake().ServerCert(); 
       
   489    if ( serverCert )
       
   490       {//store signing alg
       
   491       //cannot convert from 'enum TAlgorithmId' to 'enum TTLSSignatureAlgorithm =>
       
   492       //=> CTlsProvider MUST use the same enum as security -> the same applies to keyExchange alg
       
   493 	   const CSubjectPublicKeyInfo& publicKeyInfo = serverCert->PublicKey();
       
   494 
       
   495 	   TAlgorithmId& signAlgorithm = Handshake().SignatureAlg();
       
   496 	   signAlgorithm = publicKeyInfo.AlgorithmId();
       
   497       if ( signAlgorithm == ERSA )
       
   498          {
       
   499 	      iTlsProvider->Attributes()->isignatureAlgorithm = ERsaSigAlg;
       
   500          }
       
   501       else if ( signAlgorithm == EDSA )
       
   502          {
       
   503 	      iTlsProvider->Attributes()->isignatureAlgorithm = EDsa;
       
   504          }
       
   505       else
       
   506          {
       
   507 	      LOG(Log::Printf(_L("Unknown signing algorithm and ridiculous enum redefinitions."));)
       
   508          User::Leave( KErrSSLAlertIllegalParameter );
       
   509          }
       
   510 	   TRequestStatus* p=&aStatus;
       
   511 	   User::RequestComplete( p, KErrNone );
       
   512       return &iRecordParser;
       
   513       }
       
   514 	LOG(Log::Printf(_L("CServerCertificate::ProcessL()"));)
       
   515 
       
   516 	// Update the Handshake history and pass the server certificate chain to TLS Provider
       
   517     iStateMachine->UpdateHistory( ETlsServerCertificateRecv );
       
   518     
       
   519 	TPtr8 ptr( iRecordParser.HandshakeParser()->Message() );
       
   520 	TPtr8 ptrEncoded( ptr );
       
   521 
       
   522 #ifdef _DEBUG
       
   523    if (iHandshakeMessage) 
       
   524       {
       
   525       LOG(Log::Printf(_L("ERROR: iHandshakeMessage %x - %x, should be NULL"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CCertificateMsg ));)
       
   526       }
       
   527 	__ASSERT_DEBUG( !iHandshakeMessage, TlsPanic(ETlsPanicHandshakeMsgAlreadyExists));
       
   528 #endif
       
   529 
       
   530 	iHandshakeMessage = new(ELeave) CCertificateMsg;
       
   531 	LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CCertificateMsg ));)
       
   532 	iHandshakeMessage->iRecord.ParseL( ptr );	// Set each item's pointer to the correct part of the received message
       
   533 #ifdef _DEBUG
       
   534 	LOG(iHandshakeMessage->iRecord.Dump( KSSLLogDir,KSSLLogFileName);)
       
   535 #endif
       
   536    //prepare certificate chain for security (this should've really been TLS provider's work 
       
   537    CListNode* pNode = ((CCertificateMsg*)iHandshakeMessage)->iCertificateList.First();
       
   538    User::LeaveIfError( pNode ? KErrNone : KErrSSLAlertBadCertificate );
       
   539    //iPtr1 + iPtr2 setup to delete handshake header+cert list length
       
   540    TUint8* iPtr1 = iHandshakeMessage->Ptr();
       
   541    TUint8* iPtr2 = pNode->Ptr();
       
   542    TInt nDel = 0;
       
   543    TInt nToDel = iPtr2 - iPtr1;
       
   544    TInt nPos = iPtr1 - iHandshakeMessage->Ptr();
       
   545    ptrEncoded.Delete( nPos, nToDel );
       
   546    do
       
   547       {
       
   548       nDel += nToDel;
       
   549       iPtr1 = pNode->Ptr() - nDel;
       
   550       iPtr2 = pNode->GetBodyPtr() - nDel;
       
   551       nToDel = iPtr2 - iPtr1;
       
   552       nPos = iPtr1 - iHandshakeMessage->Ptr();
       
   553       ptrEncoded.Delete( nPos, nToDel );
       
   554       pNode = pNode->Next();
       
   555       }
       
   556    while ( pNode );
       
   557 	LOG(RFileLogger::HexDump(KSSLLogDir,KSSLLogFileName,EFileLoggingModeAppend, NULL, NULL, ptrEncoded.Ptr(), ptrEncoded.Length() ));
       
   558 	iTlsProvider->VerifyServerCertificate( ptrEncoded, serverCert, aStatus);
       
   559    
       
   560     
       
   561    return this;
       
   562 }
       
   563 
       
   564 //
       
   565 //
       
   566 TBool CServerKeyExch::AcceptMessage( const TUint8 aHandshakeType ) const
       
   567 /**
       
   568  * This method determines whether a Server Key exchange message should be accepted.
       
   569  * As server authentication is mandatory for the current implementation, either a Server 
       
   570  * certificate must have been received, or we must be using PSK to key exchange and authenticate.
       
   571  *
       
   572  * @param aHandshakeType A handshake message type
       
   573  * @return TBool Boolean indicating whether a message should be accepted
       
   574  */
       
   575 {
       
   576 	LOG(Log::Printf(_L("CServerKeyExch::AcceptMessage()"));)
       
   577 
       
   578 	return !iHandshakeMessage && 
       
   579 			((iStateMachine->History() & ETlsServerCertificateRecv) || (iStateMachine->History() & ETlsUsingPskKeyExchange)) && 
       
   580 			aHandshakeType == ETlsServerKeyExchMsg; 
       
   581 }
       
   582 
       
   583 void CServerKeyExch::CreateMessageL( TTLSKeyExchangeAlgorithm aKeyExchange, TAlgorithmId aSignAlgorithm )
       
   584    {
       
   585 	if ( aKeyExchange == ERsa )		// Provider's enum for RSA differs from Security, hence the 2 enums values
       
   586    	{
       
   587       if ( aSignAlgorithm == ERSA )
       
   588          {
       
   589          iHandshakeMessage = new(ELeave) CRsaRsaServerKeyExchMsg;
       
   590 LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CRsaRsaServerKeyExchMsg ));)
       
   591          }
       
   592    	else if ( aSignAlgorithm == EDSA)
       
   593          {
       
   594          iHandshakeMessage = new(ELeave) CRsaDsaServerKeyExchMsg;
       
   595 LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CRsaDsaServerKeyExchMsg ));)
       
   596          }
       
   597       }
       
   598    else if ( aKeyExchange == EDHE )
       
   599       {
       
   600       if ( aSignAlgorithm == ERSA )
       
   601          {
       
   602          iHandshakeMessage = new(ELeave) CDhRsaServerKeyExchMsg;
       
   603 LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CDhRsaServerKeyExchMsg ));)
       
   604          }
       
   605    	else if ( aSignAlgorithm == EDSA)
       
   606          {
       
   607          iHandshakeMessage = new(ELeave) CDhDsaServerKeyExchMsg;
       
   608 LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CDhDsaServerKeyExchMsg ));)
       
   609          }
       
   610       }
       
   611    else if ( aKeyExchange == EPsk )
       
   612    		 {
       
   613           iHandshakeMessage = new(ELeave) CPskServerKeyExchMsg;
       
   614 LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CPskServerKeyExchMsg ));)
       
   615    		 }
       
   616    
       
   617    if ( !iHandshakeMessage )
       
   618       {
       
   619 		LOG(Log::Printf(_L("CServerKeyExch::ProcessL() - Unknown signing algorithm"));)
       
   620 		User::Leave(KErrSSLAlertIllegalParameter);
       
   621 	   }
       
   622    }
       
   623 
       
   624 CAsynchEvent* CServerKeyExch::ProcessL( TRequestStatus& aStatus )
       
   625 /**
       
   626  * This message processes a Server Key exchange message. 
       
   627  * The protocol needs the Key exchange algorithm from the cipher suite and the signing
       
   628  * algorithm, if relevant, from the certificate, in order to interpret and process this 
       
   629  * message correctly.
       
   630  *
       
   631  * @param aStatus Request status for this event.
       
   632  * @return CAsynchEvent* A pointer to the next asynchronous event to be processed.
       
   633  */
       
   634 {
       
   635 	LOG(Log::Printf(_L("CServerKeyExch::ProcessL()"));)
       
   636 
       
   637 	// Get the Key exchange Algorithm and set this value in the Provider.
       
   638 	const TTLSCipherSuite cipherSuite = iTlsProvider->Attributes()->iCurrentCipherSuite;
       
   639 
       
   640 	TTLSKeyExchangeAlgorithm keyExchange = iTlsProvider->Attributes()->iPublicKeyParams->iKeyType;
       
   641 
       
   642 	TAlgorithmId& signAlgorithm = Handshake().SignatureAlg();
       
   643 
       
   644 	// Create and parse the Server Key exchange message. Set all necessary information.
       
   645    CreateMessageL( keyExchange, signAlgorithm );
       
   646 	TPtr8 ptr( iRecordParser.HandshakeParser()->Message() );
       
   647 	iHandshakeMessage->iRecord.ParseL( ptr );
       
   648 #ifdef _DEBUG
       
   649 	LOG(iHandshakeMessage->iRecord.Dump( KSSLLogDir,KSSLLogFileName);)
       
   650 #endif
       
   651 	CServerKeyExchMsg* pKeyExcMsg = (CServerKeyExchMsg*)iHandshakeMessage;
       
   652 
       
   653 	pKeyExcMsg->CopyParamsL( iTlsProvider->Attributes() );
       
   654 
       
   655 	if(!(iStateMachine->History() & ETlsUsingPskKeyExchange))
       
   656 		{
       
   657 		// Under pre-shared keys, the ServerKeyExch message does not have certificates (see RFC 4279). In
       
   658 		// this case, we do not process the certs.
       
   659 		TBuf8<KTlsMd5Length + KTlsShaLength> msgDigest;
       
   660    		pKeyExcMsg->ComputeDigestL( iTlsProvider->Attributes()->iMasterSecretInput.iClientRandom,
       
   661         		                    iTlsProvider->Attributes()->iMasterSecretInput.iServerRandom,
       
   662                                		msgDigest );
       
   663    		TPtr8 signature( pKeyExcMsg->Signature() );
       
   664 		CX509Certificate* serverCert = Handshake().ServerCert(); 
       
   665 		__ASSERT_DEBUG( serverCert, TlsPanic(ETlsPanicNullServerCertificate) );
       
   666 		const CSubjectPublicKeyInfo& publicKeyInfo = serverCert->PublicKey();
       
   667 
       
   668    		User::LeaveIfError( iTlsProvider->VerifySignatureL(publicKeyInfo, msgDigest, signature) ?
       
   669         					KErrNone : KErrSSLAlertBadCertificate );
       
   670 		}
       
   671 	
       
   672 	// Update the Handshake history. Clear message buffer at the end and return the next
       
   673 	// item to be processed.
       
   674    iStateMachine->UpdateHistory( ETlsServerKeyExchRecv );
       
   675    
       
   676 	TRequestStatus* p=&aStatus;
       
   677 	User::RequestComplete( p, KErrNone );
       
   678    return &iRecordParser;
       
   679 }
       
   680 
       
   681 TBool CServerHelloDone::AcceptMessage( const TUint8 aHandshakeType ) const
       
   682 /** 
       
   683  * This method decides whether a 'ServerHelloDone' message can be accepted.
       
   684  * This message can only be received after a Server hello message. However,
       
   685  * as this protocol implementation requires that a Server be authenticated,
       
   686  * this message can only be accepted after a Server's certificate has been received, or we must
       
   687  * be using PSK to key exchange and authenticate.
       
   688  * 
       
   689  * @param aHandshakeType A handshake message type
       
   690  * @return TBool Boolean indicating whether a message should be accepted
       
   691  */
       
   692 {
       
   693 	LOG(Log::Printf(_L("CServerHelloDone::AcceptMessage()"));)
       
   694 
       
   695 	return !iHandshakeMessage &&
       
   696 			((iStateMachine->History() & ETlsServerCertificateRecv) || (iStateMachine->History() & ETlsUsingPskKeyExchange)) && 
       
   697 			aHandshakeType == ETlsServerHelloDoneMsg; 
       
   698 }
       
   699 
       
   700 CAsynchEvent* CServerHelloDone::ProcessL( TRequestStatus& aStatus )
       
   701 /**
       
   702  * This method processes a Server Hello Done message.
       
   703  * Once this message has been received, the Server's params (from the negotiation)
       
   704  * can begin to be processed.
       
   705  *
       
   706  * @param aStatus Request status for this event.
       
   707  * @return CAsynchEvent* A pointer to the next asynchronous event to be processed.
       
   708  */
       
   709 {
       
   710 	LOG(Log::Printf(_L("CServerHelloDone::ProcessL()"));)
       
   711 	
       
   712 	iHandshakeMessage = new(ELeave)CServerHelloDoneMsg;
       
   713    LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CServerHelloDoneMsg ));)
       
   714 	TPtr8 ptr( iRecordParser.HandshakeParser()->Message() );
       
   715 	iHandshakeMessage->iRecord.ParseL( ptr );	// Set each item's pointer to the correct part of the received message
       
   716 #ifdef _DEBUG
       
   717 	LOG(iHandshakeMessage->iRecord.Dump( KSSLLogDir,KSSLLogFileName);)
       
   718 #endif
       
   719 	
       
   720 	// Update the Handshake history
       
   721 	// A ServerHelloDone message always has an empty body
       
   722 	User::LeaveIfError( ptr.Length() ? KErrSSLAlertUnexpectedMessage : KErrNone );
       
   723 	iStateMachine->UpdateHistory( ETlsServerHelloDoneRecv );
       
   724    
       
   725     // Call InitiateTransmitL() to start protocol transmissions. 
       
   726 	// Set the next event to be processed as the Record composer object
       
   727 	iTlsProvider->CreateL( Handshake().TlsSession(), aStatus);
       
   728 	return Handshake().InitiateTransmitL();
       
   729 }
       
   730 
       
   731 //
       
   732 //
       
   733 TBool CRecvFinished::AcceptMessage( const TUint8 aHandshakeType ) const
       
   734 /** 
       
   735  * This method decides whether a received 'Finished' message can be accepted.
       
   736  * A 'Finished' message can only be accepted after a 'ChangeCipherSpec' message 
       
   737  * has been received.
       
   738  * 
       
   739  * @param aHandshakeType A handshake message type
       
   740  * @return TBool Boolean indicating whether a message should be accepted
       
   741  */
       
   742 {
       
   743 	LOG(Log::Printf(_L("CRecvFinished::AcceptMessage()"));)
       
   744 	__ASSERT_DEBUG( iStateMachine->History() & ETlsChangeCipherRecv, TlsPanic(ETlsPanicChangeCipherMsgNotReceived) );
       
   745 	return !iHandshakeMessage && aHandshakeType == ETlsFinishedMsg; 
       
   746 }
       
   747 
       
   748 CAsynchEvent* CRecvFinished::ProcessL( TRequestStatus& aStatus )
       
   749 /**
       
   750  * This asynchronous method processes a received Server Finished message.
       
   751  * Note that the Finished message takes an integer which is the size of the message 
       
   752  * body only (i.e. minus the Handshake header).
       
   753  */
       
   754 {
       
   755 	LOG(Log::Printf(_L("CRecvFinished::ProcessL()"));)
       
   756 
       
   757 	TPtr8 ptr( iRecordParser.HandshakeParser()->Message() );
       
   758    TInt nLen = ptr.Length();
       
   759 	iHandshakeMessage = new(ELeave)CFinishedMsg( nLen - KTlsHandshakeHeaderSize);
       
   760    LOG(Log::Printf(_L("iHandshakeMessage %x - %x"), iHandshakeMessage, (TUint)iHandshakeMessage + sizeof( CFinishedMsg ));)
       
   761 	
       
   762 	iHandshakeMessage->iRecord.ParseL( ptr );	// Set each item's pointer to the correct part of the received message
       
   763 #ifdef _DEBUG
       
   764 	LOG(iHandshakeMessage->iRecord.Dump( KSSLLogDir,KSSLLogFileName);)
       
   765 #endif
       
   766 	CFinishedMsg* pFinishedMsg = (CFinishedMsg*)iHandshakeMessage;
       
   767 	TPtr8 body = pFinishedMsg->iFinishedData.GetBodyDes();
       
   768 
       
   769 	// Pass the information to the Provider
       
   770 	iShaPtr = static_cast<CSHA1*>( Handshake().SHA1Verify()->CopyL() ); 
       
   771 	iMd5Ptr = static_cast<CMD5*>( Handshake().MD5Verify()->CopyL() );
       
   772 	iTlsProvider->TlsSessionPtr()->VerifyServerFinishedMsgL( iMd5Ptr, iShaPtr, body, aStatus);
       
   773 		
       
   774 	ptr.Set( iRecordParser.HandshakeParser()->Message() );
       
   775    ptr.SetLength( nLen );
       
   776 	Handshake().UpdateVerify( ptr );
       
   777 	iStateMachine->UpdateHistory( ETlsFinishedRecv );
       
   778 
       
   779 	return Handshake().InitiateTransmitL();	
       
   780 }
       
   781 
       
   782 
       
   783 CRecvFinished::~CRecvFinished()
       
   784 /**
       
   785  * Destructor.
       
   786  */
       
   787 {
       
   788 	LOG(Log::Printf(_L("CRecvFinished::~CRecvFinished()"));)
       
   789 	delete iShaPtr;
       
   790 	delete iMd5Ptr;
       
   791 }
       
   792 
       
   793 CGenericExtensionList::CGenericExtensionList( CItemBase* aNext )
       
   794 	: CCompoundList(aNext, KTlsExtensionLength)
       
   795 {
       
   796 }
       
   797 
       
   798 void CGenericExtensionList::ParseL( TPtr8& aDes8 )
       
   799 {
       
   800 	if(aDes8.Length() == 0)
       
   801 		{
       
   802 		return; // No Extension list at all
       
   803 		}
       
   804 	CCompoundListHeader::ParseL( aDes8 );
       
   805 	TInt nLenExpected = CCompoundListHeader::GetBigEndian();
       
   806 
       
   807 	if(nLenExpected > aDes8.Length())
       
   808 		{
       
   809 		User::Leave( KErrBadDescriptor );
       
   810 		}
       
   811 	
       
   812 	while ( nLenExpected > 0 )
       
   813 		{
       
   814 		CGenericExtension *ext = CGenericExtension::NewLC( 0 );
       
   815 		TRecord record(ext);
       
   816 
       
   817 		record.ParseL( aDes8 );
       
   818 
       
   819 		AddNodeL(ext);
       
   820 		CleanupStack::Pop(ext);
       
   821 
       
   822 		nLenExpected -= ext->ExtensionLength();
       
   823 		}
       
   824 	if(nLenExpected < 0)
       
   825 		{
       
   826 		User::Leave( KErrBadDescriptor );
       
   827 		}
       
   828 }
       
   829 
       
   830 CGenericExtension* CGenericExtensionList::Node(TInt aIndex) const
       
   831 {
       
   832 	return static_cast<CGenericExtension*>(CCompoundList::Node(aIndex));
       
   833 }
       
   834 
       
   835 // End of file