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.
620 lines
22 KiB
620 lines
22 KiB
#include "drmkPCH.h"
|
|
|
|
#include "KList.h"
|
|
#include "StreamMgr.h"
|
|
#include "SBuffer.h"
|
|
#include "CryptoHelpers.h"
|
|
#include "HandleMgr.h"
|
|
#include "KRMStubs.h"
|
|
#include "encraption.h"
|
|
|
|
//------------------------------------------------------------------------------
|
|
//
|
|
// These are not the actual keys. The encraption algorithm in encraption.h
|
|
// is used to get clear keys.
|
|
//
|
|
static const BYTE DRMKpriv[20] = {
|
|
0xDC, 0xC4, 0x26, 0xB2, 0x4F, 0x11, 0x24, 0x8A,
|
|
0x51, 0xAC, 0x88, 0xF5, 0x47, 0x4B, 0xD5, 0x8C,
|
|
0x3C, 0x45, 0x29, 0xA1};
|
|
static const BYTE DRMKCert[104] = {
|
|
0xD4, 0x3F, 0xC8, 0x44, 0xCD, 0x86, 0x41, 0xE9,
|
|
0x7C, 0x23, 0x36, 0xAD, 0xC3, 0x22, 0x4F, 0x27,
|
|
0xC6, 0x1B, 0x5B, 0x9C, 0x75, 0x2A, 0x86, 0x32,
|
|
0x7E, 0x37, 0x24, 0x8D, 0x2B, 0x51, 0xF6, 0x6A,
|
|
0x31, 0x69, 0xA3, 0x66, 0xA8, 0x30, 0xC9, 0x4A,
|
|
0x23, 0xCC, 0x30, 0xD8, 0x19, 0x19, 0x7B, 0x9A,
|
|
0xF6, 0x32, 0xB5, 0xD8, 0x4C, 0x37, 0x1A, 0x91,
|
|
0x13, 0x71, 0xF6, 0x63, 0x41, 0x1B, 0x1A, 0x06,
|
|
0x57, 0xEC, 0x7A, 0xF8, 0x47, 0x41, 0xEF, 0x5E,
|
|
0xB9, 0x02, 0xE9, 0xE9, 0xA1, 0x52, 0x34, 0xC4,
|
|
0xCD, 0x7F, 0xDE, 0xF6, 0x09, 0x27, 0xE8, 0xB6,
|
|
0x27, 0xF0, 0x93, 0xD8, 0xE2, 0x07, 0xD2, 0xD1,
|
|
0x64, 0x8B, 0xF6, 0xD7, 0x57, 0x2C, 0xB2, 0x37};
|
|
//------------------------------------------------------------------------------
|
|
const DWORD KrmVersionNumber=100;
|
|
//------------------------------------------------------------------------------
|
|
KRMStubs* TheKrmStubs=NULL;
|
|
//------------------------------------------------------------------------------
|
|
DRM_STATUS GetKernelDigest(
|
|
BYTE *startAddress,
|
|
ULONG len,
|
|
DRMDIGEST *pDigest
|
|
)
|
|
{
|
|
BYTE* seed = (BYTE*) "a3fs9F7012341234KS84Wd04j=c50asj4*4dlcj5-q8m;ldhgfddd";
|
|
CBCKey key;
|
|
CBCState state;
|
|
CBC64Init(&key, &state, seed);
|
|
CBC64Update(&key, &state, len/16*16, startAddress);
|
|
pDigest->w1=CBC64Finalize(&key, &state, (UINT32*) &pDigest->w2);
|
|
|
|
return DRM_OK;
|
|
} // GetKernelDigest
|
|
|
|
//------------------------------------------------------------------------------
|
|
KRMStubs::KRMStubs(){
|
|
ASSERT(TheKrmStubs==NULL);
|
|
TheKrmStubs=this;
|
|
return;
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
KRMStubs::~KRMStubs(){
|
|
return;
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
// Main entry point for KRM IOCTL processing. KRMINIT1 and KRMINIT2 are
|
|
// plaintext commands, after this, the command block and the reply
|
|
// are digested and encrypted.
|
|
NTSTATUS KRMStubs::processIoctl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){
|
|
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
DWORD comm;
|
|
DWORD inSize=irpStack->Parameters.DeviceIoControl.InputBufferLength;
|
|
DWORD outSize=irpStack->Parameters.DeviceIoControl.OutputBufferLength;
|
|
DWORD bufSize=inSize>outSize?inSize:outSize;
|
|
|
|
if(!critMgr.isOK()){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Out of memory"));
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
};
|
|
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("inSize, outSize %d, %d\n", inSize, outSize));
|
|
|
|
for(DWORD j=0;j<inSize;j++){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("%x ", (DWORD) *(((BYTE*) Irp->AssociatedIrp.SystemBuffer)+j)));
|
|
};
|
|
|
|
return processCommandBuffer((BYTE* ) Irp->AssociatedIrp.SystemBuffer, inSize, outSize, Irp);
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
NTSTATUS KRMStubs::processCommandBuffer(IN BYTE* InBuf, IN DWORD InLen, IN DWORD OutBufSize, IN OUT PIRP Irp){
|
|
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Process command buffer (command size= %d)", InLen));
|
|
|
|
DWORD bufSize=InLen>OutBufSize?InLen:OutBufSize;
|
|
|
|
//
|
|
// We must have at least communication code + terminator input space.
|
|
//
|
|
if (bufSize < 2 * sizeof(DWORD)) {
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("Input buffer too small"));
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
|
|
PFILE_OBJECT file=irpStack->FileObject;
|
|
ConnectStruct* connection=TheHandleMgr->getConnection(file);
|
|
if(connection==NULL) {
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("Connection does not exist %d\n", file));
|
|
return STATUS_BAD_DESCRIPTOR_FORMAT;
|
|
};
|
|
|
|
bool secureStreamWillStart=false;
|
|
|
|
if(connection->secureStreamStarted) {
|
|
if (STATUS_SUCCESS != postReceive(InBuf, InLen, connection)) {
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("PostReceive error"));
|
|
return STATUS_BAD_DESCRIPTOR_FORMAT;
|
|
}
|
|
}
|
|
|
|
SBuffer s(InBuf, bufSize);
|
|
DWORD comm;
|
|
s >> comm;
|
|
if (KRM_OK != s.getLastError()) {
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("Bad communication code"));
|
|
return STATUS_BAD_DESCRIPTOR_FORMAT;
|
|
}
|
|
|
|
//
|
|
// if secure communication is not established reject all requests except
|
|
// the initialization calls.
|
|
//
|
|
if (!connection->secureStreamStarted &&
|
|
(_KRMINIT1 != comm && _KRMINIT2 != comm)) {
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("Bad communication pattern"));
|
|
return STATUS_BAD_DESCRIPTOR_FORMAT;
|
|
}
|
|
|
|
DRM_STATUS stat;
|
|
switch(comm){
|
|
case _GETKERNELDIGEST:
|
|
{
|
|
//
|
|
// ISSUE: 04/05/2002 ALPERS.
|
|
// Note that this handler is not 64 bit compatible. Just follows
|
|
// the rest of the property handler.
|
|
//
|
|
DWORD startAddress, len;
|
|
DRMDIGEST newDigest = { 0, 0 };
|
|
|
|
s >> startAddress >> len;
|
|
stat = s.getLastError();
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = checkTerm(s);
|
|
}
|
|
|
|
//
|
|
// Make sure the output buffer can hold len bytes.
|
|
//
|
|
if (KRM_SUCCESS(stat)) {
|
|
if (s.getLen() < sizeof(stat) + sizeof(newDigest) + sizeof(DWORD) + 64) {
|
|
stat = KRM_BUFSIZE;
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("_GETKERNELDIGEST - invalid output buffer size"));
|
|
}
|
|
}
|
|
|
|
if (KRM_SUCCESS(stat)) {
|
|
//
|
|
// ISSUE: 04/05/2002 ALPERS
|
|
// (SECURITY NOTE: Potential DOS attack)
|
|
// Note that startAddress and Len are coming from user mode
|
|
// and there is no validation.
|
|
// This IOCTL can only be send through the secure IOCTL
|
|
// interface. In order to attack here, the attacker has to
|
|
// figure out the secure IOCTL channel.
|
|
// There is one level of defense.
|
|
//
|
|
// TODO: As a second line of defense, DRMK can collect the
|
|
// same module information and compare the given address
|
|
// to its list.
|
|
//
|
|
// The reason we get the KernelAddress from UserMode is
|
|
// because of the relocation code in UserMode. The code reads
|
|
// the driver image from disk, parses PE format and finds
|
|
// the section that contains the provingFunction.
|
|
// startAddress is the beginning of the section that
|
|
// contains provingFunction.
|
|
//
|
|
stat = GetKernelDigest((BYTE *) ULongToPtr(startAddress), len, &newDigest);
|
|
}
|
|
|
|
s.reset();
|
|
s << stat << newDigest.w1 << newDigest.w2;
|
|
|
|
break;
|
|
}
|
|
//-----------------
|
|
case _KRMINIT1:
|
|
{
|
|
// return the version number and the cert
|
|
DWORD drmVersionNumber;
|
|
CERT krmCert;
|
|
|
|
s >> drmVersionNumber;
|
|
stat = s.getLastError();
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = checkTerm(s);
|
|
}
|
|
|
|
if (KRM_SUCCESS(stat)) {
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Doing KRMINIT1, for DRM version %d", drmVersionNumber));
|
|
|
|
NTSTATUS Status =
|
|
ClearKey(DRMKCert, (BYTE *) &krmCert, sizeof(DRMKCert), 5);
|
|
if (NT_SUCCESS(Status)) {
|
|
s.reset();
|
|
s << (DWORD) KRM_OK << KrmVersionNumber;
|
|
s.append((BYTE*) &krmCert, sizeof(krmCert));
|
|
stat = s.getLastError();
|
|
}
|
|
else {
|
|
stat = KRM_SYSERR;
|
|
}
|
|
}
|
|
|
|
if (!KRM_SUCCESS(stat)) {
|
|
s.reset();
|
|
s << stat;
|
|
}
|
|
|
|
break;
|
|
};
|
|
//-----------------
|
|
case _KRMINIT2:
|
|
{
|
|
DWORD datLen;
|
|
s >> datLen;
|
|
stat = s.getLastError();
|
|
if (KRM_SUCCESS(stat)) {
|
|
DWORD bufLenShouldBe=PK_ENC_CIPHERTEXT_LEN;
|
|
if (bufLenShouldBe == datLen) {
|
|
unsigned int pos;
|
|
stat = s.getGetPosAndAdvance(&pos, datLen);
|
|
if (KRM_SUCCESS(stat)) {
|
|
BYTE* cipherText=s.getBuf()+pos;
|
|
stat=initStream(cipherText, connection);
|
|
if (stat != DRM_OK) {
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("BAD InitString"));
|
|
};
|
|
}
|
|
}
|
|
else {
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("KRMINIT2 - bad string"));
|
|
stat = KRM_SYSERR;
|
|
};
|
|
}
|
|
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = checkTerm(s);
|
|
}
|
|
|
|
s.reset();
|
|
s << stat;
|
|
|
|
if (KRM_SUCCESS(stat)) {
|
|
secureStreamWillStart=true;
|
|
}
|
|
|
|
break;
|
|
};
|
|
//-----------------
|
|
case _CREATESTREAM:
|
|
{
|
|
KCritical sect(critMgr);
|
|
DWORD handle;
|
|
DRMRIGHTS rights;
|
|
STREAMKEY key;
|
|
DWORD streamId = 0;
|
|
|
|
s >> handle >> &rights >> &key;
|
|
stat = s.getLastError();
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = checkTerm(s);
|
|
}
|
|
|
|
//
|
|
// The input buffer is much bigger than output buffer.
|
|
// Therefore we are sure that SBuffer has enough space
|
|
// for the output buffer.
|
|
//
|
|
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = TheStreamMgr->createStream(ULongToPtr(handle), &streamId, &rights, &key);
|
|
}
|
|
|
|
if (KRM_SUCCESS(stat)) {
|
|
connection->streamId = streamId;
|
|
}
|
|
|
|
s.reset();
|
|
s << stat << streamId;
|
|
|
|
break;
|
|
};
|
|
//-----------------
|
|
case _DESTROYSTREAM:
|
|
{
|
|
KCritical sect(critMgr);
|
|
DWORD streamId;
|
|
s >> streamId;
|
|
stat = s.getLastError();
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = checkTerm(s);
|
|
}
|
|
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = TheStreamMgr->destroyStream(streamId);
|
|
}
|
|
|
|
s.reset();
|
|
s << stat;
|
|
break;
|
|
};
|
|
//-----------------
|
|
case _DESTROYSTREAMSBYHANDLE:
|
|
{
|
|
KCritical sect(critMgr);
|
|
DWORD handle;
|
|
s >> handle;
|
|
stat = s.getLastError();
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = checkTerm(s);
|
|
}
|
|
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = TheStreamMgr->destroyAllStreamsByHandle(ULongToHandle(handle));
|
|
}
|
|
|
|
s.reset();
|
|
s << stat;
|
|
break;
|
|
};
|
|
//-----------------
|
|
case _WALKDRIVERS:
|
|
{
|
|
KCritical sect(critMgr);
|
|
DWORD StreamId, MaxDrivers, len;
|
|
s >> StreamId >> MaxDrivers;
|
|
stat = s.getLastError();
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = checkTerm(s);
|
|
}
|
|
|
|
// check buffer size.
|
|
if (KRM_SUCCESS(stat)) {
|
|
len = sizeof(DWORD) * MaxDrivers;
|
|
if ((s.getLen() < len + 64) || (len > len + 64)) {
|
|
stat = KRM_BUFSIZE;
|
|
_DbgPrintF(DEBUGLVL_TERSE,("_WALKDRIVERS : Invalid buffer size"));
|
|
}
|
|
}
|
|
|
|
s.reset();
|
|
//
|
|
// Due to difficulties in maintaining security in the presence of Verifier
|
|
// we return an error if Verifier is detected.
|
|
//
|
|
if (KRM_SUCCESS(stat)) {
|
|
ULONG VerifierFlags;
|
|
if (NT_SUCCESS(MmIsVerifierEnabled(&VerifierFlags))) {
|
|
stat = DRM_VERIFIERENABLED;
|
|
}
|
|
}
|
|
|
|
if (KRM_SUCCESS(stat)) {
|
|
if (MaxDrivers==0) {
|
|
// just check that the stream is good
|
|
DWORD errorCode;
|
|
|
|
stat = TheStreamMgr->getStreamErrorCode(StreamId, errorCode);
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = errorCode;
|
|
}
|
|
|
|
if (KRM_SUCCESS(stat)) {
|
|
ULONG numDrivers;
|
|
stat = TheStreamMgr->walkDrivers(StreamId, NULL, numDrivers, 0);
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat=TheStreamMgr->getStreamErrorCode(StreamId, errorCode);
|
|
if (KRM_SUCCESS(stat)) {
|
|
stat = errorCode;
|
|
}
|
|
}
|
|
}
|
|
|
|
s << stat << (DWORD) 0;
|
|
}
|
|
else {
|
|
// do a full authentication run
|
|
PVOID* drivers = new PVOID[MaxDrivers];
|
|
if (drivers!=NULL) {
|
|
DWORD numDrivers = 0;
|
|
stat = TheStreamMgr->walkDrivers(StreamId, drivers, numDrivers, MaxDrivers);
|
|
|
|
s << stat << numDrivers;
|
|
|
|
//
|
|
// We checked the buffer size upfront. This should not
|
|
// fail during stream operations.
|
|
//
|
|
if ((stat==DRM_OK) ||
|
|
(stat==DRM_BADDRMLEVEL)) {
|
|
// todo - perhaps a block copy
|
|
for (DWORD j = 0; j < numDrivers; j++) {
|
|
s << drivers[j];
|
|
ASSERT(KRM_SUCCESS(s.getLastError()));
|
|
};
|
|
}
|
|
|
|
delete[] drivers;
|
|
}
|
|
else {
|
|
// allocation failed
|
|
s << (DWORD) DRM_OUTOFMEMORY << (DWORD) 0;
|
|
};
|
|
};
|
|
}
|
|
else {
|
|
s << stat << (DWORD) 0;
|
|
}
|
|
break;
|
|
}
|
|
//-----------------
|
|
default:
|
|
{
|
|
s.reset();
|
|
s << KRM_BADIOCTL;
|
|
break;
|
|
};
|
|
};
|
|
|
|
term(s);
|
|
//
|
|
// We are ignoring if we cannot put the terminator here.
|
|
// KRMProxy does not care anyway.
|
|
//
|
|
|
|
if (connection->secureStreamStarted) {
|
|
//
|
|
// ignore the return value. In case of failure we will have crap
|
|
// in SBuffer. And we will return it to user mode.
|
|
//
|
|
preSend(s, connection);
|
|
}
|
|
if (secureStreamWillStart) {
|
|
connection->secureStreamStarted = true;
|
|
}
|
|
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Returning %d bytes", s.getPutPos()));
|
|
Irp->IoStatus.Information=s.getPutPos();
|
|
|
|
return STATUS_SUCCESS;
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
NTSTATUS KRMStubs::initStream(BYTE* encText, ConnectStruct* Conn){
|
|
PRIVKEY myPrivKey;
|
|
NTSTATUS Status;
|
|
|
|
Status = ClearKey(DRMKpriv, myPrivKey.x, sizeof(DRMKpriv), 2);
|
|
if (NT_SUCCESS(Status)) {
|
|
//
|
|
// ISSUE: 04/24/2002 ALPERS
|
|
// CDRMPKCrypto allocates memory in its constructor. If the memory
|
|
// allocation fails, all functions in that object return error codes.
|
|
// Yet we are not checking the error code from PKdecrypt.
|
|
//
|
|
CDRMPKCrypto decryptor;
|
|
BYTE decryptedText[PK_ENC_PLAINTEXT_LEN];
|
|
decryptor.PKdecrypt(&myPrivKey, encText, decryptedText);
|
|
bv4_key_C(&Conn->serverKey, sizeof(decryptedText),decryptedText );
|
|
CryptoHelpers::InitMac(Conn->serverCBCKey, Conn->serverCBCState, decryptedText, sizeof(decryptedText));
|
|
}
|
|
|
|
return Status;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
NTSTATUS InitializeDriver(){
|
|
NTSTATUS DriverInitializeStatus;
|
|
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Initializing Driver"));
|
|
|
|
// Note - these dynamic allocations are 'global objects' that offer services to
|
|
// the DRMK driver.
|
|
// The services are referenced through the global pointers:
|
|
// TheStreamManager, TheTGBuilder, TheKrmStubs, and TheHandleMgr
|
|
void* temp=NULL;
|
|
#pragma prefast(suppress:14, "There is really no leak here. The cleanup is CleanupDriver")
|
|
temp=new StreamMgr;
|
|
if (temp)
|
|
{
|
|
temp = new KRMStubs;
|
|
}
|
|
if (temp)
|
|
{
|
|
temp = new HandleMgr;
|
|
}
|
|
|
|
//
|
|
// Make sure the internal states of the objects are OK.
|
|
//
|
|
if (temp)
|
|
{
|
|
if (!TheStreamMgr->getCritMgr().isOK() ||
|
|
!TheKrmStubs->getCritMgr().isOK() ||
|
|
!TheHandleMgr->getCritMgr().isOK())
|
|
{
|
|
_DbgPrintF(DEBUGLVL_TERSE, ("CritMgr allocation failed in DRMK:InitializeDriver"));
|
|
temp = NULL;
|
|
}
|
|
}
|
|
|
|
if (temp)
|
|
{
|
|
DriverInitializeStatus = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
_DbgPrintF(DEBUGLVL_TERSE,("operator::new failed in DRMK:InitializeDriver"));
|
|
DriverInitializeStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
CleanupDriver();
|
|
}
|
|
|
|
return DriverInitializeStatus;
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
NTSTATUS CleanupDriver(){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Cleaning up Driver"));
|
|
delete TheStreamMgr;TheStreamMgr=NULL;
|
|
delete TheKrmStubs;TheKrmStubs=NULL;
|
|
delete TheHandleMgr;TheHandleMgr=NULL;
|
|
return STATUS_SUCCESS;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
NTSTATUS KRMStubs::InitializeConnection(PIRP Pirp){
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Pirp);
|
|
PFILE_OBJECT file=irpStack->FileObject;
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("InititializeConnection %d", file));
|
|
ConnectStruct* conn;
|
|
bool ok=TheHandleMgr->newHandle(file, conn);
|
|
if(!ok){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Out of memory"));
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
};
|
|
return STATUS_SUCCESS;
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
NTSTATUS KRMStubs::CleanupConnection(PIRP Pirp){
|
|
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Pirp);
|
|
PFILE_OBJECT file=irpStack->FileObject;
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("CleanupConnection %x", file));
|
|
ConnectStruct* conn=TheHandleMgr->getConnection(file);
|
|
if(conn==NULL){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Connection does not exist "));
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
};
|
|
TheStreamMgr->destroyStream(conn->streamId);
|
|
TheHandleMgr->deleteHandle(file);
|
|
return STATUS_SUCCESS;
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
// see twin function in KComm
|
|
NTSTATUS KRMStubs::preSend(class SBuffer& Msg, ConnectStruct* Conn){
|
|
// first digest
|
|
DRMDIGEST digest;
|
|
DRM_STATUS stat=CryptoHelpers::Mac(Conn->serverCBCKey, Msg.getBuf(), Msg.getPutPos(), digest);
|
|
if(stat!=DRM_OK){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Bad MAC"));
|
|
return STATUS_DRIVER_INTERNAL_ERROR;
|
|
};
|
|
Msg << &digest;
|
|
stat = Msg.getLastError();
|
|
if (KRM_OK == stat) {
|
|
// then encrypt msg + digest
|
|
stat=CryptoHelpers::Xcrypt(Conn->serverKey, Msg.getBuf(), Msg.getPutPos());
|
|
if(stat!=DRM_OK){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Bad XCrypt"));
|
|
return STATUS_DRIVER_INTERNAL_ERROR;
|
|
};
|
|
}
|
|
return STATUS_SUCCESS;
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
// see twin function in KComm
|
|
NTSTATUS KRMStubs::postReceive(BYTE* Data, DWORD DatLen, ConnectStruct* Conn){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("PostReceive on %d", DatLen));
|
|
// decrypt
|
|
DRM_STATUS stat=CryptoHelpers::Xcrypt(Conn->serverKey, Data, DatLen);
|
|
if(stat!=DRM_OK){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Bad XCrypt(2)"));
|
|
return STATUS_DRIVER_INTERNAL_ERROR;
|
|
};
|
|
// check digest
|
|
DRMDIGEST digest;
|
|
if (DatLen <= sizeof(DRMDIGEST)) return STATUS_INVALID_PARAMETER;
|
|
stat=CryptoHelpers::Mac(Conn->serverCBCKey, Data, DatLen-sizeof(DRMDIGEST), digest);
|
|
if(stat!=DRM_OK){
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("Bad MAC(2)"));
|
|
return STATUS_DRIVER_INTERNAL_ERROR;
|
|
};
|
|
DRMDIGEST* msgDigest=(DRMDIGEST*) (Data+DatLen-sizeof(DRMDIGEST));
|
|
int match=memcmp(&digest, msgDigest, sizeof(DRMDIGEST));
|
|
if(match==0)return STATUS_SUCCESS;
|
|
memset(Data, 0, DatLen);
|
|
_DbgPrintF(DEBUGLVL_VERBOSE,("MAC does not match(2)"));
|
|
return STATUS_DRIVER_INTERNAL_ERROR;
|
|
};
|
|
//------------------------------------------------------------------------------
|