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.

620 lines
22 KiB

  1. #include "drmkPCH.h"
  2. #include "KList.h"
  3. #include "StreamMgr.h"
  4. #include "SBuffer.h"
  5. #include "CryptoHelpers.h"
  6. #include "HandleMgr.h"
  7. #include "KRMStubs.h"
  8. #include "encraption.h"
  9. //------------------------------------------------------------------------------
  10. //
  11. // These are not the actual keys. The encraption algorithm in encraption.h
  12. // is used to get clear keys.
  13. //
  14. static const BYTE DRMKpriv[20] = {
  15. 0xDC, 0xC4, 0x26, 0xB2, 0x4F, 0x11, 0x24, 0x8A,
  16. 0x51, 0xAC, 0x88, 0xF5, 0x47, 0x4B, 0xD5, 0x8C,
  17. 0x3C, 0x45, 0x29, 0xA1};
  18. static const BYTE DRMKCert[104] = {
  19. 0xD4, 0x3F, 0xC8, 0x44, 0xCD, 0x86, 0x41, 0xE9,
  20. 0x7C, 0x23, 0x36, 0xAD, 0xC3, 0x22, 0x4F, 0x27,
  21. 0xC6, 0x1B, 0x5B, 0x9C, 0x75, 0x2A, 0x86, 0x32,
  22. 0x7E, 0x37, 0x24, 0x8D, 0x2B, 0x51, 0xF6, 0x6A,
  23. 0x31, 0x69, 0xA3, 0x66, 0xA8, 0x30, 0xC9, 0x4A,
  24. 0x23, 0xCC, 0x30, 0xD8, 0x19, 0x19, 0x7B, 0x9A,
  25. 0xF6, 0x32, 0xB5, 0xD8, 0x4C, 0x37, 0x1A, 0x91,
  26. 0x13, 0x71, 0xF6, 0x63, 0x41, 0x1B, 0x1A, 0x06,
  27. 0x57, 0xEC, 0x7A, 0xF8, 0x47, 0x41, 0xEF, 0x5E,
  28. 0xB9, 0x02, 0xE9, 0xE9, 0xA1, 0x52, 0x34, 0xC4,
  29. 0xCD, 0x7F, 0xDE, 0xF6, 0x09, 0x27, 0xE8, 0xB6,
  30. 0x27, 0xF0, 0x93, 0xD8, 0xE2, 0x07, 0xD2, 0xD1,
  31. 0x64, 0x8B, 0xF6, 0xD7, 0x57, 0x2C, 0xB2, 0x37};
  32. //------------------------------------------------------------------------------
  33. const DWORD KrmVersionNumber=100;
  34. //------------------------------------------------------------------------------
  35. KRMStubs* TheKrmStubs=NULL;
  36. //------------------------------------------------------------------------------
  37. DRM_STATUS GetKernelDigest(
  38. BYTE *startAddress,
  39. ULONG len,
  40. DRMDIGEST *pDigest
  41. )
  42. {
  43. BYTE* seed = (BYTE*) "a3fs9F7012341234KS84Wd04j=c50asj4*4dlcj5-q8m;ldhgfddd";
  44. CBCKey key;
  45. CBCState state;
  46. CBC64Init(&key, &state, seed);
  47. CBC64Update(&key, &state, len/16*16, startAddress);
  48. pDigest->w1=CBC64Finalize(&key, &state, (UINT32*) &pDigest->w2);
  49. return DRM_OK;
  50. } // GetKernelDigest
  51. //------------------------------------------------------------------------------
  52. KRMStubs::KRMStubs(){
  53. ASSERT(TheKrmStubs==NULL);
  54. TheKrmStubs=this;
  55. return;
  56. };
  57. //------------------------------------------------------------------------------
  58. KRMStubs::~KRMStubs(){
  59. return;
  60. };
  61. //------------------------------------------------------------------------------
  62. // Main entry point for KRM IOCTL processing. KRMINIT1 and KRMINIT2 are
  63. // plaintext commands, after this, the command block and the reply
  64. // are digested and encrypted.
  65. NTSTATUS KRMStubs::processIoctl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp){
  66. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  67. DWORD comm;
  68. DWORD inSize=irpStack->Parameters.DeviceIoControl.InputBufferLength;
  69. DWORD outSize=irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  70. DWORD bufSize=inSize>outSize?inSize:outSize;
  71. if(!critMgr.isOK()){
  72. _DbgPrintF(DEBUGLVL_VERBOSE,("Out of memory"));
  73. return STATUS_INSUFFICIENT_RESOURCES;
  74. };
  75. _DbgPrintF(DEBUGLVL_VERBOSE,("inSize, outSize %d, %d\n", inSize, outSize));
  76. for(DWORD j=0;j<inSize;j++){
  77. _DbgPrintF(DEBUGLVL_VERBOSE,("%x ", (DWORD) *(((BYTE*) Irp->AssociatedIrp.SystemBuffer)+j)));
  78. };
  79. return processCommandBuffer((BYTE* ) Irp->AssociatedIrp.SystemBuffer, inSize, outSize, Irp);
  80. };
  81. //------------------------------------------------------------------------------
  82. NTSTATUS KRMStubs::processCommandBuffer(IN BYTE* InBuf, IN DWORD InLen, IN DWORD OutBufSize, IN OUT PIRP Irp){
  83. _DbgPrintF(DEBUGLVL_VERBOSE,("Process command buffer (command size= %d)", InLen));
  84. DWORD bufSize=InLen>OutBufSize?InLen:OutBufSize;
  85. //
  86. // We must have at least communication code + terminator input space.
  87. //
  88. if (bufSize < 2 * sizeof(DWORD)) {
  89. _DbgPrintF(DEBUGLVL_TERSE, ("Input buffer too small"));
  90. return STATUS_BUFFER_TOO_SMALL;
  91. }
  92. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  93. PFILE_OBJECT file=irpStack->FileObject;
  94. ConnectStruct* connection=TheHandleMgr->getConnection(file);
  95. if(connection==NULL) {
  96. _DbgPrintF(DEBUGLVL_TERSE, ("Connection does not exist %d\n", file));
  97. return STATUS_BAD_DESCRIPTOR_FORMAT;
  98. };
  99. bool secureStreamWillStart=false;
  100. if(connection->secureStreamStarted) {
  101. if (STATUS_SUCCESS != postReceive(InBuf, InLen, connection)) {
  102. _DbgPrintF(DEBUGLVL_TERSE, ("PostReceive error"));
  103. return STATUS_BAD_DESCRIPTOR_FORMAT;
  104. }
  105. }
  106. SBuffer s(InBuf, bufSize);
  107. DWORD comm;
  108. s >> comm;
  109. if (KRM_OK != s.getLastError()) {
  110. _DbgPrintF(DEBUGLVL_TERSE, ("Bad communication code"));
  111. return STATUS_BAD_DESCRIPTOR_FORMAT;
  112. }
  113. //
  114. // if secure communication is not established reject all requests except
  115. // the initialization calls.
  116. //
  117. if (!connection->secureStreamStarted &&
  118. (_KRMINIT1 != comm && _KRMINIT2 != comm)) {
  119. _DbgPrintF(DEBUGLVL_TERSE, ("Bad communication pattern"));
  120. return STATUS_BAD_DESCRIPTOR_FORMAT;
  121. }
  122. DRM_STATUS stat;
  123. switch(comm){
  124. case _GETKERNELDIGEST:
  125. {
  126. //
  127. // ISSUE: 04/05/2002 ALPERS.
  128. // Note that this handler is not 64 bit compatible. Just follows
  129. // the rest of the property handler.
  130. //
  131. DWORD startAddress, len;
  132. DRMDIGEST newDigest = { 0, 0 };
  133. s >> startAddress >> len;
  134. stat = s.getLastError();
  135. if (KRM_SUCCESS(stat)) {
  136. stat = checkTerm(s);
  137. }
  138. //
  139. // Make sure the output buffer can hold len bytes.
  140. //
  141. if (KRM_SUCCESS(stat)) {
  142. if (s.getLen() < sizeof(stat) + sizeof(newDigest) + sizeof(DWORD) + 64) {
  143. stat = KRM_BUFSIZE;
  144. _DbgPrintF(DEBUGLVL_TERSE, ("_GETKERNELDIGEST - invalid output buffer size"));
  145. }
  146. }
  147. if (KRM_SUCCESS(stat)) {
  148. //
  149. // ISSUE: 04/05/2002 ALPERS
  150. // (SECURITY NOTE: Potential DOS attack)
  151. // Note that startAddress and Len are coming from user mode
  152. // and there is no validation.
  153. // This IOCTL can only be send through the secure IOCTL
  154. // interface. In order to attack here, the attacker has to
  155. // figure out the secure IOCTL channel.
  156. // There is one level of defense.
  157. //
  158. // TODO: As a second line of defense, DRMK can collect the
  159. // same module information and compare the given address
  160. // to its list.
  161. //
  162. // The reason we get the KernelAddress from UserMode is
  163. // because of the relocation code in UserMode. The code reads
  164. // the driver image from disk, parses PE format and finds
  165. // the section that contains the provingFunction.
  166. // startAddress is the beginning of the section that
  167. // contains provingFunction.
  168. //
  169. stat = GetKernelDigest((BYTE *) ULongToPtr(startAddress), len, &newDigest);
  170. }
  171. s.reset();
  172. s << stat << newDigest.w1 << newDigest.w2;
  173. break;
  174. }
  175. //-----------------
  176. case _KRMINIT1:
  177. {
  178. // return the version number and the cert
  179. DWORD drmVersionNumber;
  180. CERT krmCert;
  181. s >> drmVersionNumber;
  182. stat = s.getLastError();
  183. if (KRM_SUCCESS(stat)) {
  184. stat = checkTerm(s);
  185. }
  186. if (KRM_SUCCESS(stat)) {
  187. _DbgPrintF(DEBUGLVL_VERBOSE,("Doing KRMINIT1, for DRM version %d", drmVersionNumber));
  188. NTSTATUS Status =
  189. ClearKey(DRMKCert, (BYTE *) &krmCert, sizeof(DRMKCert), 5);
  190. if (NT_SUCCESS(Status)) {
  191. s.reset();
  192. s << (DWORD) KRM_OK << KrmVersionNumber;
  193. s.append((BYTE*) &krmCert, sizeof(krmCert));
  194. stat = s.getLastError();
  195. }
  196. else {
  197. stat = KRM_SYSERR;
  198. }
  199. }
  200. if (!KRM_SUCCESS(stat)) {
  201. s.reset();
  202. s << stat;
  203. }
  204. break;
  205. };
  206. //-----------------
  207. case _KRMINIT2:
  208. {
  209. DWORD datLen;
  210. s >> datLen;
  211. stat = s.getLastError();
  212. if (KRM_SUCCESS(stat)) {
  213. DWORD bufLenShouldBe=PK_ENC_CIPHERTEXT_LEN;
  214. if (bufLenShouldBe == datLen) {
  215. unsigned int pos;
  216. stat = s.getGetPosAndAdvance(&pos, datLen);
  217. if (KRM_SUCCESS(stat)) {
  218. BYTE* cipherText=s.getBuf()+pos;
  219. stat=initStream(cipherText, connection);
  220. if (stat != DRM_OK) {
  221. _DbgPrintF(DEBUGLVL_TERSE, ("BAD InitString"));
  222. };
  223. }
  224. }
  225. else {
  226. _DbgPrintF(DEBUGLVL_TERSE, ("KRMINIT2 - bad string"));
  227. stat = KRM_SYSERR;
  228. };
  229. }
  230. if (KRM_SUCCESS(stat)) {
  231. stat = checkTerm(s);
  232. }
  233. s.reset();
  234. s << stat;
  235. if (KRM_SUCCESS(stat)) {
  236. secureStreamWillStart=true;
  237. }
  238. break;
  239. };
  240. //-----------------
  241. case _CREATESTREAM:
  242. {
  243. KCritical sect(critMgr);
  244. DWORD handle;
  245. DRMRIGHTS rights;
  246. STREAMKEY key;
  247. DWORD streamId = 0;
  248. s >> handle >> &rights >> &key;
  249. stat = s.getLastError();
  250. if (KRM_SUCCESS(stat)) {
  251. stat = checkTerm(s);
  252. }
  253. //
  254. // The input buffer is much bigger than output buffer.
  255. // Therefore we are sure that SBuffer has enough space
  256. // for the output buffer.
  257. //
  258. if (KRM_SUCCESS(stat)) {
  259. stat = TheStreamMgr->createStream(ULongToPtr(handle), &streamId, &rights, &key);
  260. }
  261. if (KRM_SUCCESS(stat)) {
  262. connection->streamId = streamId;
  263. }
  264. s.reset();
  265. s << stat << streamId;
  266. break;
  267. };
  268. //-----------------
  269. case _DESTROYSTREAM:
  270. {
  271. KCritical sect(critMgr);
  272. DWORD streamId;
  273. s >> streamId;
  274. stat = s.getLastError();
  275. if (KRM_SUCCESS(stat)) {
  276. stat = checkTerm(s);
  277. }
  278. if (KRM_SUCCESS(stat)) {
  279. stat = TheStreamMgr->destroyStream(streamId);
  280. }
  281. s.reset();
  282. s << stat;
  283. break;
  284. };
  285. //-----------------
  286. case _DESTROYSTREAMSBYHANDLE:
  287. {
  288. KCritical sect(critMgr);
  289. DWORD handle;
  290. s >> handle;
  291. stat = s.getLastError();
  292. if (KRM_SUCCESS(stat)) {
  293. stat = checkTerm(s);
  294. }
  295. if (KRM_SUCCESS(stat)) {
  296. stat = TheStreamMgr->destroyAllStreamsByHandle(ULongToHandle(handle));
  297. }
  298. s.reset();
  299. s << stat;
  300. break;
  301. };
  302. //-----------------
  303. case _WALKDRIVERS:
  304. {
  305. KCritical sect(critMgr);
  306. DWORD StreamId, MaxDrivers, len;
  307. s >> StreamId >> MaxDrivers;
  308. stat = s.getLastError();
  309. if (KRM_SUCCESS(stat)) {
  310. stat = checkTerm(s);
  311. }
  312. // check buffer size.
  313. if (KRM_SUCCESS(stat)) {
  314. len = sizeof(DWORD) * MaxDrivers;
  315. if ((s.getLen() < len + 64) || (len > len + 64)) {
  316. stat = KRM_BUFSIZE;
  317. _DbgPrintF(DEBUGLVL_TERSE,("_WALKDRIVERS : Invalid buffer size"));
  318. }
  319. }
  320. s.reset();
  321. //
  322. // Due to difficulties in maintaining security in the presence of Verifier
  323. // we return an error if Verifier is detected.
  324. //
  325. if (KRM_SUCCESS(stat)) {
  326. ULONG VerifierFlags;
  327. if (NT_SUCCESS(MmIsVerifierEnabled(&VerifierFlags))) {
  328. stat = DRM_VERIFIERENABLED;
  329. }
  330. }
  331. if (KRM_SUCCESS(stat)) {
  332. if (MaxDrivers==0) {
  333. // just check that the stream is good
  334. DWORD errorCode;
  335. stat = TheStreamMgr->getStreamErrorCode(StreamId, errorCode);
  336. if (KRM_SUCCESS(stat)) {
  337. stat = errorCode;
  338. }
  339. if (KRM_SUCCESS(stat)) {
  340. ULONG numDrivers;
  341. stat = TheStreamMgr->walkDrivers(StreamId, NULL, numDrivers, 0);
  342. if (KRM_SUCCESS(stat)) {
  343. stat=TheStreamMgr->getStreamErrorCode(StreamId, errorCode);
  344. if (KRM_SUCCESS(stat)) {
  345. stat = errorCode;
  346. }
  347. }
  348. }
  349. s << stat << (DWORD) 0;
  350. }
  351. else {
  352. // do a full authentication run
  353. PVOID* drivers = new PVOID[MaxDrivers];
  354. if (drivers!=NULL) {
  355. DWORD numDrivers = 0;
  356. stat = TheStreamMgr->walkDrivers(StreamId, drivers, numDrivers, MaxDrivers);
  357. s << stat << numDrivers;
  358. //
  359. // We checked the buffer size upfront. This should not
  360. // fail during stream operations.
  361. //
  362. if ((stat==DRM_OK) ||
  363. (stat==DRM_BADDRMLEVEL)) {
  364. // todo - perhaps a block copy
  365. for (DWORD j = 0; j < numDrivers; j++) {
  366. s << drivers[j];
  367. ASSERT(KRM_SUCCESS(s.getLastError()));
  368. };
  369. }
  370. delete[] drivers;
  371. }
  372. else {
  373. // allocation failed
  374. s << (DWORD) DRM_OUTOFMEMORY << (DWORD) 0;
  375. };
  376. };
  377. }
  378. else {
  379. s << stat << (DWORD) 0;
  380. }
  381. break;
  382. }
  383. //-----------------
  384. default:
  385. {
  386. s.reset();
  387. s << KRM_BADIOCTL;
  388. break;
  389. };
  390. };
  391. term(s);
  392. //
  393. // We are ignoring if we cannot put the terminator here.
  394. // KRMProxy does not care anyway.
  395. //
  396. if (connection->secureStreamStarted) {
  397. //
  398. // ignore the return value. In case of failure we will have crap
  399. // in SBuffer. And we will return it to user mode.
  400. //
  401. preSend(s, connection);
  402. }
  403. if (secureStreamWillStart) {
  404. connection->secureStreamStarted = true;
  405. }
  406. _DbgPrintF(DEBUGLVL_VERBOSE,("Returning %d bytes", s.getPutPos()));
  407. Irp->IoStatus.Information=s.getPutPos();
  408. return STATUS_SUCCESS;
  409. };
  410. //------------------------------------------------------------------------------
  411. NTSTATUS KRMStubs::initStream(BYTE* encText, ConnectStruct* Conn){
  412. PRIVKEY myPrivKey;
  413. NTSTATUS Status;
  414. Status = ClearKey(DRMKpriv, myPrivKey.x, sizeof(DRMKpriv), 2);
  415. if (NT_SUCCESS(Status)) {
  416. //
  417. // ISSUE: 04/24/2002 ALPERS
  418. // CDRMPKCrypto allocates memory in its constructor. If the memory
  419. // allocation fails, all functions in that object return error codes.
  420. // Yet we are not checking the error code from PKdecrypt.
  421. //
  422. CDRMPKCrypto decryptor;
  423. BYTE decryptedText[PK_ENC_PLAINTEXT_LEN];
  424. decryptor.PKdecrypt(&myPrivKey, encText, decryptedText);
  425. bv4_key_C(&Conn->serverKey, sizeof(decryptedText),decryptedText );
  426. CryptoHelpers::InitMac(Conn->serverCBCKey, Conn->serverCBCState, decryptedText, sizeof(decryptedText));
  427. }
  428. return Status;
  429. };
  430. //------------------------------------------------------------------------------
  431. NTSTATUS InitializeDriver(){
  432. NTSTATUS DriverInitializeStatus;
  433. _DbgPrintF(DEBUGLVL_VERBOSE,("Initializing Driver"));
  434. // Note - these dynamic allocations are 'global objects' that offer services to
  435. // the DRMK driver.
  436. // The services are referenced through the global pointers:
  437. // TheStreamManager, TheTGBuilder, TheKrmStubs, and TheHandleMgr
  438. void* temp=NULL;
  439. #pragma prefast(suppress:14, "There is really no leak here. The cleanup is CleanupDriver")
  440. temp=new StreamMgr;
  441. if (temp)
  442. {
  443. temp = new KRMStubs;
  444. }
  445. if (temp)
  446. {
  447. temp = new HandleMgr;
  448. }
  449. //
  450. // Make sure the internal states of the objects are OK.
  451. //
  452. if (temp)
  453. {
  454. if (!TheStreamMgr->getCritMgr().isOK() ||
  455. !TheKrmStubs->getCritMgr().isOK() ||
  456. !TheHandleMgr->getCritMgr().isOK())
  457. {
  458. _DbgPrintF(DEBUGLVL_TERSE, ("CritMgr allocation failed in DRMK:InitializeDriver"));
  459. temp = NULL;
  460. }
  461. }
  462. if (temp)
  463. {
  464. DriverInitializeStatus = STATUS_SUCCESS;
  465. }
  466. else
  467. {
  468. _DbgPrintF(DEBUGLVL_TERSE,("operator::new failed in DRMK:InitializeDriver"));
  469. DriverInitializeStatus = STATUS_INSUFFICIENT_RESOURCES;
  470. CleanupDriver();
  471. }
  472. return DriverInitializeStatus;
  473. };
  474. //------------------------------------------------------------------------------
  475. NTSTATUS CleanupDriver(){
  476. _DbgPrintF(DEBUGLVL_VERBOSE,("Cleaning up Driver"));
  477. delete TheStreamMgr;TheStreamMgr=NULL;
  478. delete TheKrmStubs;TheKrmStubs=NULL;
  479. delete TheHandleMgr;TheHandleMgr=NULL;
  480. return STATUS_SUCCESS;
  481. };
  482. //------------------------------------------------------------------------------
  483. NTSTATUS KRMStubs::InitializeConnection(PIRP Pirp){
  484. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Pirp);
  485. PFILE_OBJECT file=irpStack->FileObject;
  486. _DbgPrintF(DEBUGLVL_VERBOSE,("InititializeConnection %d", file));
  487. ConnectStruct* conn;
  488. bool ok=TheHandleMgr->newHandle(file, conn);
  489. if(!ok){
  490. _DbgPrintF(DEBUGLVL_VERBOSE,("Out of memory"));
  491. return STATUS_INSUFFICIENT_RESOURCES;
  492. };
  493. return STATUS_SUCCESS;
  494. };
  495. //------------------------------------------------------------------------------
  496. NTSTATUS KRMStubs::CleanupConnection(PIRP Pirp){
  497. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Pirp);
  498. PFILE_OBJECT file=irpStack->FileObject;
  499. _DbgPrintF(DEBUGLVL_VERBOSE,("CleanupConnection %x", file));
  500. ConnectStruct* conn=TheHandleMgr->getConnection(file);
  501. if(conn==NULL){
  502. _DbgPrintF(DEBUGLVL_VERBOSE,("Connection does not exist "));
  503. return STATUS_INVALID_PARAMETER_1;
  504. };
  505. TheStreamMgr->destroyStream(conn->streamId);
  506. TheHandleMgr->deleteHandle(file);
  507. return STATUS_SUCCESS;
  508. };
  509. //------------------------------------------------------------------------------
  510. // see twin function in KComm
  511. NTSTATUS KRMStubs::preSend(class SBuffer& Msg, ConnectStruct* Conn){
  512. // first digest
  513. DRMDIGEST digest;
  514. DRM_STATUS stat=CryptoHelpers::Mac(Conn->serverCBCKey, Msg.getBuf(), Msg.getPutPos(), digest);
  515. if(stat!=DRM_OK){
  516. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad MAC"));
  517. return STATUS_DRIVER_INTERNAL_ERROR;
  518. };
  519. Msg << &digest;
  520. stat = Msg.getLastError();
  521. if (KRM_OK == stat) {
  522. // then encrypt msg + digest
  523. stat=CryptoHelpers::Xcrypt(Conn->serverKey, Msg.getBuf(), Msg.getPutPos());
  524. if(stat!=DRM_OK){
  525. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad XCrypt"));
  526. return STATUS_DRIVER_INTERNAL_ERROR;
  527. };
  528. }
  529. return STATUS_SUCCESS;
  530. };
  531. //------------------------------------------------------------------------------
  532. // see twin function in KComm
  533. NTSTATUS KRMStubs::postReceive(BYTE* Data, DWORD DatLen, ConnectStruct* Conn){
  534. _DbgPrintF(DEBUGLVL_VERBOSE,("PostReceive on %d", DatLen));
  535. // decrypt
  536. DRM_STATUS stat=CryptoHelpers::Xcrypt(Conn->serverKey, Data, DatLen);
  537. if(stat!=DRM_OK){
  538. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad XCrypt(2)"));
  539. return STATUS_DRIVER_INTERNAL_ERROR;
  540. };
  541. // check digest
  542. DRMDIGEST digest;
  543. if (DatLen <= sizeof(DRMDIGEST)) return STATUS_INVALID_PARAMETER;
  544. stat=CryptoHelpers::Mac(Conn->serverCBCKey, Data, DatLen-sizeof(DRMDIGEST), digest);
  545. if(stat!=DRM_OK){
  546. _DbgPrintF(DEBUGLVL_VERBOSE,("Bad MAC(2)"));
  547. return STATUS_DRIVER_INTERNAL_ERROR;
  548. };
  549. DRMDIGEST* msgDigest=(DRMDIGEST*) (Data+DatLen-sizeof(DRMDIGEST));
  550. int match=memcmp(&digest, msgDigest, sizeof(DRMDIGEST));
  551. if(match==0)return STATUS_SUCCESS;
  552. memset(Data, 0, DatLen);
  553. _DbgPrintF(DEBUGLVL_VERBOSE,("MAC does not match(2)"));
  554. return STATUS_DRIVER_INTERNAL_ERROR;
  555. };
  556. //------------------------------------------------------------------------------