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
311 lines
7.8 KiB
/*++
|
|
|
|
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;
|
|
}
|