diff -r 89d6a7a84779 -r 25a17d01db0c Symbian3/Examples/guid-6013a680-57f9-415b-8851-c4fa63356636/_sec_engine_8cpp-source.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/Examples/guid-6013a680-57f9-415b-8851-c4fa63356636/_sec_engine_8cpp-source.html Fri Jan 22 18:26:19 2010 +0000 @@ -0,0 +1,415 @@ + +
+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 } +