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.

311 lines
7.8 KiB

  1. /*++
  2. Copyright (c) 1987-1998 Microsoft Corporation
  3. Module Name:
  4. credderi.c
  5. Abstract:
  6. Interface to credential derivation facility.
  7. Author:
  8. Scott Field (sfield) 14-Jan-1998
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. --*/
  15. #include "msp.h"
  16. #include "nlp.h"
  17. #include <sha.h>
  18. #define HMAC_K_PADSIZE (64)
  19. //
  20. // Prototype for credential derivation routines.
  21. //
  22. VOID
  23. DeriveWithHMAC_SHA1(
  24. IN PBYTE pbKeyMaterial,
  25. IN DWORD cbKeyMaterial,
  26. IN PBYTE pbData,
  27. IN DWORD cbData,
  28. IN OUT BYTE rgbHMAC[A_SHA_DIGEST_LEN] // output buffer
  29. );
  30. NTSTATUS
  31. MspNtDeriveCredential(
  32. IN PLSA_CLIENT_REQUEST ClientRequest,
  33. IN PVOID ProtocolSubmitBuffer,
  34. IN PVOID ClientBufferBase,
  35. IN ULONG SubmitBufferSize,
  36. OUT PVOID *ProtocolReturnBuffer,
  37. OUT PULONG ReturnBufferSize,
  38. OUT PNTSTATUS ProtocolStatus
  39. )
  40. /*++
  41. Routine Description:
  42. This routine is the dispatch routine for LsaCallAuthenticationPackage()
  43. with a message type of MsV1_0DeriveCredential.
  44. Arguments:
  45. The arguments to this routine are identical to those of LsaApCallPackage.
  46. Only the special attributes of these parameters as they apply to
  47. this routine are mentioned here.
  48. Return Value:
  49. STATUS_SUCCESS - Indicates the service completed successfully.
  50. STATUS_QUOTA_EXCEEDED - This error indicates that the logon
  51. could not be completed because the client does not have
  52. sufficient quota to allocate the return buffer.
  53. --*/
  54. {
  55. NTSTATUS Status = STATUS_SUCCESS;
  56. PMSV1_0_DERIVECRED_REQUEST DeriveCredRequest;
  57. PMSV1_0_DERIVECRED_RESPONSE DeriveCredResponse;
  58. CLIENT_BUFFER_DESC ClientBufferDesc;
  59. PMSV1_0_PRIMARY_CREDENTIAL Credential = NULL;
  60. PBYTE pbOwf;
  61. ULONG cbOwf;
  62. NlpInitClientBuffer( &ClientBufferDesc, ClientRequest );
  63. *ProtocolStatus = STATUS_SUCCESS;
  64. UNREFERENCED_PARAMETER(ClientBufferBase);
  65. //
  66. // Ensure the specified Submit Buffer is of reasonable size and
  67. // relocate all of the pointers to be relative to the LSA allocated
  68. // buffer.
  69. //
  70. if ( SubmitBufferSize < sizeof(MSV1_0_DERIVECRED_REQUEST) ) {
  71. Status = STATUS_INVALID_PARAMETER;
  72. goto Cleanup;
  73. }
  74. DeriveCredRequest = (PMSV1_0_DERIVECRED_REQUEST) ProtocolSubmitBuffer;
  75. //
  76. // validate supported derive types.
  77. //
  78. if( DeriveCredRequest->DeriveCredType != MSV1_0_DERIVECRED_TYPE_SHA1 &&
  79. DeriveCredRequest->DeriveCredType != MSV1_0_DERIVECRED_TYPE_SHA1_V2 )
  80. {
  81. Status = STATUS_INVALID_PARAMETER;
  82. goto Cleanup;
  83. }
  84. //
  85. // caller must pass in mixing bits into submit buffer.
  86. //
  87. if( DeriveCredRequest->DeriveCredInfoLength == 0 ) {
  88. Status = STATUS_INVALID_PARAMETER;
  89. goto Cleanup;
  90. }
  91. //
  92. // Make sure the buffer fits in the supplied size
  93. //
  94. if ( (DeriveCredRequest->DeriveCredInfoLength + sizeof(MSV1_0_DERIVECRED_REQUEST))
  95. > SubmitBufferSize )
  96. {
  97. Status = STATUS_INVALID_PARAMETER;
  98. goto Cleanup;
  99. }
  100. //
  101. // Get the OWF password for this session.
  102. //
  103. Status = NlpGetPrimaryCredential( &DeriveCredRequest->LogonId, &Credential, NULL );
  104. if ( !NT_SUCCESS( Status ) ) {
  105. goto Cleanup;
  106. }
  107. //
  108. // Allocate a buffer to return to the caller.
  109. //
  110. *ReturnBufferSize = sizeof(MSV1_0_DERIVECRED_RESPONSE) +
  111. A_SHA_DIGEST_LEN;
  112. Status = NlpAllocateClientBuffer( &ClientBufferDesc,
  113. *ReturnBufferSize,
  114. *ReturnBufferSize );
  115. if ( !NT_SUCCESS( Status ) ) {
  116. goto Cleanup;
  117. }
  118. ZeroMemory( ClientBufferDesc.MsvBuffer, *ReturnBufferSize );
  119. DeriveCredResponse = (PMSV1_0_DERIVECRED_RESPONSE) ClientBufferDesc.MsvBuffer;
  120. //
  121. // Fill in the return buffer.
  122. //
  123. DeriveCredResponse->MessageType = MsV1_0DeriveCredential;
  124. DeriveCredResponse->DeriveCredInfoLength = A_SHA_DIGEST_LEN;
  125. pbOwf = NULL;
  126. cbOwf = 0;
  127. if( DeriveCredRequest->DeriveCredType == MSV1_0_DERIVECRED_TYPE_SHA1_V2 )
  128. {
  129. //
  130. // explicitly requested derivation based on ShaOwfPassword.
  131. //
  132. if( Credential->ShaPasswordPresent )
  133. {
  134. pbOwf = (PBYTE) &(Credential->ShaOwfPassword); // key material is SHA OWF
  135. cbOwf = sizeof( SHA_OWF_PASSWORD );
  136. }
  137. }
  138. else if( DeriveCredRequest->DeriveCredType == MSV1_0_DERIVECRED_TYPE_SHA1 )
  139. {
  140. //
  141. // explicitly requested derivation based on NtOwfPassword.
  142. //
  143. if( Credential->NtPasswordPresent )
  144. {
  145. pbOwf = (PBYTE) &(Credential->NtOwfPassword); // key material is NT OWF
  146. cbOwf = sizeof( NT_OWF_PASSWORD );
  147. }
  148. }
  149. if( pbOwf == NULL )
  150. {
  151. Status = STATUS_UNSUCCESSFUL;
  152. goto Cleanup;
  153. }
  154. //
  155. // derive credential from HMAC_SHA1 crypto primitive
  156. // (the only supported crypto primitive at the moment)
  157. //
  158. DeriveWithHMAC_SHA1(
  159. pbOwf,
  160. cbOwf,
  161. DeriveCredRequest->DeriveCredSubmitBuffer,
  162. DeriveCredRequest->DeriveCredInfoLength,
  163. DeriveCredResponse->DeriveCredReturnBuffer
  164. );
  165. //
  166. // Flush the buffer to the client's address space.
  167. //
  168. Status = NlpFlushClientBuffer( &ClientBufferDesc,
  169. ProtocolReturnBuffer );
  170. Cleanup:
  171. if ( Credential != NULL ) {
  172. ZeroMemory( Credential, sizeof(*Credential) );
  173. (*Lsa.FreeLsaHeap)( Credential );
  174. }
  175. if ( !NT_SUCCESS(Status)) {
  176. NlpFreeClientBuffer( &ClientBufferDesc );
  177. }
  178. return(Status);
  179. }
  180. VOID
  181. DeriveWithHMAC_SHA1(
  182. IN PBYTE pbKeyMaterial, // input key material
  183. IN DWORD cbKeyMaterial,
  184. IN PBYTE pbData, // input mixing data
  185. IN DWORD cbData,
  186. IN OUT BYTE rgbHMAC[A_SHA_DIGEST_LEN] // output buffer
  187. )
  188. {
  189. unsigned __int64 rgbKipad[ HMAC_K_PADSIZE/sizeof(unsigned __int64) ];
  190. unsigned __int64 rgbKopad[ HMAC_K_PADSIZE/sizeof(unsigned __int64) ];
  191. A_SHA_CTX sSHAHash;
  192. DWORD dwBlock;
  193. // truncate
  194. if( cbKeyMaterial > HMAC_K_PADSIZE )
  195. {
  196. cbKeyMaterial = HMAC_K_PADSIZE;
  197. }
  198. ZeroMemory(rgbKipad, sizeof(rgbKipad));
  199. ZeroMemory(rgbKopad, sizeof(rgbKopad));
  200. CopyMemory(rgbKipad, pbKeyMaterial, cbKeyMaterial);
  201. CopyMemory(rgbKopad, pbKeyMaterial, cbKeyMaterial);
  202. // Kipad, Kopad are padded sMacKey. Now XOR across...
  203. for( dwBlock = 0; dwBlock < (HMAC_K_PADSIZE/sizeof(unsigned __int64)) ; dwBlock++ )
  204. {
  205. rgbKipad[dwBlock] ^= 0x3636363636363636;
  206. rgbKopad[dwBlock] ^= 0x5C5C5C5C5C5C5C5C;
  207. }
  208. // prepend Kipad to data, Hash to get H1
  209. A_SHAInit(&sSHAHash);
  210. A_SHAUpdate(&sSHAHash, (PBYTE)rgbKipad, sizeof(rgbKipad));
  211. A_SHAUpdate(&sSHAHash, pbData, cbData);
  212. // Finish off the hash
  213. A_SHAFinal(&sSHAHash, rgbHMAC);
  214. // prepend Kopad to H1, hash to get HMAC
  215. // note: done in place to avoid buffer copies
  216. // final hash: output value into passed-in buffer
  217. A_SHAInit(&sSHAHash);
  218. A_SHAUpdate(&sSHAHash, (PBYTE)rgbKopad, sizeof(rgbKopad));
  219. A_SHAUpdate(&sSHAHash, rgbHMAC, A_SHA_DIGEST_LEN);
  220. A_SHAFinal(&sSHAHash, rgbHMAC);
  221. RtlSecureZeroMemory( rgbKipad, sizeof(rgbKipad) );
  222. RtlSecureZeroMemory( rgbKopad, sizeof(rgbKopad) );
  223. RtlSecureZeroMemory( &sSHAHash, sizeof(sSHAHash) );
  224. return;
  225. }