networksecurity/tls/protocol/AlertProtocolEvents.cpp
changeset 0 af10295192d8
child 61 2fc972553898
child 63 425d8f4f7fa5
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 Alert protocol source file.
       
    15 // Describes the implementation of the Alert protocol (send and receive)
       
    16 // events classes
       
    17 // 
       
    18 //
       
    19 
       
    20 /**
       
    21  @file AlertProtocolEvents.cpp
       
    22 */
       
    23 
       
    24 #include "AlertProtocolEvents.h"
       
    25 #include "tlsrecorditem.h"
       
    26 #include "recordprotocolevents.h"
       
    27 #include "tlshandshake.h"
       
    28 #include "applicationdata.h"
       
    29 #include <sslerr.h>
       
    30 
       
    31 // @todo There must be a means of notifying the TLS Provider when a fatal 
       
    32 // alert happens (as this invalidates the session; i.e., no new connections
       
    33 // can subsequently be made with that session id). Can ClearSessionCache be 
       
    34 // used but identifying only one session (as opposed to all a client's 
       
    35 // sessions)?
       
    36 
       
    37 //TLS specific error <-> alert code mapping
       
    38 struct TTLSErrorAlertCodeMap 
       
    39 {
       
    40    TInt iTLSErrorCode;
       
    41    TInt iAlertCode;
       
    42 };
       
    43 
       
    44 const TUint KWarningAlertsCount = 2;
       
    45 
       
    46 enum ETLSAlertCode {
       
    47    EAlertclose_notify = 0, 
       
    48 
       
    49    EAlertunexpected_message = 10,
       
    50    EAlertbad_record_mac = 20,
       
    51    EAlertdecryption_failed = 21,
       
    52    EAlertrecord_overflow = 22,
       
    53    EAlertdecompression_failure = 30,
       
    54    EAlerthandshake_failure = 40,
       
    55    EAlertbad_certificate = 42,
       
    56    EAlertunsupported_certificate = 43,
       
    57    EAlertcertificate_revoked = 44,
       
    58    EAlertcertificate_expired = 45,
       
    59    EAlertcertificate_unknown = 46,
       
    60    EAlertillegal_parameter = 47,
       
    61    EAlertunknown_ca = 48,
       
    62    EAlertaccess_denied = 49,
       
    63    EAlertdecode_error = 50,
       
    64    EAlertdecrypt_error = 51,
       
    65    EAlertexport_restriction = 60,
       
    66    EAlertprotocol_version = 70,
       
    67    EAlertinsufficient_security = 71,
       
    68    EAlertinternal_error = 80,
       
    69    EAlertuser_canceled = 90,
       
    70    EAlertno_renegotiation = 100
       
    71 };
       
    72 
       
    73 const TTLSErrorAlertCodeMap glbTLSErrorAlertCodeMap[] = 
       
    74 {//the first two alerts are warnings the rest is fatal
       
    75    {KErrSSLAlertCloseNotify, 0},          //close_notify(0), 
       
    76    {KErrSSLAlertNoRenegotiation,100},     //no_renegotiation(100),
       
    77 
       
    78    {KErrSSLAlertUnexpectedMessage,10},    //unexpected_message(10),
       
    79    {KErrSSLAlertBadRecordMac,20},         //bad_record_mac(20),
       
    80    {KErrSSLAlertDecryptionFailed,21},     //decryption_failed(21),
       
    81    {KErrSSLAlertRecordOverflow,22},       //record_overflow(22),
       
    82    {KErrSSLAlertDecompressionFailure,30}, //decompression_failure(30),
       
    83    {KErrSSLAlertHandshakeFailure,40},     //handshake_failure(40),
       
    84    {KErrSSLAlertBadCertificate,42},       //bad_certificate(42),
       
    85    {KErrSSLAlertUnsupportedCertificate,43},//unsupported_certificate(43),
       
    86    {KErrSSLAlertCertificateRevoked,44},   //certificate_revoked(44),
       
    87    {KErrSSLAlertCertificateExpired,45},   //certificate_expired(45),
       
    88    {KErrSSLAlertCertificateUnknown,46},   //certificate_unknown(46),
       
    89    {KErrSSLAlertIllegalParameter,47},     //illegal_parameter(47),
       
    90    {KErrSSLAlertUnknownCA,48},            //unknown_ca(48),
       
    91    {KErrSSLAlertAccessDenied,49},         //access_denied(49),
       
    92    {KErrSSLAlertDecodeError,50},          //decode_error(50),
       
    93    {KErrSSLAlertDecryptError,51},         //decrypt_error(51),
       
    94    {KErrSSLAlertExportRestriction,60},    //export_restriction(60),
       
    95    {KErrSSLAlertProtocolVersion,70},      //protocol_version(70),
       
    96    {KErrSSLAlertInsufficientSecurity,71}, //insufficient_security(71),
       
    97    {KErrSSLAlertInternalError,80},        //internal_error(80),
       
    98    {KErrSSLAlertUserCanceled,90}         //user_canceled(90),
       
    99 };
       
   100 //the error which apparently don't map to any alert
       
   101 //		KErrSSLAlertAccessDenied:
       
   102 //		KErrSSLAlertDecodeError:	
       
   103 //		KErrSSLAlertDecryptError:	
       
   104 
       
   105 CAsynchEvent* CSendAlert::ProcessL( TRequestStatus& aStatus )
       
   106 {
       
   107 	// @todo The processing code can be put into a separate function (code reuse/reduce bloat).
       
   108 	// @todo Ensure that alerts are set up correctly (i.e., the code that should cause an 
       
   109 	// alert to be sent is set up correctly.
       
   110 
       
   111 	TInt error = iStateMachine->LastError();
       
   112 	LOG(Log::Printf(_L("CSendAlert::ProcessL(). Error value = %d"), error ));
       
   113    iAlertMsg.SetLength( 0 );
       
   114 	
       
   115 	switch ( error )
       
   116 	{
       
   117 		case KErrEof:
       
   118 			{	// CTlsConnection::Recv() completion status when there is no more data to 
       
   119 				// receive. This is not a SSL/TLS error.
       
   120 				TRequestStatus* p=&aStatus;
       
   121 				User::RequestComplete( p, KErrNone );
       
   122 				
       
   123 				return NULL; //stop the state machine
       
   124 			}
       
   125 		case KErrSSLAlertCloseNotify:
       
   126 			{
       
   127 				//Upon sending the close_notify from server report KErrEof to the application 
       
   128 				//to be intact with existing behaviour.	
       
   129 				iStateMachine->SetLastError( KErrEof );
       
   130 				iAlertMsg.Append( EAlertWarning );
       
   131 				iAlertMsg.Append( EAlertclose_notify );
       
   132 				iRecordComposer.SetNext( this );
       
   133             break;
       
   134 			}
       
   135 	    case KErrDisconnected:
       
   136 			{
       
   137 			/* Fix for the TLS Client hang issue DEF130128.
       
   138 			 * Server might have disconnected the TLS connection. 
       
   139 			 * Terminate the state machine */
       
   140 				TRequestStatus* p=&aStatus;
       
   141 				User::RequestComplete(p, KErrDisconnected);
       
   142 
       
   143 				return NULL; //stop the state machine
       
   144 			}
       
   145       case KErrArgument:
       
   146          {
       
   147             iStateMachine->SetLastError( KErrSSLAlertIllegalParameter );
       
   148 				iAlertMsg.Append( EAlertFatal );
       
   149 				iAlertMsg.Append( EAlertillegal_parameter );
       
   150 				iRecordComposer.SetNext( NULL );
       
   151             break;
       
   152          }
       
   153 		case KErrCancel:
       
   154 			{// A user_canceled alert should be followed by a close_notify alert. So this
       
   155 			 // event will be the next one to be processed. 
       
   156 				iRecordComposer.SetNext( NULL );
       
   157 				iAlertMsg.Append( EAlertWarning );
       
   158 				iAlertMsg.Append( EAlertclose_notify );
       
   159 				iRecordComposer.SetNext( NULL );
       
   160             break;
       
   161 			}
       
   162 		default:			
       
   163 			{	//find the matching alert code to send
       
   164             TUint nIndex = 0;
       
   165             while ( nIndex < sizeof( glbTLSErrorAlertCodeMap )/sizeof( glbTLSErrorAlertCodeMap[0] ) &&
       
   166                glbTLSErrorAlertCodeMap[nIndex].iTLSErrorCode != error )
       
   167                {
       
   168                nIndex++;
       
   169                }
       
   170 				// Set the message content and its record type.
       
   171             iAlertMsg.Append( nIndex >= KWarningAlertsCount ? EAlertFatal : EAlertWarning );
       
   172 				iAlertMsg.Append( nIndex < sizeof( glbTLSErrorAlertCodeMap )/sizeof( glbTLSErrorAlertCodeMap[0] ) ?
       
   173                glbTLSErrorAlertCodeMap[nIndex].iAlertCode : EAlertunexpected_message );
       
   174             if ( iAlertMsg[0] == EAlertFatal )
       
   175             {
       
   176 				   iRecordComposer.SetNext( NULL );
       
   177             }
       
   178             break;
       
   179 			}
       
   180 
       
   181 	} //switch
       
   182 
       
   183 	iRecordComposer.SetUserData( &iAlertMsg );
       
   184 	iRecordComposer.SetRecordType( ETlsAlertContentType );
       
   185 	iRecordComposer.ResetCurrentPos();
       
   186 	return iRecordComposer.ProcessL( aStatus );
       
   187 }
       
   188 
       
   189 CAsynchEvent* CRecvAlert::ProcessL( TRequestStatus& aStatus )
       
   190 {
       
   191 	// Get the Alert message contents from the Record Parser's iPtrHBuf (this descriptor is
       
   192 	// always set to point to the decrypted (when necessary) data.
       
   193 	TPtr8 alertMsg( NULL, 0 );
       
   194 	alertMsg.Set( iRecordParser.PtrHBuf() ); 
       
   195    User::LeaveIfError( alertMsg.Length() != KAlertMsgLength ? KErrSSLAlertUnexpectedMessage : KErrNone );
       
   196 	TUint8 alertLevel = alertMsg[0];
       
   197 	TUint8 alertDesc = alertMsg[1];
       
   198 	LOG(Log::Printf(_L("CRecvAlert::ProcessL(). Alert level = %d"), alertLevel ));
       
   199 	LOG(Log::Printf(_L("CRecvAlert::ProcessL(). Alert description = %d"), alertDesc ));
       
   200 
       
   201 	TRequestStatus* p=&aStatus;
       
   202 	User::RequestComplete( p, KErrNone );
       
   203 	if ( alertLevel == EAlertWarning )
       
   204 	   {// In all circumstances, when a warning alert is received, we carry on as normal.
       
   205 		// There is no need to set the next event as this will be unchanged from normal
       
   206 		// operation. For a Close_notify alert, we must send one in response.
       
   207 		// So the next event will be CSendAlert sending a close-notify alert.
       
   208       if ( alertDesc == EAlertclose_notify )
       
   209          {
       
   210          iStateMachine->SetLastError( KErrSSLAlertCloseNotify );
       
   211          return &iSendAlert;
       
   212          }
       
   213       else if ( alertDesc != EAlertno_renegotiation )
       
   214          {
       
   215          return &iRecordParser;
       
   216          }
       
   217       else if ( iRecordParser.ReadActive() )
       
   218          {//we must be in data mode already to receive this alert
       
   219       //if alertDesc == EAlertno_renegotiation for the moment it means that re-negotiation completed successfully
       
   220          return NULL;
       
   221          }
       
   222       alertDesc = EAlertillegal_parameter;
       
   223       }
       
   224 	//Complete the request immediately and close the connection.
       
   225    //and set the statemachine error code to return to the client
       
   226    TUint nIndex = 0;
       
   227    while ( nIndex < sizeof( glbTLSErrorAlertCodeMap )/sizeof( glbTLSErrorAlertCodeMap[0] ) &&
       
   228       glbTLSErrorAlertCodeMap[nIndex].iAlertCode != alertDesc )
       
   229       {
       
   230       nIndex++;
       
   231       }
       
   232    iStateMachine->SetLastError( nIndex < sizeof( glbTLSErrorAlertCodeMap )/sizeof( glbTLSErrorAlertCodeMap[0] ) ?
       
   233       glbTLSErrorAlertCodeMap[nIndex].iTLSErrorCode : KErrSSLAlertIllegalParameter );
       
   234 
       
   235 	return NULL;
       
   236 }
       
   237 
       
   238 TBool CRecvAlert::AcceptRecord( TInt aRecordType ) const
       
   239 /**
       
   240  * This method accepts an Alert event. Alerts are always accepted.
       
   241  */
       
   242 {
       
   243 	LOG(Log::Printf(_L("CRecvAlert::AcceptRecord()\n"));)  
       
   244 	return aRecordType == ETlsAlertContentType; 
       
   245 }
       
   246