|
|
/*++
Copyright (c) 1987-1998 Microsoft Corporation
Module Name:
credderi.c
Abstract:
Interface to credential derivation facility.
Author:
Scott Field (sfield) 14-Jan-1998
Environment:
User mode only. Contains NT-specific code. Requires ANSI C extensions: slash-slash comments, long external names.
Revision History:
--*/
#include "msp.h"
#include "nlp.h"
#include <sha.h>
#define HMAC_K_PADSIZE (64)
//
// Prototype for credential derivation routines.
//
VOID DeriveWithHMAC_SHA1( IN PBYTE pbKeyMaterial, IN DWORD cbKeyMaterial, IN PBYTE pbData, IN DWORD cbData, IN OUT BYTE rgbHMAC[A_SHA_DIGEST_LEN] // output buffer
);
NTSTATUS MspNtDeriveCredential( IN PLSA_CLIENT_REQUEST ClientRequest, IN PVOID ProtocolSubmitBuffer, IN PVOID ClientBufferBase, IN ULONG SubmitBufferSize, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferSize, OUT PNTSTATUS ProtocolStatus )
/*++
Routine Description:
This routine is the dispatch routine for LsaCallAuthenticationPackage() with a message type of MsV1_0DeriveCredential.
Arguments:
The arguments to this routine are identical to those of LsaApCallPackage. Only the special attributes of these parameters as they apply to this routine are mentioned here.
Return Value:
STATUS_SUCCESS - Indicates the service completed successfully.
STATUS_QUOTA_EXCEEDED - This error indicates that the logon could not be completed because the client does not have sufficient quota to allocate the return buffer.
--*/
{ NTSTATUS Status = STATUS_SUCCESS; PMSV1_0_DERIVECRED_REQUEST DeriveCredRequest; PMSV1_0_DERIVECRED_RESPONSE DeriveCredResponse; CLIENT_BUFFER_DESC ClientBufferDesc;
PMSV1_0_PRIMARY_CREDENTIAL Credential = NULL;
PBYTE pbOwf; ULONG cbOwf;
NlpInitClientBuffer( &ClientBufferDesc, ClientRequest ); *ProtocolStatus = STATUS_SUCCESS;
UNREFERENCED_PARAMETER(ClientBufferBase);
//
// Ensure the specified Submit Buffer is of reasonable size and
// relocate all of the pointers to be relative to the LSA allocated
// buffer.
//
if ( SubmitBufferSize < sizeof(MSV1_0_DERIVECRED_REQUEST) ) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
DeriveCredRequest = (PMSV1_0_DERIVECRED_REQUEST) ProtocolSubmitBuffer;
//
// validate supported derive types.
//
if( DeriveCredRequest->DeriveCredType != MSV1_0_DERIVECRED_TYPE_SHA1 && DeriveCredRequest->DeriveCredType != MSV1_0_DERIVECRED_TYPE_SHA1_V2 ) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
//
// caller must pass in mixing bits into submit buffer.
//
if( DeriveCredRequest->DeriveCredInfoLength == 0 ) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
//
// Make sure the buffer fits in the supplied size
//
if ( (DeriveCredRequest->DeriveCredInfoLength + sizeof(MSV1_0_DERIVECRED_REQUEST)) > SubmitBufferSize ) { Status = STATUS_INVALID_PARAMETER; goto Cleanup; }
//
// Get the OWF password for this session.
//
Status = NlpGetPrimaryCredential( &DeriveCredRequest->LogonId, &Credential, NULL );
if ( !NT_SUCCESS( Status ) ) { goto Cleanup; }
//
// Allocate a buffer to return to the caller.
//
*ReturnBufferSize = sizeof(MSV1_0_DERIVECRED_RESPONSE) + A_SHA_DIGEST_LEN;
Status = NlpAllocateClientBuffer( &ClientBufferDesc, *ReturnBufferSize, *ReturnBufferSize );
if ( !NT_SUCCESS( Status ) ) { goto Cleanup; }
ZeroMemory( ClientBufferDesc.MsvBuffer, *ReturnBufferSize ); DeriveCredResponse = (PMSV1_0_DERIVECRED_RESPONSE) ClientBufferDesc.MsvBuffer;
//
// Fill in the return buffer.
//
DeriveCredResponse->MessageType = MsV1_0DeriveCredential; DeriveCredResponse->DeriveCredInfoLength = A_SHA_DIGEST_LEN;
pbOwf = NULL; cbOwf = 0;
if( DeriveCredRequest->DeriveCredType == MSV1_0_DERIVECRED_TYPE_SHA1_V2 ) { //
// explicitly requested derivation based on ShaOwfPassword.
//
if( Credential->ShaPasswordPresent ) { pbOwf = (PBYTE) &(Credential->ShaOwfPassword); // key material is SHA OWF
cbOwf = sizeof( SHA_OWF_PASSWORD ); } } else if( DeriveCredRequest->DeriveCredType == MSV1_0_DERIVECRED_TYPE_SHA1 ) { //
// explicitly requested derivation based on NtOwfPassword.
//
if( Credential->NtPasswordPresent ) { pbOwf = (PBYTE) &(Credential->NtOwfPassword); // key material is NT OWF
cbOwf = sizeof( NT_OWF_PASSWORD ); } }
if( pbOwf == NULL ) { Status = STATUS_UNSUCCESSFUL; goto Cleanup; }
//
// derive credential from HMAC_SHA1 crypto primitive
// (the only supported crypto primitive at the moment)
//
DeriveWithHMAC_SHA1( pbOwf, cbOwf, DeriveCredRequest->DeriveCredSubmitBuffer, DeriveCredRequest->DeriveCredInfoLength, DeriveCredResponse->DeriveCredReturnBuffer );
//
// Flush the buffer to the client's address space.
//
Status = NlpFlushClientBuffer( &ClientBufferDesc, ProtocolReturnBuffer );
Cleanup:
if ( Credential != NULL ) { ZeroMemory( Credential, sizeof(*Credential) ); (*Lsa.FreeLsaHeap)( Credential ); }
if ( !NT_SUCCESS(Status)) { NlpFreeClientBuffer( &ClientBufferDesc ); }
return(Status); }
VOID DeriveWithHMAC_SHA1( IN PBYTE pbKeyMaterial, // input key material
IN DWORD cbKeyMaterial, IN PBYTE pbData, // input mixing data
IN DWORD cbData, IN OUT BYTE rgbHMAC[A_SHA_DIGEST_LEN] // output buffer
) { unsigned __int64 rgbKipad[ HMAC_K_PADSIZE/sizeof(unsigned __int64) ]; unsigned __int64 rgbKopad[ HMAC_K_PADSIZE/sizeof(unsigned __int64) ]; A_SHA_CTX sSHAHash; DWORD dwBlock;
// truncate
if( cbKeyMaterial > HMAC_K_PADSIZE ) { cbKeyMaterial = HMAC_K_PADSIZE; }
ZeroMemory(rgbKipad, sizeof(rgbKipad)); ZeroMemory(rgbKopad, sizeof(rgbKopad));
CopyMemory(rgbKipad, pbKeyMaterial, cbKeyMaterial); CopyMemory(rgbKopad, pbKeyMaterial, cbKeyMaterial);
// Kipad, Kopad are padded sMacKey. Now XOR across...
for( dwBlock = 0; dwBlock < (HMAC_K_PADSIZE/sizeof(unsigned __int64)) ; dwBlock++ ) { rgbKipad[dwBlock] ^= 0x3636363636363636; rgbKopad[dwBlock] ^= 0x5C5C5C5C5C5C5C5C; }
// prepend Kipad to data, Hash to get H1
A_SHAInit(&sSHAHash); A_SHAUpdate(&sSHAHash, (PBYTE)rgbKipad, sizeof(rgbKipad)); A_SHAUpdate(&sSHAHash, pbData, cbData);
// Finish off the hash
A_SHAFinal(&sSHAHash, rgbHMAC);
// prepend Kopad to H1, hash to get HMAC
// note: done in place to avoid buffer copies
// final hash: output value into passed-in buffer
A_SHAInit(&sSHAHash); A_SHAUpdate(&sSHAHash, (PBYTE)rgbKopad, sizeof(rgbKopad)); A_SHAUpdate(&sSHAHash, rgbHMAC, A_SHA_DIGEST_LEN); A_SHAFinal(&sSHAHash, rgbHMAC);
RtlSecureZeroMemory( rgbKipad, sizeof(rgbKipad) ); RtlSecureZeroMemory( rgbKopad, sizeof(rgbKopad) ); RtlSecureZeroMemory( &sSHAHash, sizeof(sSHAHash) );
return; }
|