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.

4408 lines
143 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 2000
  6. //
  7. // File: userapi.cxx
  8. //
  9. // Contents: User-mode APIs to the NtDigest security package
  10. //
  11. // Main user mode entry points into this dll:
  12. // SpUserModeInitialize
  13. // SpInstanceInit
  14. // SpDeleteUserModeContext
  15. // SpInitUserModeContext
  16. // SpMakeSignature
  17. // SpVerifySignature
  18. // SpSealMessage
  19. // SpUnsealMessage
  20. // SpGetContextToken
  21. // SpQueryContextAttributes
  22. // SpCompleteAuthToken
  23. // SpFormatCredentials
  24. // SpMarshallSupplementalCreds
  25. // SpExportSecurityContext
  26. // SpImportSecurityContext
  27. //
  28. // Helper functions:
  29. // SspCreateTokenDacl
  30. // SspMapContext (this is called in Lsa mode)
  31. //
  32. // History: ChandanS 26-Jul-1996 Stolen from kerberos\client2\userapi.cxx
  33. // KDamour 18Mar00 Stolen from NTLM userapi.cxx
  34. //
  35. //------------------------------------------------------------------------
  36. //
  37. // This area is still under determination as to support for userlevel functions
  38. //
  39. #include "global.h"
  40. #include <stdio.h> // For sprintf
  41. #if DBG
  42. #define TEMPSIZE 4000
  43. #endif
  44. // Winsock-ish host/network byte order converters for short and long integers.
  45. //
  46. #define htons(x) ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00))
  47. #define htonl(x) ((((x) >> 24) & 0x000000FFL) | \
  48. (((x) >> 8) & 0x0000FF00L) | \
  49. (((x) << 8) & 0x00FF0000L) | \
  50. (((x) << 24) & 0xFF000000L))
  51. //+-------------------------------------------------------------------------
  52. //
  53. // Function: SpUserModeInitialize
  54. //
  55. // Synopsis: Initialize an the Digest DLL in a client's
  56. // address space also called in LSA
  57. //
  58. // Effects:
  59. //
  60. // Arguments: LsaVersion - Version of the security dll loading the package
  61. // PackageVersion - Version of the Digest package
  62. // UserFunctionTable - Receives a copy of Digests's user mode
  63. // function table
  64. // pcTables - Receives count of tables returned.
  65. //
  66. // Requires:
  67. //
  68. // Returns: STATUS_SUCCESS - normal completion
  69. // STATUS_INVALID_PARAMETER - LsaVersion specified is incorrect
  70. //
  71. // Notes:
  72. //
  73. //
  74. //--------------------------------------------------------------------------
  75. NTSTATUS
  76. SEC_ENTRY
  77. SpUserModeInitialize(
  78. IN ULONG LsaVersion,
  79. OUT PULONG PackageVersion,
  80. OUT PSECPKG_USER_FUNCTION_TABLE * UserFunctionTable,
  81. OUT PULONG pcTables
  82. )
  83. {
  84. #if DBG
  85. DebugInitialize();
  86. #endif
  87. DebugLog((DEB_TRACE_FUNC, "SpUserModeInitialize: Entering\n" ));
  88. NTSTATUS Status = STATUS_SUCCESS;
  89. if (LsaVersion != SECPKG_INTERFACE_VERSION)
  90. {
  91. Status = STATUS_INVALID_PARAMETER;
  92. goto CleanUp;
  93. }
  94. *PackageVersion = SECPKG_INTERFACE_VERSION;
  95. g_NtDigestUserFuncTable.InstanceInit = SpInstanceInit;
  96. g_NtDigestUserFuncTable.MakeSignature = SpMakeSignature;
  97. g_NtDigestUserFuncTable.VerifySignature = SpVerifySignature;
  98. g_NtDigestUserFuncTable.SealMessage = SpSealMessage;
  99. g_NtDigestUserFuncTable.UnsealMessage = SpUnsealMessage;
  100. g_NtDigestUserFuncTable.GetContextToken = SpGetContextToken;
  101. g_NtDigestUserFuncTable.QueryContextAttributes = SpQueryContextAttributes;
  102. g_NtDigestUserFuncTable.CompleteAuthToken = SpCompleteAuthToken;
  103. g_NtDigestUserFuncTable.InitUserModeContext = SpInitUserModeContext;
  104. g_NtDigestUserFuncTable.DeleteUserModeContext = SpDeleteUserModeContext;
  105. g_NtDigestUserFuncTable.FormatCredentials = SpFormatCredentials;
  106. g_NtDigestUserFuncTable.MarshallSupplementalCreds = SpMarshallSupplementalCreds;
  107. g_NtDigestUserFuncTable.ExportContext = SpExportSecurityContext;
  108. g_NtDigestUserFuncTable.ImportContext = SpImportSecurityContext;
  109. *UserFunctionTable = &g_NtDigestUserFuncTable;
  110. *pcTables = 1;
  111. CleanUp:
  112. DebugLog((DEB_TRACE_FUNC, "SpUserModeInitialize: Leaving Status 0x%x\n", Status));
  113. return(Status);
  114. }
  115. //+-------------------------------------------------------------------------
  116. //
  117. // Function: SpInstanceInit
  118. //
  119. // Synopsis: Initialize an instance of the NtDigest package in a client's
  120. // address space. Also called once in LSA
  121. //
  122. // Effects:
  123. //
  124. // Arguments: Version - Version of the security dll loading the package
  125. // and it is Unused and Un-initialized
  126. // FunctionTable - Contains helper routines for use by NtDigest
  127. // and it is fixed static
  128. // UserFunctions - Receives a copy of NtDigest's user mode
  129. // function table - NOPE - has No information at all
  130. //
  131. // Requires:
  132. //
  133. // Returns: STATUS_SUCCESS
  134. //
  135. // Notes:
  136. //
  137. //
  138. //--------------------------------------------------------------------------
  139. NTSTATUS NTAPI
  140. SpInstanceInit(
  141. IN ULONG Version,
  142. IN PSECPKG_DLL_FUNCTIONS DllFunctionTable,
  143. OUT PVOID * UserFunctionTable
  144. )
  145. {
  146. DebugLog((DEB_TRACE_FUNC, "SpInstanceInit: Entering\n" ));
  147. NTSTATUS Status = STATUS_SUCCESS;
  148. // Save the Alloc/Free functions
  149. // Check if called in LSA or from Usermode - LSA calls SPInitialize then SPInstanceInit
  150. if (g_NtDigestState != NtDigestLsaMode)
  151. {
  152. g_NtDigestState = NtDigestUserMode; // indicate in user address space
  153. }
  154. g_UserFunctions = DllFunctionTable;
  155. // Need to initialize Crypto stuff and nonce creations
  156. Status = NonceInitialize();
  157. if (!NT_SUCCESS (Status))
  158. {
  159. DebugLog((DEB_ERROR, "SpInstanceInit: Error from NonceInitialize is %d\n", Status));
  160. goto CleanUp;
  161. }
  162. //
  163. // Init the UserMode Context stuff
  164. //
  165. Status = UserCtxtHandlerInit();
  166. if (!NT_SUCCESS (Status))
  167. {
  168. DebugLog((DEB_ERROR, "SpInstanceInit: Error from UserCtxtHandlerInit 0x%x\n", Status));
  169. goto CleanUp;
  170. }
  171. //
  172. // Read in the registry values for SSP configuration - in user mode space
  173. //
  174. SPLoadRegOptions();
  175. CleanUp:
  176. DebugLog((DEB_TRACE_FUNC, "SpInstanceInit: Leaving Status = 0x%lx\n", Status ));
  177. return(Status);
  178. }
  179. //+-------------------------------------------------------------------------
  180. //
  181. // Function: SpDeleteUserModeContext
  182. //
  183. // Synopsis: Deletes a user mode context by unlinking it and then
  184. // dereferencing it.
  185. //
  186. // Effects:
  187. //
  188. // Arguments: ContextHandle - Lsa context handle of the context to delete
  189. //
  190. // Requires:
  191. //
  192. // Returns: STATUS_SUCCESS on success, STATUS_INVALID_HANDLE if the
  193. // context can't be located
  194. //
  195. // Notes:
  196. // If this is an exported context, send a flag back to the LSA so that
  197. // Lsa does not call the SecpDeleteSecurityContext in the lsa process
  198. //
  199. //
  200. //--------------------------------------------------------------------------
  201. NTSTATUS NTAPI
  202. SpDeleteUserModeContext(
  203. IN ULONG_PTR ContextHandle
  204. )
  205. {
  206. DebugLog((DEB_TRACE_FUNC, "SpDeleteUserModeContext: Entering ContextHandle 0x%lx\n", ContextHandle ));
  207. PDIGEST_USERCONTEXT pUserContext = NULL;
  208. NTSTATUS Status = STATUS_SUCCESS;
  209. //
  210. // Find the currently existing user context and delink it
  211. // so that another context cannot Reference it before we
  212. // Dereference this one.
  213. //
  214. Status = UserCtxtHandlerHandleToContext(ContextHandle, TRUE, &pUserContext);
  215. if (!NT_SUCCESS(Status))
  216. {
  217. //
  218. // pContext is legally NULL when we are dealing with an incomplete
  219. // context. This can often be the case when the second call to
  220. // InitializeSecurityContext() fails.
  221. //
  222. /// Status = STATUS_INVALID_HANDLE;
  223. Status = STATUS_SUCCESS;
  224. DebugLog((DEB_WARN, "SpDeleteUserModeContext: UserCtxtHandlerHandleToContext not found 0x%x\n", Status ));
  225. goto CleanUp;
  226. }
  227. // Now deference
  228. if (pUserContext != NULL)
  229. {
  230. Status = UserCtxtHandlerRelease(pUserContext);
  231. if (!NT_SUCCESS(Status))
  232. {
  233. DebugLog((DEB_ERROR, "SpDeleteUserModeContext: DereferenceUserContext error Status 0x%x\n", Status ));
  234. }
  235. }
  236. CleanUp:
  237. DebugLog((DEB_TRACE_FUNC, "SpDeleteUserModeContext: Leaving ContextHandle 0x%lx status 0x%x\n",
  238. ContextHandle, Status ));
  239. return(Status);
  240. }
  241. //+-------------------------------------------------------------------------
  242. //
  243. // Function: SpInitUserModeContext
  244. //
  245. // Synopsis: Creates a user-mode context from a packed LSA mode context
  246. //
  247. // Effects:
  248. //
  249. // Arguments: ContextHandle - Lsa mode context handle for the context
  250. // PackedContext - A marshalled buffer containing the LSA
  251. // mode context.
  252. //
  253. // Requires:
  254. //
  255. // Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
  256. //
  257. // Notes:
  258. //
  259. //
  260. //--------------------------------------------------------------------------
  261. NTSTATUS NTAPI
  262. SpInitUserModeContext(
  263. IN ULONG_PTR ContextHandle,
  264. IN PSecBuffer PackedContext
  265. )
  266. {
  267. NTSTATUS Status = STATUS_SUCCESS;
  268. PDIGEST_USERCONTEXT pContext = NULL;
  269. PDIGEST_PACKED_USERCONTEXT pPackedUserContext = NULL;
  270. UINT Length = 0;
  271. DebugLog((DEB_TRACE_FUNC, "SpInitUserModeContext: Entering ContextHandle 0x%lx\n", ContextHandle ));
  272. ASSERT(PackedContext);
  273. // If Marshalled data is too small for holding a Client Context - reject it
  274. if (PackedContext->cbBuffer < sizeof(DIGEST_PACKED_USERCONTEXT))
  275. {
  276. Status = STATUS_INVALID_PARAMETER;
  277. DebugLog((DEB_ERROR, "SpInitUserModeContext: ContextData size < DIGEST_PACKED_USERCONTEXT\n" ));
  278. goto CleanUp;
  279. }
  280. pPackedUserContext = (PDIGEST_PACKED_USERCONTEXT) DigestAllocateMemory(PackedContext->cbBuffer);
  281. if (!pPackedUserContext)
  282. {
  283. Status = STATUS_INSUFFICIENT_RESOURCES;
  284. DebugLog((DEB_ERROR, "SpInitUserModeContext: DigestAllocateMemory for Packed Copy returns NULL\n" ));
  285. goto CleanUp;
  286. }
  287. // Copy the Packed User Context from LSA to local memory so it wil be long word aligned
  288. memcpy(pPackedUserContext, PackedContext->pvBuffer, PackedContext->cbBuffer);
  289. // Now we will unpack this transfered LSA context into UserMode space Context List
  290. pContext = (PDIGEST_USERCONTEXT) DigestAllocateMemory( sizeof(DIGEST_USERCONTEXT) );
  291. if (!pContext)
  292. {
  293. Status = STATUS_INSUFFICIENT_RESOURCES;
  294. DebugLog((DEB_ERROR, "SpInitUserModeContext: DigestAllocateMemory returns NULL\n" ));
  295. goto CleanUp;
  296. }
  297. Status = UserCtxtInit(pContext);
  298. if (!NT_SUCCESS(Status))
  299. {
  300. DebugLog((DEB_ERROR, "SpInitUserModeContext: UserContextInit error 0x%x\n", Status));
  301. goto CleanUp;
  302. }
  303. // Store the location of the context in the LSA
  304. pContext->LsaContext = ContextHandle;
  305. Status = DigestUnpackContext(pPackedUserContext, pContext);
  306. if (!NT_SUCCESS(Status))
  307. {
  308. DebugLog((DEB_ERROR, "SpInitUserModeContext: DigestUnpackContext error 0x%x\n", Status));
  309. goto CleanUp;
  310. }
  311. UserContextPrint(pContext);
  312. Status = UserCtxtHandlerInsertCred(pContext);
  313. if (!NT_SUCCESS(Status))
  314. {
  315. DebugLog((DEB_ERROR, "SpInitUserModeContext: UserCtxtHandlerInsertCred error status 0x%x\n", Status));
  316. goto CleanUp;
  317. }
  318. DebugLog((DEB_TRACE, "SpInitUserModeContext: (RefCount) UserContextInit created & listed 0x%x\n", pContext));
  319. CleanUp:
  320. if (!NT_SUCCESS(Status))
  321. {
  322. if (pContext != NULL)
  323. {
  324. // Release the User context on error if allocated
  325. UserCtxtFree(pContext);
  326. pContext = NULL;
  327. }
  328. }
  329. if (pPackedUserContext)
  330. {
  331. DigestFreeMemory(pPackedUserContext);
  332. pPackedUserContext = NULL;
  333. }
  334. // Let FreeContextBuffer handle freeing the virtual allocs
  335. if (PackedContext->pvBuffer != NULL)
  336. {
  337. FreeContextBuffer(PackedContext->pvBuffer);
  338. PackedContext->pvBuffer = NULL;
  339. PackedContext->cbBuffer = 0;
  340. }
  341. DebugLog((DEB_TRACE_FUNC, "SpInitUserModeContext: Leaving status 0x%x\n", Status ));
  342. return(Status);
  343. }
  344. //+-------------------------------------------------------------------------
  345. //
  346. // Function: SpMakeSignature
  347. //
  348. // Synopsis: Signs a message buffer by calculating a checksum over all
  349. // the non-read only data buffers and encrypting the checksum
  350. // along with a nonce.
  351. //
  352. // Effects:
  353. //
  354. // Arguments: ContextHandle - Handle of the context to use to sign the
  355. // message.
  356. // QualityOfProtection - Unused flags.
  357. // MessageBuffers - Contains an array of buffers to sign and
  358. // to store the signature.
  359. // MessageSequenceNumber - Sequence number for this message,
  360. // only used in datagram cases.
  361. //
  362. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  363. // was not configured for message integrity.
  364. // STATUS_INVALID_PARAMETER - the signature buffer could not
  365. // be found.
  366. // STATUS_BUFFER_TOO_SMALL - the signature buffer is too small
  367. // to hold the signature
  368. //
  369. // Returns:
  370. //
  371. // Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
  372. // routine SspHandleSignMessage. It's possible that
  373. // bugs got copied too
  374. //
  375. //
  376. //--------------------------------------------------------------------------
  377. NTSTATUS NTAPI
  378. SpMakeSignature(
  379. IN ULONG_PTR ContextHandle,
  380. IN ULONG fQOP,
  381. IN PSecBufferDesc pMessage,
  382. IN ULONG MessageSeqNo
  383. )
  384. {
  385. NTSTATUS Status = STATUS_SUCCESS;
  386. NTSTATUS SubStatus = STATUS_SUCCESS;
  387. PDIGEST_USERCONTEXT pContext = NULL;
  388. BOOL bServer = FALSE;
  389. DIGESTMODE_TYPE typeDigestMode = DIGESTMODE_UNDEFINED; // Are we in SASL or HTTP mode
  390. DebugLog((DEB_TRACE_FUNC, "SpMakeSignature:Entering ContextHandle 0x%lx\n", ContextHandle ));
  391. UNREFERENCED_PARAMETER(fQOP);
  392. Status = UserCtxtHandlerHandleToContext(ContextHandle, FALSE, &pContext);
  393. if (!NT_SUCCESS(Status))
  394. {
  395. Status = STATUS_INVALID_HANDLE;
  396. DebugLog((DEB_ERROR, "SpMakeSignature: Could not find ContextHandle\n" ));
  397. goto CleanUp;
  398. }
  399. UserContextPrint(pContext);
  400. // Check to see if Integrity is negotiated for SC
  401. bServer = pContext->CredentialUseFlags & DIGEST_CRED_INBOUND;
  402. if ((pContext->typeDigest == SASL_CLIENT) ||
  403. (pContext->typeDigest == SASL_SERVER))
  404. {
  405. typeDigestMode = DIGESTMODE_SASL;
  406. }
  407. else
  408. {
  409. typeDigestMode = DIGESTMODE_HTTP;
  410. }
  411. if (typeDigestMode == DIGESTMODE_HTTP)
  412. {
  413. DebugLog((DEB_TRACE, "SpMakeSignature: HTTP SignMessage selected\n"));
  414. Status = DigestUserHTTPHelper(
  415. pContext,
  416. eSign,
  417. pMessage,
  418. MessageSeqNo
  419. );
  420. }
  421. else
  422. {
  423. if ((bServer && !(pContext->ContextReq & ASC_REQ_INTEGRITY)) ||
  424. (!bServer && !(pContext->ContextReq & ISC_REQ_INTEGRITY)) )
  425. {
  426. Status = SEC_E_QOP_NOT_SUPPORTED;
  427. DebugLog((DEB_ERROR, "SpMakeSignature: Did not negotiate INTEGRITY\n" ));
  428. goto CleanUp;
  429. }
  430. DebugLog((DEB_TRACE, "SpMakeSignature: SASL SignMessage selected\n"));
  431. Status = DigestUserSignHelper(
  432. pContext,
  433. pMessage,
  434. MessageSeqNo
  435. );
  436. }
  437. if (!NT_SUCCESS(Status))
  438. {
  439. DebugLog((DEB_ERROR, "SpMakeSignature: DigestUserHTTP/SASLSignHelper returns %lx\n", Status ));
  440. goto CleanUp;
  441. }
  442. CleanUp:
  443. if (pContext != NULL)
  444. {
  445. SubStatus = UserCtxtHandlerRelease(pContext);
  446. // Don't destroy previous status
  447. if (NT_SUCCESS(Status))
  448. {
  449. Status = SubStatus;
  450. }
  451. }
  452. DebugLog((DEB_TRACE_FUNC, "SpMakeSignature:Leaving status 0x%lx\n", Status ));
  453. return(Status);
  454. }
  455. //+-------------------------------------------------------------------------
  456. //
  457. // Function: SpVerifySignature
  458. //
  459. // Synopsis: Verifies a signed message buffer by calculating the Digest Access
  460. // for data bufferswith the current Security Context state.
  461. //
  462. // Effects:
  463. //
  464. // Arguments: ContextHandle - Handle of the context to use to sign the
  465. // message.
  466. // MessageBuffers - Contains an array of signed buffers and
  467. // a signature buffer.
  468. // MessageSequenceNumber - Unused ULONG
  469. // QualityOfProtection - Unused flags.
  470. //
  471. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  472. // was not configured for message integrity.
  473. // STATUS_INVALID_PARAMETER - the signature buffer could not
  474. // be found or was too small.
  475. //
  476. // Returns:
  477. //
  478. // Notes: This routine should be called AFTER you have a valid security context
  479. // from (usually) acceptsecuritycontext. The usermode context has a nonce
  480. // count that is automatically incremented for each successful verify signature
  481. // function call. Therefore, calling this functio with the same noncecount
  482. // will return a failed status message.
  483. //
  484. //
  485. //--------------------------------------------------------------------------
  486. NTSTATUS NTAPI
  487. SpVerifySignature(
  488. IN ULONG_PTR ContextHandle,
  489. IN PSecBufferDesc pMessage,
  490. IN ULONG MessageSeqNo,
  491. OUT PULONG pfQOP
  492. )
  493. {
  494. NTSTATUS Status = STATUS_SUCCESS;
  495. NTSTATUS SubStatus = STATUS_SUCCESS;
  496. PDIGEST_USERCONTEXT pContext = NULL;
  497. BOOL bServer = FALSE;
  498. DIGESTMODE_TYPE typeDigestMode = DIGESTMODE_UNDEFINED; // Are we in SASL or HTTP mode
  499. DebugLog((DEB_TRACE_FUNC, "SpVerifySignature:Entering ContextHandle 0x%lx\n", ContextHandle ));
  500. // Reset output flags
  501. if (pfQOP)
  502. {
  503. *pfQOP = 0;
  504. }
  505. Status = UserCtxtHandlerHandleToContext(ContextHandle, FALSE, &pContext);
  506. if (!NT_SUCCESS(Status))
  507. {
  508. Status = STATUS_INVALID_HANDLE;
  509. DebugLog((DEB_ERROR, "SpVerifySignature: Could not find ContextHandle\n" ));
  510. goto CleanUp;
  511. }
  512. UserContextPrint(pContext);
  513. // Check to see if Integrity is negotiated for SC
  514. bServer = pContext->CredentialUseFlags & DIGEST_CRED_INBOUND;
  515. if ((pContext->typeDigest == SASL_CLIENT) ||
  516. (pContext->typeDigest == SASL_SERVER))
  517. {
  518. typeDigestMode = DIGESTMODE_SASL;
  519. }
  520. else
  521. {
  522. typeDigestMode = DIGESTMODE_HTTP;
  523. }
  524. if (typeDigestMode == DIGESTMODE_HTTP)
  525. {
  526. DebugLog((DEB_TRACE, "SpVerifySignature: HTTP VerifyMessage selected\n"));
  527. Status = DigestUserHTTPHelper(
  528. pContext,
  529. eVerify,
  530. pMessage,
  531. MessageSeqNo
  532. );
  533. }
  534. else
  535. {
  536. if ((bServer && !(pContext->ContextReq & ASC_REQ_INTEGRITY)) ||
  537. (!bServer && !(pContext->ContextReq & ISC_REQ_INTEGRITY)) )
  538. {
  539. Status = SEC_E_QOP_NOT_SUPPORTED;
  540. DebugLog((DEB_ERROR, "SpVerifySignature: Did not negotiate INTEGRITY\n" ));
  541. goto CleanUp;
  542. }
  543. else
  544. {
  545. DebugLog((DEB_TRACE, "SpVerifySignature: SASL VerifyMessage selected\n"));
  546. Status = DigestUserVerifyHelper(
  547. pContext,
  548. pMessage,
  549. MessageSeqNo
  550. );
  551. }
  552. }
  553. if (!NT_SUCCESS(Status))
  554. {
  555. DebugLog((DEB_ERROR, "SpVerifySignature: DigestUserHTTP/SASLSignHelper returns %lx\n", Status ));
  556. goto CleanUp;
  557. }
  558. CleanUp:
  559. if (pContext != NULL)
  560. {
  561. SubStatus = UserCtxtHandlerRelease(pContext);
  562. // Don't destroy previous status
  563. if (NT_SUCCESS(Status))
  564. {
  565. Status = SubStatus;
  566. }
  567. }
  568. DebugLog((DEB_TRACE_FUNC, "SpVerifySignature:Leaving status 0x%lx\n", Status ));
  569. return(Status);
  570. }
  571. //+-------------------------------------------------------------------------
  572. //
  573. // Function: SpSealMessage
  574. //
  575. // Synopsis: Verifies a signed message buffer by calculating a checksum over all
  576. // the non-read only data buffers and encrypting the checksum
  577. // along with a nonce.
  578. //
  579. // Effects:
  580. //
  581. // Arguments: ContextHandle - Handle of the context to use to sign the
  582. // message.
  583. // MessageBuffers - Contains an array of signed buffers and
  584. // a signature buffer.
  585. // MessageSequenceNumber - Sequence number for this message,
  586. // only used in datagram cases.
  587. // QualityOfProtection - Unused flags.
  588. //
  589. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  590. // was not configured for message integrity.
  591. // STATUS_INVALID_PARAMETER - the signature buffer could not
  592. // be found or was too small.
  593. //
  594. // Returns:
  595. //
  596. // Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
  597. // routine SspHandleSealMessage. It's possible that
  598. // bugs got copied too
  599. //
  600. //
  601. //--------------------------------------------------------------------------
  602. NTSTATUS NTAPI
  603. SpSealMessage(
  604. IN ULONG_PTR ContextHandle,
  605. IN ULONG fQOP,
  606. IN PSecBufferDesc pMessage,
  607. IN ULONG MessageSeqNo
  608. )
  609. {
  610. NTSTATUS Status = STATUS_SUCCESS;
  611. NTSTATUS SubStatus = STATUS_SUCCESS;
  612. PDIGEST_USERCONTEXT pContext = NULL;
  613. BOOL bServer = FALSE;
  614. DebugLog((DEB_TRACE_FUNC, "SpSealMessage:Entering ContextHandle 0x%lx\n", ContextHandle ));
  615. UNREFERENCED_PARAMETER(fQOP);
  616. Status = UserCtxtHandlerHandleToContext(ContextHandle, FALSE, &pContext);
  617. if (!NT_SUCCESS(Status))
  618. {
  619. Status = STATUS_INVALID_HANDLE;
  620. DebugLog((DEB_ERROR, "SpSealMessage: Could not find ContextHandle\n" ));
  621. goto CleanUp;
  622. }
  623. UserContextPrint(pContext);
  624. // Check to see if Confidentiality is negotiated for SC
  625. bServer = pContext->CredentialUseFlags & DIGEST_CRED_INBOUND;
  626. if ((bServer && !(pContext->ContextReq & ASC_RET_CONFIDENTIALITY)) ||
  627. (!bServer && !(pContext->ContextReq & ISC_RET_CONFIDENTIALITY)) )
  628. {
  629. // Since CONFIDENTIALITY not negoiated - check if integrity selected
  630. if ((bServer && (pContext->ContextReq & ASC_RET_INTEGRITY)) ||
  631. (!bServer && (pContext->ContextReq & ISC_RET_INTEGRITY)) )
  632. {
  633. DebugLog((DEB_TRACE, "SpSealMessage: No Confidentiality selected - use Integrity ONLY\n"));
  634. // Just call the Sign routine only
  635. Status = DigestUserSignHelper(
  636. pContext,
  637. pMessage,
  638. MessageSeqNo
  639. );
  640. }
  641. else
  642. {
  643. DebugLog((DEB_ERROR, "SpSealMessage: Neither Confidentiality nor Integrity selected\n"));
  644. Status = SEC_E_QOP_NOT_SUPPORTED;
  645. DebugLog((DEB_ERROR, "SpSealMessage: Did not negotiate CONFIDENTIALITY\n" ));
  646. goto CleanUp;
  647. }
  648. }
  649. else
  650. {
  651. // Use SignHelper for both SASL - HTTP not speced
  652. Status = DigestUserSealHelper(
  653. pContext,
  654. pMessage,
  655. MessageSeqNo
  656. );
  657. }
  658. if (!NT_SUCCESS(Status))
  659. {
  660. DebugLog((DEB_ERROR, "SpSealMessage: DigestUserSASLHelper returns %lx\n", Status ));
  661. goto CleanUp;
  662. }
  663. CleanUp:
  664. if (pContext != NULL)
  665. {
  666. SubStatus = UserCtxtHandlerRelease(pContext);
  667. // Don't destroy previous status
  668. if (NT_SUCCESS(Status))
  669. {
  670. Status = SubStatus;
  671. }
  672. }
  673. DebugLog((DEB_TRACE_FUNC, "SpSealMessage:Leaving status 0x%lx\n", Status ));
  674. return(Status);
  675. }
  676. //+-------------------------------------------------------------------------
  677. //
  678. // Function: SpUnsealMessage
  679. //
  680. // Synopsis: Verifies a signed message buffer by calculating a checksum over all
  681. // the non-read only data buffers and encrypting the checksum
  682. // along with a nonce.
  683. //
  684. // Effects:
  685. //
  686. // Arguments: ContextHandle - Handle of the context to use to sign the
  687. // message.
  688. // MessageBuffers - Contains an array of signed buffers and
  689. // a signature buffer.
  690. // MessageSequenceNumber - Sequence number for this message,
  691. // only used in datagram cases.
  692. // QualityOfProtection - Unused flags.
  693. //
  694. // Requires: STATUS_INVALID_HANDLE - the context could not be found or
  695. // was not configured for message integrity.
  696. // STATUS_INVALID_PARAMETER - the signature buffer could not
  697. // be found or was too small.
  698. //
  699. // Returns:
  700. //
  701. // Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
  702. // routine SspHandleUnsealMessage. It's possible that
  703. // bugs got copied too
  704. //
  705. //
  706. //--------------------------------------------------------------------------
  707. NTSTATUS NTAPI
  708. SpUnsealMessage(
  709. IN ULONG_PTR ContextHandle,
  710. IN PSecBufferDesc pMessage,
  711. IN ULONG MessageSeqNo,
  712. OUT PULONG pfQOP
  713. )
  714. {
  715. NTSTATUS Status = STATUS_SUCCESS;
  716. NTSTATUS SubStatus = STATUS_SUCCESS;
  717. PDIGEST_USERCONTEXT pContext = NULL;
  718. BOOL bServer; // acting as the server ?
  719. DebugLog((DEB_TRACE_FUNC, "SpUnsealMessage:Entering ContextHandle 0x%lx\n", ContextHandle ));
  720. // Reset output flags
  721. if (pfQOP)
  722. {
  723. *pfQOP = 0;
  724. }
  725. Status = UserCtxtHandlerHandleToContext(ContextHandle, FALSE, &pContext);
  726. if (!NT_SUCCESS(Status))
  727. {
  728. Status = STATUS_INVALID_HANDLE;
  729. DebugLog((DEB_ERROR, "SpUnsealMessage: Could not find ContextHandle\n" ));
  730. goto CleanUp;
  731. }
  732. UserContextPrint(pContext);
  733. // Check to see if Confidentiality is negotiated for SC
  734. bServer = pContext->CredentialUseFlags & DIGEST_CRED_INBOUND;
  735. if ((bServer && !(pContext->ContextReq & ASC_RET_CONFIDENTIALITY)) ||
  736. (!bServer && !(pContext->ContextReq & ISC_RET_CONFIDENTIALITY)) )
  737. {
  738. if ((bServer && (pContext->ContextReq & ASC_RET_INTEGRITY)) ||
  739. (!bServer && (pContext->ContextReq & ISC_RET_INTEGRITY)) )
  740. {
  741. DebugLog((DEB_TRACE, "SpUnsealMessage: No Confidentiality selected - use Integrity ONLY\n"));
  742. Status = DigestUserVerifyHelper(
  743. pContext,
  744. pMessage,
  745. MessageSeqNo
  746. );
  747. // signal QOP was only for integrity
  748. if (pfQOP)
  749. {
  750. *pfQOP = SIGN_ONLY;
  751. }
  752. }
  753. else
  754. {
  755. DebugLog((DEB_ERROR, "SpUnsealMessage: Neither Confidentiality nor Integrity selected\n"));
  756. Status = SEC_E_QOP_NOT_SUPPORTED;
  757. DebugLog((DEB_ERROR, "SpUnsealMessage: Did not negotiate CONFIDENTIALITY\n" ));
  758. goto CleanUp;
  759. }
  760. }
  761. else
  762. {
  763. Status = DigestUserUnsealHelper(
  764. pContext,
  765. pMessage,
  766. MessageSeqNo
  767. );
  768. }
  769. if (!NT_SUCCESS(Status))
  770. {
  771. DebugLog((DEB_ERROR, "SpUnsealMessage: DigestUserSASLHelper returns %lx\n", Status ));
  772. goto CleanUp;
  773. }
  774. CleanUp:
  775. if (pContext != NULL)
  776. {
  777. SubStatus = UserCtxtHandlerRelease(pContext);
  778. // Don't destroy previous status
  779. if (NT_SUCCESS(Status))
  780. {
  781. Status = SubStatus;
  782. }
  783. }
  784. DebugLog((DEB_TRACE_FUNC, "SpUnsealMessage:Leaving status 0x%lx\n", Status ));
  785. return(Status);
  786. }
  787. //+-------------------------------------------------------------------------
  788. //
  789. // Function: SpGetContextToken
  790. //
  791. // Synopsis: returns a pointer to the token for a server-side context
  792. //
  793. // Effects:
  794. //
  795. // Arguments:
  796. //
  797. // Requires:
  798. //
  799. // Returns:
  800. //
  801. // Notes: Used in ImpersonateSecurityContext SSPI Call
  802. //
  803. //
  804. //--------------------------------------------------------------------------
  805. NTSTATUS NTAPI
  806. SpGetContextToken(
  807. IN ULONG_PTR ContextHandle,
  808. OUT PHANDLE ImpersonationToken
  809. )
  810. {
  811. DebugLog((DEB_TRACE_FUNC, "SpGetContextToken: Entering ContextHandle 0x%lx\n", ContextHandle ));
  812. NTSTATUS Status = STATUS_SUCCESS;
  813. PDIGEST_USERCONTEXT pContext = NULL;
  814. Status = UserCtxtHandlerHandleToContext(ContextHandle, FALSE, &pContext);
  815. if (!NT_SUCCESS(Status))
  816. {
  817. DebugLog((DEB_ERROR, "SpGetContextToken: UserCtxtHandlerHandleToContext error 0x%x\n", Status));
  818. }
  819. DebugLog((DEB_TRACE, "SpGetContextToken: Client ImpersonationToken 0x%lx\n", pContext->ClientTokenHandle ));
  820. if (pContext && pContext->ClientTokenHandle)
  821. {
  822. *ImpersonationToken = pContext->ClientTokenHandle;
  823. goto CleanUp;
  824. }
  825. Status = STATUS_INVALID_HANDLE;
  826. DebugLog((DEB_ERROR, "SpGetContextToken: no token handle\n" ));
  827. CleanUp:
  828. if (pContext != NULL)
  829. {
  830. Status = UserCtxtHandlerRelease(pContext);
  831. }
  832. DebugLog((DEB_TRACE_FUNC, "SpGetContextToken: Leaving Status 0x%lx\n", Status ));
  833. return(Status);
  834. }
  835. //+-------------------------------------------------------------------------
  836. //
  837. // Function: SpQueryContextAttributes
  838. //
  839. // Synopsis: Querys attributes of the specified context
  840. // This API allows a customer of the security
  841. // services to determine certain attributes of
  842. // the context. These are: sizes, names, and lifespan.
  843. //
  844. // Effects:
  845. //
  846. // Arguments:
  847. //
  848. // ContextHandle - Handle to the context to query.
  849. //
  850. // Attribute - Attribute to query.
  851. //
  852. //
  853. // Buffer - Buffer to copy the data into. The buffer must
  854. // be large enough to fit the queried attribute.
  855. //
  856. //
  857. // Requires:
  858. //
  859. // Returns:
  860. //
  861. // STATUS_SUCCESS - Call completed successfully
  862. //
  863. // STATUS_INVALID_HANDLE -- Credential/Context Handle is invalid
  864. // STATUS_NOT_SUPPORTED -- Function code is not supported
  865. //
  866. // Notes:
  867. //
  868. //--------------------------------------------------------------------------
  869. NTSTATUS NTAPI
  870. SpQueryContextAttributes(
  871. IN ULONG_PTR ContextHandle,
  872. IN ULONG Attribute,
  873. IN OUT PVOID Buffer
  874. )
  875. {
  876. NTSTATUS Status = STATUS_SUCCESS;
  877. NTSTATUS SubStatus = STATUS_SUCCESS;
  878. PDIGEST_USERCONTEXT pContext = NULL;
  879. DebugLog((DEB_TRACE_FUNC, "SpQueryContextAttributes: Entering ContextHandle 0x%lx\n", ContextHandle ));
  880. PSecPkgContext_Sizes ContextSizes = NULL;
  881. PSecPkgContext_Flags ContextFlags = NULL;
  882. PSecPkgContext_DceInfo ContextDceInfo = NULL;
  883. PSecPkgContext_Names ContextNames = NULL;
  884. PSecPkgContext_PackageInfo PackageInfo = NULL;
  885. PSecPkgContext_NegotiationInfo NegInfo = NULL;
  886. PSecPkgContext_PasswordExpiry PasswordExpires = NULL;
  887. PSecPkgContext_KeyInfo KeyInfo = NULL;
  888. PSecPkgContext_AccessToken AccessToken = NULL;
  889. PSecPkgContext_StreamSizes StreamSizes = NULL;
  890. ULONG PackageInfoSize = 0;
  891. BOOL bServer = FALSE;
  892. LPWSTR pszEncryptAlgorithmName = NULL;
  893. LPWSTR pszSignatureAlgorithmName = NULL;
  894. DWORD dwBytes = 0;
  895. ULONG ulMaxMessage = 0;
  896. DIGESTMODE_TYPE typeDigestMode = DIGESTMODE_UNDEFINED; // Are we in SASL or HTTP mode
  897. Status = UserCtxtHandlerHandleToContext(ContextHandle, FALSE, &pContext);
  898. if (!NT_SUCCESS(Status))
  899. {
  900. DebugLog((DEB_ERROR, "SpQueryContextAttributes: HandleToContext error 0x%x\n", Status));
  901. Status = STATUS_INVALID_HANDLE;
  902. goto CleanUp;
  903. }
  904. // Check to see if Integrity is negotiated for SC
  905. bServer = pContext->CredentialUseFlags & DIGEST_CRED_INBOUND;
  906. if ((pContext->typeDigest == SASL_CLIENT) ||
  907. (pContext->typeDigest == SASL_SERVER))
  908. {
  909. typeDigestMode = DIGESTMODE_SASL;
  910. }
  911. else
  912. {
  913. typeDigestMode = DIGESTMODE_HTTP;
  914. }
  915. //
  916. // Handle each of the various queried attributes
  917. //
  918. DebugLog((DEB_TRACE, "SpQueryContextAttributes : 0x%lx\n", Attribute ));
  919. switch ( Attribute) {
  920. case SECPKG_ATTR_SIZES:
  921. ContextSizes = (PSecPkgContext_Sizes) Buffer;
  922. ZeroMemory(ContextSizes, sizeof(SecPkgContext_Sizes));
  923. ContextSizes->cbMaxToken = NTDIGEST_SP_MAX_TOKEN_SIZE;
  924. if (typeDigestMode == DIGESTMODE_HTTP)
  925. { // HTTP has signature the same as token in Authentication Header info
  926. ContextSizes->cbMaxSignature = NTDIGEST_SP_MAX_TOKEN_SIZE;
  927. }
  928. else
  929. { // SASL has specialized signature block
  930. ContextSizes->cbMaxSignature = MAC_BLOCK_SIZE + MAX_PADDING;
  931. }
  932. if ((pContext->typeCipher == CIPHER_3DES) ||
  933. (pContext->typeCipher == CIPHER_DES))
  934. {
  935. ContextSizes->cbBlockSize = DES_BLOCKSIZE;
  936. ContextSizes->cbSecurityTrailer = MAC_BLOCK_SIZE + MAX_PADDING;
  937. }
  938. else if ((pContext->typeCipher == CIPHER_RC4) ||
  939. (pContext->typeCipher == CIPHER_RC4_40) ||
  940. (pContext->typeCipher == CIPHER_RC4_56))
  941. {
  942. ContextSizes->cbBlockSize = RC4_BLOCKSIZE;
  943. ContextSizes->cbSecurityTrailer = MAC_BLOCK_SIZE + MAX_PADDING;
  944. }
  945. else
  946. {
  947. ContextSizes->cbBlockSize = 0;
  948. if (typeDigestMode == DIGESTMODE_HTTP)
  949. { // HTTP has signature the same as token in Authentication Header info
  950. ContextSizes->cbSecurityTrailer = 0;
  951. }
  952. else
  953. { // SASL has specialized signature block
  954. ContextSizes->cbSecurityTrailer = MAC_BLOCK_SIZE + MAX_PADDING; // handle Auth-int case
  955. }
  956. }
  957. break;
  958. case SECPKG_ATTR_DCE_INFO:
  959. ContextDceInfo = (PSecPkgContext_DceInfo) Buffer;
  960. ZeroMemory(ContextDceInfo, sizeof(SecPkgContext_DceInfo));
  961. ContextDceInfo->AuthzSvc = 0;
  962. break;
  963. case SECPKG_ATTR_NAMES:
  964. ContextNames = (PSecPkgContext_Names) Buffer;
  965. ZeroMemory(ContextNames, sizeof(SecPkgContext_Names));
  966. if (pContext->ustrAccountName.Length && pContext->ustrAccountName.Buffer)
  967. {
  968. dwBytes = pContext->ustrAccountName.Length + sizeof(WCHAR);
  969. ContextNames->sUserName = (LPWSTR)g_UserFunctions->AllocateHeap(dwBytes);
  970. if (ContextNames->sUserName)
  971. {
  972. ZeroMemory(ContextNames->sUserName, dwBytes);
  973. memcpy(ContextNames->sUserName, pContext->ustrAccountName.Buffer, pContext->ustrAccountName.Length);
  974. }
  975. else
  976. {
  977. Status = STATUS_INSUFFICIENT_RESOURCES;
  978. }
  979. }
  980. else
  981. {
  982. Status = STATUS_INSUFFICIENT_RESOURCES;
  983. }
  984. break;
  985. case SECPKG_ATTR_PACKAGE_INFO:
  986. case SECPKG_ATTR_NEGOTIATION_INFO:
  987. //
  988. // Return the information about this package. This is useful for
  989. // callers who used SPNEGO and don't know what package they got.
  990. //
  991. if ((Attribute == SECPKG_ATTR_NEGOTIATION_INFO) && (g_fParameter_Negotiate == FALSE))
  992. {
  993. Status = STATUS_NOT_SUPPORTED;
  994. goto CleanUp;
  995. }
  996. PackageInfo = (PSecPkgContext_PackageInfo) Buffer;
  997. ZeroMemory(PackageInfo, sizeof(SecPkgContext_PackageInfo));
  998. PackageInfoSize = sizeof(SecPkgInfoW) + sizeof(WDIGEST_SP_NAME) + sizeof(NTDIGEST_SP_COMMENT);
  999. PackageInfo->PackageInfo = (PSecPkgInfoW) g_UserFunctions->AllocateHeap(PackageInfoSize);
  1000. if (PackageInfo->PackageInfo == NULL)
  1001. {
  1002. Status = STATUS_INSUFFICIENT_RESOURCES;
  1003. goto CleanUp;
  1004. }
  1005. PackageInfo->PackageInfo->Name = (LPWSTR) (PackageInfo->PackageInfo + 1);
  1006. PackageInfo->PackageInfo->Comment = (LPWSTR) ((((PBYTE) PackageInfo->PackageInfo->Name)) + sizeof(WDIGEST_SP_NAME));
  1007. wcscpy(
  1008. PackageInfo->PackageInfo->Name,
  1009. WDIGEST_SP_NAME
  1010. );
  1011. wcscpy(
  1012. PackageInfo->PackageInfo->Comment,
  1013. NTDIGEST_SP_COMMENT
  1014. );
  1015. PackageInfo->PackageInfo->wVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
  1016. PackageInfo->PackageInfo->wRPCID = RPC_C_AUTHN_DIGEST;
  1017. PackageInfo->PackageInfo->fCapabilities = NTDIGEST_SP_CAPS;
  1018. PackageInfo->PackageInfo->cbMaxToken = NTDIGEST_SP_MAX_TOKEN_SIZE;
  1019. if ( Attribute == SECPKG_ATTR_NEGOTIATION_INFO )
  1020. {
  1021. NegInfo = (PSecPkgContext_NegotiationInfo) PackageInfo ;
  1022. NegInfo->NegotiationState = SECPKG_NEGOTIATION_COMPLETE ;
  1023. }
  1024. break;
  1025. case SECPKG_ATTR_PASSWORD_EXPIRY:
  1026. PasswordExpires = (PSecPkgContext_PasswordExpiry) Buffer;
  1027. if (pContext->Expires.QuadPart != 0)
  1028. {
  1029. PasswordExpires->tsPasswordExpires = pContext->Expires;
  1030. }
  1031. else
  1032. Status = STATUS_NOT_SUPPORTED;
  1033. break;
  1034. case SECPKG_ATTR_KEY_INFO:
  1035. KeyInfo = (PSecPkgContext_KeyInfo) Buffer;
  1036. ZeroMemory(KeyInfo, sizeof(SecPkgContext_KeyInfo));
  1037. if (typeDigestMode == DIGESTMODE_HTTP)
  1038. {
  1039. // HTTP mode
  1040. KeyInfo->SignatureAlgorithm = CALG_MD5;
  1041. }
  1042. else
  1043. {
  1044. // SASL mode
  1045. KeyInfo->KeySize = 128; // All modes use a 128 bit key - may have less entropy though (i.e. rc4-XX)
  1046. KeyInfo->SignatureAlgorithm = CALG_HMAC;
  1047. pszSignatureAlgorithmName = WSTR_CIPHER_HMAC_MD5;
  1048. switch (pContext->typeCipher)
  1049. {
  1050. case CIPHER_RC4:
  1051. case CIPHER_RC4_40:
  1052. case CIPHER_RC4_56:
  1053. KeyInfo->KeySize = 16 * 8; // All modes use a 128 bit key - may have less entropy though (i.e. rc4-XX)
  1054. KeyInfo->SignatureAlgorithm = CALG_RC4;
  1055. pszEncryptAlgorithmName = WSTR_CIPHER_RC4;
  1056. break;
  1057. case CIPHER_DES:
  1058. KeyInfo->KeySize = 7 * 8;
  1059. KeyInfo->SignatureAlgorithm = CALG_DES;
  1060. pszEncryptAlgorithmName = WSTR_CIPHER_DES;
  1061. break;
  1062. case CIPHER_3DES:
  1063. KeyInfo->KeySize = 14 * 8;
  1064. KeyInfo->SignatureAlgorithm = CALG_3DES_112;
  1065. pszEncryptAlgorithmName = WSTR_CIPHER_3DES;
  1066. break;
  1067. }
  1068. if (pszEncryptAlgorithmName)
  1069. {
  1070. KeyInfo->sEncryptAlgorithmName = (LPWSTR)
  1071. g_UserFunctions->AllocateHeap(sizeof(WCHAR) * (wcslen(pszEncryptAlgorithmName) + 1));
  1072. if (KeyInfo->sEncryptAlgorithmName != NULL)
  1073. {
  1074. wcscpy(
  1075. KeyInfo->sEncryptAlgorithmName,
  1076. pszEncryptAlgorithmName
  1077. );
  1078. }
  1079. else
  1080. {
  1081. Status = STATUS_INSUFFICIENT_RESOURCES;
  1082. }
  1083. }
  1084. if (pszSignatureAlgorithmName)
  1085. {
  1086. KeyInfo->sSignatureAlgorithmName = (LPWSTR)
  1087. g_UserFunctions->AllocateHeap(sizeof(WCHAR) * (wcslen(pszSignatureAlgorithmName) + 1));
  1088. if (KeyInfo->sSignatureAlgorithmName != NULL)
  1089. {
  1090. wcscpy(
  1091. KeyInfo->sSignatureAlgorithmName,
  1092. pszSignatureAlgorithmName
  1093. );
  1094. }
  1095. else
  1096. {
  1097. Status = STATUS_INSUFFICIENT_RESOURCES;
  1098. }
  1099. }
  1100. }
  1101. break;
  1102. case SECPKG_ATTR_STREAM_SIZES:
  1103. StreamSizes = (PSecPkgContext_StreamSizes) Buffer;
  1104. ZeroMemory(StreamSizes, sizeof(SecPkgContext_StreamSizes));
  1105. if (typeDigestMode == DIGESTMODE_HTTP)
  1106. {
  1107. }
  1108. else
  1109. { // SASL
  1110. ulMaxMessage = pContext->ulRecvMaxBuf;
  1111. if (pContext->ulSendMaxBuf < ulMaxMessage)
  1112. {
  1113. ulMaxMessage = pContext->ulSendMaxBuf;
  1114. }
  1115. StreamSizes->cbMaximumMessage = ulMaxMessage - (MAC_BLOCK_SIZE + MAX_PADDING);
  1116. }
  1117. if ((pContext->typeCipher == CIPHER_3DES) ||
  1118. (pContext->typeCipher == CIPHER_DES))
  1119. {
  1120. StreamSizes->cbBlockSize = DES_BLOCKSIZE;
  1121. StreamSizes->cbTrailer = MAC_BLOCK_SIZE + MAX_PADDING;
  1122. }
  1123. else if ((pContext->typeCipher == CIPHER_RC4) ||
  1124. (pContext->typeCipher == CIPHER_RC4_40) ||
  1125. (pContext->typeCipher == CIPHER_RC4_56))
  1126. {
  1127. StreamSizes->cbBlockSize = RC4_BLOCKSIZE;
  1128. StreamSizes->cbTrailer = MAC_BLOCK_SIZE + MAX_PADDING;
  1129. }
  1130. break;
  1131. case SECPKG_ATTR_ACCESS_TOKEN:
  1132. AccessToken = (PSecPkgContext_AccessToken) Buffer;
  1133. //
  1134. // ClientTokenHandle can be NULL, for instance:
  1135. // 1. client side context.
  1136. // 2. incomplete server context.
  1137. // Token is not duped - caller must not CloseHandle
  1138. AccessToken->AccessToken = (void*)pContext->ClientTokenHandle;
  1139. break;
  1140. default:
  1141. Status = STATUS_NOT_SUPPORTED;
  1142. break;
  1143. }
  1144. CleanUp:
  1145. if (!NT_SUCCESS(Status))
  1146. {
  1147. switch (Attribute) {
  1148. case SECPKG_ATTR_NAMES:
  1149. if (ContextNames != NULL && ContextNames->sUserName )
  1150. {
  1151. g_UserFunctions->FreeHeap(ContextNames->sUserName);
  1152. ContextNames->sUserName = NULL;
  1153. }
  1154. break;
  1155. case SECPKG_ATTR_DCE_INFO:
  1156. if (ContextDceInfo != NULL && ContextDceInfo->pPac)
  1157. {
  1158. g_UserFunctions->FreeHeap(ContextDceInfo->pPac);
  1159. ContextDceInfo->pPac = NULL;
  1160. }
  1161. break;
  1162. case SECPKG_ATTR_KEY_INFO:
  1163. if (KeyInfo != NULL && KeyInfo->sEncryptAlgorithmName)
  1164. {
  1165. g_UserFunctions->FreeHeap(KeyInfo->sEncryptAlgorithmName);
  1166. KeyInfo->sEncryptAlgorithmName = NULL;
  1167. }
  1168. if (KeyInfo != NULL && KeyInfo->sSignatureAlgorithmName)
  1169. {
  1170. g_UserFunctions->FreeHeap(KeyInfo->sSignatureAlgorithmName);
  1171. KeyInfo->sSignatureAlgorithmName = NULL;
  1172. }
  1173. break;
  1174. }
  1175. }
  1176. if (pContext != NULL)
  1177. {
  1178. SubStatus = UserCtxtHandlerRelease(pContext);
  1179. }
  1180. DebugLog((DEB_TRACE_FUNC, "SpQueryContextAttributes: Leaving ContextHandle 0x%lx\n", ContextHandle ));
  1181. return(Status);
  1182. }
  1183. //+-------------------------------------------------------------------------
  1184. //
  1185. // Function: SpCompleteAuthToken
  1186. //
  1187. // Synopsis: Completes a context - used to perform user mode verification of
  1188. // challenge response for non-persistent connections re-established via ASC
  1189. // call.
  1190. //
  1191. // Effects:
  1192. //
  1193. // Arguments:
  1194. //
  1195. // Requires:
  1196. //
  1197. // Returns:
  1198. //
  1199. // Notes:
  1200. //
  1201. //
  1202. //--------------------------------------------------------------------------
  1203. NTSTATUS NTAPI
  1204. SpCompleteAuthToken(
  1205. IN ULONG_PTR ContextHandle,
  1206. IN PSecBufferDesc InputBuffer
  1207. )
  1208. {
  1209. NTSTATUS Status = STATUS_SUCCESS;
  1210. ULONG ulQOP = 0;
  1211. DebugLog((DEB_TRACE_FUNC, "SpCompleteAuthToken: Entering ContextHandle 0x%lx\n", ContextHandle ));
  1212. Status = SpVerifySignature(ContextHandle, InputBuffer, 0, &ulQOP);
  1213. DebugLog((DEB_TRACE_FUNC, "SpCompleteAuthToken: Leaving ContextHandle 0x%lx Status = 0x%x\n",
  1214. ContextHandle, Status));
  1215. return(Status);
  1216. }
  1217. NTSTATUS NTAPI
  1218. SpFormatCredentials(
  1219. IN PSecBuffer Credentials,
  1220. OUT PSecBuffer FormattedCredentials
  1221. )
  1222. {
  1223. UNREFERENCED_PARAMETER (Credentials);
  1224. UNREFERENCED_PARAMETER (FormattedCredentials);
  1225. DebugLog((DEB_TRACE_FUNC, "SpFormatCredentials: Entering/Leaving\n"));
  1226. return(SEC_E_UNSUPPORTED_FUNCTION);
  1227. }
  1228. NTSTATUS NTAPI
  1229. SpMarshallSupplementalCreds(
  1230. IN ULONG CredentialSize,
  1231. IN PUCHAR Credentials,
  1232. OUT PULONG MarshalledCredSize,
  1233. OUT PVOID * MarshalledCreds
  1234. )
  1235. {
  1236. UNREFERENCED_PARAMETER (CredentialSize);
  1237. UNREFERENCED_PARAMETER (Credentials);
  1238. UNREFERENCED_PARAMETER (MarshalledCredSize);
  1239. UNREFERENCED_PARAMETER (MarshalledCreds);
  1240. DebugLog((DEB_TRACE_FUNC, "SpMarshallSupplementalCreds: Entering/Leaving\n"));
  1241. return(SEC_E_UNSUPPORTED_FUNCTION);
  1242. }
  1243. //+-------------------------------------------------------------------------
  1244. //
  1245. // Function: NtDigestMakePackedContext
  1246. //
  1247. // Synopsis: Maps a context to the caller's address space
  1248. //
  1249. // Effects:
  1250. //
  1251. // Arguments: Context - The context to map
  1252. // MappedContext - Set to TRUE on success
  1253. // ContextData - Receives a buffer in the caller's address space
  1254. // with the mapped context.
  1255. //
  1256. // Requires:
  1257. //
  1258. // Returns:
  1259. //
  1260. // Notes:
  1261. //
  1262. //
  1263. //--------------------------------------------------------------------------
  1264. NTSTATUS
  1265. NtDigestMakePackedContext(
  1266. IN PDIGEST_USERCONTEXT Context,
  1267. OUT PBOOLEAN MappedContext,
  1268. OUT PSecBuffer ContextData,
  1269. IN ULONG Flags
  1270. )
  1271. {
  1272. NTSTATUS Status = STATUS_SUCCESS;
  1273. PDIGEST_USERCONTEXT PackedContext = NULL;
  1274. ULONG ContextSize = 0, ContextNameSize = 0;
  1275. DebugLog((DEB_TRACE_FUNC, "NtDigestMakePackedContext: Entering/Leaving\n"));
  1276. return(SEC_E_UNSUPPORTED_FUNCTION);
  1277. }
  1278. //+-------------------------------------------------------------------------
  1279. //
  1280. // Function: SpExportSecurityContext
  1281. //
  1282. // Synopsis: Exports a security context to another process
  1283. //
  1284. // Effects: Allocates memory for output
  1285. //
  1286. // Arguments: ContextHandle - handle to context to export
  1287. // Flags - Flags concerning duplication. Allowable flags:
  1288. // SECPKG_CONTEXT_EXPORT_DELETE_OLD - causes old context
  1289. // to be deleted.
  1290. // PackedContext - Receives serialized context to be freed with
  1291. // FreeContextBuffer
  1292. // TokenHandle - Optionally receives handle to context's token.
  1293. //
  1294. // Requires:
  1295. //
  1296. // Returns:
  1297. //
  1298. // Notes:
  1299. //
  1300. //
  1301. //--------------------------------------------------------------------------
  1302. NTSTATUS
  1303. SpExportSecurityContext(
  1304. IN ULONG_PTR ContextHandle,
  1305. IN ULONG Flags,
  1306. OUT PSecBuffer PackedContext,
  1307. OUT PHANDLE TokenHandle
  1308. )
  1309. {
  1310. PDIGEST_USERCONTEXT Context = NULL, pvContext = NULL;
  1311. NTSTATUS Status = STATUS_SUCCESS;
  1312. NTSTATUS SubStatus = STATUS_SUCCESS;
  1313. ULONG ContextSize = 0;
  1314. BOOLEAN MappedContext = FALSE;
  1315. DebugLog((DEB_TRACE_FUNC, "SpExportSecurityContext:Entering/Leaving ContextHandle 0x%x\n", ContextHandle ));
  1316. return(SEC_E_UNSUPPORTED_FUNCTION);
  1317. }
  1318. //+-------------------------------------------------------------------------
  1319. //
  1320. // Function: NtDigestCreateUserModeContext
  1321. //
  1322. // Synopsis: Creates a user-mode context to support impersonation and
  1323. // message integrity and privacy
  1324. //
  1325. // Effects:
  1326. //
  1327. // Arguments:
  1328. //
  1329. // Requires:
  1330. //
  1331. // Returns:
  1332. //
  1333. // Notes:
  1334. //
  1335. //
  1336. //--------------------------------------------------------------------------
  1337. NTSTATUS
  1338. NtDigestCreateUserModeContext(
  1339. IN ULONG_PTR ContextHandle,
  1340. IN HANDLE Token,
  1341. IN PSecBuffer MarshalledContext,
  1342. OUT PDIGEST_USERCONTEXT * NewContext
  1343. )
  1344. {
  1345. NTSTATUS Status = STATUS_SUCCESS;
  1346. DebugLog((DEB_TRACE_FUNC, "NtDigestCreateUserModeContext: Entering/Leaving ContextHandle 0x%x\n", ContextHandle ));
  1347. return(SEC_E_UNSUPPORTED_FUNCTION);
  1348. }
  1349. //+-------------------------------------------------------------------------
  1350. //
  1351. // Function: SpImportSecurityContext
  1352. //
  1353. // Synopsis:
  1354. //
  1355. // Effects:
  1356. //
  1357. // Arguments:
  1358. //
  1359. // Requires:
  1360. //
  1361. // Returns:
  1362. //
  1363. // Notes:
  1364. //
  1365. //
  1366. //--------------------------------------------------------------------------
  1367. NTSTATUS
  1368. SpImportSecurityContext(
  1369. IN PSecBuffer PackedContext,
  1370. IN HANDLE Token,
  1371. OUT PULONG_PTR ContextHandle
  1372. )
  1373. {
  1374. NTSTATUS Status = STATUS_SUCCESS;
  1375. NTSTATUS SubStatus = STATUS_SUCCESS;
  1376. PDIGEST_USERCONTEXT Context = NULL;
  1377. DebugLog((DEB_TRACE_FUNC, "SpImportSecurityContext: Entering/Leaving ContextHandle 0x%x\n", ContextHandle));
  1378. return(SEC_E_UNSUPPORTED_FUNCTION);
  1379. }
  1380. /*++
  1381. RoutineDescription:
  1382. Gets the TOKEN_USER from an open token
  1383. Arguments:
  1384. Token - Handle to a token open for TOKEN_QUERY access
  1385. Return Value:
  1386. STATUS_INSUFFICIENT_RESOURCES - not enough memory to complete the
  1387. function.
  1388. Errors from NtQueryInformationToken.
  1389. --*/
  1390. NTSTATUS
  1391. SspGetTokenUser(
  1392. HANDLE Token,
  1393. PTOKEN_USER * pTokenUser
  1394. )
  1395. {
  1396. PTOKEN_USER LocalTokenUser = NULL;
  1397. NTSTATUS Status = STATUS_SUCCESS;
  1398. ULONG TokenUserSize = 0;
  1399. DebugLog((DEB_TRACE_FUNC, "SspGetTokenUser: Entering Token 0x%x pTokenUser 0x%x\n", Token, pTokenUser));
  1400. //
  1401. // Query the token user. First pass in NULL to get back the
  1402. // required size.
  1403. //
  1404. Status = NtQueryInformationToken(
  1405. Token,
  1406. TokenUser,
  1407. NULL,
  1408. 0,
  1409. &TokenUserSize
  1410. );
  1411. if (Status != STATUS_BUFFER_TOO_SMALL)
  1412. {
  1413. ASSERT(Status != STATUS_SUCCESS);
  1414. DebugLog((DEB_ERROR, "SspGetTokenUser: NtQueryInformationToken (1st call) returns 0x%lx for Token 0x%x\n", Status, Token ));
  1415. goto CleanUp;
  1416. }
  1417. //
  1418. // Now allocate the required ammount of memory and try again.
  1419. //
  1420. LocalTokenUser = (PTOKEN_USER) DigestAllocateMemory(TokenUserSize);
  1421. if (LocalTokenUser == NULL)
  1422. {
  1423. Status = STATUS_INSUFFICIENT_RESOURCES;
  1424. goto CleanUp;
  1425. }
  1426. Status = NtQueryInformationToken(
  1427. Token,
  1428. TokenUser,
  1429. LocalTokenUser,
  1430. TokenUserSize,
  1431. &TokenUserSize
  1432. );
  1433. if (NT_SUCCESS(Status))
  1434. {
  1435. *pTokenUser = LocalTokenUser;
  1436. }
  1437. else
  1438. {
  1439. DigestFreeMemory(LocalTokenUser);
  1440. DebugLog((DEB_ERROR, "SspGetTokenUser: NtQueryInformationToken (2nd call) returns 0x%lx for Token 0x%x\n", Status, Token ));
  1441. }
  1442. CleanUp:
  1443. DebugLog((DEB_TRACE_FUNC, "SspGetTokenUser: Leaving Token 0x%x with Status 0x%x\n", Token, Status));
  1444. return(Status);
  1445. }
  1446. /*++
  1447. RoutineDescription:
  1448. Create a local context for a real context
  1449. Don't link it to out list of local contexts.
  1450. Called inside LSA to prep packed Context buffer to send to UserMode addr space
  1451. Arguments:
  1452. pLsaContext - pointer to a Context in LSA to map over to User space
  1453. pDigest - pointer to digest auth parameters - may be NULL and use Context instead
  1454. ContextData - packed Context information to send to usermode process
  1455. Return Value:
  1456. --*/
  1457. NTSTATUS
  1458. SspMapDigestContext(
  1459. IN PDIGEST_CONTEXT pLsaContext, // LSA Context
  1460. IN PDIGEST_PARAMETER pDigest,
  1461. OUT PSecBuffer ContextData
  1462. )
  1463. {
  1464. NTSTATUS Status = STATUS_SUCCESS;
  1465. PDIGEST_PACKED_USERCONTEXT pPackedUserCtxt = NULL; // Return buffer to on good auth to UserMode addr space
  1466. USHORT cbLenNeeded = 0;
  1467. PUCHAR pucLoc = NULL;
  1468. HANDLE hTemp = NULL;
  1469. int iAuth = 0;
  1470. DebugLog((DEB_TRACE_FUNC, "SspMapContext: Entering for LSA context %lx\n", pLsaContext));
  1471. ASSERT(ContextData);
  1472. ASSERT(pLsaContext);
  1473. if (!pLsaContext)
  1474. {
  1475. Status = STATUS_INVALID_HANDLE;
  1476. DebugLog((DEB_ERROR, "SspMapContext: pLsaContext invalid\n"));
  1477. goto CleanUp;
  1478. }
  1479. // Copy over only selected fields
  1480. cbLenNeeded = sizeof(DIGEST_PACKED_USERCONTEXT);
  1481. if (pDigest)
  1482. {
  1483. cbLenNeeded += pDigest->refstrParam[MD5_AUTH_USERNAME].Length;
  1484. cbLenNeeded += pDigest->refstrParam[MD5_AUTH_REALM].Length;
  1485. cbLenNeeded += pDigest->refstrParam[MD5_AUTH_NONCE].Length;
  1486. cbLenNeeded += pDigest->refstrParam[MD5_AUTH_CNONCE].Length;
  1487. cbLenNeeded += pDigest->refstrParam[MD5_AUTH_ALGORITHM].Length;
  1488. cbLenNeeded += pDigest->refstrParam[MD5_AUTH_QOP].Length;
  1489. cbLenNeeded += pDigest->refstrParam[MD5_AUTH_AUTHZID].Length;
  1490. cbLenNeeded += pDigest->refstrParam[MD5_AUTH_OPAQUE].Length;
  1491. }
  1492. else
  1493. {
  1494. cbLenNeeded += pLsaContext->strDirective[MD5_AUTH_USERNAME].Length;
  1495. cbLenNeeded += pLsaContext->strDirective[MD5_AUTH_REALM].Length;
  1496. cbLenNeeded += pLsaContext->strDirective[MD5_AUTH_NONCE].Length;
  1497. cbLenNeeded += pLsaContext->strDirective[MD5_AUTH_CNONCE].Length;
  1498. cbLenNeeded += pLsaContext->strDirective[MD5_AUTH_ALGORITHM].Length;
  1499. cbLenNeeded += pLsaContext->strDirective[MD5_AUTH_QOP].Length;
  1500. cbLenNeeded += pLsaContext->strDirective[MD5_AUTH_AUTHZID].Length;
  1501. cbLenNeeded += pLsaContext->strDirective[MD5_AUTH_OPAQUE].Length;
  1502. }
  1503. cbLenNeeded += pLsaContext->strSessionKey.Length;
  1504. cbLenNeeded += pLsaContext->ustrAccountName.Length;
  1505. DebugLog((DEB_TRACE, "SspMapContext: Packed Digest will be %d bytes \n", cbLenNeeded));
  1506. // DigestAllocateMemory will use g_LsaFunctions->AllocateLsaHeap()
  1507. pPackedUserCtxt = (PDIGEST_PACKED_USERCONTEXT)g_LsaFunctions->AllocateLsaHeap(cbLenNeeded);
  1508. if (!pPackedUserCtxt)
  1509. {
  1510. // Failed to allocate memory to send info to usermode space
  1511. ContextData->cbBuffer = 0;
  1512. Status = SEC_E_INSUFFICIENT_MEMORY;
  1513. DebugLog((DEB_ERROR, "SspMapContext: out of memory on usermode contextdata\n"));
  1514. goto CleanUp;
  1515. }
  1516. // Now initialize the UserMode Context struct to return
  1517. ZeroMemory(pPackedUserCtxt, cbLenNeeded);
  1518. pPackedUserCtxt->Expires = pLsaContext->PasswordExpires;
  1519. pPackedUserCtxt->typeAlgorithm = (ULONG)pLsaContext->typeAlgorithm;
  1520. pPackedUserCtxt->typeCipher = (ULONG)pLsaContext->typeCipher;
  1521. pPackedUserCtxt->typeCharset = (ULONG)pLsaContext->typeCharset;
  1522. pPackedUserCtxt->typeDigest = (ULONG)pLsaContext->typeDigest;
  1523. pPackedUserCtxt->typeQOP = (ULONG)pLsaContext->typeQOP;
  1524. pPackedUserCtxt->ulSendMaxBuf = pLsaContext->ulSendMaxBuf;
  1525. pPackedUserCtxt->ulRecvMaxBuf = pLsaContext->ulRecvMaxBuf;
  1526. pPackedUserCtxt->ContextReq = (ULONG)pLsaContext->ContextReq;
  1527. pPackedUserCtxt->CredentialUseFlags = (ULONG)pLsaContext->CredentialUseFlags;
  1528. // Now mark that there is data for these items ONLY non-zero items will be written out!!!
  1529. if (pDigest)
  1530. {
  1531. pPackedUserCtxt->uDigestLen[MD5_AUTH_USERNAME] = (ULONG)pDigest->refstrParam[MD5_AUTH_USERNAME].Length;
  1532. pPackedUserCtxt->uDigestLen[MD5_AUTH_REALM] = (ULONG)pDigest->refstrParam[MD5_AUTH_REALM].Length;
  1533. pPackedUserCtxt->uDigestLen[MD5_AUTH_NONCE] = (ULONG)pDigest->refstrParam[MD5_AUTH_NONCE].Length;
  1534. pPackedUserCtxt->uDigestLen[MD5_AUTH_CNONCE] = (ULONG)pDigest->refstrParam[MD5_AUTH_CNONCE].Length;
  1535. pPackedUserCtxt->uDigestLen[MD5_AUTH_ALGORITHM] = (ULONG)pDigest->refstrParam[MD5_AUTH_ALGORITHM].Length;
  1536. pPackedUserCtxt->uDigestLen[MD5_AUTH_QOP] = (ULONG)pDigest->refstrParam[MD5_AUTH_QOP].Length;
  1537. pPackedUserCtxt->uDigestLen[MD5_AUTH_AUTHZID] = (ULONG)pDigest->refstrParam[MD5_AUTH_AUTHZID].Length;
  1538. pPackedUserCtxt->uDigestLen[MD5_AUTH_OPAQUE] = (ULONG)pDigest->refstrParam[MD5_AUTH_OPAQUE].Length;
  1539. }
  1540. else
  1541. {
  1542. pPackedUserCtxt->uDigestLen[MD5_AUTH_USERNAME] = (ULONG)pLsaContext->strDirective[MD5_AUTH_USERNAME].Length;
  1543. pPackedUserCtxt->uDigestLen[MD5_AUTH_REALM] = (ULONG)pLsaContext->strDirective[MD5_AUTH_REALM].Length;
  1544. pPackedUserCtxt->uDigestLen[MD5_AUTH_NONCE] = (ULONG)pLsaContext->strDirective[MD5_AUTH_NONCE].Length;
  1545. pPackedUserCtxt->uDigestLen[MD5_AUTH_CNONCE] = (ULONG)pLsaContext->strDirective[MD5_AUTH_CNONCE].Length;
  1546. pPackedUserCtxt->uDigestLen[MD5_AUTH_ALGORITHM] = (ULONG)pLsaContext->strDirective[MD5_AUTH_ALGORITHM].Length;
  1547. pPackedUserCtxt->uDigestLen[MD5_AUTH_QOP] = (ULONG)pLsaContext->strDirective[MD5_AUTH_QOP].Length;
  1548. pPackedUserCtxt->uDigestLen[MD5_AUTH_AUTHZID] = (ULONG)pLsaContext->strDirective[MD5_AUTH_AUTHZID].Length;
  1549. pPackedUserCtxt->uDigestLen[MD5_AUTH_OPAQUE] = (ULONG)pLsaContext->strDirective[MD5_AUTH_OPAQUE].Length;
  1550. }
  1551. pPackedUserCtxt->uSessionKeyLen = (ULONG)pLsaContext->strSessionKey.Length;
  1552. pPackedUserCtxt->uAccountNameLen = (ULONG)pLsaContext->ustrAccountName.Length;
  1553. // dup token if it exists
  1554. if (pLsaContext->TokenHandle != NULL)
  1555. {
  1556. Status = g_LsaFunctions->DuplicateHandle(
  1557. pLsaContext->TokenHandle,
  1558. &(hTemp));
  1559. if (!NT_SUCCESS(Status))
  1560. {
  1561. if (pPackedUserCtxt)
  1562. {
  1563. DigestFreeMemory(pPackedUserCtxt);
  1564. }
  1565. ContextData->cbBuffer = 0;
  1566. DebugLog((DEB_ERROR, "SspMapContext: DuplicateHandle returns 0x%lx\n", Status));
  1567. goto CleanUp;
  1568. }
  1569. // Must pack the HANDLE into a fixed size structure for IA64 and i32 formats
  1570. pPackedUserCtxt->ClientTokenHandle = (ULONG) ((ULONG_PTR)hTemp);
  1571. DebugLog((DEB_TRACE, "SspMapContext: DuplicateHandle successful ClientTokenHandle 0x%x\n", pPackedUserCtxt->ClientTokenHandle));
  1572. }
  1573. // Now copy over the string data elements
  1574. pucLoc = &(pPackedUserCtxt->ucData);
  1575. if (pDigest)
  1576. {
  1577. for (iAuth = 0; iAuth < MD5_AUTH_LAST; iAuth++)
  1578. {
  1579. if (pPackedUserCtxt->uDigestLen[iAuth])
  1580. {
  1581. memcpy(pucLoc, pDigest->refstrParam[iAuth].Buffer, pPackedUserCtxt->uDigestLen[iAuth]);
  1582. pucLoc += pPackedUserCtxt->uDigestLen[iAuth];
  1583. }
  1584. }
  1585. }
  1586. else
  1587. {
  1588. for (iAuth = 0; iAuth < MD5_AUTH_LAST; iAuth++)
  1589. {
  1590. if (pPackedUserCtxt->uDigestLen[iAuth])
  1591. {
  1592. memcpy(pucLoc, pLsaContext->strDirective[iAuth].Buffer, pPackedUserCtxt->uDigestLen[iAuth]);
  1593. pucLoc += pPackedUserCtxt->uDigestLen[iAuth];
  1594. }
  1595. }
  1596. }
  1597. if (pPackedUserCtxt->uSessionKeyLen)
  1598. {
  1599. memcpy(pucLoc, pLsaContext->strSessionKey.Buffer, pPackedUserCtxt->uSessionKeyLen);
  1600. pucLoc += pPackedUserCtxt->uSessionKeyLen;
  1601. }
  1602. if (pPackedUserCtxt->uAccountNameLen)
  1603. {
  1604. memcpy(pucLoc, pLsaContext->ustrAccountName.Buffer, pPackedUserCtxt->uAccountNameLen);
  1605. pucLoc += pPackedUserCtxt->uAccountNameLen;
  1606. }
  1607. ContextData->pvBuffer = pPackedUserCtxt;
  1608. ContextData->cbBuffer = cbLenNeeded;
  1609. ContextData->BufferType = SECBUFFER_TOKEN;
  1610. CleanUp:
  1611. DebugLog((DEB_TRACE_FUNC, "SspMapContext: Leaving LsaContext %lx Status 0x%x\n", pLsaContext, Status));
  1612. return(Status);
  1613. }
  1614. //+--------------------------------------------------------------------
  1615. //
  1616. // Function: DigestUserHTTPHelper
  1617. //
  1618. // Synopsis: Process a SecBuffer with a given User Security Context
  1619. // Used with HTTP for auth after initial ASC/ISC exchange
  1620. //
  1621. // Arguments: pContext - UserMode Context for the security state
  1622. // Op - operation to perform on the Sec buffers
  1623. // pMessage - sec buffers to processs and return output
  1624. //
  1625. // Returns: NTSTATUS
  1626. //
  1627. // Notes:
  1628. //
  1629. //---------------------------------------------------------------------
  1630. NTSTATUS NTAPI
  1631. DigestUserHTTPHelper(
  1632. IN PDIGEST_USERCONTEXT pContext,
  1633. IN eSignSealOp Op,
  1634. IN OUT PSecBufferDesc pSecBuff,
  1635. IN ULONG MessageSeqNo
  1636. )
  1637. {
  1638. NTSTATUS Status = STATUS_SUCCESS;
  1639. NTSTATUS SubStatus = STATUS_SUCCESS;
  1640. ULONG ulSeqNo = 0;
  1641. PSecBuffer pChalRspInputToken = NULL;
  1642. PSecBuffer pMethodInputToken = NULL;
  1643. PSecBuffer pURIInputToken = NULL;
  1644. PSecBuffer pHEntityInputToken = NULL;
  1645. PSecBuffer pFirstOutputToken = NULL;
  1646. DIGEST_PARAMETER Digest;
  1647. PDIGEST_CONTEXT pNewContext = NULL; // keep pointer to release new context on error
  1648. int iTemp = 0;
  1649. int iAuth = 0;
  1650. char *cptr = NULL;
  1651. char szNCOverride[2*NCNUM]; // Overrides the provided NC if non-zero using only NCNUM digits
  1652. STRING strURI;
  1653. UNICODE_STRING refustrURI;
  1654. BOOL fDefChars = FALSE;
  1655. ZeroMemory(&strURI, sizeof(strURI));
  1656. ZeroMemory(&refustrURI, sizeof(refustrURI));
  1657. DebugLog((DEB_TRACE_FUNC, "DigestUserHTTPHelper: Entering \n"));
  1658. DigestInit(&Digest);
  1659. if (pSecBuff->cBuffers < 1)
  1660. {
  1661. Status = SEC_E_INVALID_TOKEN;
  1662. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: Not enough input buffers 0x%x\n", Status));
  1663. goto CleanUp;
  1664. }
  1665. pChalRspInputToken = &(pSecBuff->pBuffers[0]);
  1666. if (!ContextIsTokenOK(pChalRspInputToken, NTDIGEST_SP_MAX_TOKEN_SIZE))
  1667. {
  1668. Status = SEC_E_INVALID_TOKEN;
  1669. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: ContextIsTokenOK (ChalRspInputToken) failed 0x%x\n", Status));
  1670. goto CleanUp;
  1671. }
  1672. // We have input in the SECBUFFER 0th location - parse it
  1673. Status = DigestParser2(pChalRspInputToken, MD5_AUTH_NAMES, MD5_AUTH_LAST, &Digest);
  1674. if (!NT_SUCCESS(Status))
  1675. {
  1676. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: DigestParser error 0x%x\n", Status));
  1677. goto CleanUp;
  1678. }
  1679. // Now determine all of the other buffers
  1680. DebugLog((DEB_TRACE, "DigestUserHTTPHelper: pContext->ContextReq 0x%lx \n", pContext->ContextReq));
  1681. DebugLog((DEB_TRACE, "DigestUserHTTPHelper: HTTP SecBuffer Format\n"));
  1682. // Retrieve the information from the SecBuffers & check proper formattting
  1683. if (pSecBuff->cBuffers < 4)
  1684. {
  1685. Status = SEC_E_INVALID_TOKEN;
  1686. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: Not enough input buffers 0x%x\n", Status));
  1687. goto CleanUp;
  1688. }
  1689. pMethodInputToken = &(pSecBuff->pBuffers[1]);
  1690. if (!ContextIsTokenOK(pMethodInputToken, NTDIGEST_SP_MAX_TOKEN_SIZE))
  1691. { // Check to make sure that string is present
  1692. Status = SEC_E_INVALID_TOKEN;
  1693. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: ContextIsTokenOK (MethodInputToken) failed 0x%x\n", Status));
  1694. goto CleanUp;
  1695. }
  1696. pURIInputToken = &(pSecBuff->pBuffers[2]);
  1697. if (!ContextIsTokenOK(pURIInputToken, NTDIGEST_SP_MAX_TOKEN_SIZE))
  1698. {
  1699. Status = SEC_E_INVALID_TOKEN;
  1700. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: ContextIsTokenOK (URIInputToken) failed 0x%x\n", Status));
  1701. goto CleanUp;
  1702. }
  1703. pHEntityInputToken = &(pSecBuff->pBuffers[3]);
  1704. if (!ContextIsTokenOK(pHEntityInputToken, NTDIGEST_SP_MAX_TOKEN_SIZE))
  1705. {
  1706. Status = SEC_E_INVALID_TOKEN;
  1707. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: ContextIsTokenOK (HEntityInputToken) failed 0x%x\n", Status));
  1708. goto CleanUp;
  1709. }
  1710. // Take care of the output buffer
  1711. if (Op == eSign)
  1712. {
  1713. if (pSecBuff->cBuffers < 5)
  1714. {
  1715. Status = SEC_E_INVALID_TOKEN;
  1716. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: No Output Buffers %d\n", Status));
  1717. goto CleanUp;
  1718. }
  1719. pFirstOutputToken = &(pSecBuff->pBuffers[4]);
  1720. if (!ContextIsTokenOK(pFirstOutputToken, 0))
  1721. {
  1722. Status = SEC_E_INVALID_TOKEN;
  1723. DebugLog((DEB_ERROR, "DigestUserHTTPHelper, ContextIsTokenOK (FirstOutputToken) failed 0x%x\n", Status));
  1724. goto CleanUp;
  1725. }
  1726. // Reset output buffer
  1727. if (pFirstOutputToken && (pFirstOutputToken->pvBuffer) && (pFirstOutputToken->cbBuffer >= 1))
  1728. {
  1729. cptr = (char *)pFirstOutputToken->pvBuffer;
  1730. *cptr = '\0';
  1731. }
  1732. }
  1733. else
  1734. {
  1735. pFirstOutputToken = NULL; // There is no output buffer
  1736. }
  1737. // Verify that there is a valid Method provided
  1738. if (!pMethodInputToken->pvBuffer || !pMethodInputToken->cbBuffer ||
  1739. (PBUFFERTYPE(pMethodInputToken) != SECBUFFER_PKG_PARAMS))
  1740. {
  1741. Status = SEC_E_INVALID_TOKEN;
  1742. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: Method SecBuffer must have valid method string status 0x%x\n", Status));
  1743. goto CleanUp;
  1744. }
  1745. iTemp = strlencounted((char *)pMethodInputToken->pvBuffer, pMethodInputToken->cbBuffer);
  1746. if (!iTemp)
  1747. {
  1748. Status = SEC_E_INVALID_TOKEN;
  1749. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: Method SecBuffer must have valid method string status 0x%x\n", Status));
  1750. goto CleanUp;
  1751. }
  1752. Digest.refstrParam[MD5_AUTH_METHOD].Length = (USHORT)iTemp;
  1753. Digest.refstrParam[MD5_AUTH_METHOD].MaximumLength = (unsigned short)(pMethodInputToken->cbBuffer);
  1754. Digest.refstrParam[MD5_AUTH_METHOD].Buffer = (char *)pMethodInputToken->pvBuffer; // refernce memory - no alloc!!!!
  1755. // Check to see if we have H(Entity) data to utilize
  1756. if (pHEntityInputToken->cbBuffer)
  1757. {
  1758. // Verify that there is a valid Method provided
  1759. if (!pHEntityInputToken->pvBuffer || (PBUFFERTYPE(pMethodInputToken) != SECBUFFER_PKG_PARAMS))
  1760. {
  1761. Status = SEC_E_INVALID_TOKEN;
  1762. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: HEntity SecBuffer must have valid string status 0x%x\n", Status));
  1763. goto CleanUp;
  1764. }
  1765. iTemp = strlencounted((char *)pHEntityInputToken->pvBuffer, pHEntityInputToken->cbBuffer);
  1766. if ((iTemp != 0) && (iTemp != (MD5_HASH_BYTESIZE * 2)))
  1767. {
  1768. Status = SEC_E_INVALID_TOKEN;
  1769. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: HEntity SecBuffer must have valid MD5 Hash data 0x%x\n", Status));
  1770. goto CleanUp;
  1771. }
  1772. if (iTemp)
  1773. {
  1774. Digest.refstrParam[MD5_AUTH_HENTITY].Length = (USHORT)iTemp;
  1775. Digest.refstrParam[MD5_AUTH_HENTITY].MaximumLength = (unsigned short)(pHEntityInputToken->cbBuffer);
  1776. Digest.refstrParam[MD5_AUTH_HENTITY].Buffer = (char *)pHEntityInputToken->pvBuffer; // refernce memory - no alloc!!!!
  1777. }
  1778. }
  1779. // Import the URI if it is a sign otherwise verify URI match if verify
  1780. if (Op == eSign)
  1781. {
  1782. // Pull in the URI provided in SecBuffer
  1783. if (!pURIInputToken || !pURIInputToken->cbBuffer || !pURIInputToken->pvBuffer)
  1784. {
  1785. Status = SEC_E_INVALID_TOKEN;
  1786. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: URI SecBuffer must have valid string 0x%x\n", Status));
  1787. goto CleanUp;
  1788. }
  1789. iTemp = 0;
  1790. if (PBUFFERTYPE(pURIInputToken) == SECBUFFER_PKG_PARAMS)
  1791. {
  1792. iTemp = strlencounted((char *)pURIInputToken->pvBuffer, pURIInputToken->cbBuffer);
  1793. if (iTemp > 0)
  1794. {
  1795. Status = StringCharDuplicate(&strURI, (char *)pURIInputToken->pvBuffer, (USHORT)iTemp);
  1796. if (!NT_SUCCESS(Status))
  1797. {
  1798. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: StringCharDuplicate error 0x%x\n", Status));
  1799. goto CleanUp;
  1800. }
  1801. }
  1802. }
  1803. else
  1804. {
  1805. Status = SEC_E_INVALID_TOKEN;
  1806. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: URI buffer type invalid error %d\n", Status));
  1807. goto CleanUp;
  1808. }
  1809. StringReference(&(Digest.refstrParam[MD5_AUTH_URI]), &strURI); // refernce memory - no alloc!!!!
  1810. }
  1811. // If we have a NonceCount in the MessageSequenceNumber then use that
  1812. if (MessageSeqNo)
  1813. {
  1814. ulSeqNo = MessageSeqNo;
  1815. }
  1816. else
  1817. {
  1818. ulSeqNo = pContext->ulNC + 1; // Else use the next sequence number
  1819. }
  1820. sprintf(szNCOverride, "%0.8x", ulSeqNo); // Buffer is twice as big as we need (for safety) so just clip out first 8 characters
  1821. szNCOverride[NCNUM] = '\0'; // clip to 8 digits
  1822. DebugLog((DEB_TRACE, "DigestUserHTTPHelper: Message Sequence NC is %s\n", szNCOverride));
  1823. Digest.refstrParam[MD5_AUTH_NC].Length = (USHORT)NCNUM;
  1824. Digest.refstrParam[MD5_AUTH_NC].MaximumLength = (unsigned short)(NCNUM+1);
  1825. Digest.refstrParam[MD5_AUTH_NC].Buffer = (char *)szNCOverride; // refernce memory - no alloc!!!!
  1826. // Now link in the stored context values into the digest if this is a SignMessage
  1827. // If there are values there from the input auth line then override them with context's value
  1828. if (Op == eSign)
  1829. {
  1830. for (iAuth = 0; iAuth < MD5_AUTH_LAST; iAuth++)
  1831. {
  1832. if (pContext->strParam[iAuth].Length)
  1833. { // Link in only if passed into the user context from the LSA context
  1834. Digest.refstrParam[iAuth].Length = pContext->strParam[iAuth].Length;
  1835. Digest.refstrParam[iAuth].MaximumLength = pContext->strParam[iAuth].MaximumLength;
  1836. Digest.refstrParam[iAuth].Buffer = pContext->strParam[iAuth].Buffer; // reference memory - no alloc!!!!
  1837. }
  1838. }
  1839. }
  1840. DebugLog((DEB_TRACE, "DigestUserHTTPHelper: Digest inputs processing completed\n"));
  1841. Status = DigestUserProcessParameters(pContext, &Digest, pFirstOutputToken);
  1842. if (!NT_SUCCESS(Status))
  1843. {
  1844. DebugLog((DEB_ERROR, "DigestUserHTTPHelper: DigestUserProcessParameters error 0x%x\n", Status));
  1845. goto CleanUp;
  1846. }
  1847. // For testing if nonce is stale, but digest calc still verified
  1848. if (Op == eVerify)
  1849. {
  1850. if (NT_SUCCESS(Status) && NonceIsExpired(&(Digest.refstrParam[MD5_AUTH_NONCE])))
  1851. {
  1852. Status = SEC_E_CONTEXT_EXPIRED;
  1853. DebugLog((DEB_TRACE, "DigestUserHTTPHelper: NONCE is out of date. Flag stale return Status 0x%x\n", Status));
  1854. }
  1855. }
  1856. pContext->ulNC = ulSeqNo; // Everything verified so increment to next nonce count
  1857. CleanUp:
  1858. DigestFree(&Digest);
  1859. StringFree(&strURI);
  1860. DebugLog((DEB_TRACE_FUNC, "DigestUserHTTPHelper: Leaving Status 0x%x\n", Status));
  1861. return(Status);
  1862. }
  1863. //+--------------------------------------------------------------------
  1864. //
  1865. // Function: DigestUserSignHelper
  1866. //
  1867. // Synopsis: Process a SecBuffer with a given User Security Context
  1868. // Used with SASL section 2.3 RFC
  1869. //
  1870. // Arguments: pContext - UserMode Context for the security state
  1871. // Op - operation to perform on the Sec buffers
  1872. // pMessage - sec buffers to processs and return output
  1873. //
  1874. //
  1875. // Returns: NTSTATUS
  1876. //
  1877. // Notes:
  1878. //
  1879. //---------------------------------------------------------------------
  1880. NTSTATUS NTAPI
  1881. DigestUserSignHelper(
  1882. IN PDIGEST_USERCONTEXT pContext,
  1883. IN OUT PSecBufferDesc pSecBuff,
  1884. IN ULONG MessageSeqNo
  1885. )
  1886. {
  1887. NTSTATUS Status = STATUS_SUCCESS;
  1888. NTSTATUS SubStatus = STATUS_SUCCESS;
  1889. PDWORD pdwSeqNum = NULL; // points to the Sequence number to use
  1890. PSecBuffer pSecBufToken = NULL;
  1891. PSecBuffer pSecBufData = NULL;
  1892. PSecBuffer pSecBufPad = NULL;
  1893. PSecBuffer pSecBufHMAC = NULL; // Points to the HMAC appended to the data block
  1894. PSecBuffer pSecBufMsg = NULL; // Points to the data section
  1895. BOOL bServer = FALSE;
  1896. SASL_MAC_BLOCK MacBlock;
  1897. DWORD dwSeqNumber = 0;
  1898. STRING strcSignKeyConst; // pointer to a constant valued string
  1899. ULONG Index = 0;
  1900. DebugLog((DEB_TRACE_FUNC, "DigestUserSignHelper: Entering \n"));
  1901. ZeroMemory(&MacBlock, sizeof(SASL_MAC_BLOCK));
  1902. RtlInitString(&strcSignKeyConst, NULL);
  1903. bServer = pContext->CredentialUseFlags & DIGEST_CRED_INBOUND;
  1904. //
  1905. // Find the body and signature SecBuffers from pMessage
  1906. //
  1907. for (Index = 0; Index < pSecBuff->cBuffers ; Index++ )
  1908. {
  1909. if (BUFFERTYPE(pSecBuff->pBuffers[Index]) == SECBUFFER_TOKEN)
  1910. {
  1911. pSecBufToken = &pSecBuff->pBuffers[Index];
  1912. }
  1913. if (BUFFERTYPE(pSecBuff->pBuffers[Index]) == SECBUFFER_DATA)
  1914. {
  1915. pSecBufData = &pSecBuff->pBuffers[Index];
  1916. }
  1917. if (BUFFERTYPE(pSecBuff->pBuffers[Index]) == SECBUFFER_PADDING)
  1918. {
  1919. pSecBufPad = &pSecBuff->pBuffers[Index];
  1920. }
  1921. }
  1922. if ((!pSecBufPad) || (!pSecBufPad->cbBuffer))
  1923. { // If no SECBUFFER_PADDING, use SECBUFFER_TOKEN
  1924. pSecBufHMAC = pSecBufToken;
  1925. }
  1926. else
  1927. {
  1928. pSecBufHMAC = pSecBufPad;
  1929. if (pSecBufToken)
  1930. {
  1931. pSecBufToken->cbBuffer = 0;
  1932. }
  1933. }
  1934. if (!ContextIsTokenOK(pSecBufHMAC, 0) || (pSecBufHMAC->cbBuffer < MAC_BLOCK_SIZE))
  1935. {
  1936. Status = SEC_E_BUFFER_TOO_SMALL;
  1937. DebugLog((DEB_ERROR, "DigestUserSignHelper: ContextIsTokenOK (SignatureToken) failed 0x%x\n", Status));
  1938. goto CleanUp;
  1939. }
  1940. if (!ContextIsTokenOK(pSecBufData, 0))
  1941. {
  1942. Status = SEC_E_INVALID_TOKEN;
  1943. DebugLog((DEB_ERROR, "DigestUserSignHelper: ContextIsTokenOK (SecBufMsg) failed 0x%x\n", Status));
  1944. goto CleanUp;
  1945. }
  1946. // Determine the sequence number & Constant Key Sring to utilize acting as the server
  1947. if (bServer)
  1948. {
  1949. pdwSeqNum = &(pContext->dwSendSeqNum);
  1950. RtlInitString(&strcSignKeyConst, SASL_S2C_SIGN_KEY);
  1951. DebugLog((DEB_TRACE, "DigestUserSignHelper: Signing in Server Mode (Message StoC) SeqNum %d\n", *pdwSeqNum));
  1952. }
  1953. else
  1954. { // acting as the client
  1955. pdwSeqNum = &(pContext->dwSendSeqNum);
  1956. RtlInitString(&strcSignKeyConst, SASL_C2S_SIGN_KEY);
  1957. DebugLog((DEB_TRACE, "DigestUserSignHelper: Signing in Client Mode (Message CtoS) SeqNum %d\n", *pdwSeqNum));
  1958. }
  1959. Status = CalculateSASLHMAC(pContext, TRUE, &strcSignKeyConst, *pdwSeqNum,
  1960. (PBYTE)pSecBufData->pvBuffer, pSecBufData->cbBuffer, &MacBlock);
  1961. if (!NT_SUCCESS (Status))
  1962. {
  1963. DebugLog((DEB_ERROR, "DigestUserSignHelper: Error in CalculateSASLHMAC status 0x%x\n", Status));
  1964. goto CleanUp;
  1965. }
  1966. // Write the calculated MAC block out to the SecBuffer
  1967. memcpy(pSecBufHMAC->pvBuffer, &MacBlock, MAC_BLOCK_SIZE);
  1968. DebugLog((DEB_TRACE, "DigestUserSignHelper: Wrote out the calculated MAC Block.\n"));
  1969. pSecBufHMAC->cbBuffer = MAC_BLOCK_SIZE; // indicate number of bytes we used for padding and HMAC block
  1970. // completed all tasks down to here. Need to update the sequence number
  1971. (*pdwSeqNum)++;
  1972. DebugLog((DEB_TRACE, "DigestUserSignHelper: Updated SeqNum to %d\n", *pdwSeqNum));
  1973. CleanUp:
  1974. DebugLog((DEB_TRACE_FUNC, "DigestUserSignHelper: Leaving Status 0x%x\n", Status));
  1975. return(Status);
  1976. }
  1977. //+--------------------------------------------------------------------
  1978. //
  1979. // Function: DigestUserVerifyHelper
  1980. //
  1981. // Synopsis: Process a SecBuffer with a given User Security Context
  1982. // Used with SASL section 2.3 RFC
  1983. //
  1984. // Arguments: pContext - UserMode Context for the security state
  1985. // Op - operation to perform on the Sec buffers
  1986. // pMessage - sec buffers to processs and return output
  1987. //
  1988. //
  1989. // Returns: NTSTATUS
  1990. //
  1991. // Notes:
  1992. //
  1993. //---------------------------------------------------------------------
  1994. NTSTATUS NTAPI
  1995. DigestUserVerifyHelper(
  1996. IN PDIGEST_USERCONTEXT pContext,
  1997. IN OUT PSecBufferDesc pSecBuff,
  1998. IN ULONG MessageSeqNo
  1999. )
  2000. {
  2001. NTSTATUS Status = STATUS_SUCCESS;
  2002. NTSTATUS SubStatus = STATUS_SUCCESS;
  2003. PDWORD pdwSeqNum = NULL; // points to the Sequence number to use
  2004. PBYTE pMsgHMAC = NULL; // Location of the HMAC in the message
  2005. PSecBuffer pSecBufData = NULL;
  2006. PSecBuffer pSecBufStream = NULL;
  2007. PSecBuffer pSecBufHMAC = NULL; // Points to the HMAC appended to the data block
  2008. PSecBuffer pSecBufMsg = NULL; // Points to the data section
  2009. BOOL bServer = FALSE;
  2010. SASL_MAC_BLOCK MacBlock;
  2011. SASL_MAC_BLOCK TokenMacBlock;
  2012. DWORD dwSeqNumber = 0;
  2013. STRING strcSignKeyConst;
  2014. ULONG cbSecBufMsgIntegrity = 0; // Number of bytes in message to calc HMAC on
  2015. ULONG Index = 0;
  2016. #if DBG
  2017. char szTemp[TEMPSIZE];
  2018. ZeroMemory(szTemp, TEMPSIZE);
  2019. #endif
  2020. DebugLog((DEB_TRACE_FUNC, "DigestUserVerifyHelper: Entering \n"));
  2021. ZeroMemory(&MacBlock, sizeof(SASL_MAC_BLOCK));
  2022. ZeroMemory(&TokenMacBlock, sizeof(SASL_MAC_BLOCK));
  2023. RtlInitString(&strcSignKeyConst, NULL);
  2024. bServer = pContext->CredentialUseFlags & DIGEST_CRED_INBOUND;
  2025. //
  2026. // Find the body and signature SecBuffers from pMessage
  2027. //
  2028. for (Index = 0; Index < pSecBuff->cBuffers ; Index++ )
  2029. {
  2030. if (BUFFERTYPE(pSecBuff->pBuffers[Index]) == SECBUFFER_DATA)
  2031. {
  2032. pSecBufData = &pSecBuff->pBuffers[Index];
  2033. }
  2034. if (BUFFERTYPE(pSecBuff->pBuffers[Index]) == SECBUFFER_STREAM)
  2035. {
  2036. pSecBufStream = &pSecBuff->pBuffers[Index];
  2037. }
  2038. }
  2039. // Must be for decrypt/verify
  2040. if ((!pSecBufStream) || (!pSecBufStream->cbBuffer))
  2041. { // If no SECBUFFER_STREAM, use SECBUFFER_DATA
  2042. pSecBufMsg = pSecBufData;
  2043. }
  2044. else
  2045. {
  2046. pSecBufMsg = pSecBufStream;
  2047. }
  2048. if ((!ContextIsTokenOK(pSecBufMsg, 0)) || (pSecBufMsg->cbBuffer < MAC_BLOCK_SIZE))
  2049. {
  2050. Status = SEC_E_INVALID_TOKEN;
  2051. DebugLog((DEB_ERROR, "DigestUserVerifyHelper: ContextIsTokenOK (SecBufMsg) decrypt/verify failed 0x%x\n", Status));
  2052. goto CleanUp;
  2053. }
  2054. // Strip off the MsgType and the Sequence Number
  2055. cbSecBufMsgIntegrity = pSecBufMsg->cbBuffer - (MAC_BLOCK_SIZE);
  2056. // Determine the sequence number to utilize acting as the server
  2057. if (bServer)
  2058. {
  2059. pdwSeqNum = &(pContext->dwRecvSeqNum);
  2060. RtlInitString(&strcSignKeyConst, SASL_C2S_SIGN_KEY);
  2061. DebugLog((DEB_TRACE, "DigestUserVerifyHelper: Verifying in Server Mode (Message CtoS) SeqNum %d\n", *pdwSeqNum));
  2062. }
  2063. else
  2064. { // acting as the client
  2065. pdwSeqNum = &(pContext->dwRecvSeqNum);
  2066. RtlInitString(&strcSignKeyConst, SASL_S2C_SIGN_KEY);
  2067. DebugLog((DEB_TRACE, "DigestUserVerifyHelper: Verifying in Client Mode (Message StoC) SeqNum %d\n", *pdwSeqNum));
  2068. }
  2069. Status = CalculateSASLHMAC(pContext, FALSE, &strcSignKeyConst, *pdwSeqNum,
  2070. (PBYTE)pSecBufMsg->pvBuffer, cbSecBufMsgIntegrity, &MacBlock);
  2071. if (!NT_SUCCESS (Status))
  2072. {
  2073. DebugLog((DEB_ERROR, "DigestUserVerifyHelper: Error in CalculateSASLHMAC status 0x%x\n", Status));
  2074. goto CleanUp;
  2075. }
  2076. DebugLog((DEB_TRACE, "DigestUserVerifyHelper: Ready to compare MacBlocks\n"));
  2077. // Check validity of MAC block ONLY do not write it out
  2078. pMsgHMAC = (PBYTE)pSecBufMsg->pvBuffer + cbSecBufMsgIntegrity;
  2079. memcpy(&TokenMacBlock, pMsgHMAC, MAC_BLOCK_SIZE);
  2080. if (MacBlock.dwSeqNumber != TokenMacBlock.dwSeqNumber)
  2081. {
  2082. Status = SEC_E_OUT_OF_SEQUENCE;
  2083. DebugLog((DEB_ERROR, "DigestUserVerifyHelper: SASL MAC blocks out of sequence. Failed verify. Status 0x%x\n", Status));
  2084. #if DBG
  2085. ZeroMemory(szTemp, TEMPSIZE);
  2086. BinToHex((PUCHAR)&TokenMacBlock, MAC_BLOCK_SIZE, szTemp);
  2087. DebugLog((DEB_TRACE, "CalculateSASLHMAC: Token's HMAC-MD5 block %s\n", szTemp));
  2088. ZeroMemory(szTemp, TEMPSIZE);
  2089. BinToHex((PUCHAR)&MacBlock, MAC_BLOCK_SIZE, szTemp);
  2090. DebugLog((DEB_TRACE, "CalculateSASLHMAC: TComputed HMAC-MD5 block %s\n", szTemp));
  2091. #endif
  2092. goto CleanUp;
  2093. }
  2094. if (memcmp(&MacBlock, &TokenMacBlock, MAC_BLOCK_SIZE))
  2095. {
  2096. Status = SEC_E_MESSAGE_ALTERED;
  2097. DebugLog((DEB_ERROR, "DigestUserVerifyHelper: SASL MAC blocks do not match. Failed verify. Status 0x%x\n", Status));
  2098. #if DBG
  2099. ZeroMemory(szTemp, TEMPSIZE);
  2100. BinToHex((PUCHAR)&TokenMacBlock, MAC_BLOCK_SIZE, szTemp);
  2101. DebugLog((DEB_TRACE, "CalculateSASLHMAC: Token's HMAC-MD5 block %s\n", szTemp));
  2102. ZeroMemory(szTemp, TEMPSIZE);
  2103. BinToHex((PUCHAR)&MacBlock, MAC_BLOCK_SIZE, szTemp);
  2104. DebugLog((DEB_TRACE, "CalculateSASLHMAC: TComputed HMAC-MD5 block %s\n", szTemp));
  2105. #endif
  2106. goto CleanUp;
  2107. }
  2108. else
  2109. {
  2110. DebugLog((DEB_TRACE, "DigestUserVerifyHelper: SASL MAC blocks match!\n"));
  2111. }
  2112. // completed all tasks down to here. Need to update the sequence number
  2113. (*pdwSeqNum)++;
  2114. // Update the Data information (without the attached HMAC info block
  2115. if (pSecBufData)
  2116. {
  2117. pSecBufData->cbBuffer = pSecBufMsg->cbBuffer - MAC_BLOCK_SIZE;
  2118. pSecBufData->pvBuffer = pSecBufMsg->pvBuffer;
  2119. }
  2120. DebugLog((DEB_TRACE, "DigestUserVerifyHelper: Updated SeqNum to %d\n", *pdwSeqNum));
  2121. CleanUp:
  2122. DebugLog((DEB_TRACE_FUNC, "DigestUserVerifyHelper: Leaving Status 0x%x\n", Status));
  2123. return(Status);
  2124. }
  2125. //+--------------------------------------------------------------------
  2126. //
  2127. // Function: DigestUserSealHelper
  2128. //
  2129. // Synopsis: Process a SecBuffer with a given User Security Context
  2130. // Used with SASL section 2.3 RFC
  2131. //
  2132. // Arguments: pContext - UserMode Context for the security state
  2133. // Op - operation to perform on the Sec buffers
  2134. // pMessage - sec buffers to processs and return output
  2135. //
  2136. //
  2137. // Returns: NTSTATUS
  2138. //
  2139. // Notes:
  2140. //
  2141. //---------------------------------------------------------------------
  2142. NTSTATUS NTAPI
  2143. DigestUserSealHelper(
  2144. IN PDIGEST_USERCONTEXT pContext,
  2145. IN OUT PSecBufferDesc pSecBuff,
  2146. IN ULONG MessageSeqNo
  2147. )
  2148. {
  2149. NTSTATUS Status = STATUS_SUCCESS;
  2150. NTSTATUS SubStatus = STATUS_SUCCESS;
  2151. PDWORD pdwSeqNum = NULL; // points to the Sequence number to use
  2152. PSecBuffer pSecBufToken = NULL;
  2153. PSecBuffer pSecBufData = NULL;
  2154. PSecBuffer pSecBufPad = NULL;
  2155. PSecBuffer pSecBufHMAC = NULL; // Points to the HMAC appended to the data block
  2156. PSecBuffer pSecBufMsg = NULL; // Points to the data section
  2157. BOOL bServer = FALSE;
  2158. SASL_MAC_BLOCK MacBlock;
  2159. DWORD dwSeqNumber = 0;
  2160. STRING strcSignKeyConst;
  2161. STRING strcSealKeyConst;
  2162. PUCHAR pbIV = NULL;
  2163. BYTE bKcTempData[MD5_HASH_BYTESIZE]; // Message integrity keys RFC 2831 sec 2.3
  2164. ULONG Index = 0;
  2165. USHORT cbHA1n = 0; // Number of bytes for Ha1 in Kcc/Kcs
  2166. DWORD cbKey = 0; // Number of bytes of Kcc/Kcs to use for the key
  2167. DWORD cbKeyNoParity = 0; // Number of bytes of Kcc/Kcs to use for the key with no parity
  2168. DWORD cbTempKey = 0;
  2169. ULONG cbBlockSize = RC4_BLOCKSIZE; // Blocksize for the given cipher
  2170. ULONG cbPrefixPadding = 0; // number of bytes needed for padding out to blocksize
  2171. ULONG cbBlocks = 0;
  2172. PBYTE pHMACTemp = NULL;
  2173. ALG_ID Algid = 0;
  2174. DebugLog((DEB_TRACE_FUNC, "DigestUserSealHelper: Entering \n"));
  2175. ZeroMemory(&MacBlock, sizeof(SASL_MAC_BLOCK));
  2176. RtlInitString(&strcSignKeyConst, NULL);
  2177. RtlInitString(&strcSealKeyConst, NULL);
  2178. bServer = pContext->CredentialUseFlags & DIGEST_CRED_INBOUND;
  2179. //
  2180. // Find the body and signature SecBuffers from pMessage
  2181. //
  2182. for (Index = 0; Index < pSecBuff->cBuffers ; Index++ )
  2183. {
  2184. if (BUFFERTYPE(pSecBuff->pBuffers[Index]) == SECBUFFER_TOKEN)
  2185. {
  2186. pSecBufToken = &pSecBuff->pBuffers[Index];
  2187. }
  2188. if (BUFFERTYPE(pSecBuff->pBuffers[Index]) == SECBUFFER_DATA)
  2189. {
  2190. pSecBufData = &pSecBuff->pBuffers[Index];
  2191. }
  2192. if (BUFFERTYPE(pSecBuff->pBuffers[Index]) == SECBUFFER_PADDING)
  2193. {
  2194. pSecBufPad = &pSecBuff->pBuffers[Index];
  2195. }
  2196. }
  2197. if ((!pSecBufPad) || (!pSecBufPad->cbBuffer))
  2198. { // If no SECBUFFER_PADDING, use SECBUFFER_TOKEN
  2199. pSecBufHMAC = pSecBufToken;
  2200. }
  2201. else
  2202. {
  2203. pSecBufHMAC = pSecBufPad;
  2204. if (pSecBufToken)
  2205. {
  2206. pSecBufToken->cbBuffer = 0;
  2207. }
  2208. }
  2209. if (!ContextIsTokenOK(pSecBufHMAC, 0) || (pSecBufHMAC->cbBuffer < (MAC_BLOCK_SIZE + MAX_PADDING)))
  2210. {
  2211. Status = SEC_E_BUFFER_TOO_SMALL;
  2212. DebugLog((DEB_ERROR, "DigestUserSealHelper: ContextIsTokenOK (SignatureToken) failed 0x%x\n", Status));
  2213. goto CleanUp;
  2214. }
  2215. if (!ContextIsTokenOK(pSecBufData, 0))
  2216. {
  2217. Status = SEC_E_INVALID_TOKEN;
  2218. DebugLog((DEB_ERROR, "DigestUserSealHelper: ContextIsTokenOK (SecBufMsg) failed 0x%x\n", Status));
  2219. goto CleanUp;
  2220. }
  2221. // Determine the sequence number & Constant Key Sring to utilize acting as the server
  2222. if (bServer)
  2223. {
  2224. pdwSeqNum = &(pContext->dwSendSeqNum);
  2225. RtlInitString(&strcSignKeyConst, SASL_S2C_SIGN_KEY);
  2226. RtlInitString(&strcSealKeyConst, SASL_S2C_SEAL_KEY);
  2227. DebugLog((DEB_TRACE, "DigestUserSealHelper: Signing in Server Mode (Message StoC) SeqNum %d\n", *pdwSeqNum));
  2228. }
  2229. else
  2230. { // acting as the client
  2231. pdwSeqNum = &(pContext->dwSendSeqNum);
  2232. RtlInitString(&strcSignKeyConst, SASL_C2S_SIGN_KEY);
  2233. RtlInitString(&strcSealKeyConst, SASL_C2S_SEAL_KEY);
  2234. DebugLog((DEB_TRACE, "DigestUserSealHelper: Signing in Client Mode (Message CtoS) SeqNum %d\n", *pdwSeqNum));
  2235. }
  2236. // Based on the Cypher selected - establish the byte count parameters - magic numbers from RFC
  2237. if (pContext->typeCipher == CIPHER_RC4)
  2238. {
  2239. cbHA1n = 16; // RFC 2831 sect 2.4
  2240. cbKey = 16; // number of bytes to use from Kcc/Kcs
  2241. Algid = CALG_RC4;
  2242. }
  2243. else if (pContext->typeCipher == CIPHER_RC4_40)
  2244. {
  2245. cbHA1n = 5; // RFC 2831 sect 2.4
  2246. cbKey = 16; // number of bytes to use from Kcc/Kcs
  2247. Algid = CALG_RC4;
  2248. }
  2249. else if (pContext->typeCipher == CIPHER_RC4_56)
  2250. {
  2251. cbHA1n = 7; // RFC 2831 sect 2.4
  2252. cbKey = 16; // number of bytes to use from Kcc/Kcs
  2253. Algid = CALG_RC4;
  2254. }
  2255. else if (pContext->typeCipher == CIPHER_DES)
  2256. {
  2257. cbHA1n = 16; // RFC 2831 sect 2.4
  2258. cbKey = 8; // number of bytes to use from Kcc/Kcs
  2259. cbKeyNoParity = 7;
  2260. cbBlockSize = DES_BLOCKSIZE; // DES uses a blocksize of 8
  2261. Algid = CALG_DES;
  2262. }
  2263. else if (pContext->typeCipher == CIPHER_3DES)
  2264. {
  2265. cbHA1n = 16; // RFC 2831 sect 2.4
  2266. cbKey = 16; // number of bytes to use from Kcc/Kcs
  2267. cbKeyNoParity = 14;
  2268. cbBlockSize = DES_BLOCKSIZE; // DES uses a blocksize of 8
  2269. Algid = CALG_3DES_112;
  2270. }
  2271. else
  2272. {
  2273. Status = SEC_E_CRYPTO_SYSTEM_INVALID;
  2274. DebugLog((DEB_ERROR, "DigestUserSealHelper: ContextIsTokenOK (SecBufMsg) failed 0x%x\n", Status));
  2275. goto CleanUp;
  2276. }
  2277. // If the cipher is not a stream cipher - the place prefix padding before SASL MAC
  2278. // Modified to include padding based on message datasize + the 10 byte HMAC
  2279. if (cbBlockSize != 1)
  2280. {
  2281. cbBlocks = (pSecBufData->cbBuffer + SASL_MAC_HMAC_SIZE) / cbBlockSize; // integer divison
  2282. cbPrefixPadding = cbBlockSize - ((pSecBufData->cbBuffer + SASL_MAC_HMAC_SIZE) - (cbBlockSize * cbBlocks));
  2283. if (!cbPrefixPadding)
  2284. {
  2285. cbPrefixPadding = cbBlockSize; // if padding is zero set it to the blocksize - i.e. always pad
  2286. }
  2287. DebugLog((DEB_TRACE, "DigestUserSealHelper: DataSize %lu BlockSize %lu Padding %lu\n",
  2288. pSecBufData->cbBuffer, cbBlockSize, cbPrefixPadding));
  2289. }
  2290. Status = CalculateSASLHMAC(pContext, TRUE, &strcSignKeyConst, *pdwSeqNum,
  2291. (PBYTE)pSecBufData->pvBuffer, pSecBufData->cbBuffer, &MacBlock);
  2292. if (!NT_SUCCESS (Status))
  2293. {
  2294. DebugLog((DEB_ERROR, "DigestUserSealHelper: Error in CalculateSASLHMAC status 0x%x\n", Status));
  2295. goto CleanUp;
  2296. }
  2297. // Write the calculated MAC block out to the SecBuffer
  2298. // Put the padding as the prefix
  2299. pHMACTemp = (PBYTE)pSecBufHMAC->pvBuffer;
  2300. memset(pHMACTemp, cbPrefixPadding, cbPrefixPadding);
  2301. memcpy(pHMACTemp + cbPrefixPadding, &MacBlock, MAC_BLOCK_SIZE);
  2302. DebugLog((DEB_TRACE, "DigestUserSealHelper: Wrote out the calculated MAC Block.\n"));
  2303. pSecBufHMAC->cbBuffer = MAC_BLOCK_SIZE + cbPrefixPadding; // indicate number of bytes we used for padding and HMAC block
  2304. // Completed the Integrity calculation, now encrypt the data if requested
  2305. // Encrypt the message, padding and first SASL_MAC_HMAC_SIZE (10) bytes of HMAC (the integrity value)
  2306. // Compute Kc for encryption (seal) & generate Cryptkey
  2307. if (pContext->hSealCryptKey == NULL)
  2308. {
  2309. ASSERT(*pdwSeqNum == 0); // Should be first call into package
  2310. // Compute on first time call to encrypt - save for other sequence numbers
  2311. Status = CalculateKc(pContext->bSessionKey, cbHA1n, &strcSealKeyConst, pContext->bKcSealHashData);
  2312. if (!NT_SUCCESS (Status))
  2313. {
  2314. DebugLog((DEB_ERROR, "DigestUserSealHelper: Error in CalculateKc status 0x%x\n", Status));
  2315. goto CleanUp;
  2316. }
  2317. // code to expand the DES key into multiple of 8 bytes (key with parity)
  2318. if ((pContext->typeCipher == CIPHER_DES) || (pContext->typeCipher == CIPHER_3DES))
  2319. {
  2320. Status = AddDESParity(pContext->bKcSealHashData,
  2321. cbKeyNoParity,
  2322. bKcTempData,
  2323. &cbTempKey);
  2324. if (!NT_SUCCESS (Status))
  2325. {
  2326. DebugLog((DEB_ERROR, "DigestUserSealHelper: Error in AddDESParity status 0x%x\n", Status));
  2327. goto CleanUp;
  2328. }
  2329. // replace with DES parity version
  2330. ASSERT(cbKey == cbTempKey);
  2331. memcpy(pContext->bSealKey, bKcTempData, cbTempKey);
  2332. pbIV = &(pContext->bKcSealHashData[8]);
  2333. }
  2334. else
  2335. {
  2336. memcpy(pContext->bSealKey, pContext->bKcSealHashData, MD5_HASH_BYTESIZE);
  2337. pbIV = NULL;
  2338. }
  2339. // generate symmetric key from the cleartext
  2340. Status = CreateSymmetricKey(Algid, cbKey, pContext->bSealKey, pbIV, &pContext->hSealCryptKey);
  2341. if (!NT_SUCCESS (Status))
  2342. {
  2343. DebugLog((DEB_ERROR, "DigestUserSealHelper: Error in CalculateKc status 0x%x\n", Status));
  2344. goto CleanUp;
  2345. }
  2346. }
  2347. if ((pContext->typeCipher == CIPHER_3DES) || (pContext->typeCipher == CIPHER_DES))
  2348. {
  2349. DebugLog((DEB_TRACE, "DigestUserSealHelper: 3DES/DES Encryption\n"));
  2350. // Specify IV - take only the last 8 bytes per RFC 2831 sect 2.4
  2351. Status = EncryptData2(pContext->hSealCryptKey, cbBlockSize,
  2352. pSecBufData->cbBuffer, (PUCHAR)pSecBufData->pvBuffer,
  2353. (cbPrefixPadding + SASL_MAC_HMAC_SIZE), pHMACTemp);
  2354. if (!NT_SUCCESS (Status))
  2355. {
  2356. DebugLog((DEB_ERROR, "DigestUserSealHelper: Error in EncryptData status 0x%x\n", Status));
  2357. goto CleanUp;
  2358. }
  2359. }
  2360. else
  2361. {
  2362. Status = EncryptData2(pContext->hSealCryptKey, cbBlockSize,
  2363. pSecBufData->cbBuffer, (PUCHAR)pSecBufData->pvBuffer,
  2364. (cbPrefixPadding + SASL_MAC_HMAC_SIZE), pHMACTemp);
  2365. if (!NT_SUCCESS (Status))
  2366. {
  2367. DebugLog((DEB_ERROR, "DigestUserSealHelper: Error in EncryptData status 0x%x\n", Status));
  2368. goto CleanUp;
  2369. }
  2370. }
  2371. DebugLog((DEB_TRACE, "DigestUserSealHelper: Data encrypted\n"));
  2372. // completed all tasks down to here. Need to update the sequence number
  2373. (*pdwSeqNum)++;
  2374. DebugLog((DEB_TRACE, "DigestUserSealHelper: Updated SeqNum to %d\n", *pdwSeqNum));
  2375. CleanUp:
  2376. DebugLog((DEB_TRACE_FUNC, "DigestUserSealHelper: Leaving Status 0x%x\n", Status));
  2377. return(Status);
  2378. }
  2379. //+--------------------------------------------------------------------
  2380. //
  2381. // Function: DigestUserUnsealHelper
  2382. //
  2383. // Synopsis: Process a SecBuffer with a given User Security Context
  2384. // Used with SASL section 2.3 RFC
  2385. //
  2386. // Arguments: pContext - UserMode Context for the security state
  2387. // Op - operation to perform on the Sec buffers
  2388. // pMessage - sec buffers to processs and return output
  2389. //
  2390. //
  2391. // Returns: NTSTATUS
  2392. //
  2393. // Notes:
  2394. //
  2395. //---------------------------------------------------------------------
  2396. NTSTATUS NTAPI
  2397. DigestUserUnsealHelper(
  2398. IN PDIGEST_USERCONTEXT pContext,
  2399. IN OUT PSecBufferDesc pSecBuff,
  2400. IN ULONG MessageSeqNo
  2401. )
  2402. {
  2403. NTSTATUS Status = STATUS_SUCCESS;
  2404. NTSTATUS SubStatus = STATUS_SUCCESS;
  2405. PDWORD pdwSeqNum = NULL; // points to the Sequence number to use
  2406. PSecBuffer pSecBufData = NULL;
  2407. PSecBuffer pSecBufStream = NULL;
  2408. PSecBuffer pSecBufHMAC = NULL; // Points to the HMAC appended to the data block
  2409. PSecBuffer pSecBufMsg = NULL; // Points to the data section
  2410. BOOL bServer = FALSE;
  2411. SASL_MAC_BLOCK MacBlock;
  2412. SASL_MAC_BLOCK TokenMacBlock; // Extract the HMAC block imbedded in the message
  2413. DWORD dwSeqNumber = 0;
  2414. STRING strcSignKeyConst;
  2415. STRING strcSealKeyConst;
  2416. PBYTE pMsgHMAC = NULL;
  2417. BYTE bKcTempData[MD5_HASH_BYTESIZE]; // Message integrity keys RFC 2831 sec 2.3
  2418. PUCHAR pbIV = NULL;
  2419. ULONG Index = 0;
  2420. USHORT cbHA1n = 0; // Number of bytes for Ha1 in Kcc/Kcs
  2421. DWORD cbKey = 0; // Number of bytes of Kcc/Kcs to use for the key
  2422. DWORD cbKeyNoParity = 0; // Number of bytes of Kcc/Kcs to use for the key with no parity
  2423. DWORD cbTempKey = 0;
  2424. ULONG cbBlockSize = 1; // Blocksize for the given cipher
  2425. UCHAR cbPrefixPadding = 0; // number of bytes needed for padding out to blocksize
  2426. ULONG cbMsg = 0; // number of bytes in the actual message
  2427. PBYTE pHMACTemp = NULL;
  2428. PBYTE pMsgPadding = NULL; // Location of a padding byte
  2429. ALG_ID Algid = 0;
  2430. ULONG cbSecBufMsgPrivacy = 0; // Number of bytes to decrypt (unseal)
  2431. #if DBG
  2432. char szTemp[TEMPSIZE];
  2433. ULONG iTempLen = 20;
  2434. ZeroMemory(szTemp, TEMPSIZE);
  2435. #endif
  2436. DebugLog((DEB_TRACE_FUNC, "DigestUserUnsealHelper: Entering\n"));
  2437. ZeroMemory(&MacBlock, sizeof(MacBlock));
  2438. ZeroMemory(&TokenMacBlock, sizeof(TokenMacBlock));
  2439. RtlInitString(&strcSignKeyConst, NULL);
  2440. RtlInitString(&strcSealKeyConst, NULL);
  2441. bServer = pContext->CredentialUseFlags & DIGEST_CRED_INBOUND;
  2442. //
  2443. // Find the body and signature SecBuffers from pMessage
  2444. //
  2445. for (Index = 0; Index < pSecBuff->cBuffers ; Index++ )
  2446. {
  2447. if (BUFFERTYPE(pSecBuff->pBuffers[Index]) == SECBUFFER_DATA)
  2448. {
  2449. pSecBufData = &pSecBuff->pBuffers[Index];
  2450. }
  2451. if (BUFFERTYPE(pSecBuff->pBuffers[Index]) == SECBUFFER_STREAM)
  2452. {
  2453. pSecBufStream = &pSecBuff->pBuffers[Index];
  2454. }
  2455. }
  2456. // Must be for decrypt/verify
  2457. if ((!pSecBufStream) || (!pSecBufStream->cbBuffer))
  2458. { // If no SECBUFFER_STREAM, use SECBUFFER_DATA
  2459. pSecBufMsg = pSecBufData;
  2460. }
  2461. else
  2462. {
  2463. pSecBufMsg = pSecBufStream;
  2464. }
  2465. if ((!ContextIsTokenOK(pSecBufMsg, 0)) || (pSecBufMsg->cbBuffer < MAC_BLOCK_SIZE))
  2466. {
  2467. Status = SEC_E_INVALID_TOKEN;
  2468. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: ContextIsTokenOK (SecBufMsg) decrypt/verify failed 0x%x\n", Status));
  2469. goto CleanUp;
  2470. }
  2471. // Strip off the MsgType and the Sequence Number
  2472. cbSecBufMsgPrivacy = pSecBufMsg->cbBuffer - (SASL_MAC_MSG_SIZE + SASL_MAC_SEQ_SIZE);
  2473. if (!ContextIsTokenOK(pSecBufMsg, 0) || (pSecBufMsg->cbBuffer < MAC_BLOCK_SIZE))
  2474. {
  2475. Status = SEC_E_BUFFER_TOO_SMALL;
  2476. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: ContextIsTokenOK (SignatureToken) failed 0x%x\n", Status));
  2477. goto CleanUp;
  2478. }
  2479. // Determine the sequence number & Constant Key Sring to utilize acting as the server
  2480. if (bServer)
  2481. {
  2482. pdwSeqNum = &(pContext->dwRecvSeqNum);
  2483. RtlInitString(&strcSignKeyConst, SASL_C2S_SIGN_KEY);
  2484. RtlInitString(&strcSealKeyConst, SASL_C2S_SEAL_KEY);
  2485. DebugLog((DEB_TRACE, "DigestUserUnsealHelper: Signing in Server Mode (Message StoC) SeqNum %d\n", *pdwSeqNum));
  2486. }
  2487. else
  2488. { // acting as the client
  2489. pdwSeqNum = &(pContext->dwRecvSeqNum);
  2490. RtlInitString(&strcSignKeyConst, SASL_S2C_SIGN_KEY);
  2491. RtlInitString(&strcSealKeyConst, SASL_S2C_SEAL_KEY);
  2492. DebugLog((DEB_TRACE, "DigestUserUnsealHelper: Signing in Client Mode (Message CtoS) SeqNum %d\n", *pdwSeqNum));
  2493. }
  2494. // Based on the Cypher selected - establish the byte count parameters - magic numbers from RFC
  2495. if (pContext->typeCipher == CIPHER_RC4)
  2496. {
  2497. cbHA1n = 16; // RFC 2831 sect 2.4
  2498. cbKey = 16; // number of bytes to use from Kcc/Kcs
  2499. Algid = CALG_RC4;
  2500. }
  2501. else if (pContext->typeCipher == CIPHER_RC4_40)
  2502. {
  2503. cbHA1n = 5; // RFC 2831 sect 2.4
  2504. cbKey = 16; // number of bytes to use from Kcc/Kcs
  2505. Algid = CALG_RC4;
  2506. }
  2507. else if (pContext->typeCipher == CIPHER_RC4_56)
  2508. {
  2509. cbHA1n = 7; // RFC 2831 sect 2.4
  2510. cbKey = 16; // number of bytes to use from Kcc/Kcs
  2511. Algid = CALG_RC4;
  2512. }
  2513. else if (pContext->typeCipher == CIPHER_DES)
  2514. {
  2515. cbHA1n = 16; // RFC 2831 sect 2.4
  2516. cbKey = 8; // number of bytes to use from Kcc/Kcs
  2517. cbKeyNoParity = 7;
  2518. cbBlockSize = 8; // DES uses a blocksize of 8
  2519. Algid = CALG_DES;
  2520. }
  2521. else if (pContext->typeCipher == CIPHER_3DES)
  2522. {
  2523. cbHA1n = 16; // RFC 2831 sect 2.4
  2524. cbKey = 16; // number of bytes to use from Kcc/Kcs
  2525. cbKeyNoParity = 14;
  2526. cbBlockSize = 8; // DES uses a blocksize of 8
  2527. Algid = CALG_3DES_112;
  2528. }
  2529. else
  2530. {
  2531. Status = SEC_E_CRYPTO_SYSTEM_INVALID;
  2532. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: ContextIsTokenOK (SecBufMsg) failed 0x%x\n", Status));
  2533. goto CleanUp;
  2534. }
  2535. // Decrypt the message, padding and first SASL_MAC_HMAC_SIZE (10) bytes of HMAC (the integrity value)
  2536. // Compute Kc for encryption (seal)
  2537. if (pContext->hUnsealCryptKey == NULL)
  2538. {
  2539. ASSERT(*pdwSeqNum == 0);
  2540. // Compute on first time call to encrypt - save for other sequence numbers
  2541. Status = CalculateKc(pContext->bSessionKey, cbHA1n, &strcSealKeyConst, pContext->bKcUnsealHashData);
  2542. if (!NT_SUCCESS (Status))
  2543. {
  2544. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: Error in CalculateKc status 0x%x\n", Status));
  2545. goto CleanUp;
  2546. }
  2547. // code to expand the DES key into multiple of 8 bytes (key with parity)
  2548. if ((pContext->typeCipher == CIPHER_DES) || (pContext->typeCipher == CIPHER_3DES))
  2549. {
  2550. Status = AddDESParity(pContext->bKcUnsealHashData,
  2551. cbKeyNoParity,
  2552. bKcTempData,
  2553. &cbTempKey);
  2554. if (!NT_SUCCESS (Status))
  2555. {
  2556. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: Error in AddDESParity status 0x%x\n", Status));
  2557. goto CleanUp;
  2558. }
  2559. // replace with DES parity version
  2560. ASSERT(cbKey == cbTempKey);
  2561. memcpy(pContext->bUnsealKey, bKcTempData, cbKey);
  2562. pbIV = &(pContext->bKcUnsealHashData[8]);
  2563. }
  2564. else
  2565. {
  2566. // For RC4 ciphers
  2567. memcpy(pContext->bUnsealKey, pContext->bKcUnsealHashData, MD5_HASH_BYTESIZE);
  2568. pbIV = NULL;
  2569. }
  2570. // generate the symmetric key from the cleartext
  2571. Status = CreateSymmetricKey(Algid, cbKey, pContext->bUnsealKey, pbIV, &pContext->hUnsealCryptKey);
  2572. if (!NT_SUCCESS (Status))
  2573. {
  2574. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: Error in CalculateKc status 0x%x\n", Status));
  2575. goto CleanUp;
  2576. }
  2577. }
  2578. if ((pContext->typeCipher == CIPHER_3DES) || (pContext->typeCipher == CIPHER_DES))
  2579. {
  2580. // Specify IV - take only the last 8 bytes per RFC 2831 sect 2.4
  2581. Status = DecryptData(pContext->hUnsealCryptKey, cbSecBufMsgPrivacy,
  2582. (PUCHAR)pSecBufMsg->pvBuffer);
  2583. if (!NT_SUCCESS (Status))
  2584. {
  2585. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: Error in DecryptData status 0x%x\n", Status));
  2586. goto CleanUp;
  2587. }
  2588. // Padding length is indicated in the actual padding - get the pad byte near HMAC
  2589. if (pSecBufMsg->cbBuffer < (MAC_BLOCK_SIZE + 1))
  2590. {
  2591. Status = STATUS_INTERNAL_ERROR;
  2592. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: Determining padding not enough space status 0x%x\n", Status));
  2593. goto CleanUp;
  2594. }
  2595. pMsgPadding = (PBYTE)pSecBufMsg->pvBuffer + (pSecBufMsg->cbBuffer - (MAC_BLOCK_SIZE + 1));
  2596. #if DBG
  2597. // Now convert the Hash to Hex - for TESTING ONLY
  2598. ZeroMemory(szTemp, TEMPSIZE);
  2599. if ((MAC_BLOCK_SIZE + 1) < iTempLen)
  2600. {
  2601. iTempLen = (MAC_BLOCK_SIZE + 1);
  2602. }
  2603. BinToHex(pMsgPadding, iTempLen, szTemp);
  2604. if (szTemp)
  2605. {
  2606. DebugLog((DEB_TRACE, "DecryptData: HMAC & padding byte Data bytes (%dof%d bytes) %s\n",
  2607. iTempLen, (MAC_BLOCK_SIZE + 1), szTemp));
  2608. }
  2609. DebugLog((DEB_TRACE, "DecryptData: MAC block size %d bytes\n", MAC_BLOCK_SIZE));
  2610. #endif
  2611. cbPrefixPadding = *pMsgPadding;
  2612. if (cbPrefixPadding > MAX_PADDING)
  2613. {
  2614. Status = STATUS_INTERNAL_ERROR;
  2615. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: Padding selected (%d) too large status 0x%x\n",
  2616. cbPrefixPadding, Status));
  2617. goto CleanUp;
  2618. }
  2619. if (pSecBufMsg->cbBuffer < (MAC_BLOCK_SIZE + cbPrefixPadding))
  2620. {
  2621. Status = STATUS_INTERNAL_ERROR;
  2622. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: Message incorrect length status 0x%x\n", Status));
  2623. goto CleanUp;
  2624. }
  2625. cbMsg = pSecBufMsg->cbBuffer - (MAC_BLOCK_SIZE + cbPrefixPadding);
  2626. DebugLog((DEB_TRACE, "DigestUserUnsealHelper: Padding found to be %d bytes\n", cbPrefixPadding));
  2627. }
  2628. else
  2629. {
  2630. Status = DecryptData(pContext->hUnsealCryptKey, cbSecBufMsgPrivacy,
  2631. (PUCHAR)pSecBufMsg->pvBuffer);
  2632. if (!NT_SUCCESS (Status))
  2633. {
  2634. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: Error in EncryptData status 0x%x\n", Status));
  2635. goto CleanUp;
  2636. }
  2637. // There is no padding on stream ciphers, so just remove the SASL HMAC block
  2638. cbMsg = pSecBufMsg->cbBuffer - MAC_BLOCK_SIZE;
  2639. DebugLog((DEB_TRACE, "DigestUserUnsealHelper: Stream Cipher - No padding\n"));
  2640. }
  2641. // Locate the beginning of the message
  2642. pMsgHMAC = (PBYTE)pSecBufMsg->pvBuffer + (pSecBufMsg->cbBuffer - MAC_BLOCK_SIZE);
  2643. Status = CalculateSASLHMAC(pContext, FALSE, &strcSignKeyConst, *pdwSeqNum,
  2644. (PBYTE)pSecBufMsg->pvBuffer, cbMsg, &MacBlock);
  2645. if (!NT_SUCCESS (Status))
  2646. {
  2647. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: Error in CalculateSASLHMAC status 0x%x\n", Status));
  2648. goto CleanUp;
  2649. }
  2650. DebugLog((DEB_TRACE, "DigestUserUnsealHelper: Ready to compare MacBlocks\n"));
  2651. // Check validity of MAC block ONLY do not write it out
  2652. memcpy(&TokenMacBlock, pMsgHMAC, MAC_BLOCK_SIZE);
  2653. if (MacBlock.dwSeqNumber != TokenMacBlock.dwSeqNumber)
  2654. {
  2655. Status = SEC_E_OUT_OF_SEQUENCE;
  2656. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: SASL MAC blocks out of sequence. Failed verify. Status 0x%x\n", Status));
  2657. #if DBG
  2658. ZeroMemory(szTemp, TEMPSIZE);
  2659. BinToHex((PUCHAR)&TokenMacBlock, MAC_BLOCK_SIZE, szTemp);
  2660. DebugLog((DEB_TRACE, "CalculateSASLHMAC: Token's HMAC-MD5 block %s\n", szTemp));
  2661. ZeroMemory(szTemp, TEMPSIZE);
  2662. BinToHex((PUCHAR)&MacBlock, MAC_BLOCK_SIZE, szTemp);
  2663. DebugLog((DEB_TRACE, "CalculateSASLHMAC: TComputed HMAC-MD5 block %s\n", szTemp));
  2664. #endif
  2665. goto CleanUp;
  2666. }
  2667. if (memcmp(&MacBlock, &TokenMacBlock, MAC_BLOCK_SIZE))
  2668. {
  2669. Status = SEC_E_MESSAGE_ALTERED;
  2670. DebugLog((DEB_ERROR, "DigestUserUnsealHelper: SASL MAC blocks do not match. Failed verify. Status 0x%x\n", Status));
  2671. #if DBG
  2672. ZeroMemory(szTemp, TEMPSIZE);
  2673. BinToHex((PUCHAR)&TokenMacBlock, MAC_BLOCK_SIZE, szTemp);
  2674. DebugLog((DEB_TRACE, "CalculateSASLHMAC: Token's HMAC-MD5 block %s\n", szTemp));
  2675. ZeroMemory(szTemp, TEMPSIZE);
  2676. BinToHex((PUCHAR)&MacBlock, MAC_BLOCK_SIZE, szTemp);
  2677. DebugLog((DEB_TRACE, "CalculateSASLHMAC: TComputed HMAC-MD5 block %s\n", szTemp));
  2678. #endif
  2679. goto CleanUp;
  2680. }
  2681. else
  2682. {
  2683. DebugLog((DEB_TRACE, "DigestUserUnsealHelper: SASL MAC blocks match!\n"));
  2684. }
  2685. // Write out to SECBUFFERDATA the length and location of message
  2686. if (pSecBufData)
  2687. {
  2688. pSecBufData->cbBuffer = cbMsg;
  2689. pSecBufData->pvBuffer = pSecBufMsg->pvBuffer;
  2690. }
  2691. // completed all tasks down to here. Need to update the sequence number
  2692. (*pdwSeqNum)++;
  2693. DebugLog((DEB_TRACE, "DigestUserUnsealHelper: Updated SeqNum to %d\n", *pdwSeqNum));
  2694. CleanUp:
  2695. DebugLog((DEB_TRACE_FUNC, "DigestUserUnsealHelper: Leaving Status 0x%x\n", Status));
  2696. return(Status);
  2697. }
  2698. // Process the Digest information with the context info and generate any output token info
  2699. NTSTATUS NTAPI
  2700. DigestUserProcessParameters(
  2701. IN PDIGEST_USERCONTEXT pContext,
  2702. IN PDIGEST_PARAMETER pDigest,
  2703. OUT PSecBuffer pFirstOutputToken)
  2704. {
  2705. NTSTATUS Status = STATUS_SUCCESS;
  2706. ULONG ulNonceCount = 0;
  2707. DebugLog((DEB_TRACE_FUNC, "DigestUserProcessParameters: Entering\n"));
  2708. // Some common input verification tests
  2709. // We must have a noncecount specified since we specified a qop in the Challenge
  2710. // If we decide to support no noncecount modes then we need to make sure that qop is not specified
  2711. if (pDigest->refstrParam[MD5_AUTH_NC].Length)
  2712. {
  2713. Status = RtlCharToInteger(pDigest->refstrParam[MD5_AUTH_NC].Buffer, HEXBASE, &ulNonceCount);
  2714. if (!NT_SUCCESS(Status))
  2715. {
  2716. Status = STATUS_INVALID_PARAMETER;
  2717. DebugLog((DEB_ERROR, "DigestUserProcessParameters: Nonce Count badly formatted\n"));
  2718. goto CleanUp;
  2719. }
  2720. }
  2721. // Check nonceCount is incremented to preclude replay
  2722. if (!(ulNonceCount > pContext->ulNC))
  2723. {
  2724. // We failed to verify next noncecount
  2725. Status = SEC_E_OUT_OF_SEQUENCE;
  2726. DebugLog((DEB_ERROR, "DigestUserProcessParameters: NonceCount failed to increment!\n"));
  2727. goto CleanUp;
  2728. }
  2729. // Since we are in UserMode we MUST have a sessionkey to use - if non then can not process
  2730. if (!pContext->strSessionKey.Length)
  2731. {
  2732. Status = SEC_E_NO_AUTHENTICATING_AUTHORITY; // indicate that we needed a call to ASC or ISC first
  2733. DebugLog((DEB_ERROR, "DigestUserProcessParameters: No Session Key contained in UserContext\n"));
  2734. goto CleanUp;
  2735. }
  2736. // Copy the SessionKey from the Context into the Digest Structure to verify against
  2737. // This will have Digest Auth routines use the SessionKey rather than recompute H(A1)
  2738. StringFree(&(pDigest->strSessionKey));
  2739. Status = StringDuplicate(&(pDigest->strSessionKey), &(pContext->strSessionKey));
  2740. if (!NT_SUCCESS(Status))
  2741. {
  2742. DebugLog((DEB_ERROR, "DigestUserProcessParameters: Failed to copy over SessionKey\n"));
  2743. goto CleanUp;
  2744. }
  2745. // Set the type of Digest Parameters we are to process
  2746. pDigest->typeDigest = pContext->typeDigest;
  2747. pDigest->typeQOP = pContext->typeQOP;
  2748. pDigest->typeAlgorithm = pContext->typeAlgorithm;
  2749. pDigest->typeCharset = pContext->typeCharset;
  2750. DigestPrint(pDigest);
  2751. // No check locally that Digest is authentic
  2752. Status = DigestCalculation(pDigest, NULL);
  2753. if (!NT_SUCCESS(Status))
  2754. {
  2755. DebugLog((DEB_ERROR, "DigestUserProcessParameters: Oh no we FAILED Authentication!!!!\n"));
  2756. goto CleanUp;
  2757. }
  2758. // Send to output buffer only if there is an output buffer
  2759. // This allows this routine to be used in UserMode
  2760. if (pFirstOutputToken)
  2761. {
  2762. Status = DigestCreateChalResp(pDigest, NULL, pFirstOutputToken);
  2763. if (!NT_SUCCESS(Status))
  2764. {
  2765. DebugLog((DEB_ERROR, "DigestUserProcessParameters: Failed to create Output String\n"));
  2766. goto CleanUp;
  2767. }
  2768. }
  2769. CleanUp:
  2770. DebugLog((DEB_TRACE_FUNC, "DigestUserProcessParameters: Leaving Status 0x%x\n", Status));
  2771. return(Status);
  2772. }
  2773. // Unpack the context from LSA mode into the User mode Context
  2774. NTSTATUS
  2775. DigestUnpackContext(
  2776. IN PDIGEST_PACKED_USERCONTEXT pPackedUserContext,
  2777. OUT PDIGEST_USERCONTEXT pContext)
  2778. {
  2779. NTSTATUS Status = STATUS_SUCCESS;
  2780. PUCHAR pucLoc = NULL;
  2781. USHORT uNumWChars = 0;
  2782. int iAuth = 0;
  2783. DebugLog((DEB_TRACE_FUNC, "DigestUnpackContext: Entering\n"));
  2784. ASSERT(pContext);
  2785. //
  2786. // If TokenHandle is NULL, we are being called as
  2787. // as an effect of InitializeSecurityContext, else we are
  2788. // being called because of AcceptSecurityContext
  2789. //
  2790. if (pPackedUserContext->ClientTokenHandle != NULL)
  2791. {
  2792. DebugLog((DEB_TRACE, "DigestUnpackContext: Called from ASC\n" ));
  2793. pContext->ClientTokenHandle = (HANDLE) ((ULONG_PTR)pPackedUserContext->ClientTokenHandle);
  2794. if (FAILED(SspCreateTokenDacl(pContext->ClientTokenHandle)))
  2795. {
  2796. Status = STATUS_INVALID_HANDLE;
  2797. DebugLog((DEB_ERROR, "DigestUnpackContext: SspCreateTokenDacl failed\n" ));
  2798. goto CleanUp;
  2799. }
  2800. }
  2801. else
  2802. {
  2803. DebugLog((DEB_TRACE, "DigestUnpackContext: Called from ISC\n" ));
  2804. }
  2805. //
  2806. // Copy over all of the other fields - some data might be binary so
  2807. // use RtlCopyMemory(Dest, Src, len)
  2808. //
  2809. pContext->Expires = pPackedUserContext->Expires;
  2810. pContext->typeAlgorithm = (ALGORITHM_TYPE)pPackedUserContext->typeAlgorithm;
  2811. pContext->typeCharset = (CHARSET_TYPE)pPackedUserContext->typeCharset;
  2812. pContext->typeCipher = (CIPHER_TYPE)pPackedUserContext->typeCipher;
  2813. pContext->typeDigest = (DIGEST_TYPE)pPackedUserContext->typeDigest;
  2814. pContext->typeQOP = (QOP_TYPE)pPackedUserContext->typeQOP;
  2815. pContext->ulSendMaxBuf = pPackedUserContext->ulSendMaxBuf;
  2816. pContext->ulRecvMaxBuf = pPackedUserContext->ulRecvMaxBuf;
  2817. pContext->ulNC = 1; // Force to one to account for ISC/ASC first message verify
  2818. pContext->lReferences = 1;
  2819. pContext->ContextReq = pPackedUserContext->ContextReq;
  2820. pContext->CredentialUseFlags = pPackedUserContext->CredentialUseFlags;
  2821. // Now check on the strings attached
  2822. pucLoc = &(pPackedUserContext->ucData);
  2823. for (iAuth = 0; iAuth < MD5_AUTH_LAST; iAuth++)
  2824. {
  2825. if (pPackedUserContext->uDigestLen[iAuth])
  2826. {
  2827. Status = StringAllocate(&(pContext->strParam[iAuth]), (USHORT)pPackedUserContext->uDigestLen[iAuth]);
  2828. if (!NT_SUCCESS(Status))
  2829. {
  2830. Status = STATUS_INSUFFICIENT_RESOURCES;
  2831. DebugLog((DEB_ERROR, "DigestUnpackContext: DigestAllocateMemory for Params returns NULL\n" ));
  2832. goto CleanUp;
  2833. }
  2834. memcpy(pContext->strParam[iAuth].Buffer, pucLoc, (USHORT)pPackedUserContext->uDigestLen[iAuth]);
  2835. pContext->strParam[iAuth].Length = (USHORT)pPackedUserContext->uDigestLen[iAuth];
  2836. pucLoc += (USHORT)pPackedUserContext->uDigestLen[iAuth];
  2837. // DebugLog((DEB_TRACE, "DigestUnpackContext: Param[%d] is length %d - %.50s\n",
  2838. // iAuth, pPackedUserContext->uDigestLen[iAuth], pContext->strParam[iAuth].Buffer ));
  2839. }
  2840. }
  2841. // Now do the SessionKey
  2842. if (pPackedUserContext->uSessionKeyLen)
  2843. {
  2844. Status = StringAllocate(&(pContext->strSessionKey), (USHORT)pPackedUserContext->uSessionKeyLen);
  2845. if (!NT_SUCCESS(Status))
  2846. {
  2847. Status = STATUS_INSUFFICIENT_RESOURCES;
  2848. DebugLog((DEB_ERROR, "DigestUnpackContext: DigestAllocateMemory for SessionKey returns NULL\n" ));
  2849. goto CleanUp;
  2850. }
  2851. memcpy(pContext->strSessionKey.Buffer, pucLoc, pPackedUserContext->uSessionKeyLen);
  2852. pContext->strSessionKey.Length = (USHORT)pPackedUserContext->uSessionKeyLen;
  2853. pucLoc += (USHORT)pPackedUserContext->uSessionKeyLen;
  2854. }
  2855. // Now do the AccountName
  2856. if (pPackedUserContext->uAccountNameLen)
  2857. {
  2858. uNumWChars = (USHORT)pPackedUserContext->uAccountNameLen / sizeof(WCHAR);
  2859. Status = UnicodeStringAllocate(&(pContext->ustrAccountName), uNumWChars);
  2860. if (!NT_SUCCESS(Status))
  2861. {
  2862. Status = STATUS_INSUFFICIENT_RESOURCES;
  2863. DebugLog((DEB_ERROR, "DigestUnpackContext: DigestAllocateMemory for AccountName returns NULL\n" ));
  2864. goto CleanUp;
  2865. }
  2866. memcpy(pContext->ustrAccountName.Buffer, pucLoc, pPackedUserContext->uAccountNameLen);
  2867. pContext->ustrAccountName.Length = (USHORT)pPackedUserContext->uAccountNameLen;
  2868. pucLoc += (USHORT)pPackedUserContext->uAccountNameLen;
  2869. }
  2870. // Now determine the binary version of the SessionKey from HEX() version
  2871. ASSERT(pContext->strSessionKey.Length == MD5_HASH_HEX_SIZE);
  2872. HexToBin(pContext->strSessionKey.Buffer, MD5_HASH_HEX_SIZE, pContext->bSessionKey);
  2873. #if DBG
  2874. char szTemp[TEMPSIZE];
  2875. ZeroMemory(szTemp, TEMPSIZE);
  2876. BinToHex(pContext->bSessionKey, MD5_HASH_BYTESIZE, szTemp);
  2877. DebugLog((DEB_TRACE, "DigestUnpackContext: verify SessionKey %Z is binary %s\n",
  2878. &(pContext->strSessionKey), szTemp));
  2879. #endif
  2880. CleanUp:
  2881. DebugLog((DEB_TRACE_FUNC, "DigestUnpackContext: Leaving Status 0x%x\n", Status));
  2882. return(Status);
  2883. }
  2884. // Printout the fields present in usercontext pContext
  2885. NTSTATUS
  2886. UserContextPrint(PDIGEST_USERCONTEXT pContext)
  2887. {
  2888. NTSTATUS Status = STATUS_SUCCESS;
  2889. int i = 0;
  2890. if (!pContext)
  2891. {
  2892. return (STATUS_INVALID_PARAMETER);
  2893. }
  2894. DebugLog((DEB_TRACE_FUNC, "UserContext: Entering for Context Handle at 0x%x\n", pContext));
  2895. DebugLog((DEB_TRACE, "UserContext: NC %ld\n", pContext->ulNC));
  2896. DebugLog((DEB_TRACE, "UserContext: LSA Context 0x%x\n", pContext->LsaContext));
  2897. if (pContext->typeDigest == DIGEST_CLIENT)
  2898. {
  2899. DebugLog((DEB_TRACE, "UserContext: DIGEST_CLIENT\n"));
  2900. }
  2901. if (pContext->typeDigest == DIGEST_SERVER)
  2902. {
  2903. DebugLog((DEB_TRACE, "UserContext: DIGEST_SERVER\n"));
  2904. }
  2905. if (pContext->typeDigest == SASL_SERVER)
  2906. {
  2907. DebugLog((DEB_TRACE, "UserContext: SASL_SERVER\n"));
  2908. }
  2909. if (pContext->typeDigest == SASL_CLIENT)
  2910. {
  2911. DebugLog((DEB_TRACE, "UserContext: SASL_CLIENT\n"));
  2912. }
  2913. if (pContext->typeQOP == AUTH)
  2914. {
  2915. DebugLog((DEB_TRACE, "UserContext: QOP: AUTH\n"));
  2916. }
  2917. if (pContext->typeQOP == AUTH_INT)
  2918. {
  2919. DebugLog((DEB_TRACE, "UserContext: QOP: AUTH_INT\n"));
  2920. }
  2921. if (pContext->typeQOP == AUTH_CONF)
  2922. {
  2923. DebugLog((DEB_TRACE, "UserContext: QOP: AUTH_CONF\n"));
  2924. }
  2925. if (pContext->typeAlgorithm == MD5)
  2926. {
  2927. DebugLog((DEB_TRACE, "UserContext: Algorithm: MD5\n"));
  2928. }
  2929. if (pContext->typeAlgorithm == MD5_SESS)
  2930. {
  2931. DebugLog((DEB_TRACE, "UserContext: Algorithm: MD5_SESS\n"));
  2932. }
  2933. if (pContext->typeCharset == ISO_8859_1)
  2934. {
  2935. DebugLog((DEB_TRACE, "UserContext: Charset: ISO 8859-1\n"));
  2936. }
  2937. if (pContext->typeCharset == UTF_8)
  2938. {
  2939. DebugLog((DEB_TRACE, "UserContext: Charset: UTF-8\n"));
  2940. }
  2941. if (pContext->typeCipher == CIPHER_RC4)
  2942. {
  2943. DebugLog((DEB_TRACE, "UserContext: Cipher: CIPHER_RC4\n"));
  2944. }
  2945. else if (pContext->typeCipher == CIPHER_RC4_40)
  2946. {
  2947. DebugLog((DEB_TRACE, "UserContext: Cipher: CIPHER_RC4_40\n"));
  2948. }
  2949. else if (pContext->typeCipher == CIPHER_RC4_56)
  2950. {
  2951. DebugLog((DEB_TRACE, "UserContext: Cipher: CIPHER_RC4_56\n"));
  2952. }
  2953. else if (pContext->typeCipher == CIPHER_DES)
  2954. {
  2955. DebugLog((DEB_TRACE, "UserContext: Cipher: CIPHER_DES\n"));
  2956. }
  2957. else if (pContext->typeCipher == CIPHER_3DES)
  2958. {
  2959. DebugLog((DEB_TRACE, "UserContext: Cipher: CIPHER_3DES\n"));
  2960. }
  2961. DebugLog((DEB_TRACE, "UserContext: ContextReq 0x%lx CredentialUseFlags 0x%x\n",
  2962. pContext->ContextReq,
  2963. pContext->CredentialUseFlags));
  2964. for (i=0; i < MD5_AUTH_LAST;i++)
  2965. {
  2966. if (pContext->strParam[i].Buffer &&
  2967. pContext->strParam[i].Length)
  2968. {
  2969. DebugLog((DEB_TRACE, "UserContext: Digest[%d] = \"%Z\"\n", i, &pContext->strParam[i]));
  2970. }
  2971. }
  2972. if (pContext->strSessionKey.Length)
  2973. {
  2974. DebugLog((DEB_TRACE, "UserContext: SessionKey %Z\n", &pContext->strSessionKey));
  2975. }
  2976. if (pContext->ustrAccountName.Length)
  2977. {
  2978. DebugLog((DEB_TRACE, "UserContext: AccountName %wZ\n", &pContext->ustrAccountName));
  2979. }
  2980. DebugLog((DEB_TRACE_FUNC, "UserContext: Leaving\n"));
  2981. return(Status);
  2982. }
  2983. // CryptoAPI function support
  2984. NTSTATUS
  2985. SEC_ENTRY
  2986. CreateSymmetricKey(
  2987. IN ALG_ID Algid,
  2988. IN DWORD cbKey,
  2989. IN UCHAR *pbKey,
  2990. IN UCHAR *pbIV,
  2991. OUT HCRYPTKEY *phKey
  2992. )
  2993. {
  2994. NTSTATUS Status = STATUS_SUCCESS;
  2995. PLAINTEXTBLOB PlainBlob;
  2996. DebugLog((DEB_TRACE_FUNC, "CreateSymmetricKey: Entering\n"));
  2997. ASSERT(*phKey == NULL);
  2998. ZeroMemory(&PlainBlob, sizeof(PlainBlob));
  2999. if (cbKey > MD5_HASH_BYTESIZE)
  3000. {
  3001. DebugLog((DEB_ERROR, "CreateSymmetricKey: Shared key too long\n"));
  3002. Status = STATUS_INTERNAL_ERROR;
  3003. goto CleanUp;
  3004. }
  3005. #if DBG
  3006. char szTemp[TEMPSIZE];
  3007. // Now convert the Hash to Hex - for TESTING ONLY
  3008. ZeroMemory(szTemp, TEMPSIZE);
  3009. BinToHex(pbKey, cbKey, szTemp);
  3010. if (szTemp)
  3011. {
  3012. DebugLog((DEB_TRACE, "CreateSymmetricKey: Creating symmetric for %s\n", szTemp));
  3013. }
  3014. #endif
  3015. PlainBlob.Blob.bType = PLAINTEXTKEYBLOB;
  3016. PlainBlob.Blob.bVersion = CUR_BLOB_VERSION;
  3017. PlainBlob.Blob.reserved = 0;
  3018. PlainBlob.Blob.aiKeyAlg = Algid;
  3019. memcpy(PlainBlob.bKey, pbKey, cbKey);
  3020. PlainBlob.dwKeyLen = cbKey;
  3021. // import thw simpleblob to get a handle to the symmetric key
  3022. if (!CryptImportKey(g_hCryptProv,
  3023. (BYTE *)&PlainBlob,
  3024. sizeof(PlainBlob),
  3025. 0,
  3026. 0,
  3027. phKey))
  3028. {
  3029. DebugLog((DEB_ERROR, "CreateSymmetricKey: CryptImportKey failed error 0x%x\n", GetLastError()));
  3030. Status = STATUS_INTERNAL_ERROR;
  3031. }
  3032. if ((Algid == CALG_DES) || (Algid == CALG_3DES_112))
  3033. {
  3034. if (!pbIV)
  3035. {
  3036. DebugLog((DEB_WARN, "CreateSymmetricKey: No IV selected for DES\n"));
  3037. }
  3038. else
  3039. {
  3040. #if DBG
  3041. // Now convert the Hash to Hex - for TESTING ONLY
  3042. ZeroMemory(szTemp, TEMPSIZE);
  3043. BinToHex(pbIV, 8, szTemp);
  3044. if (szTemp)
  3045. {
  3046. DebugLog((DEB_TRACE, "CreateSymmetricKey: IV bytes set to %s\n", szTemp));
  3047. }
  3048. #endif
  3049. if (!CryptSetKeyParam(*phKey, KP_IV, pbIV, 0))
  3050. {
  3051. DebugLog((DEB_ERROR, "CreateSymmetricKey:CryptSetKeyParam() failed : 0x%x\n", GetLastError()));
  3052. Status = STATUS_INTERNAL_ERROR;
  3053. goto CleanUp;
  3054. }
  3055. }
  3056. }
  3057. CleanUp:
  3058. DebugLog((DEB_TRACE_FUNC, "CreateSymmetricKey: Leaving status 0x%x\n", Status));
  3059. return(Status);
  3060. }
  3061. //+-------------------------------------------------------------------------
  3062. //
  3063. // Function: EncryptData2
  3064. //
  3065. // Synopsis: Encrypt a data buffer (broken into two pieces DATA and Signature)
  3066. //
  3067. // Effects: no global effect.
  3068. //
  3069. // Arguments:
  3070. //
  3071. // IN Algid -- Encryption algorithm to utilize
  3072. // IN pbIV -- DES salt (if any provided)
  3073. // IN hKey -- symmetric key to utilize
  3074. // IN cbBlocklength -- natural block length for encoding (RC will be 1 and DES will be 8)
  3075. // IN cbData -- number of data bytes to encrypt
  3076. // IN pbData -- pointer to data bytes to encrypt
  3077. // IN cbSignature -- number of signature bytes to encrypt after Data is encrypted
  3078. // IN pbSignature -- number of bytes in signature to encrypt
  3079. //
  3080. // Requires: no global requirements
  3081. //
  3082. // Returns: STATUS_SUCCESS, or resource error
  3083. //
  3084. // Notes:
  3085. //
  3086. //
  3087. //--------------------------------------------------------------------------
  3088. NTSTATUS
  3089. SEC_ENTRY
  3090. EncryptData2(
  3091. IN HCRYPTKEY hKey,
  3092. IN ULONG cbBlocklength,
  3093. IN ULONG cbData,
  3094. IN OUT UCHAR *pbData,
  3095. IN ULONG cbSignature,
  3096. IN OUT UCHAR *pbSignature
  3097. )
  3098. {
  3099. DWORD dwBytesEncrypt = 0;
  3100. ULONG cbTemp = 0;
  3101. NTSTATUS Status = STATUS_SUCCESS;
  3102. ULONG cbBlocks = 0;
  3103. ULONG cbDataExtra = 0;
  3104. ULONG cbCnt = 0; // number of bytes to alloc for merged data
  3105. PBYTE pbBuff2 = NULL; // temp alloc for merge of extra bytes & signature
  3106. PBYTE pbDataExtra = NULL; // location for start of extra memory bytes
  3107. DebugLog((DEB_TRACE_FUNC, "EncryptData2: Entering %lu bytes\n", cbData));
  3108. DebugLog((DEB_TRACE, "EncryptData2: Blocklength %lu\n", cbBlocklength));
  3109. DebugLog((DEB_TRACE, "EncryptData2: Signature block %lu bytes\n", cbSignature));
  3110. // Check if encrypting 1 or two buffers
  3111. if (!cbSignature)
  3112. {
  3113. DebugLog((DEB_TRACE, "EncryptData2: one buffer only - direct encode\n"));
  3114. DebugLog((DEB_TRACE, "EncryptData2: buffer %lu bytes\n", cbData));
  3115. // Only one buffer utilized
  3116. dwBytesEncrypt = cbData;
  3117. if (!CryptEncrypt(hKey, 0, FALSE, 0, pbData, &dwBytesEncrypt, cbData))
  3118. {
  3119. DebugLog((DEB_ERROR, "EncryptData2:CryptEncrypt one buffer failed : 0x%x\n", GetLastError()));
  3120. Status = STATUS_INTERNAL_ERROR;
  3121. goto CleanUp;
  3122. }
  3123. }
  3124. else
  3125. {
  3126. // We have two buffers to encrypt
  3127. // Identify if there are extra bytes beyond blocksize for cipher
  3128. cbBlocks = cbData / cbBlocklength; // integer division
  3129. cbDataExtra = cbData - (cbBlocklength * cbBlocks);
  3130. DebugLog((DEB_TRACE, "EncryptData2: number of cipher blocks %lu number extra bytes %lu\n",
  3131. cbBlocks, cbDataExtra));
  3132. if (cbDataExtra)
  3133. {
  3134. DebugLog((DEB_TRACE, "EncryptData2: merge signature - encrypt two buffers & replace\n"));
  3135. // extra data bytes starting memory location
  3136. pbDataExtra = pbData + (cbBlocklength * cbBlocks);
  3137. // There are bytes outside a multiple of the cipher block size
  3138. // create temp buffer for extra bytes and HMAC
  3139. cbCnt = cbDataExtra + cbSignature;
  3140. DebugLog((DEB_TRACE, "EncryptData2: merge block size %lu bytes\n", cbCnt));
  3141. pbBuff2 = (PBYTE)DigestAllocateMemory(cbCnt + MAX_PADDING);
  3142. if (!pbBuff2)
  3143. {
  3144. DebugLog((DEB_ERROR, "EncryptData2:out of memory\n"));
  3145. Status = SEC_E_INSUFFICIENT_MEMORY;
  3146. goto CleanUp;
  3147. }
  3148. // copy over the bytes to temp buffer
  3149. memcpy(pbBuff2, pbDataExtra, cbDataExtra);
  3150. memcpy(pbBuff2 + cbDataExtra, pbSignature, cbSignature);
  3151. // encrypt any multiples of blocklength in the data section (first buffer)
  3152. if (cbBlocks)
  3153. {
  3154. dwBytesEncrypt = cbBlocklength * cbBlocks;
  3155. DebugLog((DEB_TRACE, "EncryptData2: buffer 1 %lu bytes\n", dwBytesEncrypt));
  3156. if (!CryptEncrypt(hKey, 0, FALSE, 0, pbData, &dwBytesEncrypt, dwBytesEncrypt))
  3157. {
  3158. DebugLog((DEB_ERROR, "EncryptData2:CryptEncrypt first buffer (blocklength) failed : 0x%x\n", GetLastError()));
  3159. Status = STATUS_INTERNAL_ERROR;
  3160. goto CleanUp;
  3161. }
  3162. }
  3163. // encrypt the temp buffer - copy back to original locations afterwards
  3164. dwBytesEncrypt = cbCnt;
  3165. DebugLog((DEB_TRACE, "EncryptData2: buffer 2 encrypt %lu bytes in %lu byte buffer\n",
  3166. dwBytesEncrypt, cbCnt + MAX_PADDING));
  3167. if (!CryptEncrypt(hKey, 0, FALSE, 0, pbBuff2, &dwBytesEncrypt, cbCnt + MAX_PADDING))
  3168. {
  3169. DebugLog((DEB_ERROR, "EncryptData2:CryptEncrypt second buffer (blocklength) failed : 0x%x\n", GetLastError()));
  3170. Status = STATUS_INTERNAL_ERROR;
  3171. goto CleanUp;
  3172. }
  3173. memcpy(pbSignature, pbBuff2 + cbDataExtra, cbSignature);
  3174. memcpy(pbDataExtra, pbBuff2, cbDataExtra);
  3175. }
  3176. else
  3177. {
  3178. DebugLog((DEB_TRACE, "EncryptData2: multiple of cipher blocksize - encrypt two buffers directly\n"));
  3179. // encrypt data buffer and then signature buffer - data buffer is multiple of blocksize
  3180. if (cbData)
  3181. {
  3182. dwBytesEncrypt = cbData;
  3183. DebugLog((DEB_TRACE, "EncryptData2: buffer 1 %lu bytes\n", dwBytesEncrypt));
  3184. if (!CryptEncrypt(hKey, 0, FALSE, 0, pbData, &dwBytesEncrypt, cbData))
  3185. {
  3186. DebugLog((DEB_ERROR, "EncryptData2:CryptEncrypt first buffer (blocklength) failed : 0x%x\n", GetLastError()));
  3187. Status = STATUS_INTERNAL_ERROR;
  3188. goto CleanUp;
  3189. }
  3190. DebugLog((DEB_TRACE, "EncryptData2: needed %lu bytes for encrypted buffer 1\n", dwBytesEncrypt));
  3191. }
  3192. // Final encrypt of signature buffer
  3193. dwBytesEncrypt = cbSignature;
  3194. DebugLog((DEB_TRACE, "EncryptData2: buffer 2 %lu bytes\n", dwBytesEncrypt));
  3195. // We do our own padding so we must have Final=FALSE so CAPI will not add in one
  3196. if (!CryptEncrypt(hKey, 0, FALSE, 0, pbSignature, &dwBytesEncrypt, cbSignature))
  3197. {
  3198. DebugLog((DEB_ERROR, "EncryptData2:CryptEncrypt second buffer (blocklength) failed : 0x%x\n", GetLastError()));
  3199. Status = STATUS_INTERNAL_ERROR;
  3200. goto CleanUp;
  3201. }
  3202. DebugLog((DEB_TRACE, "EncryptData2: needed %lu bytes for encrypted buffer 2\n", dwBytesEncrypt));
  3203. }
  3204. }
  3205. goto CleanUp;
  3206. CleanUp:
  3207. if (pbBuff2)
  3208. {
  3209. DigestFreeMemory(pbBuff2);
  3210. pbBuff2 = NULL;
  3211. }
  3212. DebugLog((DEB_TRACE_FUNC, "EncryptData2: Leaving status 0x%x\n", Status));
  3213. return(Status);
  3214. }
  3215. NTSTATUS
  3216. SEC_ENTRY
  3217. DecryptData(
  3218. IN HCRYPTKEY hKey,
  3219. IN ULONG cbData,
  3220. IN OUT UCHAR *pbData
  3221. )
  3222. {
  3223. ULONG cb = cbData;
  3224. ULONG cbTemp = 0;
  3225. NTSTATUS Status = STATUS_SUCCESS;
  3226. #if DBG
  3227. char szTemp[TEMPSIZE];
  3228. ULONG iTempLen = 20;
  3229. ZeroMemory(szTemp, TEMPSIZE);
  3230. #endif
  3231. DebugLog((DEB_TRACE_FUNC, "DecryptData: Entering %lu bytes at 0x%x\n", cbData, pbData));
  3232. #if DBG
  3233. // Now convert the Hash to Hex - for TESTING ONLY
  3234. iTempLen = 20;
  3235. ZeroMemory(szTemp, TEMPSIZE);
  3236. if (cbData < iTempLen)
  3237. {
  3238. iTempLen = cbData;
  3239. }
  3240. BinToHex(pbData, iTempLen, szTemp);
  3241. if (szTemp)
  3242. {
  3243. DebugLog((DEB_TRACE, "DecryptData: Encrypted Data bytes (%dof%d bytes) %s\n",
  3244. iTempLen, cbData, szTemp));
  3245. }
  3246. iTempLen = 20;
  3247. ZeroMemory(szTemp, TEMPSIZE);
  3248. if (cbData < iTempLen)
  3249. {
  3250. iTempLen = cbData;
  3251. }
  3252. BinToHex((pbData + cbData - iTempLen), iTempLen, szTemp);
  3253. if (szTemp)
  3254. {
  3255. DebugLog((DEB_TRACE, "DecryptData: Encrypted end of buffer (%dof%d bytes) %s\n",
  3256. iTempLen, cbData, szTemp));
  3257. }
  3258. #endif
  3259. // import the simpleblob to get a handle to the symmetric key
  3260. if (!CryptDecrypt(hKey, 0, FALSE, 0, pbData, &cb))
  3261. {
  3262. DebugLog((DEB_ERROR, "DecryptData:CryptCreateHash() failed : 0x%x\n", GetLastError()));
  3263. Status = STATUS_INTERNAL_ERROR;
  3264. goto CleanUp;
  3265. }
  3266. #if DBG
  3267. DebugLog((DEB_ERROR, "DecryptData: Decrypted number of bytes %lu\n", cb));
  3268. // Now convert the Hash to Hex - for TESTING ONLY
  3269. iTempLen = 20;
  3270. ZeroMemory(szTemp, TEMPSIZE);
  3271. if (cb < iTempLen)
  3272. {
  3273. iTempLen = cb;
  3274. }
  3275. BinToHex(pbData, iTempLen, szTemp);
  3276. if (szTemp)
  3277. {
  3278. DebugLog((DEB_TRACE, "DecryptData: Decrypted Data bytes (%dof%d bytes) %s\n",
  3279. iTempLen, cbData, szTemp));
  3280. }
  3281. iTempLen = 20;
  3282. ZeroMemory(szTemp, TEMPSIZE);
  3283. if (cb < iTempLen)
  3284. {
  3285. iTempLen = cb;
  3286. }
  3287. BinToHex((pbData + cb - iTempLen), iTempLen, szTemp);
  3288. if (szTemp)
  3289. {
  3290. DebugLog((DEB_TRACE, "DecryptData: Decrypted end of buffer (%dof%d bytes) %s\n",
  3291. iTempLen, cbData, szTemp));
  3292. }
  3293. #endif
  3294. CleanUp:
  3295. DebugLog((DEB_TRACE_FUNC, "DecryptData: Leaving status 0x%x\n", Status));
  3296. return(Status);
  3297. }
  3298. NTSTATUS
  3299. SEC_ENTRY
  3300. CalculateSASLHMAC(
  3301. IN PDIGEST_USERCONTEXT pContext,
  3302. IN BOOL fSign,
  3303. IN PSTRING pstrSignKeyConst,
  3304. IN DWORD dwSeqNum, // Sequence number to process
  3305. IN PBYTE pData, // location of data to HMAC
  3306. IN ULONG cbData, // How many bytes of data to process
  3307. OUT PSASL_MAC_BLOCK pMacBlock)
  3308. {
  3309. NTSTATUS Status = STATUS_SUCCESS;
  3310. HCRYPTHASH hHash = NULL;
  3311. HCRYPTKEY hCryptKey = NULL;
  3312. HMAC_INFO hmacinfo;
  3313. BYTE bKiHashData[MD5_HASH_BYTESIZE]; // Message integrity keys RFC 2831 sec 2.3
  3314. DWORD cbKiHashData = 0; // Size of Message integrity keys
  3315. BYTE bHMACData[HMAC_MD5_HASH_BYTESIZE];
  3316. DWORD cbHMACData = 0;
  3317. #if DBG
  3318. char szTemp[TEMPSIZE];
  3319. ULONG iTempLen = 20;
  3320. ZeroMemory(szTemp, TEMPSIZE);
  3321. #endif
  3322. DebugLog((DEB_TRACE_FUNC, "CalculateSASLHMAC: Entering\n"));
  3323. DebugLog((DEB_TRACE, "CalculateSASLHMAC: Processing %d bytes in data block\n", cbData));
  3324. // Clear the output
  3325. ZeroMemory(pMacBlock, sizeof(SASL_MAC_BLOCK));
  3326. // Initialize local variables
  3327. ZeroMemory(bKiHashData, MD5_HASH_BYTESIZE);
  3328. ZeroMemory(bHMACData, HMAC_MD5_HASH_BYTESIZE);
  3329. ZeroMemory(&hmacinfo, sizeof(HMAC_INFO));
  3330. // Always do an integrety calculation on the input data
  3331. // We should have clear text data at this stage
  3332. if (!dwSeqNum)
  3333. {
  3334. if ( !CryptCreateHash( g_hCryptProv,
  3335. CALG_MD5,
  3336. 0,
  3337. 0,
  3338. &hHash ) )
  3339. {
  3340. DebugLog((DEB_ERROR, "CalculateSASLHMAC: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  3341. Status = STATUS_ENCRYPTION_FAILED;
  3342. goto CleanUp;
  3343. }
  3344. if ( !CryptHashData( hHash,
  3345. (const unsigned char *)pContext->bSessionKey,
  3346. MD5_HASH_BYTESIZE,
  3347. 0 ) )
  3348. {
  3349. DebugLog((DEB_ERROR, "CalculateSASLHMAC: CryptHashData failed : 0x%lx\n", GetLastError()));
  3350. Status = STATUS_ENCRYPTION_FAILED;
  3351. goto CleanUp;
  3352. }
  3353. if (pstrSignKeyConst->Length)
  3354. {
  3355. if ( !CryptHashData( hHash,
  3356. (const unsigned char *)pstrSignKeyConst->Buffer,
  3357. pstrSignKeyConst->Length,
  3358. 0 ) )
  3359. {
  3360. DebugLog((DEB_ERROR, "CalculateSASLHMAC: CryptHashData failed : 0x%lx\n", GetLastError()));
  3361. Status = STATUS_ENCRYPTION_FAILED;
  3362. goto CleanUp;
  3363. }
  3364. }
  3365. cbKiHashData = MD5_HASH_BYTESIZE;
  3366. if ( !CryptGetHashParam( hHash,
  3367. HP_HASHVAL,
  3368. bKiHashData,
  3369. &cbKiHashData,
  3370. 0 ) )
  3371. {
  3372. DebugLog((DEB_ERROR, "CalculateSASLHMAC: CryptGetHashParam failed : 0x%lx\n", GetLastError()));
  3373. Status = STATUS_ENCRYPTION_FAILED;
  3374. goto CleanUp;
  3375. }
  3376. CryptDestroyHash( hHash );
  3377. hHash = NULL;
  3378. ASSERT(cbKiHashData == MD5_HASH_BYTESIZE);
  3379. // save the key for later sign/verify use
  3380. if (fSign == TRUE)
  3381. {
  3382. memcpy(pContext->bKiSignHashData, bKiHashData, MD5_HASH_BYTESIZE);
  3383. }
  3384. else
  3385. {
  3386. memcpy(pContext->bKiVerifyHashData, bKiHashData, MD5_HASH_BYTESIZE);
  3387. }
  3388. #if DBG
  3389. // Now convert the Hash to Hex - for TESTING ONLY
  3390. ZeroMemory(szTemp, TEMPSIZE);
  3391. BinToHex(bKiHashData, MD5_HASH_BYTESIZE, szTemp);
  3392. if (szTemp)
  3393. {
  3394. DebugLog((DEB_TRACE, "CalculateSASLHMAC: Calculated Ki hash is %s\n", szTemp));
  3395. }
  3396. #endif
  3397. }
  3398. else
  3399. {
  3400. // retrieve it from the saved context info
  3401. if (fSign == TRUE)
  3402. {
  3403. memcpy(bKiHashData, pContext->bKiSignHashData, MD5_HASH_BYTESIZE);
  3404. }
  3405. else
  3406. {
  3407. memcpy(bKiHashData, pContext->bKiVerifyHashData, MD5_HASH_BYTESIZE);
  3408. }
  3409. cbKiHashData = MD5_HASH_BYTESIZE;
  3410. #if DBG
  3411. // Now convert the Hash to Hex - for TESTING ONLY
  3412. ZeroMemory(szTemp, TEMPSIZE);
  3413. BinToHex(bKiHashData, MD5_HASH_BYTESIZE, szTemp);
  3414. if (szTemp)
  3415. {
  3416. DebugLog((DEB_TRACE, "CalculateSASLHMAC: Ki retrieved from context is %s\n", szTemp));
  3417. }
  3418. #endif
  3419. }
  3420. DebugLog((DEB_TRACE, "CalculateSASLHMAC: Ready to start the HMAC calculation\n"));
  3421. // We now have Kic or Kis depending on if we are running as server or client
  3422. // Now calculate the SASL_MAC_BLOCK structure to compare or set for message
  3423. pMacBlock->wMsgType = htons(1);
  3424. pMacBlock->dwSeqNumber = htonl(dwSeqNum);
  3425. DebugLog((DEB_TRACE, "CalculateSASLHMAC: SeqNumber is %ld\n", dwSeqNum));
  3426. // Need to create the symmetric key from the cleartext shared secret
  3427. // Specified CALC_RC4 since we need to provide a valid encrypt type for import key
  3428. // not actually utilized when we do the HMAC which is simply a hash function
  3429. Status = CreateSymmetricKey(CALG_RC4, MD5_HASH_BYTESIZE, bKiHashData, NULL, &hCryptKey);
  3430. if (!NT_SUCCESS (Status))
  3431. {
  3432. DebugLog((DEB_ERROR, "CalculateSASLHMAC: Error in CreateSymmetricKey Status 0x%x\n", Status));
  3433. goto CleanUp;
  3434. }
  3435. if ( !CryptCreateHash( g_hCryptProv,
  3436. CALG_HMAC,
  3437. hCryptKey,
  3438. 0,
  3439. &hHash ) )
  3440. {
  3441. DebugLog((DEB_ERROR, "CalculateSASLHMAC: HMAC CryptCreateHash failed : 0x%lx\n", GetLastError()));
  3442. Status = STATUS_ENCRYPTION_FAILED;
  3443. goto CleanUp;
  3444. }
  3445. hmacinfo.HashAlgid = CALG_MD5; // Use MD5 as the hashing function for the HMAC
  3446. hmacinfo.cbOuterString = 0; // use default 64 byte outerstring
  3447. hmacinfo.cbInnerString = 0; // use default 64 byte innerstring
  3448. if ( !CryptSetHashParam( hHash,
  3449. HP_HMAC_INFO,
  3450. (PBYTE)&hmacinfo,
  3451. 0 ) )
  3452. {
  3453. DebugLog((DEB_ERROR, "CalculateSASLHMAC: HMAC CryptSetHashParam failed : 0x%lx\n", GetLastError()));
  3454. Status = STATUS_ENCRYPTION_FAILED;
  3455. goto CleanUp;
  3456. }
  3457. // Prepend SeqNum to the data stream to perform HMAC on
  3458. // Need to form the network order version first
  3459. #if DBG
  3460. // Now convert the Hash to Hex - for TESTING ONLY
  3461. ZeroMemory(szTemp, TEMPSIZE);
  3462. BinToHex((PUCHAR)&pMacBlock->dwSeqNumber, sizeof(DWORD), szTemp);
  3463. if (szTemp)
  3464. {
  3465. DebugLog((DEB_TRACE, "CalculateSASLHMAC: HMAC component SeqNum %s\n", szTemp));
  3466. }
  3467. #endif
  3468. if ( !CryptHashData( hHash,
  3469. (const unsigned char *)&pMacBlock->dwSeqNumber,
  3470. sizeof(DWORD),
  3471. 0 ) )
  3472. {
  3473. DebugLog((DEB_ERROR, "CalculateSASLHMAC: HMAC CryptHashData failed : 0x%lx\n", GetLastError()));
  3474. Status = STATUS_ENCRYPTION_FAILED;
  3475. goto CleanUp;
  3476. }
  3477. // Now HMAC the data to protect
  3478. #if DBG
  3479. // Now convert the Hash to Hex - for TESTING ONLY
  3480. ZeroMemory(szTemp, TEMPSIZE);
  3481. if (cbData < iTempLen)
  3482. {
  3483. iTempLen = cbData;
  3484. }
  3485. BinToHex(pData, iTempLen, szTemp);
  3486. if (szTemp)
  3487. {
  3488. DebugLog((DEB_TRACE, "CalculateSASLHMAC: HMAC component Data (%dof%d bytes) %s\n",
  3489. iTempLen, cbData, szTemp));
  3490. }
  3491. #endif
  3492. if (cbData)
  3493. {
  3494. if ( !CryptHashData( hHash,
  3495. pData,
  3496. cbData,
  3497. 0 ) )
  3498. {
  3499. DebugLog((DEB_ERROR, "CalculateSASLHMAC: HMAC CryptHashData failed : 0x%lx\n", GetLastError()));
  3500. Status = STATUS_ENCRYPTION_FAILED;
  3501. goto CleanUp;
  3502. }
  3503. }
  3504. cbHMACData = HMAC_MD5_HASH_BYTESIZE;
  3505. if ( !CryptGetHashParam( hHash,
  3506. HP_HASHVAL,
  3507. bHMACData,
  3508. &cbHMACData,
  3509. 0 ) )
  3510. {
  3511. DebugLog((DEB_ERROR, "CalculateSASLHMAC: HMAC CryptGetHashParam failed : 0x%lx\n", GetLastError()));
  3512. Status = STATUS_ENCRYPTION_FAILED;
  3513. goto CleanUp;
  3514. }
  3515. DebugLog((DEB_TRACE, "CalculateSASLHMAC: HMAC hash length %d bytes\n", cbHMACData));
  3516. ASSERT(cbHMACData == HMAC_MD5_HASH_BYTESIZE);
  3517. CryptDestroyKey( hCryptKey );
  3518. hCryptKey = NULL;
  3519. CryptDestroyHash( hHash );
  3520. hHash = NULL;
  3521. // We now have the HMAC so form up the MAC block for SASL
  3522. // Now convert the Hash to Hex - for TESTING ONLY
  3523. if (cbHMACData != HMAC_MD5_HASH_BYTESIZE)
  3524. {
  3525. // This should never happen
  3526. DebugLog((DEB_ERROR, "CalculateSASLHMAC: HMAC-MD5 result length incorrect\n"));
  3527. Status = STATUS_ENCRYPTION_FAILED;
  3528. goto CleanUp;
  3529. }
  3530. #if DBG
  3531. ZeroMemory(szTemp, TEMPSIZE);
  3532. BinToHex(bHMACData, HMAC_MD5_HASH_BYTESIZE, szTemp);
  3533. DebugLog((DEB_TRACE, "CalculateSASLHMAC: HMAC-MD5 is %s\n", szTemp));
  3534. #endif
  3535. memcpy(pMacBlock->hmacMD5, bHMACData, SASL_MAC_HMAC_SIZE);
  3536. #if DBG
  3537. ZeroMemory(szTemp, TEMPSIZE);
  3538. BinToHex((PUCHAR)pMacBlock, HMAC_MD5_HASH_BYTESIZE, szTemp);
  3539. DebugLog((DEB_TRACE, "CalculateSASLHMAC: HMAC-MD5 block is %s\n", szTemp));
  3540. #endif
  3541. CleanUp:
  3542. // Release Key resources
  3543. if (hCryptKey)
  3544. {
  3545. CryptDestroyKey( hCryptKey );
  3546. hCryptKey = NULL;
  3547. }
  3548. // Release Hash resources
  3549. if (hHash)
  3550. {
  3551. CryptDestroyHash( hHash );
  3552. hHash = NULL;
  3553. }
  3554. DebugLog((DEB_TRACE_FUNC, "CalculateSASLHMAC: Leaving status 0x%x\n", Status));
  3555. return(Status);
  3556. }
  3557. NTSTATUS
  3558. SEC_ENTRY
  3559. CalculateKc(
  3560. IN PBYTE pbSessionKey,
  3561. IN USHORT cbHA1n,
  3562. IN PSTRING pstrSealKeyConst,
  3563. IN PBYTE pHashData) // MD5 hash for Kc
  3564. {
  3565. NTSTATUS Status = STATUS_SUCCESS;
  3566. HCRYPTHASH hHash = NULL;
  3567. DWORD cbKcHashData = 0; // Size of Message integrity keys
  3568. ASSERT(cbHA1n <= MD5_HASH_BYTESIZE);
  3569. ASSERT(cbHA1n > 0);
  3570. #if DBG
  3571. char szTemp[TEMPSIZE];
  3572. ZeroMemory(szTemp, TEMPSIZE);
  3573. BinToHex(pbSessionKey, MD5_HASH_BYTESIZE, szTemp);
  3574. DebugLog((DEB_TRACE_FUNC, "CalculateKc: Entering\n"));
  3575. DebugLog((DEB_TRACE_FUNC, "CalculateKc: Binary SessionKey %s\n", szTemp));
  3576. DebugLog((DEB_TRACE_FUNC, "CalculateKc: cbHA1n %d\n", cbHA1n));
  3577. DebugLog((DEB_TRACE_FUNC, "CalculateKc: SealKeyConst %Z\n", pstrSealKeyConst));
  3578. #endif
  3579. // Clear the output
  3580. ZeroMemory(pHashData, MD5_HASH_BYTESIZE);
  3581. // Kc = MD5( {H(A1)[0...cbHA1n], ConstantString}) take only the first cbHA1n bytes of H(A1)
  3582. if ( !CryptCreateHash( g_hCryptProv,
  3583. CALG_MD5,
  3584. 0,
  3585. 0,
  3586. &hHash ) )
  3587. {
  3588. DebugLog((DEB_ERROR, "CalculateKc: CryptCreateHash failed : 0x%lx\n", GetLastError()));
  3589. Status = STATUS_ENCRYPTION_FAILED;
  3590. goto CleanUp;
  3591. }
  3592. if ( !CryptHashData( hHash,
  3593. (const unsigned char *)pbSessionKey,
  3594. cbHA1n,
  3595. 0 ) )
  3596. {
  3597. DebugLog((DEB_ERROR, "CalculateKc: CryptHashData failed : 0x%lx\n", GetLastError()));
  3598. Status = STATUS_ENCRYPTION_FAILED;
  3599. goto CleanUp;
  3600. }
  3601. if (pstrSealKeyConst->Length)
  3602. {
  3603. if ( !CryptHashData( hHash,
  3604. (const unsigned char *)pstrSealKeyConst->Buffer,
  3605. pstrSealKeyConst->Length,
  3606. 0 ) )
  3607. {
  3608. DebugLog((DEB_ERROR, "CalculateKc: CryptHashData failed : 0x%lx\n", GetLastError()));
  3609. Status = STATUS_ENCRYPTION_FAILED;
  3610. goto CleanUp;
  3611. }
  3612. }
  3613. cbKcHashData = MD5_HASH_BYTESIZE;
  3614. if ( !CryptGetHashParam( hHash,
  3615. HP_HASHVAL,
  3616. pHashData,
  3617. &cbKcHashData,
  3618. 0 ) )
  3619. {
  3620. DebugLog((DEB_ERROR, "CalculateKc: CryptGetHashParam failed : 0x%lx\n", GetLastError()));
  3621. Status = STATUS_ENCRYPTION_FAILED;
  3622. goto CleanUp;
  3623. }
  3624. CryptDestroyHash( hHash );
  3625. hHash = NULL;
  3626. DebugLog((DEB_TRACE, "CalculateKc: readback hash with %d bytes\n", cbKcHashData));
  3627. #if DBG
  3628. // Now convert the Hash to Hex - for TESTING ONLY
  3629. ZeroMemory(szTemp, TEMPSIZE);
  3630. BinToHex(pHashData, MD5_HASH_BYTESIZE, szTemp);
  3631. if (szTemp)
  3632. {
  3633. DebugLog((DEB_TRACE, "CalculateKc: Kc hash is %s\n", szTemp));
  3634. }
  3635. #endif
  3636. CleanUp:
  3637. // Release Hash resources
  3638. if (hHash)
  3639. {
  3640. CryptDestroyHash( hHash );
  3641. hHash = NULL;
  3642. }
  3643. DebugLog((DEB_TRACE_FUNC, "CalculateKc: Leaving status 0x%x\n", Status));
  3644. return(Status);
  3645. }
  3646. BYTE DESParityTable[] = {0x00,0x01,0x01,0x02,0x01,0x02,0x02,0x03,
  3647. 0x01,0x02,0x02,0x03,0x02,0x03,0x03,0x04};
  3648. //
  3649. // set the parity on the DES key - ODD parity
  3650. // NOTE : must be called before deskey
  3651. // key must be cbKey number of bytes
  3652. // routine from RSA lib
  3653. //
  3654. void
  3655. SetDESParity(
  3656. PBYTE pbKey,
  3657. DWORD cbKey
  3658. )
  3659. {
  3660. DWORD i;
  3661. for (i=0;i<cbKey;i++)
  3662. {
  3663. if (!((DESParityTable[pbKey[i]>>4] + DESParityTable[pbKey[i]&0x0F]) % 2))
  3664. pbKey[i] = pbKey[i] ^ 0x01;
  3665. }
  3666. }
  3667. //+-------------------------------------------------------------------------
  3668. //
  3669. // Function: addDESParity
  3670. //
  3671. // Synopsis: This routine is called for DES plaintext keys to add in Odd parity bits
  3672. // Input of 7 bytes will be expanded to 8bytes with parity
  3673. // Input of 14 bytes will be expanded to 14 bytes
  3674. //
  3675. // Effects: no global effect.
  3676. //
  3677. // Arguments:
  3678. //
  3679. // IN pbSrckey -- buffer with key to expand
  3680. // IN cbKey -- size of input non-parity expanded key
  3681. // OUT pbOutputkey -- buffer with key to expand
  3682. //
  3683. // Requires: no global requirements
  3684. //
  3685. // Returns: STATUS_SUCCESS, or resource error
  3686. //
  3687. // Notes:
  3688. //
  3689. //
  3690. //--------------------------------------------------------------------------
  3691. NTSTATUS
  3692. AddDESParity(
  3693. IN PBYTE pbSrcKey,
  3694. IN DWORD cbSrcKey,
  3695. OUT PBYTE pbDstKey,
  3696. OUT PDWORD pcbDstKey
  3697. )
  3698. {
  3699. NTSTATUS Status = STATUS_SUCCESS;
  3700. BYTE bKiHashData[MD5_HASH_BYTESIZE]; // Message integrity keys RFC 2831 sec 2.3
  3701. ASSERT(pbSrcKey);
  3702. ASSERT(pbDstKey);
  3703. ASSERT(pcbDstKey);
  3704. ZeroMemory(pbDstKey, MD5_HASH_BYTESIZE);
  3705. if ((cbSrcKey != 7) && (cbSrcKey != 14))
  3706. {
  3707. DebugLog((DEB_ERROR, "AddDESParity: wrong input size buffer\n"));
  3708. Status = STATUS_INTERNAL_ERROR;
  3709. goto CleanUp;
  3710. }
  3711. pbDstKey[0] = pbSrcKey[0];
  3712. pbDstKey[1] = (pbSrcKey[1] >> 1) | ((pbSrcKey[0] & 0x01) << 7);
  3713. pbDstKey[2] = (pbSrcKey[2] >> 2) | ((pbSrcKey[1] & 0x03) << 6);
  3714. pbDstKey[3] = (pbSrcKey[3] >> 3) | ((pbSrcKey[2] & 0x07) << 5);
  3715. pbDstKey[4] = (pbSrcKey[4] >> 4) | ((pbSrcKey[3] & 0x0F) << 4);
  3716. pbDstKey[5] = (pbSrcKey[5] >> 5) | ((pbSrcKey[4] & 0x1F) << 3);
  3717. pbDstKey[6] = (pbSrcKey[6] >> 6) | ((pbSrcKey[5] & 0x3F) << 2);
  3718. pbDstKey[7] = (pbSrcKey[6] << 1);
  3719. SetDESParity(pbDstKey, 8);
  3720. *pcbDstKey = 8;
  3721. // Now check if need to expand the 14 bytes into the full 16 byte buffer
  3722. if (cbSrcKey == 14)
  3723. {
  3724. pbDstKey[0 + 8] = pbSrcKey[0 + 7];
  3725. pbDstKey[1 + 8] = (pbSrcKey[1 + 7] >> 1) | ((pbSrcKey[0 + 7] & 0x01) << 7);
  3726. pbDstKey[2 + 8] = (pbSrcKey[2 + 7] >> 2) | ((pbSrcKey[1 + 7] & 0x03) << 6);
  3727. pbDstKey[3 + 8] = (pbSrcKey[3 + 7] >> 3) | ((pbSrcKey[2 + 7] & 0x07) << 5);
  3728. pbDstKey[4 + 8] = (pbSrcKey[4 + 7] >> 4) | ((pbSrcKey[3 + 7] & 0x0F) << 4);
  3729. pbDstKey[5 + 8] = (pbSrcKey[5 + 7] >> 5) | ((pbSrcKey[4 + 7] & 0x1F) << 3);
  3730. pbDstKey[6 + 8] = (pbSrcKey[6 + 7] >> 6) | ((pbSrcKey[5 + 7] & 0x3F) << 2);
  3731. pbDstKey[7 + 8] = (pbSrcKey[6 + 7] << 1);
  3732. SetDESParity(pbDstKey + 8, 8);
  3733. *pcbDstKey = 16;
  3734. }
  3735. #if DBG
  3736. char szTemp[TEMPSIZE];
  3737. ZeroMemory(szTemp, TEMPSIZE);
  3738. BinToHex(pbSrcKey, (UINT)cbSrcKey, szTemp);
  3739. DebugLog((DEB_TRACE, "AddDESParity: Key no-parity : %s\n", szTemp));
  3740. ZeroMemory(szTemp, TEMPSIZE);
  3741. BinToHex(pbDstKey, (UINT)*pcbDstKey, szTemp);
  3742. DebugLog((DEB_TRACE, "AddDESParity: Key expanded with parity : %s\n", szTemp));
  3743. #endif
  3744. CleanUp:
  3745. return Status;
  3746. }