examples/Networking/SecureSockets/SecEngine.cpp

00001 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
00002 // All rights reserved.
00003 // This component and the accompanying materials are made available
00004 // under the terms of "Eclipse Public License v1.0"
00005 // which accompanies this distribution, and is available
00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
00007 //
00008 // Initial Contributors:
00009 // Nokia Corporation - initial contribution.
00010 //
00011 // Contributors:
00012 //
00013 // Description:
00014 //
00015 
00016 #include "SecEngine.h"
00017 
00018 // Send buffer size
00019 const TInt KSendBufferSize = 256;
00020 // Receive buffer size
00021 const TInt KReceiveBufferSize = 256;
00022 
00023 // HTTP messages
00024 _LIT8(KSimpleGet, "GET ");
00025 _LIT8(KNewLine, "\n"); 
00026 
00027 // Progress messages
00028 _LIT(KConnnectedMessage, "\nConnecting to %S:%d%S\n");
00029 _LIT(KSecureConnnectingMessage, "\nMaking secure connection");
00030 _LIT(KGettingPageMessage, "\nRequesting web page");
00031 _LIT(KReceivingMessage,"\nReceiving server response");
00032 _LIT(KCipherSuiteInUseMessage,"\nCipher suite in use: %S");
00033 _LIT(KProtocolMessage, "\nProtocol used in connection: %S");
00034 _LIT(KReceivedMessage,"\nReceived server response");
00035 _LIT(KCompleteMessage,"\nTransaction complete: bytes recieved %d");
00036 _LIT(KFileErrorMessage,"\nError in writing data to file");
00037 _LIT(KCancelledMessage,"\nConnection closed");
00038 
00039 // State reporting messages
00040 _LIT( KStateErrESocketConnected, "\nError in state ESocketConnected: %d\n" );
00041 _LIT( KStateErrESettingCiphers, "\nError in state ESettingCiphers: %d\n" );
00042 _LIT( KStateErrSecureConnected, "\nError in state ESecureConnected: %d\n" );
00043 _LIT( KStateErrGetRequestSent, "\nError in state EGetRequestSent: %d\n" );
00044 _LIT( KStateErrEDataReceived, "\nError in state EDataReceived: %d\n" );
00045 
00046 // Panic code
00047 _LIT( KSecEnginePanic, "SEC-ENGINE");
00048 
00049 //
00050 // CSecEngine
00051 //
00052 
00053 CSecEngine* CSecEngine::NewL()
00054         {
00055         CSecEngine* self = new(ELeave) CSecEngine;
00056         CleanupStack::PushL( self );
00057         self->ConstructL();
00058         CleanupStack::Pop();            
00059         return self;
00060         }
00061 
00062 // Constructor should also call the parent constructor to set the priority
00063 // of the active object.
00064 CSecEngine::CSecEngine() 
00065 : CActive(0), iSndBuffer(0,0), iRcvBuffer(0,0)
00066         {
00067         }
00068 
00069 CSecEngine::~CSecEngine()
00070         {
00071         // Cancel any outstanding request- this cleans up
00072         // resources created during a connection
00073         //Cancel();     
00074         ConnectionClosed();
00075         // Clean up engine's permanent resources
00076         delete iSndBuffer.Ptr();    
00077         delete iRcvBuffer.Ptr();                        
00078         iTimer.Close();
00079         iSocketServ.Close();
00080         }
00081 
00082 void CSecEngine::ConstructL()
00083         {
00084         iSndBuffer.Set((TUint8*)User::AllocL(KSendBufferSize),0,KSendBufferSize);
00085         iRcvBuffer.Set((TUint8*)User::AllocL(KReceiveBufferSize),0,KReceiveBufferSize);
00086         // Connect the socket server
00087         User::LeaveIfError( iSocketServ.Connect());     
00088         // Create a local timer
00089         User::LeaveIfError( iTimer.CreateLocal());
00090         // Set initial state
00091         iRunState = ESocketConnected;
00092         iInUse = EFalse;
00093 
00094         CActiveScheduler::Add( this );
00095         }
00096 
00097 void CSecEngine::ConnectL(const TConnectSettings& aConnectSettings)
00098         {
00099         iConnectSettings = &aConnectSettings;
00100 
00101         // Set initial values for flags & buffers
00102         iSuccess = ETrue;
00103         iInUse = ETrue;
00104         iRunState = ESocketConnected;
00105         iSndBuffer.SetLength( 0 );
00106         iRcvBuffer.SetLength( 0 );
00107         iTotalBytesRead = 0;
00108 
00109         // Interpret server address
00110         if (iInetAddr.Input(iConnectSettings->iAddress) != KErrNone)
00111                 // Success if already in dotted-decimal format
00112                 {
00113                 // Connect to a host resolver (for DNS resolution) - happens sychronously
00114                 User::LeaveIfError( iHostResolver.Open( iSocketServ, KAfInet, KProtocolInetTcp ));
00115                 // Try to resolve symbolic name
00116                 TNameEntry nameEntry;
00117                 User::LeaveIfError (iHostResolver.GetByName( iConnectSettings->iAddress, nameEntry ));
00118                 TSockAddr sockAddr = nameEntry().iAddr;
00119                 iInetAddr = iInetAddr.Cast( sockAddr );
00120                 iHostResolver.Close();
00121                 }
00122         // Store other connection parameters
00123         iInetAddr.SetPort( iConnectSettings->iPortNum );
00124                                                         
00125         // Open a TCP socket
00126         User::LeaveIfError( iSocket.Open( iSocketServ, KAfInet, KSockStream, KProtocolInetTcp ) );      
00127 
00128         // Connect to the server, asynchronously
00129         iSocket.Connect( iInetAddr, iStatus );  
00130         SetActive();
00131 
00132         // Print status
00133         iConsole->Printf(KConnnectedMessage, 
00134                 &iConnectSettings->iAddress, 
00135                 iConnectSettings->iPortNum, 
00136                 &iConnectSettings->iPage );     
00137         }
00138 
00139 void CSecEngine::SetConsole( CConsoleBase& aConsole )
00140         {
00141         iConsole = &aConsole;
00142         }
00143 
00144 void CSecEngine::SetOutputFile( RFile& aOutputFile )
00145         {
00146         iOutputFile = &aOutputFile;
00147         }
00148 
00149 TBool CSecEngine::InUse()
00150         {
00151         return iInUse;
00152         }
00153 
00154 void CSecEngine::RunL()
00155         {
00156         switch ( iRunState )
00157                 {
00158         case ESocketConnected:
00159                 MakeSecureConnectionL();
00160                 break;
00161 
00162         case ESecureConnected:
00163                 MakePageRequestL();
00164                 break;
00165 
00166         case EGetRequestSent:
00167                 GetServerResponseL();
00168                 break;
00169 
00170         case EDataReceived:
00171                 ReadServerResponseL();
00172                 break;
00173 
00174         case EConnectionClosed:
00175                 ConnectionClosed();
00176                 break;
00177 
00178         default:
00179                 break;
00180                 } // end switch
00181         }
00182 
00183 TInt CSecEngine::RunError( TInt aError )
00184         {
00185         // Panic prevents looping
00186         __ASSERT_ALWAYS(iRunState != EConnectionClosed, 
00187                 User::Panic(KSecEnginePanic,0));
00188 
00189         // do a switch on the state to get the right err message
00190         switch (iRunState)
00191                 {
00192                 case ESocketConnected:
00193                         iConsole->Printf(KStateErrESocketConnected, aError );
00194                         break;
00195                 case ESettingCiphers:
00196                         iConsole->Printf(KStateErrESettingCiphers, aError );
00197                         break;
00198                 case ESecureConnected:
00199                         iConsole->Printf(KStateErrSecureConnected, aError);
00200                         break;
00201                 case EGetRequestSent:
00202                         iConsole->Printf(KStateErrGetRequestSent, aError);
00203                         break;
00204                 case EDataReceived:
00205                         iConsole->Printf(KStateErrEDataReceived, aError);
00206                         break;
00207                 default:
00208                         break;
00209                 }
00210 
00211         iRunState = EConnectionClosed;
00212         iSuccess = EFalse;
00213         iTimer.After( iStatus, 1000000 );
00214         SetActive();
00215 
00216         return KErrNone;
00217         }
00218 
00219 void CSecEngine::DoCancel()
00220         {
00221         iConsole->Printf(KCancelledMessage);
00222         ConnectionClosed();
00223         }
00224 
00225 void CSecEngine::MakeSecureConnectionL()
00226         {
00227         User::LeaveIfError(iStatus.Int()); // errors caught by RunError()
00228 
00229         // Construct the TLS socket, to use the TLS1.0 protocol.
00230         // Specifying SSL3.0 would also use the same implementation
00231         iConsole->Printf(KSecureConnnectingMessage);
00232         _LIT(KTLS1,"TLS1.0");
00233         iTlsSocket = CSecureSocket::NewL( iSocket, KTLS1 );
00234 
00235         // Set any options before the handshake starts
00236 
00237         // Clears any previous options
00238         iTlsSocket->FlushSessionCache();
00239         
00240 /*      Note: You could here set the available ciphers with code such as the following:
00241         TBuf8<2> buf;
00242         buf.SetLength(2);
00243         buf[0]=0; buf[1]=10;
00244         iTlsSocket->SetAvailableCipherSuites( buf ); */
00245         
00246         // start the handshake 
00247         iTlsSocket->StartClientHandshake( iStatus );
00248 
00249         iRunState = ESecureConnected;
00250         SetActive();
00251         }
00252 
00253 void CSecEngine::MakePageRequestL()
00254         {
00255         // The secure connection has now been made.
00256         // Send a get request for the page.
00257         User::LeaveIfError(iStatus.Int());
00258         iConsole->Printf(KGettingPageMessage);
00259         
00260         // Create a GET request
00261         iSndBuffer+=KSimpleGet;
00262         iSndBuffer+=iConnectSettings->iPage;
00263         iSndBuffer+=KNewLine;
00264 
00265         // Send the request
00266         iRunState = EGetRequestSent;
00267         iTlsSocket->Send( iSndBuffer, iStatus, iBytesSent );
00268         SetActive();
00269         }
00270 
00271 void CSecEngine::GetServerResponseL()           
00272         {
00273         // The get request has been sent, can now try and receive the data
00274         User::LeaveIfError(iStatus.Int());
00275         iConsole->Printf(KReceivingMessage);
00276         
00277         // Print the cipher suite that has been negotiated.
00278         TBuf8<2> buf; 
00279         User::LeaveIfError(iTlsSocket->CurrentCipherSuite( buf ));
00280         PrintCipherNameL(buf);
00281 
00282         // Print the protocol version string
00283         TBuf<32> protocol;
00284         User::LeaveIfError(iTlsSocket->Protocol( protocol ));
00285         iConsole->Printf(KProtocolMessage, &protocol );
00286         
00287         // Print info about the server's certificate
00288         const CX509Certificate *servCert = iTlsSocket->ServerCert();
00289         if ( servCert ) PrintCertInfo( *servCert );
00290         
00291         // Read asynchonously-returns when buffer full
00292         iRunState = EDataReceived;
00293         iTlsSocket->Recv( iRcvBuffer, iStatus );
00294         SetActive();
00295         }
00296 
00297 void CSecEngine::ReadServerResponseL()
00298         {
00299         // Any error other than KErrEof means the test is a failure
00300         if (iStatus!=KErrEof) User::LeaveIfError(iStatus.Int());
00301         iConsole->Printf(KReceivedMessage);
00302 
00303         // Put the received data in the output file & reset the receive buffer
00304         iTotalBytesRead += iRcvBuffer.Length();
00305         TInt ret = iOutputFile->Write(iRcvBuffer);
00306         if (ret != KErrNone) iConsole->Printf(KFileErrorMessage);
00307         
00308         // Case 1: error is KErrEof (message complete) or no data received, so stop
00309         if ( ( iStatus==KErrEof ) || ( iRcvBuffer.Length() == 0 ) )
00310                 {
00311                 iConsole->Printf(KCompleteMessage, iTotalBytesRead);
00312                 // Close the socket neatly
00313                 iRunState = EConnectionClosed;
00314                 iTimer.After( iStatus, 1000000 );
00315                 SetActive();
00316                 return; 
00317                 }
00318 
00319         // Case 2: there's more data to get from the server
00320         iRcvBuffer.SetLength( 0 );
00321         iRunState = EDataReceived;
00322         iTlsSocket->Recv( iRcvBuffer, iStatus );
00323         SetActive(); 
00324         }
00325 
00326 void CSecEngine::ConnectionClosed()
00327         {
00328         if (!iInUse) return;
00329         // Clean up
00330         iHostResolver.Close();
00331         delete iTlsSocket;
00332         iTlsSocket =0;
00333         iSocket.Close();
00334 
00335         // Wait here for an unload of the ssl.dll to make sure that a session is not
00336         // reconnected next time. 
00337         User::After( 1000000 );
00338         iInUse = EFalse;
00339         }
00340 
00341 void CSecEngine::PrintCipherNameL(const TDes8& aBuf)
00342         {
00343         TLex8 lex(aBuf);
00344         TUint cipherCode=aBuf[1];
00345         if ((cipherCode<1) || (cipherCode > 0x1B))
00346                 User::Leave(KErrArgument);
00347         const TText* KCipherNameArray[0x1B] = 
00348                 {
00349                 _S("TLS_RSA_WITH_NULL_MD5"),
00350                 _S("TLS_RSA_WITH_NULL_SHA"),
00351                 _S("TLS_RSA_EXPORT_WITH_RC4_40_MD5"),
00352                 _S("TLS_RSA_WITH_RC4_128_MD5"),
00353                 _S("TLS_RSA_WITH_RC4_128_SHA"),
00354                 _S("TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"),
00355                 _S("TLS_RSA_WITH_IDEA_CBC_SHA"),
00356                 _S("TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"),
00357                 _S("TLS_RSA_WITH_DES_CBC_SHA"),
00358                 _S("TLS_RSA_WITH_3DES_EDE_CBC_SHA"),
00359                 _S("TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"),
00360                 _S("TLS_DH_DSS_WITH_DES_CBC_SHA"),
00361                 _S("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"),
00362                 _S("TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"),
00363                 _S("TLS_DH_RSA_WITH_DES_CBC_SHA"),
00364                 _S("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"),
00365                 _S("TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"),
00366                 _S("TLS_DHE_DSS_WITH_DES_CBC_SHA"),
00367                 _S("TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"),
00368                 _S("TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"),
00369                 _S("TLS_DHE_RSA_WITH_DES_CBC_SHA"),
00370                 _S("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"),
00371                 _S("TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"),
00372                 _S("TLS_DH_anon_WITH_RC4_128_MD5"),
00373                 _S("TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"),
00374                 _S("TLS_DH_anon_WITH_DES_CBC_SHA"),
00375                 _S("TLS_DH_anon_WITH_3DES_EDE_CBC_SHA")
00376                 };
00377 
00378         TPtrC name(KCipherNameArray[cipherCode-1]);
00379         iConsole->Printf(KCipherSuiteInUseMessage, &name );
00380         }
00381 
00382 void CSecEngine::PrintCertInfo(const CX509Certificate& aSource)
00383         {
00384         _LIT(KCertInfoMessage1, "\nCertificate received: \n\tIssuer %S \n\tSubject %S");
00385         _LIT(KCertInfoMessage2, "\n\tValid from %S to %S");
00386         _LIT(KDateString,"%F%/0%M%/1%Y%/2%D%/3");
00387 
00388         TRAP_IGNORE(
00389                 // Print issuer and subject
00390                 HBufC* issuer = aSource.IssuerL();
00391                 HBufC* subject = aSource.SubjectL();
00392                 iConsole->Printf(KCertInfoMessage1, issuer, subject);
00393                 delete issuer;
00394                 delete subject;
00395                 
00396                 // Print validity period
00397                 TBuf<20> startTime;
00398                 TBuf<20> finishTime;
00399                 aSource.ValidityPeriod().Start().FormatL(startTime,KDateString);
00400                 aSource.ValidityPeriod().Finish().FormatL(finishTime,KDateString);
00401                 iConsole->Printf(KCertInfoMessage2, &startTime, &finishTime);
00402                 );
00403         }

Generated on Thu Jan 21 10:33:00 2010 for TB10.1 Example Applications by  doxygen 1.5.3