Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4069 lines
111 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. ssocket.cxx
  5. Abstract:
  6. Contains secure sockets functions and ICSecureSocket methods
  7. Contents:
  8. SecurityPkgInitialize
  9. ReadCertificateIntoCertInfoStruct
  10. ChkCertificateCommonNameIsValid
  11. ChkCertificateExpired
  12. ICSecureSocket::ICSecureSocket
  13. ICSecureSocket::~ICSecureSocket
  14. ICSecureSocket::Connect
  15. CFsm_SecureConnect::RunSM
  16. ICSecureSocket::Connect_Fsm
  17. ICSecureSocket::SecureHandshakeWithServer
  18. CFsm_SecureHandshake::RunSM
  19. ICSecureSocket::SecureHandshake_Fsm
  20. ICSecureSocket::NegotiateSecConnection
  21. CFsm_SecureNegotiate::RunSM
  22. ICSecureSocket::SecureNegotiate_Fsm
  23. ICSecureSocket::SSPINegotiateLoop
  24. CFsm_NegotiateLoop::RunSM
  25. ICSecureSocket::NegotiateLoop_Fsm
  26. ICSecureSocket::Disconnect
  27. ICSecureSocket::Send
  28. CFsm_SecureSend::RunSM
  29. ICSecureSocket::Send_Fsm
  30. ICSecureSocket::Receive
  31. CFsm_SecureReceive::RunSM
  32. ICSecureSocket::Receive_Fsm
  33. ICSecureSocket::SetHostName
  34. (ICSecureSocket::EncryptData)
  35. (ICSecureSocket::DecryptData)
  36. (ICSecureSocket::TerminateSecConnection)
  37. ICSecureSocket::GetCertInfo
  38. Author:
  39. Richard L Firth (rfirth) 08-Apr-1997
  40. Environment:
  41. Win32 user mode
  42. Revision History:
  43. 08-Apr-1997 rfirth
  44. Created from ixport.cxx
  45. --*/
  46. #include <wininetp.h>
  47. #include <perfdiag.hxx>
  48. #include <ierrui.hxx>
  49. extern "C" {
  50. #include <nt.h>
  51. #include <ntrtl.h>
  52. #include <nturtl.h>
  53. #include <ntsecapi.h>
  54. #include <windows.h>
  55. #include <stdio.h>
  56. #include <stdlib.h>
  57. #include <softpub.h>
  58. }
  59. //
  60. //
  61. // List of encryption packages: PCT, SSL, etc
  62. //
  63. //
  64. // BUGBUG [arthurbi] The SSL and PCT package names
  65. // are hard coded into the stucture below. We need
  66. // to be more flexible in case someone write a FOO security
  67. // package.
  68. //
  69. // BUGBUG: Don't change the order of the packages below. some old SSL2 sites deny the UNISP
  70. // provider, and if we walk down the list to PCT1 or SSL3, things hang.
  71. struct _SEC_PROVIDER SecProviders[] =
  72. {
  73. UNISP_NAME, INVALID_CRED_VALUE , ENC_CAPS_PCT | ENC_CAPS_SSL | ENC_CAPS_SCHANNEL_CREDS, FALSE, SP_PROT_CLIENTS, NULL,
  74. UNISP_NAME, INVALID_CRED_VALUE , ENC_CAPS_SSL | ENC_CAPS_SCHANNEL_CREDS, FALSE, SP_PROT_SSL2_CLIENT, NULL,
  75. // PCT1SP_NAME, INVALID_CRED_VALUE , ENC_CAPS_PCT| ENC_CAPS_SCHANNEL_CREDS, FALSE, SP_PROT_PCT1_CLIENT, NULL,
  76. // SSL3SP_NAME, INVALID_CRED_VALUE , ENC_CAPS_SSL| ENC_CAPS_SCHANNEL_CREDS, FALSE, SP_PROT_SSL3_CLIENT, NULL,
  77. NULL, INVALID_CRED_VALUE , FALSE, FALSE, 0
  78. };
  79. //
  80. // dwEncFlags - Global Status of calling and initalizing the SCHANNEL and various
  81. // other encyrption support DLL & APIs. Failure in the process will
  82. // cause this to be set to an error state, success prevents re-initalizaiton
  83. //
  84. DWORD dwEncFlags = 0;
  85. //
  86. // GlobalSecureProtocolsCopy - Copy of the current protocols the user wants to use
  87. // changing them allows us to restrict to specific protocols
  88. //
  89. DWORD GlobalSecureProtocolsCopy = DEFAULT_SECURE_PROTOCOLS;
  90. #ifdef SECPKG_ATTR_PROTO_INFO
  91. PRIVATE
  92. LPTSTR
  93. ProtoInfoToString(
  94. IN const PSecPkgContext_ProtoInfo pProtoInfo);
  95. #endif
  96. //
  97. // general security package functions
  98. //
  99. BOOL
  100. SecurityPkgInitialize(
  101. BOOL fForce
  102. )
  103. /*++
  104. Routine Description:
  105. This function finds a list of security packages that are supported
  106. on the client's machine, check if pct or ssl is supported, and
  107. create a credential handle for each supported pkg.
  108. Arguments:
  109. None
  110. Return Value:
  111. TRUE if at least one security pkg is found; otherwise FALSE
  112. --*/
  113. {
  114. TimeStamp tsExpiry;
  115. SECURITY_STATUS scRet;
  116. PSecPkgInfo pPackageInfo = NULL;
  117. ULONG cPackages;
  118. ULONG fCapabilities;
  119. ULONG i;
  120. ULONG j;
  121. DWORD cProviders = 0;
  122. SCHANNEL_CRED DefaultCredData = {SCHANNEL_CRED_VERSION,
  123. 0,
  124. NULL,
  125. 0,
  126. 0,
  127. NULL,
  128. 0,
  129. NULL,
  130. SP_PROT_CLIENTS,
  131. 0,
  132. 0,
  133. 0,
  134. SCH_CRED_MANUAL_CRED_VALIDATION |
  135. SCH_CRED_NO_DEFAULT_CREDS
  136. };
  137. //
  138. // Set new DWORD for our copy of the global protocol settings.
  139. //
  140. bool fSame = (GlobalSecureProtocolsCopy==GlobalSecureProtocols);
  141. GlobalSecureProtocolsCopy = GlobalSecureProtocols;
  142. //
  143. // check if this routine has been called. if yes, return TRUE
  144. // if we've found a supported pkg; otherwise FALSE
  145. //
  146. if ( dwEncFlags == ENC_CAPS_NOT_INSTALLED )
  147. return FALSE;
  148. else if ((dwEncFlags&ENC_CAPS_TYPE_MASK) && fSame && !fForce)
  149. return TRUE;
  150. //
  151. // Initialize dwEncFlags
  152. //
  153. dwEncFlags = ENC_CAPS_NOT_INSTALLED;
  154. //
  155. // Check if at least one security package is supported
  156. //
  157. scRet = g_EnumerateSecurityPackages( &cPackages,
  158. &pPackageInfo );
  159. if ( scRet != STATUS_SUCCESS )
  160. {
  161. DEBUG_PRINT(API,
  162. ERROR,
  163. ("EnumerateSecurityPackages failed, error %lx\n",
  164. scRet
  165. ));
  166. SetLastError( scRet );
  167. return FALSE;
  168. }
  169. for ( i = 0; i < cPackages ; i++ )
  170. {
  171. //
  172. // Use only if the package name is the PCT/SSL package
  173. //
  174. fCapabilities = pPackageInfo[i].fCapabilities;
  175. if ( fCapabilities & SECPKG_FLAG_STREAM )
  176. {
  177. //
  178. // Check if the package supports server side authentication
  179. // and all recv/sent messages are tamper proof
  180. //
  181. if ( fCapabilities & SECPKG_FLAG_CLIENT_ONLY ||
  182. !(fCapabilities & SECPKG_FLAG_PRIVACY ))
  183. {
  184. continue;
  185. }
  186. //
  187. // Check if the pkg matches one of our known packages
  188. //
  189. for ( j = 0; SecProviders[j].pszName != NULL; j++ )
  190. {
  191. if ( !stricmp( pPackageInfo[i].Name, SecProviders[j].pszName ) )
  192. {
  193. CredHandle OldCred;
  194. PVOID pCredData = NULL;
  195. //
  196. // Create a credential handle for each supported pkg
  197. //
  198. INET_ASSERT((SecProviders[j].dwFlags & ENC_CAPS_SCHANNEL_CREDS));
  199. pCredData = &DefaultCredData;
  200. if (SecProviders[j].pCertCtxt != NULL) {
  201. DefaultCredData.cCreds = 1;
  202. DefaultCredData.paCred = &SecProviders[j].pCertCtxt;
  203. }
  204. //
  205. // Enable Supported protocols in the Default Cred Data, then acquire the Credential
  206. //
  207. DefaultCredData.grbitEnabledProtocols = (GlobalSecureProtocols & SecProviders[j].dwProtocolFlags);
  208. OldCred.dwUpper = SecProviders[j].hCreds.dwUpper;
  209. OldCred.dwLower = SecProviders[j].hCreds.dwLower;
  210. // Zero out previous credentials
  211. SecProviders[j].hCreds.dwUpper = SecProviders[j].hCreds.dwLower = 0;
  212. scRet = g_AcquireCredentialsHandle(
  213. NULL,
  214. SecProviders[j].pszName, // Package
  215. SECPKG_CRED_OUTBOUND,
  216. NULL,
  217. pCredData,
  218. NULL,
  219. NULL,
  220. &(SecProviders[j].hCreds), // Handle
  221. &tsExpiry );
  222. if(!IS_CRED_INVALID(&OldCred))
  223. {
  224. g_FreeCredentialsHandle(&OldCred);
  225. }
  226. DefaultCredData.cCreds = 0;
  227. DefaultCredData.paCred = NULL;
  228. if ( scRet != STATUS_SUCCESS )
  229. {
  230. DEBUG_PRINT(API,
  231. WARNING,
  232. ("AcquireCredentialHandle failed, error %lx\n",
  233. scRet
  234. ));
  235. SecProviders[j].fEnabled = FALSE;
  236. SecProviders[j].hCreds.dwUpper = 0xffffffff;
  237. SecProviders[j].hCreds.dwLower = 0xffffffff;
  238. }
  239. else
  240. {
  241. DEBUG_PRINT(
  242. API,
  243. INFO,
  244. ("AcquireCredentialHandle() supports %s, acquires %x:%x\n",
  245. SecProviders[j].pszName,
  246. SecProviders[j].hCreds.dwUpper,
  247. SecProviders[j].hCreds.dwLower
  248. ));
  249. SecProviders[j].fEnabled = TRUE;
  250. cProviders++;
  251. dwEncFlags |= SecProviders[j].dwFlags;
  252. }
  253. }
  254. }
  255. }
  256. }
  257. if ( !cProviders )
  258. {
  259. //
  260. // No security packages were found, return FALSE to caller
  261. //
  262. DEBUG_PRINT(API,
  263. ERROR,
  264. ("No security packages were found, error %lx\n",
  265. SEC_E_SECPKG_NOT_FOUND
  266. ));
  267. g_FreeContextBuffer( pPackageInfo );
  268. SetLastError( (DWORD) SEC_E_SECPKG_NOT_FOUND );
  269. return FALSE;
  270. }
  271. //
  272. // Successfully found a security package(s)
  273. //
  274. return TRUE;
  275. }
  276. DWORD
  277. QuerySecurityInfo(
  278. IN CtxtHandle *hContext,
  279. OUT LPINTERNET_SECURITY_INFO pInfo)
  280. {
  281. SECURITY_STATUS scRet;
  282. scRet = g_QueryContextAttributes(hContext,
  283. SECPKG_ATTR_REMOTE_CERT_CONTEXT,
  284. &pInfo->pCertificate );
  285. if (scRet != ERROR_SUCCESS)
  286. {
  287. //
  288. // Map the SSPI error.
  289. //
  290. return MapInternetError((DWORD) scRet);
  291. }
  292. scRet = g_QueryContextAttributes(hContext,
  293. SECPKG_ATTR_CONNECTION_INFO,
  294. &pInfo->dwProtocol );
  295. if (scRet != ERROR_SUCCESS)
  296. {
  297. //
  298. // Map the SSPI error.
  299. //
  300. return MapInternetError((DWORD) scRet);
  301. }
  302. pInfo->dwSize = sizeof(INTERNET_SECURITY_INFO);
  303. return ERROR_SUCCESS;
  304. }
  305. // Helper function to detect Fortezza connections.
  306. BOOL IsCertificateFortezza(PCCERT_CONTEXT pCertContext)
  307. {
  308. INET_ASSERT(pCertContext != NULL);
  309. if (pCertContext == NULL)
  310. return FALSE;
  311. LPSTR pszOid = pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId;
  312. if (pszOid)
  313. {
  314. if (strcmp(pszOid, szOID_INFOSEC_mosaicUpdatedSig) == 0 ||
  315. strcmp(pszOid, szOID_INFOSEC_mosaicKMandUpdSig) == 0)
  316. {
  317. return TRUE;
  318. }
  319. }
  320. return FALSE;
  321. }
  322. LONG WinVerifySecureChannel(HWND hwnd, WINTRUST_DATA *pWTD)
  323. /*++
  324. Routine Description:
  325. Wininet's wrapper for secure channel WinVerifyTrust calls.
  326. Arguments:
  327. hWnd - in case WinVerifyTrust needs to do UI.
  328. pWTD - pointer to WINTRUST_DATA containing details about the
  329. secure channel. Passed to WinVerifyTrust.
  330. Return Value:
  331. WIN32 error code.
  332. --*/
  333. {
  334. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  335. BOOL async;
  336. LONG lResult;
  337. BOOL bFortezza;
  338. GUID gHTTPS = HTTPSPROV_ACTION;
  339. if (lpThreadInfo != NULL) {
  340. async = _InternetGetAsync(lpThreadInfo);
  341. _InternetSetAsync(lpThreadInfo, FALSE);
  342. }
  343. bFortezza = IsCertificateFortezza(pWTD->pCert->psCertContext);
  344. if (bFortezza && g_CryptInstallDefaultContext == NULL)
  345. {
  346. // HACK: we have no way to verify a connection without
  347. // a crypt32 which has the new APIs exposed. Till IE5 picks up
  348. // the new crypto bits we will assume Fortezza connections
  349. // verify correctly.
  350. lResult = ERROR_SUCCESS;
  351. }
  352. else
  353. {
  354. HCRYPTDEFAULTCONTEXT hCryptDefaultContext = NULL;
  355. if (bFortezza)
  356. {
  357. if (!g_CryptInstallDefaultContext(
  358. GlobalFortezzaCryptProv,
  359. CRYPT_DEFAULT_CONTEXT_CERT_SIGN_OID,
  360. szOID_INFOSEC_mosaicUpdatedSig, // check with John Banes
  361. 0, // dwFlags
  362. NULL, // pvReserved
  363. &hCryptDefaultContext
  364. ))
  365. {
  366. lResult = GetLastError();
  367. goto quit;
  368. }
  369. }
  370. lResult = g_WinVerifyTrust(hwnd, &gHTTPS, pWTD);
  371. DEBUG_PUT(("WinVerifyTrust returned: %x\n", lResult));
  372. if (hCryptDefaultContext)
  373. {
  374. // Ignore error code while freeing since we can't do anything
  375. // meaningful about it here.
  376. BOOL bResult;
  377. bResult = g_CryptUninstallDefaultContext(
  378. hCryptDefaultContext,
  379. 0,
  380. NULL);
  381. INET_ASSERT(bResult);
  382. }
  383. }
  384. quit:
  385. if (lpThreadInfo != NULL) {
  386. _InternetSetAsync(lpThreadInfo, async);
  387. }
  388. return lResult;
  389. }
  390. //
  391. // ICSecureSocket methods
  392. //
  393. ICSecureSocket::ICSecureSocket(
  394. IN DWORD dwErrorFlags,
  395. IN INTERNET_SCHEME tScheme
  396. )
  397. /*++
  398. Routine Description:
  399. ICSecureSocket constructor
  400. Arguments:
  401. tScheme - which protocol scheme we are creating the socket for
  402. Return Value:
  403. None.
  404. --*/
  405. {
  406. DEBUG_ENTER((DBG_OBJECTS,
  407. None,
  408. "ICSecureSocket::ICSecureSocket",
  409. "{%#x}",
  410. this
  411. ));
  412. SIGN_SECURE_SOCKET();
  413. m_hContext.dwLower = m_hContext.dwUpper = 0;
  414. m_dwProviderIndex = 0;
  415. m_dwFlags |= SF_SECURE;
  416. m_dwErrorFlags = dwErrorFlags;
  417. m_lpszHostName = NULL;
  418. m_pdblbufBuffer = NULL;
  419. m_pSecurityInfo = NULL;
  420. DEBUG_LEAVE(0);
  421. }
  422. ICSecureSocket::~ICSecureSocket()
  423. /*++
  424. Routine Description:
  425. ICSecureSocket destructor. Virtual function
  426. Arguments:
  427. None.
  428. Return Value:
  429. None.
  430. --*/
  431. {
  432. DEBUG_ENTER((DBG_OBJECTS,
  433. None,
  434. "ICSecureSocket::~ICSecureSocket",
  435. "{%#x [%q, sock=%#x, port=%d]}",
  436. this,
  437. GetHostName(),
  438. GetSocket(),
  439. GetSourcePort()
  440. ));
  441. CHECK_SECURE_SOCKET();
  442. INET_ASSERT(IsSecure());
  443. if (m_pdblbufBuffer != NULL) {
  444. delete m_pdblbufBuffer;
  445. }
  446. // Free security context associated with this object if it's
  447. // still allocated.
  448. TerminateSecConnection();
  449. /* SCLE ref */
  450. SetSecurityEntry(NULL);
  451. if (m_lpszHostName != NULL) {
  452. m_lpszHostName = (LPSTR)FREE_MEMORY(m_lpszHostName);
  453. INET_ASSERT(m_lpszHostName == NULL);
  454. }
  455. //if ( _pCertChainList )
  456. // delete _pCertChainList;
  457. DEBUG_LEAVE(0);
  458. }
  459. DWORD
  460. ICSecureSocket::Connect(
  461. IN LONG Timeout,
  462. IN INT Retries,
  463. IN DWORD dwFlags
  464. )
  465. /*++
  466. Routine Description:
  467. Initiate secure connection with server
  468. Arguments:
  469. Timeout - maximum amount of time (mSec) to wait for connection
  470. Retries - maximum number of attempts to connect
  471. dwFlags - flags controlling request
  472. Return Value:
  473. DWORD
  474. Success - ERROR_SUCCESS
  475. ERROR_IO_PENDING
  476. Operation will complete asynchronously
  477. Failure - ERROR_NOT_ENOUGH_MEMORY
  478. Couldn't create FSM
  479. --*/
  480. {
  481. DEBUG_ENTER((DBG_SOCKETS,
  482. Dword,
  483. "ICSecureSocket::Connect",
  484. "{%#x [%#x]} %d, %d, %#x",
  485. this,
  486. m_Socket,
  487. Timeout,
  488. Retries,
  489. dwFlags
  490. ));
  491. INET_ASSERT(IsSecure());
  492. DWORD error = DoFsm(new CFsm_SecureConnect(Timeout,
  493. Retries,
  494. dwFlags,
  495. this
  496. ));
  497. DEBUG_LEAVE(error);
  498. return error;
  499. }
  500. DWORD
  501. CFsm_SecureConnect::RunSM(
  502. IN CFsm * Fsm
  503. )
  504. {
  505. DEBUG_ENTER((DBG_SOCKETS,
  506. Dword,
  507. "CFsm_SecureConnect::RunSM",
  508. "%#x",
  509. Fsm
  510. ));
  511. ICSecureSocket * pSecureSocket = (ICSecureSocket *)Fsm->GetContext();
  512. CFsm_SecureConnect * stateMachine = (CFsm_SecureConnect *)Fsm;
  513. DWORD error;
  514. switch (Fsm->GetState()) {
  515. case FSM_STATE_INIT:
  516. case FSM_STATE_CONTINUE:
  517. error = pSecureSocket->Connect_Fsm(stateMachine);
  518. break;
  519. default:
  520. error = ERROR_INTERNET_INTERNAL_ERROR;
  521. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  522. INET_ASSERT(FALSE);
  523. break;
  524. }
  525. DEBUG_LEAVE(error);
  526. return error;
  527. }
  528. DWORD
  529. ICSecureSocket::Connect_Fsm(
  530. IN CFsm_SecureConnect * Fsm
  531. )
  532. {
  533. DEBUG_ENTER((DBG_SOCKETS,
  534. Dword,
  535. "ICSecureSocket::Connect_Fsm",
  536. "%#x",
  537. Fsm
  538. ));
  539. CFsm_SecureConnect & fsm = *Fsm;
  540. DWORD error = fsm.GetError();
  541. if (fsm.GetState() != FSM_STATE_INIT) {
  542. switch (fsm.GetFunctionState()) {
  543. case FSM_STATE_2:
  544. goto connect_continue;
  545. case FSM_STATE_3:
  546. goto negotiate_continue;
  547. default:
  548. error = ERROR_INTERNET_INTERNAL_ERROR;
  549. INET_ASSERT(FALSE);
  550. goto quit;
  551. }
  552. }
  553. m_dwProviderIndex = 0;
  554. //SetNonSecure();
  555. //
  556. // Hack for SSL2 Client Hello, set to FALSE,
  557. // but if we fail on the first recv, fReOpenSocket
  558. // is set to TRUE.
  559. //
  560. do {
  561. //
  562. // Attempt to do the connect
  563. //
  564. fsm.SetFunctionState(FSM_STATE_2);
  565. error = ICSocket::Connect(fsm.m_Timeout, fsm.m_Retries, fsm.m_dwFlags);
  566. connect_continue:
  567. if (error != ERROR_SUCCESS) {
  568. break;
  569. }
  570. if (m_dwFlags & SF_ENCRYPT) {
  571. fsm.SetFunctionState(FSM_STATE_3);
  572. error = SecureHandshakeWithServer(fsm.m_dwFlags, &fsm.m_bAttemptReconnect);
  573. if (error == ERROR_IO_PENDING) {
  574. break;
  575. }
  576. negotiate_continue:
  577. //
  578. // SSL2 hack for old IIS servers.
  579. // We re-open the socket, and call again.
  580. //
  581. if ((error != ERROR_SUCCESS) && fsm.m_bAttemptReconnect) {
  582. Disconnect(fsm.m_dwFlags);
  583. }
  584. }
  585. } while (fsm.m_bAttemptReconnect);
  586. quit:
  587. if (error != ERROR_IO_PENDING) {
  588. fsm.SetDone();
  589. if ((error != ERROR_SUCCESS) && IsOpen()) {
  590. Disconnect(fsm.m_dwFlags);
  591. }
  592. }
  593. DEBUG_LEAVE(error);
  594. return error;
  595. }
  596. DWORD
  597. ICSecureSocket::SecureHandshakeWithServer(
  598. IN DWORD dwFlags,
  599. OUT LPBOOL lpbAttemptReconnect
  600. )
  601. /*++
  602. Routine Description:
  603. For SSL/PCT or some secure channel this function attempts to use
  604. an arbitrary Socket for handshaking with a server. The assumption
  605. is made that caller can recall this function on failure
  606. Arguments:
  607. dwFlags -
  608. lpbAttemptReconnect -
  609. Return Value:
  610. DWORD
  611. Success - ERROR_SUCCESS
  612. Failure - WSA error
  613. --*/
  614. {
  615. DEBUG_ENTER((DBG_SOCKETS,
  616. Dword,
  617. "ICSecureSocket::SecureHandshakeWithServer",
  618. "%#x, %#x [%B]",
  619. dwFlags,
  620. lpbAttemptReconnect,
  621. *lpbAttemptReconnect
  622. ));
  623. INET_ASSERT(IsSecure());
  624. DWORD error = DoFsm(new CFsm_SecureHandshake(dwFlags,
  625. lpbAttemptReconnect,
  626. this
  627. ));
  628. DEBUG_LEAVE(error);
  629. return error;
  630. }
  631. DWORD
  632. CFsm_SecureHandshake::RunSM(
  633. IN CFsm * Fsm
  634. )
  635. {
  636. DEBUG_ENTER((DBG_SOCKETS,
  637. Dword,
  638. "CFsm_SecureHandshake::RunSM",
  639. "%#x",
  640. Fsm
  641. ));
  642. ICSecureSocket * pSecureSocket = (ICSecureSocket *)Fsm->GetContext();
  643. CFsm_SecureHandshake * stateMachine = (CFsm_SecureHandshake *)Fsm;
  644. DWORD error;
  645. switch (Fsm->GetState()) {
  646. case FSM_STATE_INIT:
  647. case FSM_STATE_CONTINUE:
  648. error = pSecureSocket->SecureHandshake_Fsm(stateMachine);
  649. break;
  650. default:
  651. error = ERROR_INTERNET_INTERNAL_ERROR;
  652. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  653. INET_ASSERT(FALSE);
  654. break;
  655. }
  656. DEBUG_LEAVE(error);
  657. return error;
  658. }
  659. DWORD
  660. ICSecureSocket::SecureHandshake_Fsm(
  661. IN CFsm_SecureHandshake * Fsm
  662. )
  663. {
  664. DEBUG_ENTER((DBG_SOCKETS,
  665. Dword,
  666. "ICSecureSocket::SecureHandshake_Fsm",
  667. "%#x",
  668. Fsm
  669. ));
  670. CFsm_SecureHandshake & fsm = *Fsm;
  671. DWORD error = fsm.GetError();
  672. DWORD dwSecureFlags;
  673. DWORD dwCertFlags;
  674. BOOL fErrorInvalidCa;
  675. if (fsm.GetState() != FSM_STATE_INIT) {
  676. switch (fsm.GetFunctionState()) {
  677. case FSM_STATE_2:
  678. goto negotiate_continue;
  679. default:
  680. error = ERROR_INTERNET_INTERNAL_ERROR;
  681. INET_ASSERT(FALSE);
  682. goto quit;
  683. }
  684. }
  685. //INET_ASSERT(fsm.m_dwFlags & SF_ENCRYPT);
  686. INET_ASSERT(m_Socket != INVALID_SOCKET);
  687. *fsm.m_lpbAttemptReconnect = FALSE;
  688. error = ERROR_SUCCESS;
  689. //
  690. // Save Off Flags in our Internal Object.
  691. // Treat SF_ENCRYPT just like SF_DECRYPT
  692. //
  693. m_dwFlags |= SF_DECRYPT;
  694. m_dwFlags |= fsm.m_dwFlags;
  695. INET_ASSERT(!(m_dwFlags
  696. & ~(SF_NON_BLOCKING
  697. | SF_SECURE
  698. | SF_ENCRYPT
  699. | SF_DECRYPT
  700. | SF_INDICATE
  701. | SF_SENDING_DATA
  702. )));
  703. //
  704. // Allocate Internal Buffer for SSL/PCT data.
  705. //
  706. if (m_pdblbufBuffer == NULL) {
  707. BOOL fInitSuccess;
  708. m_pdblbufBuffer = new DBLBUFFER();
  709. if (m_pdblbufBuffer == NULL) {
  710. error = ERROR_NOT_ENOUGH_MEMORY;
  711. goto quit;
  712. }
  713. fInitSuccess = m_pdblbufBuffer->InitBuffer(TRUE);
  714. if (!fInitSuccess) {
  715. error = ERROR_NOT_ENOUGH_MEMORY;
  716. goto quit;
  717. }
  718. }
  719. // First make sure the security dlls are loaded.
  720. error = LoadSecurity();
  721. if (error != ERROR_SUCCESS) {
  722. goto quit;
  723. }
  724. // If the user has the Fortezza CSP but has not logged on to the card yet.
  725. // return back an error to indicate that we need to put up additional UI.
  726. // if (IsFortezzaInstalled( ) && !AttemptedFortezzaLogin( ))
  727. //{
  728. // error = ERROR_INTERNET_FORTEZZA_LOGIN_NEEDED;
  729. // goto quit;
  730. //}
  731. //
  732. // dwEncFlags is a global flag set to the
  733. // supported security pkg mask
  734. //
  735. LOCK_SECURITY();
  736. if (dwEncFlags == ENC_CAPS_NOT_INSTALLED) {
  737. error = (DWORD)SEC_E_SECPKG_NOT_FOUND;
  738. } else if (dwEncFlags == 0) {
  739. //
  740. // first time thru, do the load.
  741. //
  742. DEBUG_PRINT(SOCKETS,
  743. INFO,
  744. ("Loading security dll\n"
  745. ));
  746. if ( !SecurityPkgInitialize() ) {
  747. error = GetLastError();
  748. UNLOCK_SECURITY();
  749. goto quit;
  750. }
  751. }
  752. UNLOCK_SECURITY();
  753. if ( error != ERROR_SUCCESS )
  754. {
  755. goto quit;
  756. }
  757. //
  758. // If we succeed in loading or and initalizing the Security DLLs, we
  759. // attempt to negotiate the connection
  760. //
  761. DEBUG_PRINT(SOCKETS,
  762. INFO,
  763. ("Negotiate secure channel\n"
  764. ));
  765. //
  766. // Turn of Encryption/Decryption before the handshake,
  767. // since the NegotiateSecConnection does its own Send and Recvs
  768. // of specialized data.
  769. //
  770. m_dwFlags &= ~(SF_ENCRYPT | SF_DECRYPT);
  771. fsm.SetFunctionState(FSM_STATE_2);
  772. error = NegotiateSecConnection(fsm.m_dwFlags,
  773. fsm.m_lpbAttemptReconnect
  774. );
  775. if (error == ERROR_IO_PENDING) {
  776. goto quit;
  777. }
  778. negotiate_continue:
  779. m_dwFlags |= (SF_ENCRYPT | SF_DECRYPT);
  780. if (error != ERROR_SUCCESS) {
  781. goto quit;
  782. }
  783. //
  784. // Find out what size Key we're using, and set the flags
  785. // acordingly.
  786. //
  787. dwSecureFlags = 0;
  788. if ((m_pSecurityInfo && !m_pSecurityInfo->InCache()) || !IsValidCacheEntry()) {
  789. error = VerifyTrust();
  790. if (error != ERROR_SUCCESS) {
  791. goto quit;
  792. }
  793. }
  794. else if (m_pSecurityInfo)
  795. {
  796. // RAID 752640: Here we are sure we are talking to the same server whose certificate
  797. // we've verified before. However it's possible that the certificate has expired or
  798. // been revoked since last time we checked. Therefore if the user/app cares about
  799. // certifciate expiration or revocation checking, we need to re-verify the trust.
  800. if (!(m_pSecurityInfo->GetSecureFlags() &
  801. (SECURITY_FLAG_IGNORE_CERT_DATE_INVALID | DLG_FLAGS_SEC_CERT_DATE_INVALID)))
  802. {
  803. #define SECURITY_FLAG_CHECK_EXPIRATION 0x00040000
  804. #ifdef DBG
  805. OutputDebugStringA("WinInet: re-verify certificate expiration\n");
  806. #endif
  807. error = ReVerifyTrust(SECURITY_FLAG_CHECK_EXPIRATION);
  808. if (error != ERROR_SUCCESS)
  809. {
  810. goto quit;
  811. }
  812. }
  813. if (GlobalEnableRevocation &&
  814. !(m_pSecurityInfo->GetSecureFlags() & DLG_FLAGS_SEC_CERT_REV_FAILED))
  815. {
  816. #define SECURITY_FLAG_CHECK_REVOCATION 0x00020000
  817. #ifdef DBG
  818. OutputDebugStringA("WinInet: re-verify certificate revocation\n");
  819. #endif
  820. error = ReVerifyTrust(SECURITY_FLAG_CHECK_REVOCATION);
  821. if (error != ERROR_SUCCESS)
  822. {
  823. goto quit;
  824. }
  825. }
  826. }
  827. //
  828. // we've got a secure connection, set the flags.
  829. //
  830. SetSecure();
  831. if(m_pSecurityInfo)
  832. {
  833. INTERNET_SECURITY_INFO ciInfo;
  834. m_pSecurityInfo->CopyOut(ciInfo);
  835. if(ciInfo.dwCipherStrength < 56)
  836. {
  837. SetSecureFlags(SECURITY_FLAG_STRENGTH_WEAK);
  838. }
  839. else if (ciInfo.dwCipherStrength==80 &&
  840. (ciInfo.aiCipher == CALG_SKIPJACK || ciInfo.aiCipher==CALG_TEK))
  841. {
  842. SetSecureFlags(SECURITY_FLAG_FORTEZZA);
  843. }
  844. else if(ciInfo.dwCipherStrength < 96)
  845. {
  846. SetSecureFlags(SECURITY_FLAG_STRENGTH_MEDIUM);
  847. }
  848. else
  849. {
  850. SetSecureFlags(SECURITY_FLAG_STRENGTH_STRONG);
  851. }
  852. if(ciInfo.pCertificate)
  853. {
  854. CertFreeCertificateContext(ciInfo.pCertificate);
  855. ciInfo.pCertificate = NULL;
  856. }
  857. }
  858. quit:
  859. if (error != ERROR_IO_PENDING) {
  860. fsm.SetDone();
  861. }
  862. DEBUG_LEAVE(error);
  863. return error;
  864. }
  865. BOOL ICSecureSocket:: IsValidCacheEntry()
  866. {
  867. INTERNET_SECURITY_INFO ciCert;
  868. INTERNET_SECURITY_INFO ciInfo;
  869. DWORD error;
  870. BOOL fRet = FALSE;
  871. ciCert.pCertificate = NULL;
  872. ciInfo.pCertificate = NULL;
  873. error = QuerySecurityInfo(&m_hContext, &ciCert);
  874. if( (error == ERROR_SUCCESS) && ciCert.pCertificate && m_pSecurityInfo)
  875. {
  876. m_pSecurityInfo->CopyOut(ciInfo);
  877. if(ciInfo.pCertificate->cbCertEncoded != ciCert.pCertificate->cbCertEncoded ||
  878. memcmp(ciInfo.pCertificate->pbCertEncoded , ciCert.pCertificate->pbCertEncoded , ciInfo.pCertificate->cbCertEncoded))
  879. {
  880. GlobalCertCache.Remove(GetHostName());
  881. SECURITY_CACHE_LIST_ENTRY* pSecurityInfo = new SECURITY_CACHE_LIST_ENTRY(GetHostName());
  882. (*m_ppSecurityInfo)->Release();
  883. *m_ppSecurityInfo = pSecurityInfo;
  884. pSecurityInfo->AddRef();
  885. SetSecurityEntry(&pSecurityInfo);
  886. }
  887. else
  888. fRet = TRUE;
  889. }
  890. if (ciCert.pCertificate)
  891. {
  892. CertFreeCertificateContext(ciCert.pCertificate);
  893. }
  894. if (ciInfo.pCertificate)
  895. {
  896. CertFreeCertificateContext(ciInfo.pCertificate);
  897. }
  898. return fRet;
  899. }
  900. DWORD ICSecureSocket::ReVerifyTrust(
  901. DWORD dwRecheckFlag // either SECURITY_FLAG_CHECK_EXPIRATION or
  902. // SECURITY_FLAG_CHECK_REVOCATION
  903. )
  904. {
  905. WINTRUST_DATA sWTD;
  906. WINTRUST_CERT_INFO sWTCI;
  907. HTTPSPolicyCallbackData polHttps;
  908. DWORD error = ERROR_SUCCESS;
  909. HINTERNET hInternet = NULL;
  910. HINTERNET hInternetMapped = NULL;
  911. LPINTERNET_THREAD_INFO lpThreadInfo = NULL;
  912. DWORD dwFlags = 0; // HTTPS policy flags to ignore errors
  913. INTERNET_SECURITY_INFO ciInfo;
  914. ciInfo.pCertificate = NULL;
  915. m_pSecurityInfo->CopyOut(ciInfo);
  916. INET_ASSERT(ciInfo.pCertificate);
  917. memset(&sWTCI, 0x00, sizeof(WINTRUST_CERT_INFO));
  918. sWTCI.cbStruct = sizeof(WINTRUST_CERT_INFO);
  919. sWTCI.psCertContext = (CERT_CONTEXT *)ciInfo.pCertificate;
  920. sWTCI.chStores = 1;
  921. sWTCI.pahStores = (HCERTSTORE *)&ciInfo.pCertificate->hCertStore;
  922. memset(&polHttps, 0x00, sizeof(HTTPSPolicyCallbackData));
  923. polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData);
  924. polHttps.dwAuthType = AUTHTYPE_SERVER;
  925. // this function only re-validate two cert properties (exipiry & revocation), so we ask CryptNet
  926. // to ignore irrelavant errors here.
  927. polHttps.fdwChecks = SECURITY_FLAG_IGNORE_UNKNOWN_CA |
  928. SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
  929. ((dwRecheckFlag == SECURITY_FLAG_CHECK_EXPIRATION) ?
  930. 0 :
  931. SECURITY_FLAG_IGNORE_CERT_DATE_INVALID);
  932. memset(&sWTD, 0x00, sizeof(WINTRUST_DATA));
  933. sWTD.cbStruct = sizeof(WINTRUST_DATA);
  934. sWTD.dwUIChoice = WTD_UI_NONE;
  935. sWTD.pPolicyCallbackData = (LPVOID)&polHttps;
  936. sWTD.dwUnionChoice = WTD_CHOICE_CERT;
  937. sWTD.pCert = &sWTCI;
  938. sWTD.pwszURLReference = NULL;
  939. if (dwRecheckFlag == SECURITY_FLAG_CHECK_REVOCATION)
  940. {
  941. sWTD.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
  942. sWTD.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN;
  943. }
  944. lpThreadInfo = InternetGetThreadInfo();
  945. if (lpThreadInfo != NULL)
  946. {
  947. hInternet = lpThreadInfo->hObject;
  948. hInternetMapped = lpThreadInfo->hObjectMapped;
  949. }
  950. error = WinVerifySecureChannel(NULL, &sWTD);
  951. error = MapInternetError(error);
  952. if (lpThreadInfo != NULL)
  953. {
  954. _InternetSetObjectHandle(lpThreadInfo, hInternet, hInternetMapped);
  955. }
  956. // Handle revocation problem as special case
  957. if (ERROR_INTERNET_SEC_CERT_REV_FAILED == error)
  958. dwFlags |= DLG_FLAGS_SEC_CERT_REV_FAILED;
  959. if (ERROR_SUCCESS != error &&
  960. (m_dwErrorFlags & INTERNET_ERROR_MASK_COMBINED_SEC_CERT))
  961. {
  962. BOOL fCertError = FALSE;
  963. if (error != ERROR_INTERNET_SECURITY_CHANNEL_ERROR)
  964. {
  965. if (!(polHttps.fdwChecks & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID))
  966. {
  967. if (ERROR_INTERNET_SEC_CERT_DATE_INVALID == error)
  968. {
  969. dwFlags |= DLG_FLAGS_SEC_CERT_DATE_INVALID;
  970. fCertError = TRUE;
  971. }
  972. else
  973. {
  974. // we are checking cert expiration; therefore we only expect the CERT_DATE_INVALID
  975. // error if WinVerifyTrust fails.
  976. INET_ASSERT(FALSE);
  977. }
  978. }
  979. else if (sWTD.fdwRevocationChecks == WTD_REVOKE_WHOLECHAIN)
  980. {
  981. if (ERROR_INTERNET_SEC_CERT_REVOKED == error)
  982. {
  983. dwFlags = 0;
  984. }
  985. else if (ERROR_INTERNET_SEC_CERT_REV_FAILED == error)
  986. {
  987. dwFlags = DLG_FLAGS_SEC_CERT_REV_FAILED;
  988. }
  989. else
  990. {
  991. // we are checking cert revocation; therefore we only expect the CERT_REV_FAILED
  992. // or CERT_REVOKED error if WinVerifyTrust fails.
  993. INET_ASSERT(FALSE);
  994. }
  995. }
  996. else
  997. {
  998. // this function only re-validate two cert properties (exipiry & revocation)
  999. INET_ASSERT(FALSE);
  1000. }
  1001. }
  1002. //
  1003. // Change the error only if one of the known certifciate errors was
  1004. // encountered.
  1005. //
  1006. if (fCertError)
  1007. {
  1008. error = ERROR_INTERNET_SEC_CERT_ERRORS;
  1009. m_pSecurityInfo->SetSecureFlags(dwFlags);
  1010. }
  1011. else if (dwFlags & DLG_FLAGS_SEC_CERT_REV_FAILED)
  1012. {
  1013. INET_ASSERT(dwFlags==DLG_FLAGS_SEC_CERT_REV_FAILED);
  1014. error = ERROR_INTERNET_SEC_CERT_REV_FAILED;
  1015. m_pSecurityInfo->SetSecureFlags(DLG_FLAGS_SEC_CERT_REV_FAILED);
  1016. }
  1017. }
  1018. if (ciInfo.pCertificate)
  1019. {
  1020. CertFreeCertificateContext(ciInfo.pCertificate);
  1021. }
  1022. if (error != ERROR_SUCCESS)
  1023. {
  1024. GlobalCertCache.Remove(GetHostName());
  1025. }
  1026. return error;
  1027. }
  1028. DWORD
  1029. ICSecureSocket::VerifyTrust(
  1030. )
  1031. /*++
  1032. Routine Description:
  1033. This function establishes a secure channel with the server by
  1034. performing the security handshake protocol. It will walk
  1035. the list of installed security packages until it finds a package
  1036. that succeeds in the security handshake. If one package fails
  1037. it is up to the caller to re-call NegotiateSecConnection with
  1038. a re-opened socket so another socket can attempt the connection.
  1039. Return Value:
  1040. DWORD
  1041. Success - ERROR_SUCCESS
  1042. Failure -
  1043. --*/
  1044. {
  1045. // We've done our handshake, now update the security info
  1046. INTERNET_SECURITY_INFO ciCert;
  1047. DWORD dwCertFlags = 0;
  1048. WINTRUST_DATA sWTD;
  1049. WINTRUST_CERT_INFO sWTCI;
  1050. HTTPSPolicyCallbackData polHttps;
  1051. DWORD cbServerName;
  1052. DWORD error;
  1053. HINTERNET hInternet;
  1054. HINTERNET hInternetMapped;
  1055. LPINTERNET_THREAD_INFO lpThreadInfo = NULL;
  1056. DWORD dwFlags = 0; // HTTPS policy flags to ignore errors
  1057. DEBUG_ENTER((DBG_SOCKETS,
  1058. Dword,
  1059. "ICSecureSocket::VerifyTrust",
  1060. "{%#x",
  1061. this
  1062. ));
  1063. // HACK HACK: 67640
  1064. // WinVerifyTrust can do a nested HttpSendRequest which causes the hObject's on the
  1065. // thread to get messed up. This happens only when the ceritificate has a URL for
  1066. // a CRL in it. We save and restore these values to workaround the problem.
  1067. // Need to work out a better solution to handle this but it is too close to ship to
  1068. // try anything with greater code impact.
  1069. lpThreadInfo = InternetGetThreadInfo();
  1070. if (lpThreadInfo != NULL) {
  1071. hInternet = lpThreadInfo->hObject;
  1072. hInternetMapped = lpThreadInfo->hObjectMapped;
  1073. }
  1074. error = QuerySecurityInfo(&m_hContext, &ciCert);
  1075. if (error != ERROR_SUCCESS) {
  1076. goto quit;
  1077. }
  1078. if(m_pSecurityInfo)
  1079. {
  1080. *m_pSecurityInfo = &ciCert;
  1081. dwCertFlags = m_pSecurityInfo->GetSecureFlags();
  1082. }
  1083. if (ciCert.pCertificate == NULL) {
  1084. error = ERROR_INTERNET_INTERNAL_ERROR;
  1085. goto quit;
  1086. }
  1087. memset(&sWTD, 0x00, sizeof(WINTRUST_DATA));
  1088. sWTD.cbStruct = sizeof(WINTRUST_DATA);
  1089. sWTD.dwUIChoice = WTD_UI_NONE;
  1090. sWTD.pPolicyCallbackData = (LPVOID)&polHttps;
  1091. sWTD.dwUnionChoice = WTD_CHOICE_CERT;
  1092. sWTD.pCert = &sWTCI;
  1093. sWTD.pwszURLReference = NULL;
  1094. if (GlobalEnableRevocation && !(dwCertFlags & DLG_FLAGS_SEC_CERT_REV_FAILED))
  1095. sWTD.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
  1096. memset(&sWTCI, 0x00, sizeof(WINTRUST_CERT_INFO));
  1097. sWTCI.cbStruct = sizeof(WINTRUST_CERT_INFO);
  1098. sWTCI.psCertContext = (CERT_CONTEXT *)ciCert.pCertificate;
  1099. sWTCI.chStores = 1;
  1100. sWTCI.pahStores = (HCERTSTORE *)&ciCert.pCertificate->hCertStore;
  1101. memset(&polHttps, 0x00, sizeof(HTTPSPolicyCallbackData));
  1102. polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData);
  1103. polHttps.dwAuthType = AUTHTYPE_SERVER;
  1104. // Check for everything if looping.
  1105. //
  1106. // This only incurs a perf hit in cases where ignore flags are set.
  1107. // The sacrifice is made so the UI won't lie since the pass/fail
  1108. // status in the UI is grouped.
  1109. polHttps.fdwChecks = (m_dwErrorFlags &
  1110. INTERNET_ERROR_MASK_COMBINED_SEC_CERT) ?
  1111. dwFlags : dwCertFlags;
  1112. cbServerName = MultiByteToWideChar(CP_ACP, 0, m_lpszHostName, -1, NULL, 0);
  1113. polHttps.pwszServerName = new WCHAR[cbServerName+1];
  1114. if(polHttps.pwszServerName == 0)
  1115. {
  1116. error = ERROR_NOT_ENOUGH_MEMORY;
  1117. goto quit;
  1118. }
  1119. sWTCI.pcwszDisplayName = polHttps.pwszServerName;
  1120. cbServerName = MultiByteToWideChar(CP_ACP, 0, m_lpszHostName, -1, polHttps.pwszServerName, cbServerName);
  1121. error = LoadWinTrust();
  1122. if(ERROR_SUCCESS == error)
  1123. {
  1124. error = WinVerifySecureChannel(NULL, &sWTD);
  1125. }
  1126. error = MapInternetError(error);
  1127. // Handle revocation problem as special case
  1128. if (ERROR_INTERNET_SEC_CERT_REV_FAILED == error)
  1129. dwFlags |= DLG_FLAGS_SEC_CERT_REV_FAILED;
  1130. // Revocation failed is separate, so it should be ignored.
  1131. // Revoked will kill the request altogether.
  1132. if (!(dwCertFlags & ~DLG_FLAGS_SEC_CERT_REV_FAILED))
  1133. {
  1134. // We're going to loop through all errors
  1135. // (doesn't count revocation)
  1136. m_pSecurityInfo->SetFullyValidated(TRUE);
  1137. }
  1138. //
  1139. // If there was problem with the certificate and the caller requested
  1140. // combined SSL errors cycle through all possible certificate errors.
  1141. //
  1142. if (ERROR_SUCCESS != error &&
  1143. (m_dwErrorFlags & INTERNET_ERROR_MASK_COMBINED_SEC_CERT) &&
  1144. m_pSecurityInfo)
  1145. {
  1146. BOOL fCertError = FALSE;
  1147. dwCertFlags = m_pSecurityInfo->GetSecureFlags();
  1148. do
  1149. {
  1150. if (ERROR_INTERNET_INVALID_CA == error)
  1151. {
  1152. polHttps.fdwChecks |= DLG_FLAGS_IGNORE_INVALID_CA;
  1153. dwFlags |= DLG_FLAGS_INVALID_CA;
  1154. if (!(dwCertFlags & SECURITY_FLAG_IGNORE_UNKNOWN_CA))
  1155. fCertError = TRUE;
  1156. }
  1157. else if (ERROR_INTERNET_SEC_CERT_CN_INVALID == error)
  1158. {
  1159. polHttps.fdwChecks |= DLG_FLAGS_IGNORE_CERT_CN_INVALID;
  1160. dwFlags |= DLG_FLAGS_SEC_CERT_CN_INVALID;
  1161. if (GlobalWarnOnBadCertRecving &&
  1162. !(dwCertFlags & SECURITY_FLAG_IGNORE_CERT_CN_INVALID))
  1163. fCertError = TRUE;
  1164. }
  1165. else if (ERROR_INTERNET_SEC_CERT_DATE_INVALID == error)
  1166. {
  1167. polHttps.fdwChecks |= DLG_FLAGS_IGNORE_CERT_DATE_INVALID;
  1168. dwFlags |= DLG_FLAGS_SEC_CERT_DATE_INVALID;
  1169. if (!(dwCertFlags & SECURITY_FLAG_IGNORE_CERT_DATE_INVALID))
  1170. fCertError = TRUE;
  1171. }
  1172. else if (ERROR_INTERNET_SEC_CERT_REVOKED == error)
  1173. {
  1174. // During this loop revoked comes after the untrusted
  1175. // root error. Clean up and break out with the revoked
  1176. // error since it should take precedence.
  1177. fCertError = FALSE;
  1178. dwFlags = 0;
  1179. break;
  1180. }
  1181. else if (ERROR_INTERNET_SEC_CERT_REV_FAILED == error)
  1182. {
  1183. // Break out and give precedence for rev failed cases, too.
  1184. dwFlags = DLG_FLAGS_SEC_CERT_REV_FAILED;
  1185. fCertError = FALSE;
  1186. break;
  1187. }
  1188. else
  1189. {
  1190. //
  1191. // Pass all other errors through.
  1192. //
  1193. break;
  1194. }
  1195. error = WinVerifySecureChannel(NULL, &sWTD);
  1196. error = MapInternetError(error);
  1197. } while (ERROR_SUCCESS != error);
  1198. //
  1199. // Change the error only if one of the known certifciate errors was
  1200. // encountered.
  1201. //
  1202. if (fCertError)
  1203. {
  1204. error = ERROR_INTERNET_SEC_CERT_ERRORS;
  1205. m_pSecurityInfo->SetSecureFlags(dwFlags);
  1206. }
  1207. else if (dwFlags & DLG_FLAGS_SEC_CERT_REV_FAILED)
  1208. {
  1209. INET_ASSERT(dwFlags==DLG_FLAGS_SEC_CERT_REV_FAILED);
  1210. error = ERROR_INTERNET_SEC_CERT_REV_FAILED;
  1211. m_pSecurityInfo->SetSecureFlags(DLG_FLAGS_SEC_CERT_REV_FAILED);
  1212. }
  1213. }
  1214. delete [] polHttps.pwszServerName;
  1215. if(ciCert.pCertificate)
  1216. {
  1217. CertFreeCertificateContext(ciCert.pCertificate);
  1218. }
  1219. if (error != ERROR_SUCCESS)
  1220. {
  1221. goto quit;
  1222. }
  1223. // Only cache if we weren't supposed to ignore any results.
  1224. // For security reasons, it may be important next time.
  1225. if(m_pSecurityInfo && (!m_pSecurityInfo->InCache()) &&
  1226. m_pSecurityInfo->GetFullyValidated())
  1227. {
  1228. // Add it to the cache if it's not already there.
  1229. /* SCLE ref */
  1230. GlobalCertCache.Add(m_pSecurityInfo);
  1231. }
  1232. quit:
  1233. if (lpThreadInfo != NULL) {
  1234. _InternetSetObjectHandle(lpThreadInfo, hInternet, hInternetMapped);
  1235. }
  1236. DEBUG_LEAVE(error);
  1237. return error;
  1238. }
  1239. DWORD
  1240. ICSecureSocket::NegotiateSecConnection(
  1241. IN DWORD dwFlags,
  1242. OUT LPBOOL lpbAttemptReconnect
  1243. )
  1244. /*++
  1245. Routine Description:
  1246. This function establishes a secure channel with the server by
  1247. performing the security handshake protocol. It will walk
  1248. the list of installed security packages until it finds a package
  1249. that succeeds in the security handshake. If one package fails
  1250. it is up to the caller to re-call NegotiateSecConnection with
  1251. a re-opened socket so another socket can attempt the connection.
  1252. Arguments:
  1253. dwFlags - Socket Flags that may need to be passed on to Socket Calls
  1254. (needed to support Async I/O)
  1255. lpbAttemptReconnect - on return, if this value is TRUE, the caller should call
  1256. this function again, and it will try another protocol.
  1257. Return Value:
  1258. DWORD
  1259. Success - ERROR_SUCCESS
  1260. Failure -
  1261. --*/
  1262. {
  1263. DEBUG_ENTER((DBG_SOCKETS,
  1264. Dword,
  1265. "ICSecureSocket::NegotiateSecConnection",
  1266. "{%#x [%#x]} %#x, %#x [%B]",
  1267. this,
  1268. m_Socket,
  1269. dwFlags,
  1270. lpbAttemptReconnect,
  1271. *lpbAttemptReconnect
  1272. ));
  1273. INET_ASSERT(IsSecure());
  1274. DWORD error = DoFsm(new CFsm_SecureNegotiate(dwFlags,
  1275. lpbAttemptReconnect,
  1276. this
  1277. ));
  1278. DEBUG_LEAVE(error);
  1279. return error;
  1280. }
  1281. DWORD
  1282. CFsm_SecureNegotiate::RunSM(
  1283. IN CFsm * Fsm
  1284. )
  1285. {
  1286. DEBUG_ENTER((DBG_SOCKETS,
  1287. Dword,
  1288. "CFsm_SecureNegotiate::RunSM",
  1289. "%#x",
  1290. Fsm
  1291. ));
  1292. ICSecureSocket * pSecureSocket = (ICSecureSocket *)Fsm->GetContext();
  1293. CFsm_SecureNegotiate * stateMachine = (CFsm_SecureNegotiate *)Fsm;
  1294. DWORD error;
  1295. switch (Fsm->GetState()) {
  1296. case FSM_STATE_INIT:
  1297. case FSM_STATE_CONTINUE:
  1298. error = pSecureSocket->SecureNegotiate_Fsm(stateMachine);
  1299. break;
  1300. default:
  1301. error = ERROR_INTERNET_INTERNAL_ERROR;
  1302. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  1303. INET_ASSERT(FALSE);
  1304. break;
  1305. }
  1306. DEBUG_LEAVE(error);
  1307. return error;
  1308. }
  1309. DWORD
  1310. ICSecureSocket::SecureNegotiate_Fsm(
  1311. IN CFsm_SecureNegotiate * Fsm
  1312. )
  1313. {
  1314. DEBUG_ENTER((DBG_SOCKETS,
  1315. Dword,
  1316. "ICSecureSocket::SecureNegotiate_Fsm",
  1317. "%#x",
  1318. Fsm
  1319. ));
  1320. CFsm_SecureNegotiate & fsm = *Fsm;
  1321. DWORD error = fsm.GetError();
  1322. DWORD dwSSPIFlags = 0;
  1323. if (fsm.GetState() != FSM_STATE_INIT) {
  1324. switch (fsm.GetFunctionState()) {
  1325. case FSM_STATE_2:
  1326. goto send_continue;
  1327. case FSM_STATE_3:
  1328. goto negotiate_loop_continue;
  1329. default:
  1330. error = ERROR_INTERNET_INTERNAL_ERROR;
  1331. INET_ASSERT(FALSE);
  1332. goto quit;
  1333. }
  1334. }
  1335. INET_ASSERT(IsOpen());
  1336. *fsm.m_lpbAttemptReconnect = FALSE;
  1337. //
  1338. // set OutBuffer for InitializeSecurityContext call
  1339. //
  1340. fsm.m_OutBuffer.cBuffers = 1;
  1341. fsm.m_OutBuffer.pBuffers = fsm.m_OutBuffers;
  1342. fsm.m_OutBuffer.ulVersion = SECBUFFER_VERSION;
  1343. if(GlobalSecureProtocols != GlobalSecureProtocolsCopy)
  1344. {
  1345. LOCK_SECURITY();
  1346. //ReInit the credentials if our settings have changed.
  1347. SecurityPkgInitialize();
  1348. UNLOCK_SECURITY();
  1349. }
  1350. //
  1351. // Pick the provider we're going to use.
  1352. //
  1353. while ((SecProviders[GetProviderIndex()].pszName != NULL)
  1354. && ( !SecProviders[GetProviderIndex()].fEnabled
  1355. || !(SecProviders[GetProviderIndex()].dwProtocolFlags & GlobalSecureProtocols) ) ) {
  1356. //
  1357. // Next provider
  1358. //
  1359. SetProviderIndex(GetProviderIndex() + 1);
  1360. }
  1361. if (SecProviders[GetProviderIndex()].pszName == NULL) {
  1362. //
  1363. // BUGBUG shouldn't we error out here?
  1364. //
  1365. SetProviderIndex(0);
  1366. goto error_exit;
  1367. }
  1368. DWORD i;
  1369. i = GetProviderIndex();
  1370. DEBUG_PRINT(API,
  1371. INFO,
  1372. ("Starting handshake protocol with pkg %d - %s\n",
  1373. i,
  1374. SecProviders[i].pszName
  1375. ));
  1376. //
  1377. // 1. initiate a client HELLO message and generate a token
  1378. //
  1379. fsm.m_OutBuffers[0].pvBuffer = NULL;
  1380. fsm.m_OutBuffers[0].BufferType = SECBUFFER_TOKEN;
  1381. SECURITY_STATUS scRet;
  1382. DWORD ContextAttr;
  1383. TimeStamp tsExpiry;
  1384. fsm.m_bDoingClientAuth = FALSE;
  1385. // Resynchronize the certificate store to catch
  1386. // recently installed certificates
  1387. if(g_bOpenMyCertStore && g_hMyCertStore == NULL)
  1388. ReopenMyCertStore();
  1389. if (g_hMyCertStore)
  1390. CertControlStore(g_hMyCertStore, 0, CERT_STORE_CTRL_AUTO_RESYNC, NULL);
  1391. //
  1392. // We need a credential handle,
  1393. // if we're doing client do the magic to get a specialized
  1394. // one otherwise use the standard global one.
  1395. //
  1396. if ( IsCredClear(fsm.m_hCreds) )
  1397. {
  1398. fsm.m_hCreds = SecProviders[i].hCreds;
  1399. if (GetCertContextArray())
  1400. {
  1401. if (GetCertContextArray()->GetSelectedCertContext())
  1402. {
  1403. error = CliAuthSelectCredential(
  1404. &m_hContext,
  1405. SecProviders[i].pszName,
  1406. GetCertContextArray(),
  1407. &fsm.m_hCreds);
  1408. if (error != ERROR_SUCCESS) {
  1409. goto quit;
  1410. }
  1411. fsm.m_bDoingClientAuth = TRUE;
  1412. }
  1413. dwSSPIFlags |= ISC_REQ_USE_SUPPLIED_CREDS;
  1414. }
  1415. else if (m_pSecurityInfo && m_pSecurityInfo->GetForceNewSession())
  1416. {
  1417. // Force new session to be negotiated because
  1418. // the user flushed client auth certs for the session.
  1419. // Clear the force flag after we enter the loop.
  1420. dwSSPIFlags |= ISC_REQ_USE_SESSION_KEY;
  1421. }
  1422. }
  1423. scRet = g_InitializeSecurityContext(&fsm.m_hCreds,
  1424. NULL,
  1425. (LPSTR)GetHostName(),
  1426. ISC_REQ_SEQUENCE_DETECT
  1427. | ISC_REQ_REPLAY_DETECT
  1428. | ISC_REQ_CONFIDENTIALITY
  1429. | ISC_REQ_ALLOCATE_MEMORY
  1430. | dwSSPIFlags,
  1431. 0,
  1432. SECURITY_NATIVE_DREP,
  1433. NULL, // default, don't do hack.
  1434. 0,
  1435. &m_hContext,
  1436. &fsm.m_OutBuffer, // address where output data go
  1437. &ContextAttr,
  1438. &tsExpiry
  1439. );
  1440. DEBUG_PRINT(API,
  1441. INFO,
  1442. ("1. InitializeSecurityContext returned %s [%x]. hContext = %#x:%#x\n",
  1443. InternetMapSSPIError((DWORD)scRet),
  1444. scRet,
  1445. m_hContext.dwUpper,
  1446. m_hContext.dwLower
  1447. ));
  1448. if (scRet == SEC_E_INVALID_HANDLE) {
  1449. SecProviders[i].fEnabled = FALSE;
  1450. }
  1451. if (scRet == SEC_E_INVALID_TOKEN) {
  1452. error = ERROR_INTERNET_CANNOT_CONNECT;
  1453. } else {
  1454. //
  1455. // Turn the error in to one we understand */
  1456. //
  1457. error = MapInternetError((DWORD)scRet);
  1458. }
  1459. if (scRet != SEC_I_CONTINUE_NEEDED) {
  1460. goto error_exit;
  1461. }
  1462. DEBUG_PRINT(API,
  1463. INFO,
  1464. ("1. OutBuffer is <%x, %d, %x>\n",
  1465. fsm.m_OutBuffers[0].pvBuffer,
  1466. fsm.m_OutBuffers[0].cbBuffer,
  1467. fsm.m_OutBuffers[0].BufferType
  1468. ));
  1469. if ((fsm.m_OutBuffers[0].cbBuffer != 0)
  1470. && (fsm.m_OutBuffers[0].pvBuffer != NULL)) {
  1471. //
  1472. // Send response to server if there is one
  1473. //
  1474. fsm.SetFunctionState(FSM_STATE_2);
  1475. error = ICSocket::Send(fsm.m_OutBuffers[0].pvBuffer,
  1476. fsm.m_OutBuffers[0].cbBuffer,
  1477. 0
  1478. );
  1479. if (error == ERROR_IO_PENDING) {
  1480. goto quit;
  1481. }
  1482. send_continue:
  1483. g_FreeContextBuffer(fsm.m_OutBuffers[0].pvBuffer);
  1484. fsm.m_OutBuffers[0].pvBuffer = NULL;
  1485. if (error != ERROR_SUCCESS) {
  1486. //
  1487. // We should deal with this better
  1488. //
  1489. goto error_exit;
  1490. }
  1491. }
  1492. fsm.SetFunctionState(FSM_STATE_3);
  1493. error = SSPINegotiateLoop(NULL, fsm.m_dwFlags, fsm.m_hCreds, TRUE, fsm.m_bDoingClientAuth);
  1494. if (error == ERROR_IO_PENDING) {
  1495. goto quit;
  1496. }
  1497. negotiate_loop_continue:
  1498. error_exit:
  1499. //
  1500. // We're not actually deleting the handle, rather we're no longer keeping
  1501. // a reference to the Credential handle in our fsm after we hand it off
  1502. //
  1503. if ( fsm.m_bDoingClientAuth )
  1504. {
  1505. ClearCreds(fsm.m_hCreds);
  1506. fsm.m_bDoingClientAuth = FALSE;
  1507. }
  1508. if (error == ERROR_INTERNET_CANNOT_CONNECT) {
  1509. //
  1510. // error was a CANNOT_CONNECT, so try the next protocol.
  1511. //
  1512. SetProviderIndex(GetProviderIndex() + 1);
  1513. if (SecProviders[GetProviderIndex()].pszName == NULL) {
  1514. SetProviderIndex(0);
  1515. *fsm.m_lpbAttemptReconnect = FALSE;
  1516. } else {
  1517. *fsm.m_lpbAttemptReconnect = TRUE;
  1518. }
  1519. }
  1520. quit:
  1521. if (error != ERROR_IO_PENDING) {
  1522. fsm.SetDone();
  1523. }
  1524. DEBUG_LEAVE(error);
  1525. return error;
  1526. }
  1527. DWORD
  1528. ICSecureSocket::SSPINegotiateLoop(
  1529. OUT DBLBUFFER * pdblbufBuffer,
  1530. IN DWORD dwFlags,
  1531. CredHandle hCreds,
  1532. IN BOOL bDoInitialRead,
  1533. IN BOOL bDoingClientAuth
  1534. )
  1535. /*++
  1536. Routine Description:
  1537. This function completes the handshakes needed to establish a
  1538. security protocol. The initial handshakes are either generated
  1539. by NegotiateSecureConnection, when generating a new connection, or
  1540. during a receive when a REDO request is received.
  1541. Arguments:
  1542. pdblbufBuffer - an input buffer into which to put any Extra data left over
  1543. after the handshake. This data is assumed to be application
  1544. data, and will be decrypted later.
  1545. dwFlags - Socket Flags that may need to be passed on to Socket Calls
  1546. (needed to support Async I/O)
  1547. bDoInitialRead - if TRUE, this function will do a read before calling
  1548. InitializeSecurityContext, otherwise, it passes in 0 bytes of data.
  1549. Return Value:
  1550. ERROR_SUCCESS - we successfully completed our connection.
  1551. ERROR_INTERNET_CANNOT_CONNECT - The connection was dropped on us, possibly because we used a bad
  1552. protocol. Try the next protocol.
  1553. ERROR_* - Other internet error, disconnect.
  1554. Comments:
  1555. BUGBUG (hack alert) [arthurbi]
  1556. Do to a bug in IIS 1.0 Servers we cannot connect because
  1557. we send a "Client SSL 3 Message". This message confuses the
  1558. server and causes it to close the socket. The fix is to
  1559. reopen the socket and send a "Client SSL 2 Message." Newer
  1560. versions of the server will be fixed.
  1561. --*/
  1562. {
  1563. DEBUG_ENTER((DBG_SOCKETS,
  1564. Dword,
  1565. "ICSecureSocket::SSPINegotiateLoop",
  1566. "{%#x [%#x]} %#x, %#x, %B",
  1567. this,
  1568. m_Socket,
  1569. pdblbufBuffer,
  1570. dwFlags,
  1571. bDoInitialRead
  1572. ));
  1573. INET_ASSERT(IsSecure());
  1574. DWORD error = DoFsm(new CFsm_NegotiateLoop(pdblbufBuffer,
  1575. dwFlags,
  1576. bDoInitialRead,
  1577. bDoingClientAuth,
  1578. hCreds,
  1579. this
  1580. ));
  1581. DEBUG_LEAVE(error);
  1582. return error;
  1583. }
  1584. DWORD
  1585. CFsm_NegotiateLoop::RunSM(
  1586. IN CFsm * Fsm
  1587. )
  1588. {
  1589. DEBUG_ENTER((DBG_SOCKETS,
  1590. Dword,
  1591. "CFsm_NegotiateLoop::RunSM",
  1592. "%#x",
  1593. Fsm
  1594. ));
  1595. ICSecureSocket * pSecureSocket = (ICSecureSocket *)Fsm->GetContext();
  1596. CFsm_NegotiateLoop * stateMachine = (CFsm_NegotiateLoop *)Fsm;
  1597. DWORD error;
  1598. switch (Fsm->GetState()) {
  1599. case FSM_STATE_INIT:
  1600. case FSM_STATE_CONTINUE:
  1601. error = pSecureSocket->NegotiateLoop_Fsm(stateMachine);
  1602. break;
  1603. default:
  1604. error = ERROR_INTERNET_INTERNAL_ERROR;
  1605. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  1606. INET_ASSERT(FALSE);
  1607. break;
  1608. }
  1609. DEBUG_LEAVE(error);
  1610. return error;
  1611. }
  1612. DWORD
  1613. ICSecureSocket::NegotiateLoop_Fsm(
  1614. IN CFsm_NegotiateLoop * Fsm
  1615. )
  1616. {
  1617. DEBUG_ENTER((DBG_SOCKETS,
  1618. Dword,
  1619. "ICSecureSocket::NegotiateLoop_Fsm",
  1620. "%#x",
  1621. Fsm
  1622. ));
  1623. CFsm_NegotiateLoop & fsm = *Fsm;
  1624. DWORD error = fsm.GetError();
  1625. if (fsm.GetState() != FSM_STATE_INIT) {
  1626. switch (fsm.GetFunctionState()) {
  1627. case FSM_STATE_2:
  1628. goto receive_continue;
  1629. case FSM_STATE_3:
  1630. goto send_continue;
  1631. default:
  1632. error = ERROR_INTERNET_INTERNAL_ERROR;
  1633. INET_ASSERT(FALSE);
  1634. goto quit;
  1635. }
  1636. }
  1637. INET_ASSERT(IsOpen());
  1638. fsm.m_dwProviderIndex = GetProviderIndex();
  1639. fsm.m_dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT
  1640. | ISC_REQ_REPLAY_DETECT
  1641. | ISC_REQ_CONFIDENTIALITY
  1642. | ISC_REQ_ALLOCATE_MEMORY
  1643. | ISC_RET_EXTENDED_ERROR;
  1644. //
  1645. // set OutBuffer for InitializeSecurityContext call
  1646. //
  1647. fsm.m_OutBuffer.cBuffers = 1;
  1648. fsm.m_OutBuffer.pBuffers = fsm.m_OutBuffers;
  1649. fsm.m_OutBuffer.ulVersion = SECBUFFER_VERSION;
  1650. //
  1651. // If we have a selected cert chain, then try to
  1652. // generate a credential from that list.
  1653. //
  1654. if (IsCredClear(fsm.m_hCreds))
  1655. {
  1656. fsm.m_hCreds = SecProviders[fsm.m_dwProviderIndex].hCreds;
  1657. if ( GetCertContextArray() &&
  1658. GetCertContextArray()->GetSelectedCertContext() )
  1659. {
  1660. error = CliAuthSelectCredential(
  1661. &m_hContext,
  1662. SecProviders[fsm.m_dwProviderIndex].pszName,
  1663. GetCertContextArray(),
  1664. &fsm.m_hCreds);
  1665. if (error != ERROR_SUCCESS) {
  1666. goto quit;
  1667. }
  1668. fsm.m_bDoingClientAuth = TRUE;
  1669. }
  1670. else if (m_pSecurityInfo && m_pSecurityInfo->GetForceNewSession())
  1671. {
  1672. // Force new session to be negotiated because
  1673. // the user flushed client auth certs for the session.
  1674. fsm.m_dwSSPIFlags |= ISC_REQ_USE_SESSION_KEY;
  1675. m_pSecurityInfo->SetForceNewSession(FALSE);
  1676. }
  1677. }
  1678. if (fsm.m_bDoingClientAuth ||
  1679. GetCertContextArray() )
  1680. {
  1681. fsm.m_dwSSPIFlags |= ISC_REQ_USE_SUPPLIED_CREDS;
  1682. }
  1683. fsm.m_scRet = SEC_I_CONTINUE_NEEDED;
  1684. while (fsm.m_scRet == SEC_I_CONTINUE_NEEDED ||
  1685. fsm.m_scRet == SEC_E_INCOMPLETE_MESSAGE ||
  1686. fsm.m_scRet == SEC_I_INCOMPLETE_CREDENTIALS) {
  1687. //
  1688. // send to target server
  1689. // if we've got a SEC_E_INCOMPLETE_MESSAGE we need to do a read
  1690. // again because we didn't get the entire message we expected from
  1691. // the server.
  1692. //
  1693. //
  1694. // receive response from server and pass token into security pkg
  1695. // BUT only if we haven't already received extra data
  1696. // from SSPI which we need to process in lu of actual data
  1697. // data from WinSock, and if the package has not returned
  1698. // one of the defined warnings that indicates that we should
  1699. // pass the previous buffer again.
  1700. //
  1701. // Make sure fsm.m_lpszBuffer holds the input data to be passed
  1702. // to initialize security context. There are 4 cases:
  1703. // 1) We have Extra Data, so we don't need to do a socket receive
  1704. // 2) We were called during a re-negotiate, so if this is the first
  1705. // time through the loop, we have 0 bytes.
  1706. // 3) We are recovering from a SEC_I_INCOMPLETE_CREDENTIALS, so
  1707. // use the same buffer again.
  1708. // 4) We do a SocketReceive
  1709. // We'll indicate 1 and 3 by having the fsm.m_dwBytesReceived count being the number of bytes
  1710. // left in the buffer to be re-sent or sent to the sspi call.
  1711. // If bytes-received is zero, then either we are doing a Redo, or we need to receive
  1712. // data. fsm.m_bDoRead let's us know if for some reason we should do or not do this read
  1713. if ((0 == fsm.m_dwBytesReceived) || (fsm.m_scRet == SEC_E_INCOMPLETE_MESSAGE)) {
  1714. if (fsm.m_bDoRead) {
  1715. fsm.SetFunctionState(FSM_STATE_2);
  1716. error = ICSocket::Receive((LPVOID *)&fsm.m_lpszBuffer,
  1717. &fsm.m_dwBufferLength,
  1718. &fsm.m_dwBufferLeft,
  1719. &fsm.m_dwBytesReceived,
  1720. 0,
  1721. SF_EXPAND,
  1722. &fsm.m_bEofReceive
  1723. );
  1724. if (error == ERROR_IO_PENDING) {
  1725. goto done;
  1726. }
  1727. receive_continue:
  1728. if ((error != ERROR_SUCCESS) || fsm.m_bEofReceive) {
  1729. DEBUG_PRINT(API,
  1730. ERROR,
  1731. ("SocketReceive failed\n"
  1732. ));
  1733. if (error == ERROR_SUCCESS) {
  1734. error = ERROR_INTERNET_CANNOT_CONNECT;
  1735. }
  1736. break;
  1737. }
  1738. } else {
  1739. fsm.m_bDoRead = TRUE;
  1740. }
  1741. }
  1742. if (fsm.m_scRet == SEC_I_INCOMPLETE_CREDENTIALS) {
  1743. CERT_CONTEXT_ARRAY* pCertContextArray;
  1744. //
  1745. // If've already done Client Auth, and it fails again
  1746. // then we fail.
  1747. //
  1748. if (fsm.m_bDoingClientAuth) {
  1749. error = ERROR_CANCELLED;
  1750. goto quit;
  1751. }
  1752. //
  1753. // If we don't already have a cert chain list,
  1754. // then get one, and make our selection
  1755. //
  1756. INET_ASSERT(!GetCertContextArray());
  1757. pCertContextArray = NULL;
  1758. //delete pCertChainList;
  1759. //SetCertChainList(NULL);
  1760. error = CliAuthAcquireCertContexts(
  1761. &m_hContext,
  1762. SecProviders[fsm.m_dwProviderIndex].pszName,
  1763. &pCertContextArray
  1764. );
  1765. SetCertContextArray(pCertContextArray);
  1766. if (error == ERROR_SUCCESS) {
  1767. error = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED;
  1768. }
  1769. fsm.m_scRet = error;
  1770. break;
  1771. }
  1772. //
  1773. // InBuffers[1] is for getting extra data that
  1774. // SSPI/SCHANNEL doesn't proccess on this
  1775. // run around the loop.
  1776. //
  1777. fsm.m_InBuffers[0].pvBuffer = fsm.m_lpszBuffer;
  1778. fsm.m_InBuffers[0].cbBuffer = fsm.m_dwBytesReceived;
  1779. fsm.m_InBuffers[0].BufferType = SECBUFFER_TOKEN;
  1780. fsm.m_InBuffers[1].pvBuffer = NULL;
  1781. fsm.m_InBuffers[1].cbBuffer = 0;
  1782. fsm.m_InBuffers[1].BufferType = SECBUFFER_EMPTY;
  1783. //
  1784. // Initialize these so if we fail, pvBuffer contains NULL,
  1785. // so we don't try to free random garbage at the quit
  1786. //
  1787. fsm.m_OutBuffers[0].pvBuffer = NULL;
  1788. fsm.m_OutBuffers[0].BufferType = SECBUFFER_TOKEN;
  1789. fsm.m_OutBuffers[0].cbBuffer = 0;
  1790. SecBufferDesc InBuffer;
  1791. InBuffer.cBuffers = 2;
  1792. InBuffer.pBuffers = fsm.m_InBuffers;
  1793. InBuffer.ulVersion = SECBUFFER_VERSION;
  1794. DWORD ContextAttr;
  1795. TimeStamp tsExpiry;
  1796. fsm.m_scRet = g_InitializeSecurityContext(&fsm.m_hCreds,
  1797. &m_hContext,
  1798. NULL,
  1799. fsm.m_dwSSPIFlags,
  1800. 0,
  1801. SECURITY_NATIVE_DREP,
  1802. &InBuffer,
  1803. 0,
  1804. NULL,
  1805. &fsm.m_OutBuffer,
  1806. &ContextAttr,
  1807. &tsExpiry
  1808. );
  1809. DEBUG_PRINT(API,
  1810. INFO,
  1811. ("3. InitializeSecurityContext returned %s [%x]\n",
  1812. InternetMapSSPIError((DWORD)fsm.m_scRet),
  1813. fsm.m_scRet
  1814. ));
  1815. if (fsm.m_scRet == STATUS_SUCCESS ||
  1816. fsm.m_scRet == SEC_I_CONTINUE_NEEDED ||
  1817. (FAILED(fsm.m_scRet) && (0 != (ContextAttr & ISC_RET_EXTENDED_ERROR))))
  1818. {
  1819. if (fsm.m_OutBuffers[0].cbBuffer != 0 &&
  1820. fsm.m_OutBuffers[0].pvBuffer != NULL )
  1821. {
  1822. //
  1823. // Send response to server if there is one
  1824. //
  1825. fsm.SetFunctionState(FSM_STATE_3);
  1826. error = ICSocket::Send(fsm.m_OutBuffers[0].pvBuffer,
  1827. fsm.m_OutBuffers[0].cbBuffer,
  1828. 0
  1829. );
  1830. if (error == ERROR_IO_PENDING) {
  1831. goto done;
  1832. }
  1833. send_continue:
  1834. g_FreeContextBuffer(fsm.m_OutBuffers[0].pvBuffer);
  1835. fsm.m_OutBuffers[0].pvBuffer = NULL;
  1836. }
  1837. }
  1838. if ( fsm.m_scRet == STATUS_SUCCESS )
  1839. {
  1840. DEBUG_PRINT(API,
  1841. INFO,
  1842. ("NegotiateSecConnection succeeded.\n"));
  1843. if (fsm.m_pdblbufBuffer)
  1844. {
  1845. if ( fsm.m_InBuffers[1].BufferType == SECBUFFER_EXTRA )
  1846. {
  1847. fsm.m_pdblbufBuffer->CopyIn(
  1848. (LPBYTE) (fsm.m_lpszBuffer + (fsm.m_dwBytesReceived - fsm.m_InBuffers[1].cbBuffer)),
  1849. fsm.m_InBuffers[1].cbBuffer
  1850. );
  1851. }
  1852. else
  1853. {
  1854. fsm.m_pdblbufBuffer->SetInputBufferSize(0);
  1855. }
  1856. }
  1857. //
  1858. // Bail out to quit
  1859. //
  1860. break;
  1861. }
  1862. else if (FAILED(fsm.m_scRet) && (fsm.m_scRet != SEC_E_INCOMPLETE_MESSAGE))
  1863. {
  1864. //
  1865. // free security context handle and delete the local
  1866. // data structures associated with the handle and
  1867. // try another pkg if available
  1868. //
  1869. DEBUG_PRINT(API,
  1870. INFO,
  1871. ("3. InitializeSecurityContext failed, %lx\n",
  1872. fsm.m_scRet
  1873. ));
  1874. // Turn the error in to one we understand */
  1875. error = MapInternetError((DWORD)fsm.m_scRet);
  1876. TerminateSecConnection();
  1877. /* Break out to try next protocol */
  1878. break;
  1879. }
  1880. if ((fsm.m_scRet != SEC_E_INCOMPLETE_MESSAGE)
  1881. && (fsm.m_scRet != SEC_I_INCOMPLETE_CREDENTIALS)) {
  1882. DEBUG_PRINT(API,
  1883. INFO,
  1884. ("3. OutBuffer is <%x, %d, %x>\n",
  1885. fsm.m_OutBuffers[0].pvBuffer,
  1886. fsm.m_OutBuffers[0].cbBuffer,
  1887. fsm.m_OutBuffers[0].BufferType
  1888. ));
  1889. if (fsm.m_InBuffers[1].BufferType == SECBUFFER_EXTRA) {
  1890. //
  1891. // skip next recv and set up buffers
  1892. // so InitalizeSecurityContext pulls its
  1893. // info from the Extra it returned previously.
  1894. //
  1895. DEBUG_PRINT(API,
  1896. INFO,
  1897. ("Got SECBUFFER_EXTRA, moving %d bytes to front of buffer\n",
  1898. fsm.m_InBuffers[1].cbBuffer
  1899. ));
  1900. INET_ASSERT(fsm.m_InBuffers[1].cbBuffer > 0);
  1901. MoveMemory(
  1902. fsm.m_lpszBuffer, // dest
  1903. fsm.m_lpszBuffer + (fsm.m_dwBytesReceived - fsm.m_InBuffers[1].cbBuffer),
  1904. fsm.m_InBuffers[1].cbBuffer // size
  1905. );
  1906. fsm.m_dwBytesReceived = fsm.m_InBuffers[1].cbBuffer;
  1907. fsm.m_dwBufferLeft = fsm.m_dwBufferLength - fsm.m_dwBytesReceived;
  1908. } else {
  1909. //
  1910. // prepare for next receive
  1911. //
  1912. fsm.m_dwBufferLeft = fsm.m_dwBufferLength;
  1913. fsm.m_dwBytesReceived = 0;
  1914. }
  1915. }
  1916. }
  1917. quit:
  1918. if (fsm.m_lpszBuffer != NULL) {
  1919. fsm.m_lpszBuffer = (LPSTR)FREE_MEMORY(fsm.m_lpszBuffer);
  1920. INET_ASSERT(fsm.m_lpszBuffer == NULL);
  1921. }
  1922. done:
  1923. if (error != ERROR_IO_PENDING) {
  1924. fsm.SetDone();
  1925. }
  1926. DEBUG_LEAVE(error);
  1927. return error;
  1928. }
  1929. DWORD
  1930. ICSecureSocket::Disconnect(
  1931. IN DWORD dwFlags
  1932. )
  1933. /*++
  1934. Routine Description:
  1935. Undoes the work of ConnectSocket - i.e. closes a connected socket. We make
  1936. callbacks to inform the app that this socket is being closed
  1937. Arguments:
  1938. dwFlags - controlling operation
  1939. Return Value:
  1940. DWORD
  1941. Success - ERROR_SUCCESS
  1942. Failure - WSA error
  1943. --*/
  1944. {
  1945. DEBUG_ENTER((DBG_SOCKETS,
  1946. Dword,
  1947. "ICSecureSocket::Disconnect",
  1948. "{%#x} %#x",
  1949. m_Socket,
  1950. dwFlags
  1951. ));
  1952. INET_ASSERT(IsSecure());
  1953. DWORD error = ICSocket::Disconnect(dwFlags);
  1954. //
  1955. // delete security context handle for the connection
  1956. //
  1957. if ((m_dwFlags & (SF_ENCRYPT | SF_DECRYPT))
  1958. && dwEncFlags != ENC_CAPS_NOT_INSTALLED) {
  1959. TerminateSecConnection();
  1960. }
  1961. //
  1962. // Zero out the pending input buffer
  1963. //
  1964. if (m_pdblbufBuffer != NULL) {
  1965. m_pdblbufBuffer->SetInputBufferSize(0);
  1966. }
  1967. DEBUG_LEAVE(error);
  1968. return error;
  1969. }
  1970. DWORD
  1971. ICSecureSocket::Send(
  1972. IN LPVOID lpBuffer,
  1973. IN DWORD dwBufferLength,
  1974. IN DWORD dwFlags
  1975. )
  1976. /*++
  1977. Routine Description:
  1978. Sends data over a secure connection
  1979. Arguments:
  1980. lpBuffer - pointer to user data to send
  1981. dwBufferLength - length of user data
  1982. dwFlags - flags controlling operation
  1983. Return Value:
  1984. DWORD
  1985. Success - ERROR_SUCCESS
  1986. Failure -
  1987. --*/
  1988. {
  1989. DEBUG_ENTER((DBG_SOCKETS,
  1990. Dword,
  1991. "ICSecureSocket::Send",
  1992. "{%#x [%#x]} %#x, %d, %#x",
  1993. this,
  1994. m_Socket,
  1995. lpBuffer,
  1996. dwBufferLength,
  1997. dwFlags
  1998. ));
  1999. INET_ASSERT(lpBuffer != NULL);
  2000. INET_ASSERT((int)dwBufferLength > 0);
  2001. INET_ASSERT(IsSecure());
  2002. DWORD error = DoFsm(new CFsm_SecureSend(lpBuffer,
  2003. dwBufferLength,
  2004. dwFlags,
  2005. this
  2006. ));
  2007. DEBUG_LEAVE(error);
  2008. return error;
  2009. }
  2010. DWORD
  2011. CFsm_SecureSend::RunSM(
  2012. IN CFsm * Fsm
  2013. )
  2014. /*++
  2015. Routine Description:
  2016. description-of-function.
  2017. Arguments:
  2018. Fsm -
  2019. Return Value:
  2020. DWORD
  2021. --*/
  2022. {
  2023. DEBUG_ENTER((DBG_SOCKETS,
  2024. Dword,
  2025. "CFsm_SecureSend::RunSM",
  2026. "%#x",
  2027. Fsm
  2028. ));
  2029. ICSecureSocket * pSecureSocket = (ICSecureSocket *)Fsm->GetContext();
  2030. CFsm_SecureSend * stateMachine = (CFsm_SecureSend *)Fsm;
  2031. DWORD error;
  2032. switch (Fsm->GetState()) {
  2033. case FSM_STATE_INIT:
  2034. case FSM_STATE_CONTINUE:
  2035. error = pSecureSocket->Send_Fsm(stateMachine);
  2036. break;
  2037. default:
  2038. error = ERROR_INTERNET_INTERNAL_ERROR;
  2039. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  2040. INET_ASSERT(FALSE);
  2041. break;
  2042. }
  2043. DEBUG_LEAVE(error);
  2044. return error;
  2045. }
  2046. DWORD
  2047. ICSecureSocket::Send_Fsm(
  2048. IN CFsm_SecureSend * Fsm
  2049. )
  2050. /*++
  2051. Routine Description:
  2052. description-of-function.
  2053. Arguments:
  2054. Fsm -
  2055. Return Value:
  2056. DWORD
  2057. --*/
  2058. {
  2059. DEBUG_ENTER((DBG_SOCKETS,
  2060. Dword,
  2061. "ICSecureSocket::Send_Fsm",
  2062. "%#x",
  2063. Fsm
  2064. ));
  2065. CFsm_SecureSend & fsm = *Fsm;
  2066. DWORD error = fsm.GetError();
  2067. if (fsm.GetState() == FSM_STATE_INIT) {
  2068. //
  2069. // Log The Data BEFORE we Encrypt It ( if we do )
  2070. //
  2071. DEBUG_DUMP_API(SOCKETS,
  2072. "sending data:\n",
  2073. fsm.m_lpBuffer,
  2074. fsm.m_dwBufferLength
  2075. );
  2076. }
  2077. while (((int)fsm.m_dwBufferLength > 0) && (error == ERROR_SUCCESS)) {
  2078. LPVOID lpBuffer;
  2079. DWORD dwLength;
  2080. DWORD dwBytes;
  2081. if (m_dwFlags & SF_ENCRYPT) {
  2082. DWORD dwBytesEncrypted;
  2083. DEBUG_PRINT(SOCKETS,
  2084. INFO,
  2085. ("Encrypting data..\n"
  2086. ));
  2087. error = EncryptData(fsm.m_lpBuffer,
  2088. fsm.m_dwBufferLength,
  2089. &fsm.m_lpCryptBuffer,
  2090. &fsm.m_dwCryptBufferLength,
  2091. &dwBytesEncrypted
  2092. );
  2093. if (error != ERROR_SUCCESS) {
  2094. break;
  2095. }
  2096. INET_ASSERT(fsm.m_lpCryptBuffer != NULL);
  2097. INET_ASSERT((int)fsm.m_dwCryptBufferLength > 0);
  2098. INET_ASSERT(dwBytesEncrypted <= fsm.m_dwBufferLength);
  2099. lpBuffer = fsm.m_lpCryptBuffer;
  2100. dwLength = fsm.m_dwCryptBufferLength;
  2101. dwBytes = dwBytesEncrypted;
  2102. } else {
  2103. lpBuffer = fsm.m_lpBuffer;
  2104. dwLength = fsm.m_dwBufferLength;
  2105. dwBytes = dwLength;
  2106. }
  2107. fsm.m_lpBuffer = (LPVOID)((LPBYTE)fsm.m_lpBuffer + dwBytes);
  2108. fsm.m_dwBufferLength -= dwBytes;
  2109. error = ICSocket::Send(lpBuffer, dwLength, fsm.m_dwFlags);
  2110. if (error != ERROR_SUCCESS) {
  2111. break;
  2112. }
  2113. }
  2114. if (error != ERROR_IO_PENDING) {
  2115. fsm.SetDone();
  2116. //
  2117. // Free Encryption Buffer if doing SSL/PCT
  2118. //
  2119. if (fsm.m_lpCryptBuffer != NULL ) {
  2120. fsm.m_lpCryptBuffer = (LPVOID)FREE_MEMORY(fsm.m_lpCryptBuffer);
  2121. INET_ASSERT(fsm.m_lpCryptBuffer == NULL);
  2122. }
  2123. }
  2124. DEBUG_LEAVE(error);
  2125. return error;
  2126. }
  2127. DWORD
  2128. ICSecureSocket::Receive(
  2129. IN OUT LPVOID* lplpBuffer,
  2130. IN OUT LPDWORD lpdwBufferLength,
  2131. IN OUT LPDWORD lpdwBufferRemaining,
  2132. IN OUT LPDWORD lpdwBytesReceived,
  2133. IN DWORD dwExtraSpace,
  2134. IN DWORD dwFlags,
  2135. OUT LPBOOL lpbEof
  2136. )
  2137. /*++
  2138. Routine Description:
  2139. Receives and decrypts data from a secure connection
  2140. Arguments:
  2141. lplpBuffer - see ICSocket::Receive
  2142. lpdwBufferLength -
  2143. lpdwBufferRemaining -
  2144. lpdwBytesReceived -
  2145. dwExtraSpace -
  2146. dwFlags -
  2147. lpbEof -
  2148. Return Value:
  2149. DWORD
  2150. Success - ERROR_SUCCESS
  2151. Failure -
  2152. --*/
  2153. {
  2154. INET_ASSERT(lplpBuffer != NULL);
  2155. INET_ASSERT(lpdwBufferLength != NULL);
  2156. INET_ASSERT((*lpdwBufferLength == 0) ? (dwFlags & SF_EXPAND) : TRUE);
  2157. INET_ASSERT(IsSecure());
  2158. DEBUG_ENTER((DBG_SOCKETS,
  2159. Dword,
  2160. "ICSecureSocket::Receive",
  2161. "%#x [%#x], %#x [%d], %#x [%d], %#x [%d], %d, %#x, %#x [%B]",
  2162. lplpBuffer,
  2163. *lplpBuffer,
  2164. lpdwBufferLength,
  2165. *lpdwBufferLength,
  2166. lpdwBufferRemaining,
  2167. *lpdwBufferRemaining,
  2168. lpdwBytesReceived,
  2169. *lpdwBytesReceived,
  2170. dwExtraSpace,
  2171. dwFlags,
  2172. lpbEof,
  2173. *lpbEof
  2174. ));
  2175. DWORD error = DoFsm(new CFsm_SecureReceive(lplpBuffer,
  2176. lpdwBufferLength,
  2177. lpdwBufferRemaining,
  2178. lpdwBytesReceived,
  2179. dwExtraSpace,
  2180. dwFlags,
  2181. lpbEof,
  2182. this
  2183. ));
  2184. DEBUG_LEAVE(error);
  2185. return error;
  2186. }
  2187. DWORD
  2188. CFsm_SecureReceive::RunSM(
  2189. IN CFsm * Fsm
  2190. )
  2191. /*++
  2192. Routine Description:
  2193. description-of-function.
  2194. Arguments:
  2195. Fsm -
  2196. Return Value:
  2197. DWORD
  2198. --*/
  2199. {
  2200. DEBUG_ENTER((DBG_SOCKETS,
  2201. Dword,
  2202. "CFsm_SecureReceive::RunSM",
  2203. "%#x",
  2204. Fsm
  2205. ));
  2206. ICSecureSocket * pSecureSocket = (ICSecureSocket *)Fsm->GetContext();
  2207. CFsm_SecureReceive * stateMachine = (CFsm_SecureReceive *)Fsm;
  2208. DWORD error;
  2209. switch (Fsm->GetState()) {
  2210. case FSM_STATE_INIT:
  2211. case FSM_STATE_CONTINUE:
  2212. error = pSecureSocket->Receive_Fsm(stateMachine);
  2213. break;
  2214. default:
  2215. error = ERROR_INTERNET_INTERNAL_ERROR;
  2216. Fsm->SetDone(ERROR_INTERNET_INTERNAL_ERROR);
  2217. INET_ASSERT(FALSE);
  2218. break;
  2219. }
  2220. DEBUG_LEAVE(error);
  2221. return error;
  2222. }
  2223. DWORD
  2224. ICSecureSocket::Receive_Fsm(
  2225. IN CFsm_SecureReceive * Fsm
  2226. )
  2227. /*++
  2228. Routine Description:
  2229. description-of-function.
  2230. Arguments:
  2231. Fsm -
  2232. Return Value:
  2233. DWORD
  2234. --*/
  2235. {
  2236. DEBUG_ENTER((DBG_SOCKETS,
  2237. Dword,
  2238. "ICSecureSocket::Receive_Fsm",
  2239. "%#x",
  2240. Fsm
  2241. ));
  2242. //INET_ASSERT(m_dwFlags & SF_DECRYPT);
  2243. CFsm_SecureReceive & fsm = *Fsm;
  2244. DWORD error = fsm.GetError();
  2245. LPVOID * lplpBuffer;
  2246. LPDWORD lpdwBufferLength;
  2247. LPDWORD lpdwBufferLeft;
  2248. LPDWORD lpdwBytesReceived;
  2249. if (fsm.GetState() != FSM_STATE_INIT) {
  2250. switch (fsm.GetFunctionState()) {
  2251. case FSM_STATE_2:
  2252. goto negotiate_continue;
  2253. case FSM_STATE_3:
  2254. goto receive_continue;
  2255. default:
  2256. error = ERROR_INTERNET_INTERNAL_ERROR;
  2257. INET_ASSERT(FALSE);
  2258. goto quit;
  2259. }
  2260. }
  2261. //
  2262. // if we weren't given a buffer, but the caller told us its okay to resize
  2263. // then we allocate the initial buffer
  2264. //
  2265. if ((fsm.m_dwBufferLength == 0) || (fsm.m_dwBufferLeft == 0)) {
  2266. INET_ASSERT((fsm.m_dwBufferLength == 0) ? (fsm.m_dwBufferLeft == 0) : TRUE);
  2267. if (fsm.m_dwFlags & SF_EXPAND) {
  2268. //
  2269. // allocate a fixed memory buffer
  2270. //
  2271. //
  2272. // BUGBUG - the initial buffer size should come from the handle
  2273. // object
  2274. //
  2275. fsm.m_dwBufferLeft = DEFAULT_RECEIVE_BUFFER_INCREMENT;
  2276. if (fsm.m_dwBufferLength == 0) {
  2277. fsm.m_bAllocated = TRUE;
  2278. }
  2279. fsm.m_dwBufferLength += fsm.m_dwBufferLeft;
  2280. DEBUG_PRINT(SOCKETS,
  2281. INFO,
  2282. ("resizing %#x to %d\n",
  2283. fsm.m_hBuffer,
  2284. fsm.m_dwBufferLength
  2285. ));
  2286. fsm.m_hBuffer = ResizeBuffer(fsm.m_hBuffer,
  2287. fsm.m_dwBufferLength,
  2288. FALSE);
  2289. if (fsm.m_hBuffer == (HLOCAL)NULL) {
  2290. error = GetLastError();
  2291. INET_ASSERT(error != ERROR_SUCCESS);
  2292. fsm.m_bAllocated = FALSE;
  2293. }
  2294. } else {
  2295. //
  2296. // the caller didn't say its okay to resize
  2297. //
  2298. error = ERROR_INSUFFICIENT_BUFFER;
  2299. }
  2300. } else if (fsm.m_hBuffer == (HLOCAL)NULL) {
  2301. error = ERROR_INSUFFICIENT_BUFFER;
  2302. }
  2303. if (error != ERROR_SUCCESS) {
  2304. goto quit;
  2305. }
  2306. //
  2307. // keep the app informed (if requested to do so)
  2308. //
  2309. if (fsm.m_dwFlags & SF_INDICATE) {
  2310. InternetIndicateStatus(INTERNET_STATUS_RECEIVING_RESPONSE,
  2311. NULL,
  2312. 0
  2313. );
  2314. }
  2315. fsm.m_dwReadFlags = fsm.m_dwFlags;
  2316. //
  2317. // Loop Through our Reads, assembling enough unencrypted bytes
  2318. // to return back to the client. In the non-SSL/PCT case, we should
  2319. // be able to quit after one iteration.
  2320. //
  2321. do {
  2322. LPVOID * lplpReadBuffer;
  2323. LPDWORD lpdwReadBufferLength;
  2324. LPDWORD lpdwReadBufferLeft;
  2325. LPDWORD lpdwReadBufferReceived;
  2326. //
  2327. // If we're attempting to read SSL/PCT data, we need examine, whether
  2328. // we have all the bytes decrypted and read already in our scratch buffer.
  2329. //
  2330. if (m_dwFlags & SF_DECRYPT) {
  2331. DEBUG_PRINT(SOCKETS,
  2332. INFO,
  2333. ("Decrypting data..\n"
  2334. ));
  2335. if (m_pdblbufBuffer != NULL) {
  2336. DEBUG_DUMP_API(SOCKETS,
  2337. "About to decrypt this data:\n",
  2338. (LPBYTE)m_pdblbufBuffer->GetInputBufferPointer(),
  2339. m_pdblbufBuffer->GetInputBufferSize()
  2340. );
  2341. }
  2342. fsm.m_dwDecryptError = DecryptData(&fsm.m_dwInputBytesLeft,
  2343. (LPBYTE)fsm.m_hBuffer,
  2344. &fsm.m_dwBufferLeft,
  2345. &fsm.m_dwBytesReceived,
  2346. &fsm.m_dwBytesRead
  2347. );
  2348. if (fsm.m_dwDecryptError == SEC_E_INCOMPLETE_MESSAGE &&
  2349. fsm.m_bEof &&
  2350. m_pdblbufBuffer->GetInputBufferSize() > 0) {
  2351. error = ERROR_HTTP_INVALID_SERVER_RESPONSE;
  2352. goto error_exit;
  2353. }
  2354. else if (fsm.m_dwDecryptError == SEC_I_RENEGOTIATE) {
  2355. CredHandle hDummyCreds;
  2356. //
  2357. // BUGBUG - don't have to do this - Receive() called from
  2358. // SSPINegotiateLoop() won't come back through here
  2359. //
  2360. m_dwFlags &= ~(SF_ENCRYPT | SF_DECRYPT);
  2361. ClearCreds(hDummyCreds);
  2362. fsm.SetFunctionState(FSM_STATE_2);
  2363. error = SSPINegotiateLoop(m_pdblbufBuffer,
  2364. fsm.m_dwFlags,
  2365. hDummyCreds,
  2366. FALSE,
  2367. FALSE);
  2368. if (error == ERROR_IO_PENDING) {
  2369. goto error_exit;
  2370. }
  2371. negotiate_continue:
  2372. m_dwFlags |= (SF_ENCRYPT | SF_DECRYPT);
  2373. if (error != ERROR_SUCCESS) {
  2374. break;
  2375. }
  2376. fsm.m_dwDecryptError = (ULONG)SEC_E_INCOMPLETE_MESSAGE;
  2377. //
  2378. // If there was extra data, and it was shoved back into
  2379. // dblbuffer, then we should redo the decryption, since
  2380. // it now has extra input data to process.
  2381. //
  2382. if (m_pdblbufBuffer->GetInputBufferSize() > 0) {
  2383. continue;
  2384. }
  2385. //
  2386. // Okay, here we've received 0 bytes, so so we have to
  2387. // receive more data, and process it. Do this by zero-ing
  2388. // out the input buffer, and setting the decrypt_error to be
  2389. // Incomplete.
  2390. //
  2391. }
  2392. //
  2393. // If we have no buffer left to fill, or the caller ask for a single recv
  2394. // and we've managed to read something into the buffer, then return by breaking.
  2395. //
  2396. if ((fsm.m_dwBufferLeft == 0)
  2397. || (!(fsm.m_dwFlags & SF_RECEIVE_ALL) && (fsm.m_dwBytesRead > 0))) {
  2398. break; // we're done.
  2399. }
  2400. INET_ASSERT(error == ERROR_SUCCESS);
  2401. //
  2402. // BUGBUG [arthurbi] GetInputBufferSize needs to be called before getting
  2403. // the pointer, because the pointer may be moved around while generating
  2404. // the size.
  2405. //
  2406. DWORD remaining;
  2407. DWORD inputSize;
  2408. inputSize = m_pdblbufBuffer->GetInputBufferSize();
  2409. remaining = m_pdblbufBuffer->GetInputBufferRemaining();
  2410. fsm.m_dwBufferLengthDummy = inputSize + remaining;
  2411. fsm.m_dwBufferLeftDummy = remaining;
  2412. fsm.m_dwBufferReceivedDummy = inputSize;
  2413. fsm.m_lpBufferDummy = m_pdblbufBuffer->GetInputBufferPointer();
  2414. //
  2415. // We need to be careful, and only recv one block of data at a time
  2416. // if we're not we break keep-alive by doing too many reads.
  2417. //
  2418. // So unless we know ( by the non-0 return ) exactly how many bytes
  2419. // to read, we shut off SF_RECEIVE_ALL.
  2420. //
  2421. fsm.m_dwReadFlags &= ~(SF_RECEIVE_ALL
  2422. | SF_INDICATE
  2423. | SF_EXPAND
  2424. | SF_COMPRESS
  2425. );
  2426. if (fsm.m_dwInputBytesLeft != 0) {
  2427. //
  2428. // don't add RECEIVE_ALL if NO_WAIT already set by caller - they
  2429. // are mutually exclusive
  2430. //
  2431. if (!(fsm.m_dwReadFlags & SF_NO_WAIT)) {
  2432. fsm.m_dwReadFlags |= SF_RECEIVE_ALL;
  2433. }
  2434. fsm.m_dwBufferLeftDummy = min(fsm.m_dwInputBytesLeft,
  2435. fsm.m_dwBufferLeftDummy);
  2436. }
  2437. lplpReadBuffer = (LPVOID *)&fsm.m_lpBufferDummy;
  2438. lpdwReadBufferLength = &fsm.m_dwBufferLengthDummy;
  2439. lpdwReadBufferLeft = &fsm.m_dwBufferLeftDummy;
  2440. lpdwReadBufferReceived = &fsm.m_dwBufferReceivedDummy;
  2441. } else {
  2442. lplpReadBuffer = &fsm.m_hBuffer;
  2443. lpdwReadBufferLength = &fsm.m_dwBufferLength;
  2444. lpdwReadBufferLeft = &fsm.m_dwBufferLeft;
  2445. lpdwReadBufferReceived = &fsm.m_dwBytesReceived;
  2446. }
  2447. //
  2448. // receive some data, assuming the socket is not closed.
  2449. //
  2450. if (!fsm.m_bEof) {
  2451. //fsm.m_dwBytesReceivedPre = *lpdwReadBufferReceived;
  2452. fsm.SetFunctionState(FSM_STATE_3);
  2453. error = ICSocket::Receive(lplpReadBuffer,
  2454. lpdwReadBufferLength,
  2455. lpdwReadBufferLeft,
  2456. lpdwReadBufferReceived,
  2457. fsm.m_dwExtraSpace,
  2458. fsm.m_dwReadFlags,
  2459. &fsm.m_bEof
  2460. );
  2461. if (error == ERROR_IO_PENDING) {
  2462. goto error_exit;
  2463. }
  2464. receive_continue:
  2465. //fsm.m_dwBytesRead += fsm.m_dwByReceived - fsm.m_dwDCBufferRecvPre;
  2466. if (error != ERROR_SUCCESS) {
  2467. goto quit;
  2468. }
  2469. //
  2470. // Once again, for SSL/PCT we need to update our input buffer after the read.
  2471. //
  2472. if (m_dwFlags & SF_DECRYPT) {
  2473. m_pdblbufBuffer->SetInputBufferSize(fsm.m_dwBufferReceivedDummy);
  2474. }
  2475. }
  2476. } while ((m_dwFlags & SF_DECRYPT)
  2477. && (error == ERROR_SUCCESS)
  2478. && (fsm.m_dwDecryptError == SEC_E_INCOMPLETE_MESSAGE)
  2479. && (!fsm.m_bEof || (m_pdblbufBuffer->GetInputBufferSize() > 0)));
  2480. if (error == ERROR_SUCCESS) {
  2481. //
  2482. // inform the app that we finished, and tell it how much we received
  2483. // this time
  2484. //
  2485. if (fsm.m_dwFlags & SF_INDICATE) {
  2486. InternetIndicateStatus(INTERNET_STATUS_RESPONSE_RECEIVED,
  2487. &fsm.m_dwBytesRead,
  2488. sizeof(fsm.m_dwBytesRead)
  2489. );
  2490. }
  2491. //
  2492. // if we received the entire response and the caller specified
  2493. // SF_COMPRESS then we shrink the buffer to fit. We may end up growing
  2494. // the buffer to contain dwExtraSpace if it is not zero and we just
  2495. // happened to fill the current buffer
  2496. //
  2497. if (fsm.m_bEof && (fsm.m_dwFlags & SF_COMPRESS)) {
  2498. fsm.m_dwBufferLeft = fsm.m_dwExtraSpace;
  2499. //
  2500. // include any extra that the caller required
  2501. //
  2502. fsm.m_dwBufferLength = fsm.m_dwBytesReceived + fsm.m_dwExtraSpace;
  2503. DEBUG_PRINT(SOCKETS,
  2504. INFO,
  2505. ("shrinking buffer %#x to %d (%#x) bytes (includes %d extra)\n",
  2506. fsm.m_hBuffer,
  2507. fsm.m_dwBufferLength,
  2508. fsm.m_dwBufferLength,
  2509. fsm.m_dwExtraSpace
  2510. ));
  2511. fsm.m_hBuffer = ResizeBuffer(fsm.m_hBuffer,
  2512. fsm.m_dwBufferLength,
  2513. FALSE);
  2514. INET_ASSERT((fsm.m_hBuffer == NULL)
  2515. ? ((fsm.m_dwBytesReceived + fsm.m_dwExtraSpace) == 0)
  2516. : TRUE
  2517. );
  2518. }
  2519. DEBUG_PRINT_API(SOCKETS,
  2520. INFO,
  2521. ("read %d bytes @ %#x from socket %#x\n",
  2522. fsm.m_dwBytesRead,
  2523. (LPBYTE)fsm.m_hBuffer + *fsm.m_lpdwBytesReceived,
  2524. m_Socket
  2525. ));
  2526. DEBUG_DUMP_API(SOCKETS,
  2527. "received data:\n",
  2528. (LPBYTE)fsm.m_hBuffer + *fsm.m_lpdwBytesReceived,
  2529. fsm.m_dwBytesRead
  2530. );
  2531. }
  2532. quit:
  2533. //
  2534. // if we failed but allocated a buffer then we need to free it (we were
  2535. // leaking this buffer if the request was cancelled)
  2536. //
  2537. if ((error != ERROR_SUCCESS) && fsm.m_bAllocated && (fsm.m_hBuffer != NULL)) {
  2538. //dprintf("SocketReceive() freeing allocated buffer %#x\n", hBuffer);
  2539. fsm.m_hBuffer = (HLOCAL)FREE_MEMORY(fsm.m_hBuffer);
  2540. INET_ASSERT(fsm.m_hBuffer == NULL);
  2541. fsm.m_dwBufferLength = 0;
  2542. fsm.m_dwBufferLeft = 0;
  2543. fsm.m_dwBytesReceived = 0;
  2544. fsm.m_bEof = TRUE;
  2545. }
  2546. DEBUG_PRINT(SOCKETS,
  2547. INFO,
  2548. ("returning: lpBuffer=%#x, bufferLength=%d, bufferLeft=%d, bytesReceived=%d\n",
  2549. fsm.m_hBuffer,
  2550. fsm.m_dwBufferLength,
  2551. fsm.m_dwBufferLeft,
  2552. fsm.m_dwBytesReceived
  2553. ));
  2554. //
  2555. // update output parameters
  2556. //
  2557. *fsm.m_lplpBuffer = (LPVOID)fsm.m_hBuffer;
  2558. *fsm.m_lpdwBufferLength = fsm.m_dwBufferLength;
  2559. *fsm.m_lpdwBufferRemaining = fsm.m_dwBufferLeft;
  2560. *fsm.m_lpdwBytesReceived = fsm.m_dwBytesReceived;
  2561. //
  2562. // Hack, we hide eof's from caller, since we may have buffered data sitting around
  2563. //
  2564. if ((m_dwFlags & SF_DECRYPT) && (fsm.m_dwBytesRead != 0)) {
  2565. fsm.m_bEof = FALSE;
  2566. }
  2567. *fsm.m_lpbEof = fsm.m_bEof;
  2568. //
  2569. // map any sockets error to WinInet error
  2570. //
  2571. if (error != ERROR_SUCCESS) {
  2572. error = MapInternetError(error);
  2573. }
  2574. error_exit:
  2575. if (error != ERROR_IO_PENDING) {
  2576. fsm.SetDone();
  2577. }
  2578. DEBUG_LEAVE(error);
  2579. return error;
  2580. }
  2581. DWORD
  2582. ICSecureSocket::SetHostName(
  2583. IN LPSTR lpszHostName
  2584. )
  2585. /*++
  2586. Routine Description:
  2587. Set name of server we are connected to. Find or create a security cache
  2588. entry for this name
  2589. Arguments:
  2590. lpszHostName - name to set
  2591. Return Value:
  2592. DWORD
  2593. Success - ERROR_SUCCESS
  2594. Failure - ERROR_NOT_ENOUGH_MEMORY
  2595. --*/
  2596. {
  2597. DEBUG_ENTER((DBG_SOCKETS,
  2598. Dword,
  2599. "ICSecureSocket::SetHostName",
  2600. "{%#x [%q %#x/%d]} %q",
  2601. this,
  2602. m_lpszHostName,
  2603. GetSocket(),
  2604. GetSourcePort(),
  2605. lpszHostName
  2606. ));
  2607. INET_ASSERT(IsSecure());
  2608. INET_ASSERT((lpszHostName != NULL) || (m_lpszHostName == NULL));
  2609. DWORD error = ERROR_SUCCESS;
  2610. if (lpszHostName != NULL) {
  2611. if (m_lpszHostName != NULL) {
  2612. m_lpszHostName = (LPSTR)FREE_MEMORY(m_lpszHostName);
  2613. INET_ASSERT(m_lpszHostName == NULL);
  2614. }
  2615. m_lpszHostName = NewString(lpszHostName);
  2616. if (m_lpszHostName == NULL) {
  2617. error = ERROR_NOT_ENOUGH_MEMORY;
  2618. } else if (m_pSecurityInfo == NULL) {
  2619. /* SCLE ref */
  2620. m_pSecurityInfo = GlobalCertCache.Find(lpszHostName);
  2621. if (m_pSecurityInfo == NULL) {
  2622. /* SCLE ref */
  2623. m_pSecurityInfo = new SECURITY_CACHE_LIST_ENTRY(lpszHostName);
  2624. }
  2625. }
  2626. }
  2627. DEBUG_LEAVE(error);
  2628. return error;
  2629. }
  2630. //
  2631. // private ICSecureSocket methods
  2632. //
  2633. DWORD
  2634. ICSecureSocket::EncryptData(
  2635. IN LPVOID lpBuffer,
  2636. IN DWORD dwInBufferLen,
  2637. OUT LPVOID * lplpBuffer,
  2638. OUT LPDWORD lpdwOutBufferLen,
  2639. OUT LPDWORD lpdwInBufferBytesEncrypted
  2640. )
  2641. /*++
  2642. Routine Description:
  2643. This function encrypts data in the lplpbuffer.
  2644. Arguments:
  2645. lpBuffer - pointer to buffer containing unencrypted user data
  2646. dwInBufferLen - length of input buffer
  2647. lplpBuffer - pointer to pointer to encrypted user buffer
  2648. lpdwOutBufferLen - pointer to length of output lplpbuffer
  2649. lpdwInBufferBytesEncrypted - pointer to length of bytes read and encrypted in output buffer
  2650. Return Value:
  2651. Error Code
  2652. --*/
  2653. {
  2654. DEBUG_ENTER((DBG_SOCKETS,
  2655. Dword,
  2656. "ICSecureSocket::EncryptData",
  2657. "%#x, %d, %#x, %#x, %#x",
  2658. lpBuffer,
  2659. dwInBufferLen,
  2660. lplpBuffer,
  2661. lpdwOutBufferLen,
  2662. lpdwInBufferBytesEncrypted
  2663. ));
  2664. SECURITY_STATUS scRet = STATUS_SUCCESS;
  2665. SecBufferDesc Buffer;
  2666. SecBuffer Buffers[3];
  2667. HLOCAL hBuffer;
  2668. DWORD error;
  2669. DWORD dwMaxDataBufferSize;
  2670. DWORD dwExtraInputBufferLen;
  2671. SecPkgContext_StreamSizes Sizes;
  2672. INET_ASSERT(IsSecure());
  2673. INET_ASSERT(lpBuffer != NULL);
  2674. INET_ASSERT(dwInBufferLen != 0);
  2675. INET_ASSERT(lplpBuffer != NULL);
  2676. INET_ASSERT(lpdwOutBufferLen != NULL);
  2677. INET_ASSERT(lpdwInBufferBytesEncrypted != NULL);
  2678. hBuffer = (HLOCAL) *lplpBuffer;
  2679. *lpdwOutBufferLen = 0;
  2680. *lpdwInBufferBytesEncrypted = 0;
  2681. //INET_ASSERT(hBuffer == NULL );
  2682. //
  2683. // find the header and trailer sizes
  2684. //
  2685. scRet = g_QueryContextAttributes(&m_hContext,
  2686. SECPKG_ATTR_STREAM_SIZES,
  2687. &Sizes );
  2688. if (scRet != ERROR_SUCCESS) {
  2689. //
  2690. // Map the SSPI error.
  2691. //
  2692. DEBUG_PRINT(API,
  2693. INFO,
  2694. ("QueryContextAttributes returned, %s [%x] (%s)\n",
  2695. InternetMapSSPIError((DWORD)scRet),
  2696. scRet,
  2697. InternetMapError(scRet)
  2698. ));
  2699. error = MapInternetError((DWORD) scRet);
  2700. goto quit;
  2701. } else {
  2702. DEBUG_PRINT(API,
  2703. INFO,
  2704. ("QueryContextAttributes returned header=%d, trailer=%d, maxmessage=%d\n",
  2705. Sizes.cbHeader,
  2706. Sizes.cbTrailer,
  2707. Sizes.cbMaximumMessage
  2708. ));
  2709. }
  2710. INET_ASSERT(Sizes.cbMaximumMessage > (Sizes.cbHeader + Sizes.cbTrailer));
  2711. //
  2712. // Figure out the max SSL packet we can send over the wire.
  2713. // If the data is too big to send, then remeber how much
  2714. // we did send, and how much we didn't send.
  2715. //
  2716. dwMaxDataBufferSize = Sizes.cbMaximumMessage - (Sizes.cbHeader + Sizes.cbTrailer);
  2717. dwExtraInputBufferLen =
  2718. (dwMaxDataBufferSize < dwInBufferLen ) ?
  2719. (dwInBufferLen - dwMaxDataBufferSize) : 0;
  2720. dwInBufferLen =
  2721. ( dwExtraInputBufferLen > 0 ) ?
  2722. dwMaxDataBufferSize :
  2723. dwInBufferLen;
  2724. DEBUG_PRINT(API,
  2725. INFO,
  2726. ("resizing %#x to %d\n",
  2727. hBuffer,
  2728. dwInBufferLen + Sizes.cbHeader + Sizes.cbTrailer
  2729. ));
  2730. hBuffer = ResizeBuffer(hBuffer,
  2731. dwInBufferLen + Sizes.cbHeader + Sizes.cbTrailer,
  2732. FALSE );
  2733. if (hBuffer == (HLOCAL)NULL) {
  2734. error = GetLastError();
  2735. INET_ASSERT(error != ERROR_SUCCESS);
  2736. goto quit;
  2737. }
  2738. //
  2739. // prepare data for SecBuffer
  2740. //
  2741. Buffers[0].pvBuffer = hBuffer;
  2742. Buffers[0].cbBuffer = Sizes.cbHeader;
  2743. Buffers[0].BufferType = SECBUFFER_TOKEN;
  2744. Buffers[1].pvBuffer = (LPBYTE)hBuffer + Sizes.cbHeader;
  2745. memcpy(Buffers[1].pvBuffer,
  2746. lpBuffer,
  2747. dwInBufferLen);
  2748. Buffers[1].cbBuffer = dwInBufferLen;
  2749. Buffers[1].BufferType = SECBUFFER_DATA;
  2750. //
  2751. // check if security pkg supports trailer: PCT does
  2752. //
  2753. if ( Sizes.cbTrailer ) {
  2754. Buffers[2].pvBuffer = (LPBYTE)hBuffer + Sizes.cbHeader + dwInBufferLen;
  2755. Buffers[2].cbBuffer = Sizes.cbTrailer;
  2756. Buffers[2].BufferType = SECBUFFER_TOKEN;
  2757. } else {
  2758. Buffers[2].pvBuffer = NULL;
  2759. Buffers[2].cbBuffer = 0;
  2760. Buffers[2].BufferType = SECBUFFER_EMPTY;
  2761. }
  2762. Buffer.cBuffers = 3;
  2763. Buffer.pBuffers = Buffers;
  2764. Buffer.ulVersion = SECBUFFER_VERSION;
  2765. scRet = g_SealMessage(&m_hContext,
  2766. 0,
  2767. &Buffer,
  2768. 0);
  2769. DEBUG_PRINT(API,
  2770. INFO,
  2771. ("SealMessage returned, %s [%x]\n",
  2772. InternetMapSSPIError((DWORD)scRet),
  2773. scRet
  2774. ));
  2775. if (scRet != ERROR_SUCCESS) {
  2776. //
  2777. // Map the SSPI error.
  2778. //
  2779. DEBUG_PRINT(API,
  2780. ERROR,
  2781. ("SealMessage returned, %s [%x]\n",
  2782. InternetMapSSPIError((DWORD)scRet),
  2783. scRet
  2784. ));
  2785. error = MapInternetError((DWORD) scRet);
  2786. if (hBuffer != NULL) {
  2787. FREE_MEMORY(hBuffer);
  2788. }
  2789. goto quit;
  2790. } else {
  2791. error = ERROR_SUCCESS;
  2792. }
  2793. *lplpBuffer = Buffers[0].pvBuffer;
  2794. *lpdwOutBufferLen = Sizes.cbHeader + Buffers[1].cbBuffer +
  2795. Buffers[2].cbBuffer;
  2796. *lpdwInBufferBytesEncrypted = dwInBufferLen;
  2797. DEBUG_PRINT(API,
  2798. INFO,
  2799. ("SealMessage returned Buffer = %x, EncryptBytes = %d, UnencryptBytes=%d\n",
  2800. *lplpBuffer,
  2801. *lpdwOutBufferLen,
  2802. dwInBufferLen
  2803. ));
  2804. quit:
  2805. DEBUG_LEAVE(error);
  2806. return error;
  2807. }
  2808. #define SSLPCT_SMALLESTHEADERCHUNK 3
  2809. DWORD
  2810. ICSecureSocket::DecryptData(
  2811. OUT DWORD * lpdwBytesNeeded,
  2812. OUT LPBYTE lpOutBuffer,
  2813. IN OUT LPDWORD lpdwOutBufferLeft,
  2814. IN OUT LPDWORD lpdwOutBufferReceived,
  2815. IN OUT LPDWORD lpdwOutBufferBytesRead
  2816. )
  2817. /*++
  2818. Routine Description:
  2819. This function decrypts data into the lpOutBuffer. It attempts to fill lpOutBuffer.
  2820. If it fails, it may do so because more bytes are
  2821. needed to fill lplpEncDecBuffer or lplpEndDecBuffer is not big enough to fully
  2822. contain a complete server generated SSL/PCT message.
  2823. Return Value:
  2824. Error Code
  2825. --*/
  2826. {
  2827. INET_ASSERT(IsSecure());
  2828. INET_ASSERT(lpOutBuffer);
  2829. INET_ASSERT(lpdwOutBufferBytesRead);
  2830. INET_ASSERT(lpdwBytesNeeded);
  2831. DEBUG_ENTER((DBG_SOCKETS,
  2832. Dword,
  2833. "ICSecureSocket::DecryptData",
  2834. "{%#x [%#x:%#x], %#x} %#x [%d], %#x, %#x [%d], %#x [%d], %#x [%d]",
  2835. &m_hContext,
  2836. m_hContext.dwUpper,
  2837. m_hContext.dwLower,
  2838. m_pdblbufBuffer,
  2839. lpdwBytesNeeded,
  2840. *lpdwBytesNeeded,
  2841. lpOutBuffer,
  2842. lpdwOutBufferLeft,
  2843. *lpdwOutBufferLeft,
  2844. lpdwOutBufferReceived,
  2845. *lpdwOutBufferReceived,
  2846. lpdwOutBufferBytesRead,
  2847. *lpdwOutBufferBytesRead
  2848. ));
  2849. SecBufferDesc Buffer;
  2850. SecBuffer Buffers[4]; // the 4 buffers are: header, data, trailer, extra
  2851. DWORD scRet = ERROR_SUCCESS;
  2852. *lpdwBytesNeeded = 0;
  2853. //
  2854. // HOW THIS THING WORKS:
  2855. // We sit in a loop, attempting to fill our passed in buffer with
  2856. // decrypted data. If there is no decrypted data we check to
  2857. // see if there is encrypted data sitting in our buffer.
  2858. //
  2859. // Assuming there is enough we decrypt a chunk, and place it in the
  2860. // output buffer of our double buffer class. We reloop and try to
  2861. // copy it to our passed in byffer.
  2862. //
  2863. // If there is more encrypted data, and more space to fill in
  2864. // the user buffer, we attempt to decrypt the next chunk of this.
  2865. //
  2866. // If we do not have enough data, we return with an error, and
  2867. // expect a network read to be done.
  2868. //
  2869. do {
  2870. //
  2871. // Check to see if we can fill up User buffer.
  2872. //
  2873. m_pdblbufBuffer->CopyOut(
  2874. lpOutBuffer,
  2875. lpdwOutBufferLeft,
  2876. lpdwOutBufferReceived,
  2877. lpdwOutBufferBytesRead
  2878. );
  2879. //
  2880. // If we've filled our output buffer, than exit with ERROR_SUCCESS
  2881. //
  2882. if ( *lpdwOutBufferLeft == 0)
  2883. {
  2884. break;
  2885. }
  2886. //
  2887. // If we've got less than ~3 bytes return so we can read more data.
  2888. //
  2889. if (m_pdblbufBuffer->GetInputBufferSize() < SSLPCT_SMALLESTHEADERCHUNK) {
  2890. scRet = (DWORD) SEC_E_INCOMPLETE_MESSAGE;
  2891. break;
  2892. }
  2893. //
  2894. // prepare data the SecBuffer for a call to SSL/PCT decryption code.
  2895. //
  2896. Buffers[0].pvBuffer = m_pdblbufBuffer->GetInputBufferPointer( );
  2897. Buffers[0].cbBuffer = m_pdblbufBuffer->GetInputBufferSize(); // # of bytes to decrypt
  2898. Buffers[0].BufferType = SECBUFFER_DATA;
  2899. int i;
  2900. for ( i = 1; i < 4; i++ )
  2901. {
  2902. //
  2903. // clear other 3 buffers for receving result from SSPI package
  2904. //
  2905. Buffers[i].pvBuffer = NULL;
  2906. Buffers[i].cbBuffer = 0;
  2907. Buffers[i].BufferType = SECBUFFER_EMPTY;
  2908. }
  2909. Buffer.cBuffers = 4; // the 4 buffers are: header, data, trailer, extra
  2910. Buffer.pBuffers = Buffers;
  2911. Buffer.ulVersion = SECBUFFER_VERSION;
  2912. //
  2913. // Decrypt the DATA !!!
  2914. //
  2915. scRet = g_UnsealMessage(&m_hContext,
  2916. &Buffer,
  2917. 0,
  2918. NULL );
  2919. DEBUG_PRINT(API,
  2920. INFO,
  2921. ("UnsealMessage returned, %s [%x]\n",
  2922. InternetMapSSPIError((DWORD)scRet),
  2923. scRet
  2924. ));
  2925. if ( scRet != ERROR_SUCCESS &&
  2926. scRet != SEC_I_RENEGOTIATE)
  2927. {
  2928. DEBUG_PRINT(API,
  2929. ERROR,
  2930. ("UnsealMessage failed, error %lx\n",
  2931. scRet
  2932. ));
  2933. INET_ASSERT( scRet != SEC_E_MESSAGE_ALTERED );
  2934. if ( scRet == SEC_E_INCOMPLETE_MESSAGE )
  2935. {
  2936. DWORD dwAddlBufferNeeded = Buffers[1].cbBuffer;
  2937. DEBUG_PRINT(API,
  2938. INFO,
  2939. ("UnsealMessage short of %d bytes\n",
  2940. dwAddlBufferNeeded
  2941. ));
  2942. //
  2943. // If we're missing data, return to get the missing data.
  2944. // But make sure we have enough room first!
  2945. //
  2946. if (!m_pdblbufBuffer->ResizeBufferIfNeeded(dwAddlBufferNeeded)) {
  2947. scRet = ERROR_NOT_ENOUGH_MEMORY;
  2948. }
  2949. *lpdwBytesNeeded = dwAddlBufferNeeded;
  2950. break;
  2951. }
  2952. else if ( scRet == 0x00090317 /*SEC_I_CONTEXT_EXPIRED*/)
  2953. {
  2954. //
  2955. // Ignore this error and treat this like a simple terminator
  2956. // to end the connection.
  2957. //
  2958. scRet = ERROR_SUCCESS;
  2959. }
  2960. else
  2961. {
  2962. break;
  2963. }
  2964. }
  2965. //
  2966. // Success we decrypted a block
  2967. //
  2968. LPBYTE lpExtraBuffer;
  2969. DWORD dwExtraBufferSize;
  2970. LPBYTE lpDecryptedBuffer;
  2971. DWORD dwDecryptedBufferSize;
  2972. lpDecryptedBuffer = (LPBYTE) Buffers[1].pvBuffer;
  2973. dwDecryptedBufferSize = Buffers[1].cbBuffer;
  2974. //
  2975. // BUGBUG [arthurbi] this is hack to work with the OLD SSLSSPI.DLL .
  2976. // They return extra on the second buffer instead of the third.
  2977. //
  2978. if ( Buffers[2].BufferType == SECBUFFER_EXTRA )
  2979. {
  2980. lpExtraBuffer = (LPBYTE) Buffers[2].pvBuffer;
  2981. dwExtraBufferSize = Buffers[2].cbBuffer;
  2982. }
  2983. else if ( Buffers[3].BufferType == SECBUFFER_EXTRA )
  2984. {
  2985. lpExtraBuffer = (LPBYTE) Buffers[3].pvBuffer;
  2986. dwExtraBufferSize = Buffers[3].cbBuffer;
  2987. }
  2988. else
  2989. {
  2990. lpExtraBuffer = NULL;
  2991. dwExtraBufferSize = 0;
  2992. }
  2993. m_pdblbufBuffer->SetOutputInputBuffer(
  2994. lpDecryptedBuffer,
  2995. dwDecryptedBufferSize,
  2996. lpExtraBuffer,
  2997. dwExtraBufferSize,
  2998. FALSE // don't combine.
  2999. );
  3000. if ( dwDecryptedBufferSize == 0 )
  3001. break; // No more data to process
  3002. INET_ASSERT( *lpdwOutBufferLeft ); // don't expect to get here this way.
  3003. } while ( *lpdwOutBufferLeft && scRet == ERROR_SUCCESS );
  3004. DEBUG_PRINT(API,
  3005. INFO,
  3006. ("DecryptData returning, "
  3007. "OutBuffer = %x, DecryptBytesRecv = %d\n",
  3008. lpOutBuffer,
  3009. *lpdwOutBufferBytesRead
  3010. ));
  3011. DEBUG_LEAVE((DWORD)scRet);
  3012. return ( scRet );
  3013. }
  3014. VOID
  3015. ICSecureSocket::TerminateSecConnection(
  3016. VOID
  3017. )
  3018. /*++
  3019. Routine Description:
  3020. This function deletes the security context handle which result
  3021. in deleting the local data structures with which they are associated.
  3022. Arguments:
  3023. None
  3024. Return Value:
  3025. None
  3026. --*/
  3027. {
  3028. DEBUG_ENTER((DBG_SOCKETS,
  3029. None,
  3030. "ICSecureSocket::TerminateSecConnection",
  3031. "{%#x [%#x:%#x]}",
  3032. this,
  3033. m_hContext.dwUpper,
  3034. m_hContext.dwLower
  3035. ));
  3036. INET_ASSERT(IsSecure());
  3037. //INET_ASSERT(m_hContext.dwLower != 0);
  3038. //INET_ASSERT(m_hContext.dwUpper != 0);
  3039. if (GlobalSecFuncTable) {
  3040. if (!((m_hContext.dwLower == 0) && (m_hContext.dwUpper == 0))) {
  3041. // There are cases where because of circular dependencies
  3042. // schannel could get unloaded before wininet. In that case
  3043. // this call could fault. This usually happens when the process
  3044. // is shutting down.
  3045. __try {
  3046. g_DeleteSecurityContext(&m_hContext);
  3047. } __except(EXCEPTION_EXECUTE_HANDLER) {
  3048. }
  3049. ENDEXCEPT
  3050. m_hContext.dwLower = m_hContext.dwUpper = 0;
  3051. }
  3052. } else {
  3053. DEBUG_PRINT(API,
  3054. ERROR,
  3055. ("Attempting to Delete a security context, with a NULL SSPI func table!(missing SCHANNEL.DLL?)\n"
  3056. ));
  3057. }
  3058. DEBUG_LEAVE(0);
  3059. }
  3060. #ifdef SECPKG_ATTR_PROTO_INFO
  3061. /*++
  3062. ProtoInfoToString:
  3063. This routine converts an SSPI SecPkgContext_ProtoInfo structure into a
  3064. string. The returned string must be released via LocalFree.
  3065. Arguments:
  3066. pProtoInfo supplies the SecPkgContext_ProtoInfo structure to be converted to
  3067. string representation.
  3068. Return Value:
  3069. Non-NULL is the address of the returned string. This must be freed via
  3070. LocalFree once it is no longer needed.
  3071. NULL implies no memory is available.
  3072. Author:
  3073. Doug Barlow (dbarlow) 4/23/1996
  3074. --*/
  3075. PRIVATE
  3076. LPTSTR
  3077. ProtoInfoToString(
  3078. IN const PSecPkgContext_ProtoInfo pProtoInfo)
  3079. {
  3080. TCHAR
  3081. szValue[32],
  3082. szSep[8];
  3083. LPTSTR
  3084. szFinal
  3085. = NULL;
  3086. DWORD
  3087. length;
  3088. length = GetLocaleInfo(
  3089. LOCALE_USER_DEFAULT,
  3090. LOCALE_SDECIMAL,
  3091. szSep,
  3092. sizeof(szSep) / sizeof(TCHAR));
  3093. if (0 >= length)
  3094. lstrcpy(szSep, TEXT("."));
  3095. length = wsprintf(
  3096. szValue,
  3097. TEXT("%d%s%d"),
  3098. pProtoInfo->majorVersion,
  3099. szSep,
  3100. pProtoInfo->minorVersion);
  3101. INET_ASSERT(sizeof(szValue) / sizeof(TCHAR) > length);
  3102. length = lstrlen(pProtoInfo->sProtocolName);
  3103. length += 2; // Space and Trailing NULL
  3104. length += lstrlen(szValue);
  3105. szFinal = (LPTSTR)ALLOCATE_MEMORY(LMEM_FIXED, length * sizeof(TCHAR));
  3106. if (NULL != szFinal)
  3107. {
  3108. lstrcpy(szFinal, pProtoInfo->sProtocolName);
  3109. lstrcat(szFinal, TEXT(" "));
  3110. lstrcat(szFinal, szValue);
  3111. }
  3112. return szFinal;
  3113. }
  3114. #endif