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

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