Source code of Windows XP (NT5)
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.

1789 lines
48 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Secure channel support.
  4. // Code lifted from the SDK sample security\ssl.
  5. //
  6. // Copyright (C) Microsoft Corporation, 2000.
  7. //
  8. //----------------------------------------------------------------------------
  9. #include "pch.hpp"
  10. HMODULE g_hSecurity;
  11. SecurityFunctionTable g_SecurityFunc;
  12. HCERTSTORE g_hMyCertStore;
  13. enum
  14. {
  15. SEQ_INTERNAL = 0xffffff00
  16. };
  17. //----------------------------------------------------------------------------
  18. //
  19. // Basic schannel support functions.
  20. //
  21. //----------------------------------------------------------------------------
  22. void
  23. DbgDumpBuffers(PCSTR Name, SecBufferDesc* Desc)
  24. {
  25. #if 0
  26. ULONG i;
  27. g_NtDllCalls.DbgPrint("%s desc %p has %d buffers\n",
  28. Name, Desc, Desc->cBuffers);
  29. for (i = 0; i < Desc->cBuffers; i++)
  30. {
  31. g_NtDllCalls.DbgPrint(" type %d, %X bytes at %p\n",
  32. Desc->pBuffers[i].BufferType,
  33. Desc->pBuffers[i].cbBuffer,
  34. Desc->pBuffers[i].pvBuffer);
  35. }
  36. #endif
  37. }
  38. #if 0
  39. #define DSCHAN(Args) g_NtDllCalls.DbgPrint Args
  40. #define DumpBuffers(Name, Desc) DbgDumpBuffers(Name, Desc)
  41. #else
  42. #define DSCHAN(Args)
  43. #define DumpBuffers(Name, Desc)
  44. #endif
  45. #if 0
  46. #define DSCHAN_IO(Args) g_NtDllCalls.DbgPrint Args
  47. #define DumpBuffersIo(Name, Desc) DbgDumpBuffers(Name, Desc)
  48. #else
  49. #define DSCHAN_IO(Args)
  50. #define DumpBuffersIo(Name, Desc)
  51. #endif
  52. HRESULT
  53. LoadSecurityLibrary(void)
  54. {
  55. HRESULT Status;
  56. if ((Status = InitDynamicCalls(&g_Crypt32CallsDesc)) != S_OK)
  57. {
  58. return Status;
  59. }
  60. PSecurityFunctionTable pSecurityFunc;
  61. INIT_SECURITY_INTERFACE pInitSecurityInterface;
  62. if (g_hSecurity != NULL)
  63. {
  64. // Already loaded.
  65. return S_OK;
  66. }
  67. if (g_Crypt32Calls.CertOpenStore == NULL)
  68. {
  69. // Unable to load crypt32.dll.
  70. return HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
  71. }
  72. g_hSecurity = LoadLibrary("security.dll");
  73. if (g_hSecurity == NULL)
  74. {
  75. goto EH_Fail;
  76. }
  77. pInitSecurityInterface = (INIT_SECURITY_INTERFACE)
  78. GetProcAddress(g_hSecurity, "InitSecurityInterfaceA");
  79. if (pInitSecurityInterface == NULL)
  80. {
  81. goto EH_Dll;
  82. }
  83. pSecurityFunc = pInitSecurityInterface();
  84. if (pSecurityFunc == NULL)
  85. {
  86. goto EH_Dll;
  87. }
  88. memcpy(&g_SecurityFunc, pSecurityFunc, sizeof(g_SecurityFunc));
  89. return S_OK;
  90. EH_Dll:
  91. FreeLibrary(g_hSecurity);
  92. g_hSecurity = NULL;
  93. EH_Fail:
  94. return WIN32_LAST_STATUS();
  95. }
  96. HRESULT
  97. CreateCredentials(LPSTR pszUserName,
  98. BOOL fMachineStore,
  99. BOOL Server,
  100. ULONG dwProtocol,
  101. SCHANNEL_CRED* ScCreds,
  102. PCredHandle phCreds)
  103. {
  104. TimeStamp tsExpiry;
  105. SECURITY_STATUS Status;
  106. PCCERT_CONTEXT pCertContext = NULL;
  107. // Open the "MY" certificate store.
  108. if (g_hMyCertStore == NULL)
  109. {
  110. if (fMachineStore)
  111. {
  112. g_hMyCertStore = g_Crypt32Calls.
  113. CertOpenStore(CERT_STORE_PROV_SYSTEM,
  114. X509_ASN_ENCODING,
  115. 0,
  116. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  117. L"MY");
  118. }
  119. else
  120. {
  121. g_hMyCertStore = g_Crypt32Calls.
  122. CertOpenSystemStore(0, "MY");
  123. }
  124. if (!g_hMyCertStore)
  125. {
  126. Status = WIN32_LAST_STATUS();
  127. goto Exit;
  128. }
  129. }
  130. //
  131. // If a user name is specified, then attempt to find a client
  132. // certificate. Otherwise, just create a NULL credential.
  133. //
  134. if (pszUserName != NULL && *pszUserName)
  135. {
  136. // Find certificate. Note that this sample just searches for a
  137. // certificate that contains the user name somewhere in the subject
  138. // name. A real application should be a bit less casual.
  139. pCertContext = g_Crypt32Calls.
  140. CertFindCertificateInStore(g_hMyCertStore,
  141. X509_ASN_ENCODING,
  142. 0,
  143. CERT_FIND_SUBJECT_STR_A,
  144. pszUserName,
  145. NULL);
  146. if (pCertContext == NULL)
  147. {
  148. Status = WIN32_LAST_STATUS();
  149. goto Exit;
  150. }
  151. }
  152. //
  153. // Build Schannel credential structure. Currently, this sample only
  154. // specifies the protocol to be used (and optionally the certificate,
  155. // of course). Real applications may wish to specify other parameters
  156. // as well.
  157. //
  158. ZeroMemory(ScCreds, sizeof(*ScCreds));
  159. ScCreds->dwVersion = SCHANNEL_CRED_VERSION;
  160. if (pCertContext != NULL)
  161. {
  162. ScCreds->cCreds = 1;
  163. ScCreds->paCred = &pCertContext;
  164. }
  165. ScCreds->grbitEnabledProtocols = dwProtocol;
  166. if (!Server)
  167. {
  168. if (pCertContext != NULL)
  169. {
  170. ScCreds->dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
  171. }
  172. else
  173. {
  174. ScCreds->dwFlags |= SCH_CRED_USE_DEFAULT_CREDS;
  175. }
  176. ScCreds->dwFlags |= SCH_CRED_MANUAL_CRED_VALIDATION;
  177. }
  178. //
  179. // Create an SSPI credential.
  180. //
  181. //
  182. // NOTE: In theory, an application could enumerate the security packages
  183. // until it finds one with attributes it likes. Some applications
  184. // (such as IIS) enumerate the packages and call AcquireCredentialsHandle
  185. // on each until it finds one that accepts the SCHANNEL_CRED structure.
  186. // If an application has its heart set on using SSL, like this sample
  187. // does, then just hardcoding the UNISP_NAME package name when calling
  188. // AcquireCredentialsHandle is not a bad thing.
  189. //
  190. Status = g_SecurityFunc.AcquireCredentialsHandle(
  191. NULL, // Name of principal
  192. UNISP_NAME_A, // Name of package
  193. Server ? // Flags indicating use
  194. SECPKG_CRED_INBOUND :
  195. SECPKG_CRED_OUTBOUND,
  196. NULL, // Pointer to logon ID
  197. ScCreds, // Package specific data
  198. NULL, // Pointer to GetKey() func
  199. NULL, // Value to pass to GetKey()
  200. phCreds, // (out) Cred Handle
  201. &tsExpiry); // (out) Lifetime (optional)
  202. //
  203. // Free the certificate context. Schannel has already made its own copy.
  204. //
  205. if (pCertContext)
  206. {
  207. g_Crypt32Calls.CertFreeCertificateContext(pCertContext);
  208. }
  209. Exit:
  210. DSCHAN(("CreateCredentials returns %X\n", Status));
  211. return Status;
  212. }
  213. HRESULT
  214. VerifyRemoteCertificate(PCtxtHandle Context,
  215. PSTR pszServerName,
  216. DWORD dwCertFlags)
  217. {
  218. SSL_EXTRA_CERT_CHAIN_POLICY_PARA SslPara;
  219. CERT_CHAIN_POLICY_PARA PolicyPara;
  220. CERT_CHAIN_POLICY_STATUS PolicyStatus;
  221. CERT_CHAIN_PARA ChainPara;
  222. PCCERT_CHAIN_CONTEXT pChain = NULL;
  223. PCCERT_CONTEXT pCert = NULL;
  224. HRESULT Status;
  225. PWSTR pwszServerName;
  226. DWORD cchServerName;
  227. // Read the remote certificate.
  228. if ((Status = g_SecurityFunc.
  229. QueryContextAttributes(Context,
  230. SECPKG_ATTR_REMOTE_CERT_CONTEXT,
  231. &pCert)) != S_OK)
  232. {
  233. goto Exit;
  234. }
  235. if (pCert == NULL)
  236. {
  237. Status = SEC_E_WRONG_PRINCIPAL;
  238. goto EH_Cert;
  239. }
  240. if (pszServerName != NULL && *pszServerName)
  241. {
  242. //
  243. // Convert server name to unicode.
  244. //
  245. cchServerName = MultiByteToWideChar(CP_ACP, 0, pszServerName,
  246. -1, NULL, 0);
  247. pwszServerName = (PWSTR)
  248. LocalAlloc(LMEM_FIXED, cchServerName * sizeof(WCHAR));
  249. if (pwszServerName == NULL)
  250. {
  251. Status = SEC_E_INSUFFICIENT_MEMORY;
  252. goto EH_Cert;
  253. }
  254. cchServerName = MultiByteToWideChar(CP_ACP, 0, pszServerName,
  255. -1, pwszServerName, cchServerName);
  256. if (cchServerName == 0)
  257. {
  258. Status = SEC_E_WRONG_PRINCIPAL;
  259. goto EH_Name;
  260. }
  261. }
  262. else
  263. {
  264. pwszServerName = NULL;
  265. }
  266. //
  267. // Build certificate chain.
  268. //
  269. ZeroMemory(&ChainPara, sizeof(ChainPara));
  270. ChainPara.cbSize = sizeof(ChainPara);
  271. if (!g_Crypt32Calls.CertGetCertificateChain(NULL,
  272. pCert,
  273. NULL,
  274. pCert->hCertStore,
  275. &ChainPara,
  276. 0,
  277. NULL,
  278. &pChain))
  279. {
  280. Status = WIN32_LAST_STATUS();
  281. goto EH_Name;
  282. }
  283. //
  284. // Validate certificate chain.
  285. //
  286. ZeroMemory(&SslPara, sizeof(SslPara));
  287. SslPara.cbStruct = sizeof(SslPara);
  288. SslPara.dwAuthType = pwszServerName == NULL ?
  289. AUTHTYPE_CLIENT : AUTHTYPE_SERVER;
  290. SslPara.fdwChecks = dwCertFlags;
  291. SslPara.pwszServerName = pwszServerName;
  292. ZeroMemory(&PolicyPara, sizeof(PolicyPara));
  293. PolicyPara.cbSize = sizeof(PolicyPara);
  294. PolicyPara.pvExtraPolicyPara = &SslPara;
  295. ZeroMemory(&PolicyStatus, sizeof(PolicyStatus));
  296. PolicyStatus.cbSize = sizeof(PolicyStatus);
  297. if (!g_Crypt32Calls.CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL,
  298. pChain,
  299. &PolicyPara,
  300. &PolicyStatus))
  301. {
  302. Status = WIN32_LAST_STATUS();
  303. goto EH_Chain;
  304. }
  305. if (PolicyStatus.dwError)
  306. {
  307. Status = PolicyStatus.dwError;
  308. }
  309. else
  310. {
  311. Status = S_OK;
  312. }
  313. EH_Chain:
  314. g_Crypt32Calls.CertFreeCertificateChain(pChain);
  315. EH_Name:
  316. if (pwszServerName != NULL)
  317. {
  318. LocalFree(pwszServerName);
  319. }
  320. EH_Cert:
  321. g_Crypt32Calls.CertFreeCertificateContext(pCert);
  322. Exit:
  323. DSCHAN(("VerifyRemoteCertificate returns %X\n", Status));
  324. return Status;
  325. }
  326. //----------------------------------------------------------------------------
  327. //
  328. // Schannel wrapper transport.
  329. //
  330. //----------------------------------------------------------------------------
  331. #define SecHandleIsValid(Handle) \
  332. ((Handle)->dwLower != -1 || (Handle)->dwUpper != -1)
  333. DbgRpcSecureChannelTransport::
  334. DbgRpcSecureChannelTransport(ULONG ThisTransport,
  335. ULONG BaseTransport)
  336. {
  337. m_Name = g_DbgRpcTransportNames[ThisTransport];
  338. m_ThisTransport = ThisTransport;
  339. m_BaseTransport = BaseTransport;
  340. m_Stream = NULL;
  341. SecInvalidateHandle(&m_Creds);
  342. m_OwnCreds = FALSE;
  343. SecInvalidateHandle(&m_Context);
  344. m_OwnContext = FALSE;
  345. m_BufferUsed = 0;
  346. m_Server = FALSE;
  347. }
  348. DbgRpcSecureChannelTransport::~DbgRpcSecureChannelTransport(void)
  349. {
  350. if (SecHandleIsValid(&m_Context))
  351. {
  352. if (m_Server)
  353. {
  354. DisconnectFromClient();
  355. }
  356. else
  357. {
  358. DisconnectFromServer();
  359. }
  360. }
  361. delete m_Stream;
  362. if (m_OwnContext && SecHandleIsValid(&m_Context))
  363. {
  364. g_SecurityFunc.DeleteSecurityContext(&m_Context);
  365. }
  366. if (m_OwnCreds && SecHandleIsValid(&m_Creds))
  367. {
  368. g_SecurityFunc.FreeCredentialsHandle(&m_Creds);
  369. }
  370. }
  371. ULONG
  372. DbgRpcSecureChannelTransport::GetNumberParameters(void)
  373. {
  374. return 2 + (m_Stream != NULL ? m_Stream->GetNumberParameters() : 0);
  375. }
  376. void
  377. DbgRpcSecureChannelTransport::GetParameter(ULONG Index, PSTR Name, PSTR Value)
  378. {
  379. switch(Index)
  380. {
  381. case 0:
  382. if (m_Protocol)
  383. {
  384. strcpy(Name, "Proto");
  385. switch(m_Protocol)
  386. {
  387. case SP_PROT_PCT1:
  388. strcpy(Name, "PCT1");
  389. break;
  390. case SP_PROT_SSL2:
  391. strcpy(Name, "SSL2");
  392. break;
  393. case SP_PROT_SSL3:
  394. strcpy(Name, "SSL3");
  395. break;
  396. case SP_PROT_TLS1:
  397. strcpy(Name, "TLS1");
  398. break;
  399. }
  400. }
  401. break;
  402. case 1:
  403. if (m_User[0])
  404. {
  405. strcpy(Name, m_MachineStore ? "MachUser" : "CertUser");
  406. strcpy(Value, m_User);
  407. }
  408. break;
  409. default:
  410. if (m_Stream != NULL)
  411. {
  412. m_Stream->GetParameter(Index - 2, Name, Value);
  413. }
  414. break;
  415. }
  416. }
  417. void
  418. DbgRpcSecureChannelTransport::ResetParameters(void)
  419. {
  420. m_Protocol = 0;
  421. m_User[0] = 0;
  422. m_MachineStore = FALSE;
  423. if (m_Stream == NULL)
  424. {
  425. m_Stream = DbgRpcNewTransport(m_BaseTransport);
  426. }
  427. if (m_Stream != NULL)
  428. {
  429. m_Stream->ResetParameters();
  430. }
  431. }
  432. BOOL
  433. DbgRpcSecureChannelTransport::SetParameter(PCSTR Name, PCSTR Value)
  434. {
  435. if (m_Stream == NULL)
  436. {
  437. // Force all initialization to fail.
  438. return FALSE;
  439. }
  440. if (!_stricmp(Name, "proto"))
  441. {
  442. if (Value == NULL)
  443. {
  444. DbgRpcError("%s parameters: "
  445. "the protocol name was not specified correctly\n",
  446. m_Name);
  447. return FALSE;
  448. }
  449. if (!_stricmp(Value, "pct1"))
  450. {
  451. m_Protocol = SP_PROT_PCT1;
  452. }
  453. else if (!_stricmp(Value, "ssl2"))
  454. {
  455. m_Protocol = SP_PROT_SSL2;
  456. }
  457. else if (!_stricmp(Value, "ssl3"))
  458. {
  459. m_Protocol = SP_PROT_SSL3;
  460. }
  461. else if (!_stricmp(Value, "tls1"))
  462. {
  463. m_Protocol = SP_PROT_TLS1;
  464. }
  465. else
  466. {
  467. DbgRpcError("%s parameters: unknown protocol '%s'\n", Value,
  468. m_Name);
  469. return FALSE;
  470. }
  471. }
  472. else if (!_stricmp(Name, "machuser"))
  473. {
  474. if (Value == NULL)
  475. {
  476. DbgRpcError("%s parameters: "
  477. "the user name was not specified correctly\n",
  478. m_Name);
  479. return FALSE;
  480. }
  481. m_User[0] = 0;
  482. strncat(m_User, Value, sizeof(m_User) - 1);
  483. m_MachineStore = TRUE;
  484. }
  485. else if (!_stricmp(Name, "certuser"))
  486. {
  487. if (Value == NULL)
  488. {
  489. DbgRpcError("%s parameters: "
  490. "the user name was not specified correctly\n",
  491. m_Name);
  492. return FALSE;
  493. }
  494. m_User[0] = 0;
  495. strncat(m_User, Value, sizeof(m_User) - 1);
  496. m_MachineStore = FALSE;
  497. }
  498. else
  499. {
  500. if (!m_Stream->SetParameter(Name, Value))
  501. {
  502. return FALSE;
  503. }
  504. }
  505. return TRUE;
  506. }
  507. DbgRpcTransport*
  508. DbgRpcSecureChannelTransport::Clone(void)
  509. {
  510. DbgRpcTransport* Stream = m_Stream->Clone();
  511. if (Stream == NULL)
  512. {
  513. return NULL;
  514. }
  515. DbgRpcSecureChannelTransport* Trans =
  516. new DbgRpcSecureChannelTransport(m_ThisTransport, m_BaseTransport);
  517. if (Trans != NULL)
  518. {
  519. Trans->m_Stream = Stream;
  520. Trans->m_Creds = m_Creds;
  521. Trans->m_OwnCreds = FALSE;
  522. Trans->m_Context = m_Context;
  523. Trans->m_OwnContext = FALSE;
  524. Trans->m_Protocol = m_Protocol;
  525. strcpy(Trans->m_User, m_User);
  526. Trans->m_MachineStore = m_MachineStore;
  527. Trans->m_Sizes = m_Sizes;
  528. Trans->m_MaxChunk = m_MaxChunk;
  529. Trans->m_Server = m_Server;
  530. }
  531. else
  532. {
  533. delete Stream;
  534. }
  535. return Trans;
  536. }
  537. HRESULT
  538. DbgRpcSecureChannelTransport::CreateServer(void)
  539. {
  540. HRESULT Status;
  541. if ((Status = LoadSecurityLibrary()) != S_OK)
  542. {
  543. return Status;
  544. }
  545. if ((Status = CreateCredentials(m_User, m_MachineStore, TRUE,
  546. m_Protocol, &m_ScCreds, &m_Creds)) != S_OK)
  547. {
  548. return Status;
  549. }
  550. m_OwnCreds = TRUE;
  551. if ((Status = m_Stream->CreateServer()) != S_OK)
  552. {
  553. return Status;
  554. }
  555. m_Server = TRUE;
  556. return S_OK;
  557. }
  558. HRESULT
  559. DbgRpcSecureChannelTransport::AcceptConnection(DbgRpcTransport** ClientTrans,
  560. PSTR Identity)
  561. {
  562. HRESULT Status;
  563. DbgRpcTransport* Stream;
  564. if ((Status = m_Stream->AcceptConnection(&Stream, Identity)) != S_OK)
  565. {
  566. return Status;
  567. }
  568. DbgRpcSecureChannelTransport* Trans =
  569. new DbgRpcSecureChannelTransport(m_ThisTransport, m_BaseTransport);
  570. if (Trans == NULL)
  571. {
  572. delete Stream;
  573. return E_OUTOFMEMORY;
  574. }
  575. Trans->m_Stream = Stream;
  576. Trans->m_Creds = m_Creds;
  577. Trans->m_OwnCreds = FALSE;
  578. Trans->m_Server = TRUE;
  579. if ((Status = Trans->AuthenticateClientConnection()) != S_OK)
  580. {
  581. goto EH_Trans;
  582. }
  583. if ((Status = Trans->GetSizes()) != S_OK)
  584. {
  585. goto EH_Trans;
  586. }
  587. // Attempt to validate client certificate.
  588. if ((Status = VerifyRemoteCertificate(&Trans->m_Context, NULL, 0)) != S_OK)
  589. {
  590. goto EH_Trans;
  591. }
  592. *ClientTrans = Trans;
  593. return S_OK;
  594. EH_Trans:
  595. delete Trans;
  596. return Status;
  597. }
  598. HRESULT
  599. DbgRpcSecureChannelTransport::ConnectServer(void)
  600. {
  601. HRESULT Status = m_Stream->ConnectServer();
  602. if (Status != S_OK)
  603. {
  604. return Status;
  605. }
  606. if ((Status = LoadSecurityLibrary()) != S_OK)
  607. {
  608. return Status;
  609. }
  610. if ((Status = CreateCredentials(m_User, m_MachineStore, FALSE,
  611. m_Protocol, &m_ScCreds, &m_Creds)) != S_OK)
  612. {
  613. return Status;
  614. }
  615. m_OwnCreds = TRUE;
  616. if ((Status = InitiateServerConnection(m_Stream->m_ServerName)) != S_OK)
  617. {
  618. return Status;
  619. }
  620. if ((Status = AuthenticateServerConnection()) != S_OK)
  621. {
  622. return Status;
  623. }
  624. if ((Status = GetSizes()) != S_OK)
  625. {
  626. return Status;
  627. }
  628. // Attempt to validate server certificate.
  629. if ((Status = VerifyRemoteCertificate(&m_Context,
  630. m_Stream->m_ServerName, 0)) != S_OK)
  631. {
  632. // If this fails with CERT_E_CN_NO_MATCH it's most
  633. // likely that the server name wasn't given as a fully
  634. // qualified machine name. We may just want to ignore that error.
  635. return Status;
  636. }
  637. return S_OK;
  638. }
  639. ULONG
  640. DbgRpcSecureChannelTransport::Read(ULONG Seq, PVOID Buffer, ULONG Len)
  641. {
  642. SecBufferDesc Message;
  643. SecBuffer Buffers[4];
  644. DWORD Status;
  645. ULONG Complete;
  646. DSCHAN_IO(("Start read(%X) with %X bytes cached\n",
  647. Len, m_BufferUsed));
  648. //
  649. // Initialize security buffer structs
  650. //
  651. Message.ulVersion = SECBUFFER_VERSION;
  652. Message.cBuffers = 4;
  653. Message.pBuffers = Buffers;
  654. //
  655. // Receive the data from the client.
  656. //
  657. Complete = 0;
  658. while (Complete < Len)
  659. {
  660. do
  661. {
  662. // Pass in the data we have so far.
  663. Buffers[0].pvBuffer = m_Buffer;
  664. Buffers[0].cbBuffer = m_BufferUsed;
  665. Buffers[0].BufferType = SECBUFFER_DATA;
  666. // Provide extra buffers for header, trailer
  667. // and possibly extra data.
  668. Buffers[1].BufferType = SECBUFFER_EMPTY;
  669. Buffers[2].BufferType = SECBUFFER_EMPTY;
  670. Buffers[3].BufferType = SECBUFFER_EMPTY;
  671. Status = g_SecurityFunc.DecryptMessage(&m_Context, &Message,
  672. Seq, NULL);
  673. DSCHAN_IO(("Read DecryptMessage on %X bytes returns %X\n",
  674. m_BufferUsed, Status));
  675. DumpBuffersIo("Read", &Message);
  676. if (Status == SEC_E_INCOMPLETE_MESSAGE)
  677. {
  678. DSCHAN_IO((" Missing %X bytes\n", Buffers[1].cbBuffer));
  679. ULONG Read = StreamRead(Seq, m_Buffer + m_BufferUsed,
  680. sizeof(m_Buffer) - m_BufferUsed);
  681. if (Read == 0)
  682. {
  683. return Complete;
  684. }
  685. m_BufferUsed += Read;
  686. }
  687. else if (Status == SEC_I_RENEGOTIATE)
  688. {
  689. // The server wants to perform another handshake
  690. // sequence.
  691. if ((Status = AuthenticateServerConnection()) != S_OK)
  692. {
  693. break;
  694. }
  695. }
  696. }
  697. while (Status == SEC_E_INCOMPLETE_MESSAGE);
  698. if (Status != S_OK)
  699. {
  700. break;
  701. }
  702. // Buffers 0,1,2 should be header, data, trailer.
  703. DBG_ASSERT(Buffers[1].BufferType == SECBUFFER_DATA);
  704. DSCHAN_IO((" %X bytes of %X read\n",
  705. Buffers[1].cbBuffer, Len));
  706. memcpy((PUCHAR)Buffer + Complete,
  707. Buffers[1].pvBuffer, Buffers[1].cbBuffer);
  708. Complete += Buffers[1].cbBuffer;
  709. // Check for extra data in buffer 3.
  710. if (Buffers[3].BufferType == SECBUFFER_EXTRA)
  711. {
  712. DSCHAN_IO((" %X bytes extra\n"));
  713. memmove(m_Buffer, Buffers[3].pvBuffer, Buffers[3].cbBuffer);
  714. m_BufferUsed = Buffers[3].cbBuffer;
  715. }
  716. else
  717. {
  718. m_BufferUsed = 0;
  719. }
  720. }
  721. DSCHAN_IO((" Read returns %X bytes\n", Complete));
  722. return Complete;
  723. }
  724. ULONG
  725. DbgRpcSecureChannelTransport::Write(ULONG Seq, PVOID Buffer, ULONG Len)
  726. {
  727. SecBufferDesc Message;
  728. SecBuffer Buffers[3];
  729. DWORD Status;
  730. ULONG Complete;
  731. DSCHAN_IO(("Start write(%X) with %X bytes cached\n",
  732. Len, m_BufferUsed));
  733. Message.ulVersion = SECBUFFER_VERSION;
  734. Message.cBuffers = 3;
  735. Message.pBuffers = Buffers;
  736. Complete = 0;
  737. while (Complete < Len)
  738. {
  739. ULONG Chunk;
  740. //
  741. // Set up header, data and trailer buffers so
  742. // that EncryptMessage has room for everything
  743. // in one contiguous buffer.
  744. //
  745. Buffers[0].pvBuffer = m_Buffer + m_BufferUsed;
  746. Buffers[0].cbBuffer = m_Sizes.cbHeader;
  747. Buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
  748. //
  749. // Data is encrypted in-place so copy data
  750. // from the user's buffer into the working buffer.
  751. // Part of the working buffer may be taken up
  752. // by queued data so work with what's left.
  753. //
  754. if (Len > m_MaxChunk - m_BufferUsed)
  755. {
  756. Chunk = m_MaxChunk - m_BufferUsed;
  757. }
  758. else
  759. {
  760. Chunk = Len;
  761. }
  762. DSCHAN_IO((" write %X bytes of %X\n", Chunk, Len));
  763. Buffers[1].pvBuffer =
  764. (PUCHAR)Buffers[0].pvBuffer + Buffers[0].cbBuffer;
  765. Buffers[1].cbBuffer = Chunk;
  766. Buffers[1].BufferType = SECBUFFER_DATA;
  767. memcpy(Buffers[1].pvBuffer, (PUCHAR)Buffer + Complete, Chunk);
  768. Buffers[2].pvBuffer =
  769. (PUCHAR)Buffers[1].pvBuffer + Buffers[1].cbBuffer;
  770. Buffers[2].cbBuffer = m_Sizes.cbTrailer;
  771. Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
  772. Status = g_SecurityFunc.EncryptMessage(&m_Context, 0, &Message, Seq);
  773. if (Status != S_OK)
  774. {
  775. break;
  776. }
  777. DumpBuffersIo("Write encrypt", &Message);
  778. ULONG Total, Written;
  779. Total = Buffers[0].cbBuffer + Buffers[1].cbBuffer +
  780. Buffers[2].cbBuffer;
  781. Written = StreamWrite(Seq, Buffers[0].pvBuffer, Total);
  782. if (Written != Total)
  783. {
  784. break;
  785. }
  786. Complete += Chunk;
  787. }
  788. DSCHAN_IO((" Write returns %X bytes\n", Complete));
  789. return Complete;
  790. }
  791. HRESULT
  792. DbgRpcSecureChannelTransport::GetSizes(void)
  793. {
  794. HRESULT Status;
  795. //
  796. // Find out how big the header will be:
  797. //
  798. if ((Status = g_SecurityFunc.
  799. QueryContextAttributes(&m_Context, SECPKG_ATTR_STREAM_SIZES,
  800. &m_Sizes)) != S_OK)
  801. {
  802. return Status;
  803. }
  804. // Compute the largest chunk that can be encrypted at
  805. // once in the transport's data buffer.
  806. m_MaxChunk = sizeof(m_Buffer) - (m_Sizes.cbHeader + m_Sizes.cbTrailer);
  807. if (m_MaxChunk > m_Sizes.cbMaximumMessage)
  808. {
  809. m_MaxChunk = m_Sizes.cbMaximumMessage;
  810. }
  811. return S_OK;
  812. }
  813. HRESULT
  814. DbgRpcSecureChannelTransport::AuthenticateClientConnection(void)
  815. {
  816. TimeStamp tsExpiry;
  817. SECURITY_STATUS Status;
  818. SecBufferDesc InBuffer;
  819. SecBufferDesc OutBuffer;
  820. SecBuffer InBuffers[2];
  821. SecBuffer OutBuffers[1];
  822. BOOL fInitContext = TRUE;
  823. DWORD dwSSPIFlags, dwSSPIOutFlags;
  824. ULONG Seq;
  825. Status = SEC_E_SECPKG_NOT_FOUND; //default error if we run out of packages
  826. dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
  827. ASC_REQ_REPLAY_DETECT |
  828. ASC_REQ_CONFIDENTIALITY |
  829. ASC_REQ_EXTENDED_ERROR |
  830. ASC_REQ_ALLOCATE_MEMORY |
  831. ASC_REQ_STREAM |
  832. ASC_REQ_MUTUAL_AUTH;
  833. //
  834. // Set buffers for AcceptSecurityContext call
  835. //
  836. InBuffer.cBuffers = 2;
  837. InBuffer.pBuffers = InBuffers;
  838. InBuffer.ulVersion = SECBUFFER_VERSION;
  839. OutBuffer.cBuffers = 1;
  840. OutBuffer.pBuffers = OutBuffers;
  841. OutBuffer.ulVersion = SECBUFFER_VERSION;
  842. Status = SEC_I_CONTINUE_NEEDED;
  843. m_BufferUsed = 0;
  844. while ( Status == SEC_I_CONTINUE_NEEDED ||
  845. Status == SEC_E_INCOMPLETE_MESSAGE ||
  846. Status == SEC_I_INCOMPLETE_CREDENTIALS)
  847. {
  848. if (0 == m_BufferUsed || Status == SEC_E_INCOMPLETE_MESSAGE)
  849. {
  850. ULONG Read = StreamRead(SEQ_INTERNAL, m_Buffer + m_BufferUsed,
  851. sizeof(m_Buffer) - m_BufferUsed);
  852. if (Read == 0)
  853. {
  854. Status = HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  855. goto Exit;
  856. }
  857. else
  858. {
  859. m_BufferUsed += Read;
  860. }
  861. }
  862. //
  863. // InBuffers[1] is for getting extra data that
  864. // SSPI/SCHANNEL doesn't proccess on this
  865. // run around the loop.
  866. //
  867. InBuffers[0].pvBuffer = m_Buffer;
  868. InBuffers[0].cbBuffer = m_BufferUsed;
  869. InBuffers[0].BufferType = SECBUFFER_TOKEN;
  870. InBuffers[1].pvBuffer = NULL;
  871. InBuffers[1].cbBuffer = 0;
  872. InBuffers[1].BufferType = SECBUFFER_EMPTY;
  873. //
  874. // Initialize these so if we fail, pvBuffer contains NULL,
  875. // so we don't try to free random garbage at the quit
  876. //
  877. OutBuffers[0].pvBuffer = NULL;
  878. OutBuffers[0].cbBuffer = 0;
  879. OutBuffers[0].BufferType = SECBUFFER_TOKEN;
  880. Status = g_SecurityFunc.AcceptSecurityContext(
  881. &m_Creds,
  882. (fInitContext ? NULL : &m_Context),
  883. &InBuffer,
  884. dwSSPIFlags,
  885. SECURITY_NATIVE_DREP,
  886. (fInitContext ? &m_Context : NULL),
  887. &OutBuffer,
  888. &dwSSPIOutFlags,
  889. &tsExpiry);
  890. DSCHAN(("ASC on %X bytes returns %X\n",
  891. m_BufferUsed, Status));
  892. DumpBuffers("ASC in", &InBuffer);
  893. DumpBuffers("ASC out", &OutBuffer);
  894. if (SUCCEEDED(Status))
  895. {
  896. fInitContext = FALSE;
  897. m_OwnContext = TRUE;
  898. }
  899. if ( Status == SEC_E_OK ||
  900. Status == SEC_I_CONTINUE_NEEDED ||
  901. (FAILED(Status) &&
  902. (0 != (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))))
  903. {
  904. if (OutBuffers[0].cbBuffer != 0 &&
  905. OutBuffers[0].pvBuffer != NULL )
  906. {
  907. ULONG Written;
  908. DSCHAN((" write back %X bytes\n", OutBuffers[0].cbBuffer));
  909. //
  910. // Send response to server if there is one
  911. //
  912. Written = StreamWrite(SEQ_INTERNAL, OutBuffers[0].pvBuffer,
  913. OutBuffers[0].cbBuffer);
  914. g_SecurityFunc.FreeContextBuffer( OutBuffers[0].pvBuffer );
  915. OutBuffers[0].pvBuffer = NULL;
  916. if (Written != OutBuffers[0].cbBuffer)
  917. {
  918. Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  919. goto Exit;
  920. }
  921. }
  922. }
  923. if ( Status == SEC_E_OK )
  924. {
  925. if ( InBuffers[1].BufferType == SECBUFFER_EXTRA )
  926. {
  927. DSCHAN_IO((" ASC returns with %X extra bytes\n",
  928. InBuffers[1].cbBuffer));
  929. memmove(m_Buffer,
  930. m_Buffer + (m_BufferUsed - InBuffers[1].cbBuffer),
  931. InBuffers[1].cbBuffer);
  932. m_BufferUsed = InBuffers[1].cbBuffer;
  933. }
  934. else
  935. {
  936. m_BufferUsed = 0;
  937. }
  938. goto Exit;
  939. }
  940. else if (FAILED(Status) && (Status != SEC_E_INCOMPLETE_MESSAGE))
  941. {
  942. goto Exit;
  943. }
  944. if ( Status != SEC_E_INCOMPLETE_MESSAGE &&
  945. Status != SEC_I_INCOMPLETE_CREDENTIALS)
  946. {
  947. if ( InBuffers[1].BufferType == SECBUFFER_EXTRA )
  948. {
  949. DSCHAN_IO((" ASC loops with %X extra bytes\n",
  950. InBuffers[1].cbBuffer));
  951. memmove(m_Buffer,
  952. m_Buffer + (m_BufferUsed - InBuffers[1].cbBuffer),
  953. InBuffers[1].cbBuffer);
  954. m_BufferUsed = InBuffers[1].cbBuffer;
  955. }
  956. else
  957. {
  958. //
  959. // prepare for next receive
  960. //
  961. m_BufferUsed = 0;
  962. }
  963. }
  964. }
  965. Exit:
  966. DSCHAN(("AuthClient returns %X\n", Status));
  967. return Status;
  968. }
  969. HRESULT
  970. DbgRpcSecureChannelTransport::InitiateServerConnection(LPSTR pszServerName)
  971. {
  972. SecBufferDesc OutBuffer;
  973. SecBuffer OutBuffers[1];
  974. DWORD dwSSPIFlags;
  975. DWORD dwSSPIOutFlags;
  976. TimeStamp tsExpiry;
  977. SECURITY_STATUS Status;
  978. DWORD cbData;
  979. dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
  980. ISC_REQ_REPLAY_DETECT |
  981. ISC_REQ_CONFIDENTIALITY |
  982. ISC_REQ_EXTENDED_ERROR |
  983. ISC_REQ_ALLOCATE_MEMORY |
  984. ISC_REQ_STREAM |
  985. ISC_REQ_MUTUAL_AUTH;
  986. //
  987. // Initiate a ClientHello message and generate a token.
  988. //
  989. OutBuffers[0].pvBuffer = NULL;
  990. OutBuffers[0].BufferType = SECBUFFER_TOKEN;
  991. OutBuffers[0].cbBuffer = 0;
  992. OutBuffer.cBuffers = 1;
  993. OutBuffer.pBuffers = OutBuffers;
  994. OutBuffer.ulVersion = SECBUFFER_VERSION;
  995. Status = g_SecurityFunc.InitializeSecurityContextA(
  996. &m_Creds,
  997. NULL,
  998. pszServerName,
  999. dwSSPIFlags,
  1000. 0,
  1001. SECURITY_NATIVE_DREP,
  1002. NULL,
  1003. 0,
  1004. &m_Context,
  1005. &OutBuffer,
  1006. &dwSSPIOutFlags,
  1007. &tsExpiry);
  1008. DSCHAN(("First ISC returns %X\n", Status));
  1009. DumpBuffers("First ISC out", &OutBuffer);
  1010. if (Status != SEC_I_CONTINUE_NEEDED)
  1011. {
  1012. goto Exit;
  1013. }
  1014. m_OwnContext = TRUE;
  1015. // Send response to server if there is one.
  1016. if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
  1017. {
  1018. DSCHAN((" write back %X bytes\n", OutBuffers[0].cbBuffer));
  1019. cbData = StreamWrite(SEQ_INTERNAL, OutBuffers[0].pvBuffer,
  1020. OutBuffers[0].cbBuffer);
  1021. if(cbData == 0)
  1022. {
  1023. g_SecurityFunc.FreeContextBuffer(OutBuffers[0].pvBuffer);
  1024. if (m_OwnContext)
  1025. {
  1026. g_SecurityFunc.DeleteSecurityContext(&m_Context);
  1027. SecInvalidateHandle(&m_Context);
  1028. }
  1029. Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  1030. goto Exit;
  1031. }
  1032. // Free output buffer.
  1033. g_SecurityFunc.FreeContextBuffer(OutBuffers[0].pvBuffer);
  1034. OutBuffers[0].pvBuffer = NULL;
  1035. }
  1036. Status = S_OK;
  1037. Exit:
  1038. DSCHAN(("InitServer returns %X\n", Status));
  1039. return Status;
  1040. }
  1041. HRESULT
  1042. DbgRpcSecureChannelTransport::AuthenticateServerConnection(void)
  1043. {
  1044. SecBufferDesc InBuffer;
  1045. SecBuffer InBuffers[2];
  1046. SecBufferDesc OutBuffer;
  1047. SecBuffer OutBuffers[1];
  1048. DWORD dwSSPIFlags;
  1049. DWORD dwSSPIOutFlags;
  1050. TimeStamp tsExpiry;
  1051. SECURITY_STATUS Status;
  1052. DWORD cbData;
  1053. ULONG ReadNeeded;
  1054. dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
  1055. ISC_REQ_REPLAY_DETECT |
  1056. ISC_REQ_CONFIDENTIALITY |
  1057. ISC_REQ_EXTENDED_ERROR |
  1058. ISC_REQ_ALLOCATE_MEMORY |
  1059. ISC_REQ_STREAM;
  1060. m_BufferUsed = 0;
  1061. ReadNeeded = 1;
  1062. //
  1063. // Loop until the handshake is finished or an error occurs.
  1064. //
  1065. Status = SEC_I_CONTINUE_NEEDED;
  1066. while(Status == SEC_I_CONTINUE_NEEDED ||
  1067. Status == SEC_E_INCOMPLETE_MESSAGE ||
  1068. Status == SEC_I_INCOMPLETE_CREDENTIALS)
  1069. {
  1070. //
  1071. // Read data from server.
  1072. //
  1073. if (0 == m_BufferUsed || Status == SEC_E_INCOMPLETE_MESSAGE)
  1074. {
  1075. if (ReadNeeded > 0)
  1076. {
  1077. cbData = StreamRead(SEQ_INTERNAL, m_Buffer + m_BufferUsed,
  1078. sizeof(m_Buffer) - m_BufferUsed);
  1079. if(cbData == 0)
  1080. {
  1081. Status = HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  1082. break;
  1083. }
  1084. m_BufferUsed += cbData;
  1085. }
  1086. else
  1087. {
  1088. ReadNeeded = 1;
  1089. }
  1090. }
  1091. //
  1092. // Set up the input buffers. Buffer 0 is used to pass in data
  1093. // received from the server. Schannel will consume some or all
  1094. // of this. Leftover data (if any) will be placed in buffer 1 and
  1095. // given a buffer type of SECBUFFER_EXTRA.
  1096. //
  1097. InBuffers[0].pvBuffer = m_Buffer;
  1098. InBuffers[0].cbBuffer = m_BufferUsed;
  1099. InBuffers[0].BufferType = SECBUFFER_TOKEN;
  1100. InBuffers[1].pvBuffer = NULL;
  1101. InBuffers[1].cbBuffer = 0;
  1102. InBuffers[1].BufferType = SECBUFFER_EMPTY;
  1103. InBuffer.cBuffers = 2;
  1104. InBuffer.pBuffers = InBuffers;
  1105. InBuffer.ulVersion = SECBUFFER_VERSION;
  1106. //
  1107. // Set up the output buffers. These are initialized to NULL
  1108. // so as to make it less likely we'll attempt to free random
  1109. // garbage later.
  1110. //
  1111. OutBuffers[0].pvBuffer = NULL;
  1112. OutBuffers[0].BufferType= SECBUFFER_TOKEN;
  1113. OutBuffers[0].cbBuffer = 0;
  1114. OutBuffer.cBuffers = 1;
  1115. OutBuffer.pBuffers = OutBuffers;
  1116. OutBuffer.ulVersion = SECBUFFER_VERSION;
  1117. //
  1118. // Call InitializeSecurityContext.
  1119. //
  1120. Status = g_SecurityFunc.InitializeSecurityContextA(
  1121. &m_Creds,
  1122. &m_Context,
  1123. NULL,
  1124. dwSSPIFlags,
  1125. 0,
  1126. SECURITY_NATIVE_DREP,
  1127. &InBuffer,
  1128. 0,
  1129. NULL,
  1130. &OutBuffer,
  1131. &dwSSPIOutFlags,
  1132. &tsExpiry);
  1133. DSCHAN(("ISC on %X bytes returns %X\n",
  1134. m_BufferUsed, Status));
  1135. DumpBuffers("ISC in", &InBuffer);
  1136. DumpBuffers("ISC out", &OutBuffer);
  1137. //
  1138. // If InitializeSecurityContext was successful (or if the error was
  1139. // one of the special extended ones), send the contends of the output
  1140. // buffer to the server.
  1141. //
  1142. if(Status == SEC_E_OK ||
  1143. Status == SEC_I_CONTINUE_NEEDED ||
  1144. FAILED(Status) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR))
  1145. {
  1146. if(OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
  1147. {
  1148. DSCHAN((" write back %X bytes\n", OutBuffers[0].cbBuffer));
  1149. cbData = StreamWrite(SEQ_INTERNAL, OutBuffers[0].pvBuffer,
  1150. OutBuffers[0].cbBuffer);
  1151. if(cbData == 0)
  1152. {
  1153. g_SecurityFunc.FreeContextBuffer(OutBuffers[0].pvBuffer);
  1154. if (m_OwnContext)
  1155. {
  1156. g_SecurityFunc.DeleteSecurityContext(&m_Context);
  1157. SecInvalidateHandle(&m_Context);
  1158. }
  1159. Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  1160. goto Exit;
  1161. }
  1162. // Free output buffer.
  1163. g_SecurityFunc.FreeContextBuffer(OutBuffers[0].pvBuffer);
  1164. OutBuffers[0].pvBuffer = NULL;
  1165. }
  1166. }
  1167. //
  1168. // If InitializeSecurityContext returned SEC_E_INCOMPLETE_MESSAGE,
  1169. // then we need to read more data from the server and try again.
  1170. //
  1171. if(Status == SEC_E_INCOMPLETE_MESSAGE)
  1172. {
  1173. continue;
  1174. }
  1175. //
  1176. // If InitializeSecurityContext returned SEC_E_OK, then the
  1177. // handshake completed successfully.
  1178. //
  1179. if(Status == SEC_E_OK)
  1180. {
  1181. //
  1182. // If the "extra" buffer contains data, this is encrypted application
  1183. // protocol layer stuff. It needs to be saved. The application layer
  1184. // will later decrypt it with DecryptMessage.
  1185. //
  1186. if(InBuffers[1].BufferType == SECBUFFER_EXTRA)
  1187. {
  1188. DSCHAN_IO((" ISC returns with %X extra bytes\n",
  1189. InBuffers[1].cbBuffer));
  1190. memmove(m_Buffer,
  1191. m_Buffer + (m_BufferUsed - InBuffers[1].cbBuffer),
  1192. InBuffers[1].cbBuffer);
  1193. m_BufferUsed = InBuffers[1].cbBuffer;
  1194. }
  1195. else
  1196. {
  1197. m_BufferUsed = 0;
  1198. }
  1199. //
  1200. // Bail out to quit
  1201. //
  1202. break;
  1203. }
  1204. //
  1205. // Check for fatal error.
  1206. //
  1207. if(FAILED(Status))
  1208. {
  1209. break;
  1210. }
  1211. //
  1212. // If InitializeSecurityContext returned SEC_I_INCOMPLETE_CREDENTIALS,
  1213. // then the server just requested client authentication.
  1214. //
  1215. if(Status == SEC_I_INCOMPLETE_CREDENTIALS)
  1216. {
  1217. DSCHAN(("Get new client credentials\n"));
  1218. //
  1219. // Display trusted issuers info.
  1220. //
  1221. GetNewClientCredentials();
  1222. //
  1223. // Now would be a good time perhaps to prompt the user to select
  1224. // a client certificate and obtain a new credential handle,
  1225. // but I don't have the energy nor inclination.
  1226. //
  1227. // As this is currently written, Schannel will send a "no
  1228. // certificate" alert to the server in place of a certificate.
  1229. // The server might be cool with this, or it might drop the
  1230. // connection.
  1231. //
  1232. // Go around again.
  1233. ReadNeeded = 0;
  1234. Status = SEC_I_CONTINUE_NEEDED;
  1235. continue;
  1236. }
  1237. //
  1238. // Copy any leftover data from the "extra" buffer, and go around
  1239. // again.
  1240. //
  1241. if ( InBuffers[1].BufferType == SECBUFFER_EXTRA )
  1242. {
  1243. DSCHAN((" ISC loops with %X extra bytes\n",
  1244. InBuffers[1].cbBuffer));
  1245. memmove(m_Buffer,
  1246. m_Buffer + (m_BufferUsed - InBuffers[1].cbBuffer),
  1247. InBuffers[1].cbBuffer);
  1248. m_BufferUsed = InBuffers[1].cbBuffer;
  1249. }
  1250. else
  1251. {
  1252. m_BufferUsed = 0;
  1253. }
  1254. }
  1255. // Delete the security context in the case of a fatal error.
  1256. if(FAILED(Status))
  1257. {
  1258. if (m_OwnContext)
  1259. {
  1260. g_SecurityFunc.DeleteSecurityContext(&m_Context);
  1261. SecInvalidateHandle(&m_Context);
  1262. }
  1263. }
  1264. Exit:
  1265. DSCHAN(("AuthServer returns %X\n", Status));
  1266. return Status;
  1267. }
  1268. void
  1269. DbgRpcSecureChannelTransport::GetNewClientCredentials(void)
  1270. {
  1271. CredHandle hCreds;
  1272. SecPkgContext_IssuerListInfoEx IssuerListInfo;
  1273. PCCERT_CHAIN_CONTEXT pChainContext;
  1274. CERT_CHAIN_FIND_BY_ISSUER_PARA FindByIssuerPara;
  1275. PCCERT_CONTEXT pCertContext;
  1276. TimeStamp tsExpiry;
  1277. SECURITY_STATUS Status;
  1278. //
  1279. // Read list of trusted issuers from schannel.
  1280. //
  1281. Status = g_SecurityFunc.QueryContextAttributes(&m_Context,
  1282. SECPKG_ATTR_ISSUER_LIST_EX,
  1283. (PVOID)&IssuerListInfo);
  1284. if (Status != SEC_E_OK)
  1285. {
  1286. goto Exit;
  1287. }
  1288. //
  1289. // Enumerate the client certificates.
  1290. //
  1291. ZeroMemory(&FindByIssuerPara, sizeof(FindByIssuerPara));
  1292. FindByIssuerPara.cbSize = sizeof(FindByIssuerPara);
  1293. FindByIssuerPara.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH;
  1294. FindByIssuerPara.dwKeySpec = 0;
  1295. FindByIssuerPara.cIssuer = IssuerListInfo.cIssuers;
  1296. FindByIssuerPara.rgIssuer = IssuerListInfo.aIssuers;
  1297. pChainContext = NULL;
  1298. while(TRUE)
  1299. {
  1300. // Find a certificate chain.
  1301. pChainContext = g_Crypt32Calls.
  1302. CertFindChainInStore(g_hMyCertStore,
  1303. X509_ASN_ENCODING,
  1304. 0,
  1305. CERT_CHAIN_FIND_BY_ISSUER,
  1306. &FindByIssuerPara,
  1307. pChainContext);
  1308. if(pChainContext == NULL)
  1309. {
  1310. break;
  1311. }
  1312. // Get pointer to leaf certificate context.
  1313. pCertContext = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext;
  1314. // Create schannel credential.
  1315. m_ScCreds.cCreds = 1;
  1316. m_ScCreds.paCred = &pCertContext;
  1317. Status = g_SecurityFunc.AcquireCredentialsHandleA(
  1318. NULL, // Name of principal
  1319. UNISP_NAME_A, // Name of package
  1320. SECPKG_CRED_OUTBOUND, // Flags indicating use
  1321. NULL, // Pointer to logon ID
  1322. &m_ScCreds, // Package specific data
  1323. NULL, // Pointer to GetKey() func
  1324. NULL, // Value to pass to GetKey()
  1325. &hCreds, // (out) Cred Handle
  1326. &tsExpiry); // (out) Lifetime (optional)
  1327. if(Status != SEC_E_OK)
  1328. {
  1329. continue;
  1330. }
  1331. // Destroy the old credentials.
  1332. if (m_OwnCreds)
  1333. {
  1334. g_SecurityFunc.FreeCredentialsHandle(&m_Creds);
  1335. }
  1336. // XXX drewb - This doesn't really work if this
  1337. // isn't the credential owner.
  1338. m_Creds = hCreds;
  1339. break;
  1340. }
  1341. Exit:
  1342. DSCHAN(("GetNewClientCredentials returns %X\n", Status));
  1343. }
  1344. void
  1345. DbgRpcSecureChannelTransport::DisconnectFromClient(void)
  1346. {
  1347. DWORD dwType;
  1348. PBYTE pbMessage;
  1349. DWORD cbMessage;
  1350. DWORD cbData;
  1351. SecBufferDesc OutBuffer;
  1352. SecBuffer OutBuffers[1];
  1353. DWORD dwSSPIFlags;
  1354. DWORD dwSSPIOutFlags;
  1355. TimeStamp tsExpiry;
  1356. DWORD Status;
  1357. //
  1358. // Notify schannel that we are about to close the connection.
  1359. //
  1360. dwType = SCHANNEL_SHUTDOWN;
  1361. OutBuffers[0].pvBuffer = &dwType;
  1362. OutBuffers[0].BufferType = SECBUFFER_TOKEN;
  1363. OutBuffers[0].cbBuffer = sizeof(dwType);
  1364. OutBuffer.cBuffers = 1;
  1365. OutBuffer.pBuffers = OutBuffers;
  1366. OutBuffer.ulVersion = SECBUFFER_VERSION;
  1367. Status = g_SecurityFunc.ApplyControlToken(&m_Context, &OutBuffer);
  1368. if(FAILED(Status))
  1369. {
  1370. goto cleanup;
  1371. }
  1372. //
  1373. // Build an SSL close notify message.
  1374. //
  1375. dwSSPIFlags = ASC_REQ_SEQUENCE_DETECT |
  1376. ASC_REQ_REPLAY_DETECT |
  1377. ASC_REQ_CONFIDENTIALITY |
  1378. ASC_REQ_EXTENDED_ERROR |
  1379. ASC_REQ_ALLOCATE_MEMORY |
  1380. ASC_REQ_STREAM;
  1381. OutBuffers[0].pvBuffer = NULL;
  1382. OutBuffers[0].BufferType = SECBUFFER_TOKEN;
  1383. OutBuffers[0].cbBuffer = 0;
  1384. OutBuffer.cBuffers = 1;
  1385. OutBuffer.pBuffers = OutBuffers;
  1386. OutBuffer.ulVersion = SECBUFFER_VERSION;
  1387. Status = g_SecurityFunc.AcceptSecurityContext(
  1388. &m_Creds,
  1389. &m_Context,
  1390. NULL,
  1391. dwSSPIFlags,
  1392. SECURITY_NATIVE_DREP,
  1393. NULL,
  1394. &OutBuffer,
  1395. &dwSSPIOutFlags,
  1396. &tsExpiry);
  1397. DSCHAN(("DisASC returns %X\n", Status));
  1398. DumpBuffers("DisASC out", &OutBuffer);
  1399. if(FAILED(Status))
  1400. {
  1401. goto cleanup;
  1402. }
  1403. pbMessage = (PBYTE)OutBuffers[0].pvBuffer;
  1404. cbMessage = OutBuffers[0].cbBuffer;
  1405. //
  1406. // Send the close notify message to the client.
  1407. //
  1408. if (pbMessage != NULL && cbMessage != 0)
  1409. {
  1410. DSCHAN((" write back %X bytes\n", cbMessage));
  1411. cbData = StreamWrite(SEQ_INTERNAL, pbMessage, cbMessage);
  1412. if (cbData == 0)
  1413. {
  1414. Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  1415. goto cleanup;
  1416. }
  1417. // Free output buffer.
  1418. g_SecurityFunc.FreeContextBuffer(pbMessage);
  1419. }
  1420. cleanup:
  1421. DSCHAN(("DisconnectFromClient returns %X\n", Status));
  1422. }
  1423. void
  1424. DbgRpcSecureChannelTransport::DisconnectFromServer(void)
  1425. {
  1426. DWORD dwType;
  1427. PBYTE pbMessage;
  1428. DWORD cbMessage;
  1429. DWORD cbData;
  1430. SecBufferDesc OutBuffer;
  1431. SecBuffer OutBuffers[1];
  1432. DWORD dwSSPIFlags;
  1433. DWORD dwSSPIOutFlags;
  1434. TimeStamp tsExpiry;
  1435. DWORD Status;
  1436. //
  1437. // Notify schannel that we are about to close the connection.
  1438. //
  1439. dwType = SCHANNEL_SHUTDOWN;
  1440. OutBuffers[0].pvBuffer = &dwType;
  1441. OutBuffers[0].BufferType = SECBUFFER_TOKEN;
  1442. OutBuffers[0].cbBuffer = sizeof(dwType);
  1443. OutBuffer.cBuffers = 1;
  1444. OutBuffer.pBuffers = OutBuffers;
  1445. OutBuffer.ulVersion = SECBUFFER_VERSION;
  1446. Status = g_SecurityFunc.ApplyControlToken(&m_Context, &OutBuffer);
  1447. if(FAILED(Status))
  1448. {
  1449. goto cleanup;
  1450. }
  1451. //
  1452. // Build an SSL close notify message.
  1453. //
  1454. dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
  1455. ISC_REQ_REPLAY_DETECT |
  1456. ISC_REQ_CONFIDENTIALITY |
  1457. ISC_REQ_EXTENDED_ERROR |
  1458. ISC_REQ_ALLOCATE_MEMORY |
  1459. ISC_REQ_STREAM;
  1460. OutBuffers[0].pvBuffer = NULL;
  1461. OutBuffers[0].BufferType = SECBUFFER_TOKEN;
  1462. OutBuffers[0].cbBuffer = 0;
  1463. OutBuffer.cBuffers = 1;
  1464. OutBuffer.pBuffers = OutBuffers;
  1465. OutBuffer.ulVersion = SECBUFFER_VERSION;
  1466. Status = g_SecurityFunc.InitializeSecurityContextA(
  1467. &m_Creds,
  1468. &m_Context,
  1469. NULL,
  1470. dwSSPIFlags,
  1471. 0,
  1472. SECURITY_NATIVE_DREP,
  1473. NULL,
  1474. 0,
  1475. &m_Context,
  1476. &OutBuffer,
  1477. &dwSSPIOutFlags,
  1478. &tsExpiry);
  1479. DSCHAN(("DisISC returns %X\n", Status));
  1480. DumpBuffers("DisISC out", &OutBuffer);
  1481. if(FAILED(Status))
  1482. {
  1483. goto cleanup;
  1484. }
  1485. pbMessage = (PBYTE)OutBuffers[0].pvBuffer;
  1486. cbMessage = OutBuffers[0].cbBuffer;
  1487. //
  1488. // Send the close notify message to the server.
  1489. //
  1490. if(pbMessage != NULL && cbMessage != 0)
  1491. {
  1492. DSCHAN((" write back %X bytes\n", cbMessage));
  1493. cbData = StreamWrite(SEQ_INTERNAL, pbMessage, cbMessage);
  1494. if (cbData == 0)
  1495. {
  1496. Status = HRESULT_FROM_WIN32(ERROR_WRITE_FAULT);
  1497. goto cleanup;
  1498. }
  1499. // Free output buffer.
  1500. g_SecurityFunc.FreeContextBuffer(pbMessage);
  1501. }
  1502. cleanup:
  1503. DSCHAN(("DisconnectFromServer returns %X\n", Status));
  1504. }