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.

1803 lines
51 KiB

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