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.

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