1 /*-- 2 3 Copyright (C) Microsoft Corporation. All rights reserved. 4 5 Module Name: 6 7 aacs.c 8 9 Abstract: 10 11 The CDROM class driver implementation of handling AACS IOCTLs. 12 13 Environment: 14 15 kernel mode only 16 17 Notes: 18 19 20 Revision History: 21 22 --*/ 23 24 #include "stddef.h" 25 #include "string.h" 26 27 #include "ntddk.h" 28 #include "ntddstor.h" 29 #include "cdrom.h" 30 #include "ioctl.h" 31 #include "scratch.h" 32 33 #ifdef DEBUG_USE_WPP 34 #include "aacs.tmh" 35 #endif 36 37 #ifdef ALLOC_PRAGMA 38 39 #pragma alloc_text(PAGE, DeviceHandleAacsReadMediaKeyBlock) 40 #pragma alloc_text(PAGE, DeviceHandleAacsStartSession) 41 #pragma alloc_text(PAGE, DeviceHandleAacsEndSession) 42 #pragma alloc_text(PAGE, DeviceHandleAacsSendCertificate) 43 #pragma alloc_text(PAGE, DeviceHandleAacsGetCertificate) 44 #pragma alloc_text(PAGE, DeviceHandleAacsGetChallengeKey) 45 #pragma alloc_text(PAGE, DeviceHandleAacsReadSerialNumber) 46 #pragma alloc_text(PAGE, DeviceHandleAacsReadMediaId) 47 #pragma alloc_text(PAGE, DeviceHandleAacsReadBindingNonce) 48 #pragma alloc_text(PAGE, DeviceHandleAacsGenerateBindingNonce) 49 #pragma alloc_text(PAGE, DeviceHandleReadVolumeId) 50 #pragma alloc_text(PAGE, DeviceHandleSendChallengeKey) 51 52 #endif 53 54 _IRQL_requires_max_(APC_LEVEL) 55 NTSTATUS 56 DeviceHandleAacsReadMediaKeyBlock( 57 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 58 _In_ WDFREQUEST Request, 59 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 60 _Out_ size_t * DataLength 61 ) 62 /*++ 63 64 Routine Description: 65 This routine is used to process IOCTLs: 66 IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE 67 IOCTL_AACS_READ_MEDIA_KEY_BLOCK 68 Arguments: 69 DeviceExtension - device context 70 71 Request - the request that will be formatted 72 73 RequestParameters - request parameter structur 74 75 DataLength - data transferred length 76 77 Return Value: 78 NTSTATUS 79 80 --*/ 81 { 82 NTSTATUS status = STATUS_SUCCESS; 83 PAACS_LAYER_NUMBER layerNumber = NULL; 84 PVOID outputBuffer = NULL; 85 ULONG transferSize = sizeof(READ_DVD_STRUCTURES_HEADER); 86 87 PAGED_CODE(); 88 89 *DataLength = 0; 90 91 status = WdfRequestRetrieveInputBuffer(Request, 92 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 93 (PVOID*)&layerNumber, 94 NULL); 95 96 if (NT_SUCCESS(status)) 97 { 98 status = WdfRequestRetrieveOutputBuffer(Request, 99 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 100 (PVOID*)&outputBuffer, 101 NULL); 102 } 103 104 if (NT_SUCCESS(status)) 105 { 106 if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK) 107 { 108 // maximum size for this transfer is one pack + header 109 transferSize += AACS_MKB_PACK_SIZE; 110 } 111 112 if (transferSize > DeviceExtension->ScratchContext.ScratchBufferSize) 113 { 114 // rare case. normally the size of scratch buffer is 64k. 115 status = STATUS_INTERNAL_ERROR; 116 } 117 } 118 119 if (NT_SUCCESS(status)) 120 { 121 UCHAR rmdBlockNumber = 0; 122 BOOLEAN sendChangedCommand = TRUE; 123 BOOLEAN shouldRetry = TRUE; 124 CDB cdb; 125 126 ScratchBuffer_BeginUse(DeviceExtension); 127 128 RtlZeroMemory(&cdb, sizeof(CDB)); 129 // Set up the CDB 130 cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE; 131 // cdb->AsByte[1] = 0x01; // AACS sub-command not required for this 132 133 cdb.READ_DVD_STRUCTURE.LayerNumber = (UCHAR)(*layerNumber); 134 cdb.READ_DVD_STRUCTURE.Format = 0x83; // MKB 135 cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(transferSize >> (8*1)); 136 cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(transferSize >> (8*0)); 137 138 while (sendChangedCommand) 139 { 140 // RMDBlockNumber is set to zero.... 141 // RMDBlockNumber[3] maybe changed for other blocks. 142 cdb.READ_DVD_STRUCTURE.RMDBlockNumber[3] = rmdBlockNumber; 143 144 if (shouldRetry) 145 { 146 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, TRUE, &cdb, 12); 147 } 148 149 #ifdef ENABLE_AACS_TESTING 150 if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE) 151 { 152 static const UCHAR results[] = { 0x80, 0x02, 0x00, 0x02 }; 153 RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); 154 status = STATUS_SUCCESS; 155 } 156 else if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK) 157 { 158 static const UCHAR results[] = { 0x80, 0x02, 0x00, 0x02 }; 159 static const UCHAR defaultFill = 0x30; // '0' 160 RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x8004, defaultFill); 161 RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); 162 status = STATUS_SUCCESS; 163 } 164 #endif //ENABLE_AACS_TESTING 165 166 if (NT_SUCCESS(status)) 167 { 168 // command succeeded, process data... 169 PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; 170 UCHAR thisPackNumber = cdb.READ_DVD_STRUCTURE.RMDBlockNumber[3]; 171 UCHAR otherPacks = header->Reserved[1]; 172 173 // validate and zero-base the otherPacks 174 if (otherPacks == 0) 175 { 176 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT, 177 "AACS: Device is reporting zero total packs (invalid)\n")); 178 *DataLength = 0; 179 status = STATUS_IO_DEVICE_ERROR; 180 } 181 else 182 { 183 otherPacks--; 184 185 if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE) 186 { 187 // if not already requested last pack, do so now 188 if (otherPacks != thisPackNumber) 189 { 190 // re-send the command for the other pack number. 191 // this is safe here because NT_SUCCESS() is TRUE, 192 // and all the rest of this routine does is SetHardError() 193 // and release of resources we're still about to use. 194 195 // re-zero the output buffer 196 RtlZeroMemory(DeviceExtension->ScratchContext.ScratchBuffer, sizeof(READ_DVD_STRUCTURES_HEADER)); 197 198 // modify the CDB to get the very last pack of the MKB 199 rmdBlockNumber = otherPacks; 200 201 transferSize = sizeof(READ_DVD_STRUCTURES_HEADER); 202 203 // keep items clean 204 ScratchBuffer_ResetItems(DeviceExtension, TRUE); 205 206 // make sure the loop will be executed for modified command. 207 sendChangedCommand = TRUE; 208 shouldRetry = TRUE; 209 } 210 else 211 { 212 // this request already got the last pack 213 // so just interpret the data 214 REVERSE_SHORT(&header->Length); 215 if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) 216 { 217 *DataLength = 0; 218 status = STATUS_IO_DEVICE_ERROR; 219 } 220 else 221 { 222 ULONG totalSize = header->Length; 223 // subtract out any remaining bytes in the header 224 // to get the number of usable bytes in this pack 225 totalSize -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); 226 totalSize += otherPacks * AACS_MKB_PACK_SIZE; 227 228 // save the result and complete the request 229 *((PULONG)outputBuffer) = totalSize; 230 *DataLength = sizeof(ULONG); 231 status = STATUS_SUCCESS; 232 } 233 // This will exit the loop of sendChangedCommand 234 sendChangedCommand = FALSE; 235 shouldRetry = FALSE; 236 } 237 } 238 else if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK) 239 { 240 // make length field native byte ordering 241 REVERSE_SHORT(&header->Length); 242 243 // exit if getting invalid data from the drive 244 if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) 245 { 246 *DataLength = 0; 247 status = STATUS_IO_DEVICE_ERROR; 248 } 249 else 250 { 251 // success, how many bytes to copy for this pack? 252 ULONG totalSize = header->Length; 253 size_t originalBufferSize; 254 255 // subtract out any remaining bytes in the header 256 // to get the number of usable bytes in this pack 257 totalSize -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); 258 259 // if not the final pack, this should be a full transfer per spec 260 NT_ASSERT( (totalSize == AACS_MKB_PACK_SIZE) || (thisPackNumber == otherPacks) ); 261 262 // validate the user's buffer is large enough to accept the full data 263 originalBufferSize = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength; 264 265 if (originalBufferSize < (totalSize + (AACS_MKB_PACK_SIZE*thisPackNumber))) 266 { 267 // just return a slightly bigger-than-normal size 268 *DataLength = (otherPacks + 1)*AACS_MKB_PACK_SIZE; 269 status = STATUS_BUFFER_TOO_SMALL; 270 } 271 else 272 { 273 PUCHAR whereToCopy; 274 // determine where to copy to the user's memory 275 whereToCopy = outputBuffer; 276 whereToCopy += AACS_MKB_PACK_SIZE * thisPackNumber; 277 278 RtlCopyMemory(whereToCopy, header->Data, totalSize); 279 280 // update the Information field here because we already 281 // have calculated the size of the block 282 *DataLength = totalSize + (AACS_MKB_PACK_SIZE * thisPackNumber); 283 status = STATUS_SUCCESS; 284 285 // if there are more packs to get from the device, send it again.... 286 if (thisPackNumber != otherPacks) 287 { 288 // re-send the command for the next pack number. 289 // this is safe here because NT_SUCCESS() is TRUE, 290 // and all the rest of this routine does is SetHardError() 291 // and release of resources we're still about to use. 292 293 // re-zero the output buffer 294 RtlZeroMemory(DeviceExtension->ScratchContext.ScratchBuffer, sizeof(READ_DVD_STRUCTURES_HEADER)); 295 296 // modify the CDB to get the next pack of the MKB 297 rmdBlockNumber = cdb.READ_DVD_STRUCTURE.RMDBlockNumber[3]++; 298 299 // modify the SRB to be resent 300 // 301 transferSize = AACS_MKB_PACK_SIZE + sizeof(READ_DVD_STRUCTURES_HEADER); 302 303 // keep items clean 304 ScratchBuffer_ResetItems(DeviceExtension, FALSE); 305 306 // make sure the loop will be executed for modified command. 307 sendChangedCommand = TRUE; 308 shouldRetry = TRUE; 309 } 310 else 311 { 312 // else, that was the end of the transfer, so just complete the request 313 sendChangedCommand = FALSE; 314 } 315 } 316 } 317 318 } // end of IOCTL_AACS_READ_MEDIA_KEY_BLOCK 319 } 320 } // end of NT_SUCCESS(status) 321 322 if (!NT_SUCCESS(status)) 323 { 324 // command failed. 325 sendChangedCommand = FALSE; 326 } 327 } //end of while (sendChangedCommand) 328 329 ScratchBuffer_EndUse(DeviceExtension); 330 } 331 332 return status; 333 } 334 335 _IRQL_requires_max_(APC_LEVEL) 336 NTSTATUS 337 DeviceHandleAacsStartSession( 338 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 339 _In_ WDFREQUEST Request, 340 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 341 _Out_ size_t * DataLength 342 ) 343 /*++ 344 345 Routine Description: 346 This routine is used to process IOCTL: 347 IOCTL_AACS_START_SESSION 348 Arguments: 349 DeviceExtension - device context 350 351 Request - the request that will be formatted 352 353 RequestParameters - request parameter structur 354 355 DataLength - data transferred length 356 357 Return Value: 358 NTSTATUS 359 360 --*/ 361 { 362 //AacsGetAgid 363 364 NTSTATUS status = STATUS_SUCCESS; 365 PDVD_SESSION_ID sessionId = NULL; 366 367 PAGED_CODE(); 368 369 *DataLength = 0; 370 371 status = WdfRequestRetrieveOutputBuffer(Request, 372 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 373 (PVOID*)&sessionId, 374 NULL); 375 376 if (NT_SUCCESS(status)) 377 { 378 ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(CDVD_REPORT_AGID_DATA); 379 CDB cdb; 380 381 ScratchBuffer_BeginUse(DeviceExtension); 382 383 RtlZeroMemory(&cdb, sizeof(CDB)); 384 // Set up the CDB 385 cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY; 386 cdb.AsByte[7] = 0x02; // AACS key class 387 cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); 388 cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); 389 cdb.REPORT_KEY.KeyFormat = 0x00; // DVD_REPORT_AGID? 390 391 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); 392 393 #ifdef ENABLE_AACS_TESTING 394 static const UCHAR results[] = { 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0 }; 395 RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); 396 status = STATUS_SUCCESS; 397 #endif 398 if (NT_SUCCESS(status)) 399 { 400 PCDVD_KEY_HEADER keyHeader = DeviceExtension->ScratchContext.ScratchBuffer; 401 PCDVD_REPORT_AGID_DATA keyData = (PCDVD_REPORT_AGID_DATA)keyHeader->Data; 402 403 *sessionId = (DVD_SESSION_ID)(keyData->AGID); 404 *DataLength = sizeof(DVD_SESSION_ID); 405 } 406 407 ScratchBuffer_EndUse(DeviceExtension); 408 } 409 410 return status; 411 } 412 413 _IRQL_requires_max_(APC_LEVEL) 414 NTSTATUS 415 DeviceHandleAacsEndSession( 416 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 417 _In_ WDFREQUEST Request, 418 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 419 _Out_ size_t * DataLength 420 ) 421 /*++ 422 423 Routine Description: 424 This routine is used to process IOCTL: 425 IOCTL_AACS_END_SESSION 426 Arguments: 427 DeviceExtension - device context 428 429 Request - the request that will be formatted 430 431 RequestParameters - request parameter structur 432 433 DataLength - data transferred length 434 435 Return Value: 436 NTSTATUS 437 438 --*/ 439 { 440 //AacsReleaseAgid 441 442 NTSTATUS status = STATUS_SUCCESS; 443 PDVD_SESSION_ID sessionId = NULL; 444 445 PAGED_CODE(); 446 447 *DataLength = 0; 448 449 status = WdfRequestRetrieveInputBuffer(Request, 450 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 451 (PVOID*)&sessionId, 452 NULL); 453 454 if (NT_SUCCESS(status)) 455 { 456 ULONG transferSize = 0; 457 CDB cdb; 458 DVD_SESSION_ID currentSession = 0; 459 DVD_SESSION_ID limitSession = 0; 460 461 if(*sessionId == DVD_END_ALL_SESSIONS) 462 { 463 currentSession = 0; 464 limitSession = MAX_COPY_PROTECT_AGID - 1; 465 } 466 else 467 { 468 currentSession = *sessionId; 469 limitSession = *sessionId; 470 } 471 472 ScratchBuffer_BeginUse(DeviceExtension); 473 474 do 475 { 476 RtlZeroMemory(&cdb, sizeof(CDB)); 477 // Set up the CDB 478 cdb.SEND_KEY.OperationCode = SCSIOP_SEND_KEY; 479 cdb.AsByte[7] = 0x02; // AACS key class 480 cdb.SEND_KEY.AGID = (UCHAR)(currentSession); 481 cdb.SEND_KEY.KeyFormat = DVD_INVALIDATE_AGID; 482 483 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 12); 484 485 currentSession++; 486 } while ((currentSession <= limitSession) && NT_SUCCESS(status)); 487 488 #ifdef ENABLE_AACS_TESTING 489 status = STATUS_SUCCESS; 490 #endif 491 492 ScratchBuffer_EndUse(DeviceExtension); 493 } 494 495 return status; 496 } 497 498 _IRQL_requires_max_(APC_LEVEL) 499 NTSTATUS 500 DeviceHandleAacsSendCertificate( 501 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 502 _In_ WDFREQUEST Request, 503 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 504 _Out_ size_t * DataLength 505 ) 506 /*++ 507 508 Routine Description: 509 This routine is used to process IOCTL: 510 IOCTL_AACS_SEND_CERTIFICATE 511 Arguments: 512 DeviceExtension - device context 513 514 Request - the request that will be formatted 515 516 RequestParameters - request parameter structur 517 518 DataLength - data transferred length 519 520 Return Value: 521 NTSTATUS 522 523 --*/ 524 { 525 //AacsSendHostCertificate 526 527 NTSTATUS status = STATUS_SUCCESS; 528 PAACS_SEND_CERTIFICATE input = NULL; 529 530 PAGED_CODE(); 531 532 *DataLength = 0; 533 534 status = WdfRequestRetrieveInputBuffer(Request, 535 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 536 (PVOID*)&input, 537 NULL); 538 539 if (NT_SUCCESS(status)) 540 { 541 ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CERTIFICATE); 542 CDB cdb; 543 544 ScratchBuffer_BeginUse(DeviceExtension); 545 546 // copy the input buffer to the data buffer for the transfer 547 { 548 PCDVD_KEY_HEADER header = (PCDVD_KEY_HEADER)DeviceExtension->ScratchContext.ScratchBuffer; 549 ULONG tmp = dataTransferLength; 550 551 tmp -= RTL_SIZEOF_THROUGH_FIELD(CDVD_KEY_HEADER, DataLength); 552 553 header->DataLength[0] = (UCHAR)(tmp >> (8*1)); 554 header->DataLength[1] = (UCHAR)(tmp >> (8*0)); 555 RtlCopyMemory(header->Data, &(input->Certificate), sizeof(AACS_CERTIFICATE)); 556 } 557 558 RtlZeroMemory(&cdb, sizeof(CDB)); 559 // Set up the CDB 560 cdb.SEND_KEY.OperationCode = SCSIOP_SEND_KEY; 561 cdb.AsByte[7] = 0x02; // AACS key class 562 cdb.SEND_KEY.ParameterListLength[0] = (UCHAR)(dataTransferLength >> (8*1)); 563 cdb.SEND_KEY.ParameterListLength[1] = (UCHAR)(dataTransferLength >> (8*0)); 564 cdb.SEND_KEY.AGID = (UCHAR)( input->SessionId ); 565 cdb.SEND_KEY.KeyFormat = 0x01; // Send Host Challenge Certificate 566 567 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, FALSE, &cdb, 12); 568 569 #ifdef ENABLE_AACS_TESTING 570 status = STATUS_SUCCESS; 571 #endif 572 if (NT_SUCCESS(status)) 573 { 574 *DataLength = 0; 575 } 576 577 ScratchBuffer_EndUse(DeviceExtension); 578 } 579 580 return status; 581 } 582 583 _IRQL_requires_max_(APC_LEVEL) 584 NTSTATUS 585 DeviceHandleAacsGetCertificate( 586 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 587 _In_ WDFREQUEST Request, 588 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 589 _Out_ size_t * DataLength 590 ) 591 /*++ 592 593 Routine Description: 594 This routine is used to process IOCTL: 595 IOCTL_AACS_GET_CERTIFICATE 596 Arguments: 597 DeviceExtension - device context 598 599 Request - the request that will be formatted 600 601 RequestParameters - request parameter structur 602 603 DataLength - data transferred length 604 605 Return Value: 606 NTSTATUS 607 608 --*/ 609 { 610 //AacsGetDriveCertificate 611 612 NTSTATUS status = STATUS_SUCCESS; 613 PDVD_SESSION_ID input = NULL; 614 PVOID outputBuffer = NULL; 615 616 PAGED_CODE(); 617 618 *DataLength = 0; 619 620 status = WdfRequestRetrieveInputBuffer(Request, 621 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 622 (PVOID*)&input, 623 NULL); 624 625 if (NT_SUCCESS(status)) 626 { 627 status = WdfRequestRetrieveOutputBuffer(Request, 628 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 629 (PVOID*)&outputBuffer, 630 NULL); 631 } 632 633 if (NT_SUCCESS(status)) 634 { 635 ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CERTIFICATE); 636 CDB cdb; 637 638 ScratchBuffer_BeginUse(DeviceExtension); 639 640 RtlZeroMemory(&cdb, sizeof(CDB)); 641 // Set up the CDB 642 cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY; 643 cdb.AsByte[7] = 0x02; // AACS key class 644 cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); 645 cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); 646 cdb.REPORT_KEY.AGID = (UCHAR)(*input); 647 cdb.REPORT_KEY.KeyFormat = 0x01; // Return a drive certificate challenge 648 649 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); 650 651 #ifdef ENABLE_AACS_TESTING 652 static const UCHAR results[] = { 0x00, 0x72, 0x00, 0x00 }; 653 static const UCHAR defaultFill = 0x31; // '1' 654 RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0074, defaultFill); 655 RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); 656 status = STATUS_SUCCESS; 657 #endif 658 if (NT_SUCCESS(status)) 659 { 660 PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; 661 ULONG dataLengthToCopy = sizeof(AACS_CERTIFICATE); 662 663 // make length field native byte ordering 664 REVERSE_SHORT(&header->Length); 665 666 // exit if getting invalid data from the drive 667 if (header->Length < (sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length))) 668 { 669 *DataLength = 0; 670 status = STATUS_IO_DEVICE_ERROR; 671 } 672 673 if (NT_SUCCESS(status)) 674 { 675 // adjust data length to reflect only the addition data 676 header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); 677 678 // exit if the drive is returning an unexpected data size 679 if (header->Length != dataLengthToCopy) 680 { 681 *DataLength = 0; 682 status = STATUS_IO_DEVICE_ERROR; 683 } 684 } 685 686 if (NT_SUCCESS(status)) 687 { 688 // else copy the data to the user's buffer 689 RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); 690 *DataLength = dataLengthToCopy; 691 } 692 } 693 694 ScratchBuffer_EndUse(DeviceExtension); 695 } 696 697 return status; 698 } 699 700 _IRQL_requires_max_(APC_LEVEL) 701 NTSTATUS 702 DeviceHandleAacsGetChallengeKey( 703 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 704 _In_ WDFREQUEST Request, 705 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 706 _Out_ size_t * DataLength 707 ) 708 /*++ 709 710 Routine Description: 711 This routine is used to process IOCTL: 712 IOCTL_AACS_GET_CHALLENGE_KEY 713 Arguments: 714 DeviceExtension - device context 715 716 Request - the request that will be formatted 717 718 RequestParameters - request parameter structur 719 720 DataLength - data transferred length 721 722 Return Value: 723 NTSTATUS 724 725 --*/ 726 { 727 //AacsGetChallengeKey 728 729 NTSTATUS status = STATUS_SUCCESS; 730 PDVD_SESSION_ID input = NULL; 731 PVOID outputBuffer = NULL; 732 733 PAGED_CODE(); 734 735 *DataLength = 0; 736 737 status = WdfRequestRetrieveInputBuffer(Request, 738 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 739 (PVOID*)&input, 740 NULL); 741 742 if (NT_SUCCESS(status)) 743 { 744 status = WdfRequestRetrieveOutputBuffer(Request, 745 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 746 (PVOID*)&outputBuffer, 747 NULL); 748 } 749 750 if (NT_SUCCESS(status)) 751 { 752 ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CHALLENGE_KEY); 753 CDB cdb; 754 755 ScratchBuffer_BeginUse(DeviceExtension); 756 757 RtlZeroMemory(&cdb, sizeof(CDB)); 758 // Set up the CDB 759 cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY; 760 cdb.AsByte[7] = 0x02; // AACS key class 761 cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); 762 cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); 763 cdb.REPORT_KEY.AGID = (UCHAR)(*input); 764 cdb.REPORT_KEY.KeyFormat = 0x02; // Return a drive certificate challenge 765 766 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); 767 768 #ifdef ENABLE_AACS_TESTING 769 static const UCHAR results[] = { 0x00, 0x52, 0x00, 0x00 }; 770 static const UCHAR defaultFill = 0x32; // '2' 771 RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0054, defaultFill); 772 RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); 773 status = STATUS_SUCCESS; 774 #endif 775 if (NT_SUCCESS(status)) 776 { 777 PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; 778 ULONG dataLengthToCopy = sizeof(AACS_CHALLENGE_KEY); 779 780 // make length field native byte ordering 781 REVERSE_SHORT(&header->Length); 782 783 // exit if getting invalid data from the drive 784 if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) 785 { 786 *DataLength = 0; 787 status = STATUS_IO_DEVICE_ERROR; 788 } 789 790 if (NT_SUCCESS(status)) 791 { 792 // adjust data length to reflect only the addition data 793 header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); 794 795 // exit if the drive is returning an unexpected data size 796 if (header->Length != dataLengthToCopy) 797 { 798 *DataLength = 0; 799 status = STATUS_IO_DEVICE_ERROR; 800 } 801 } 802 803 if (NT_SUCCESS(status)) 804 { 805 // else copy the data to the user's buffer 806 RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); 807 *DataLength = dataLengthToCopy; 808 } 809 } 810 811 ScratchBuffer_EndUse(DeviceExtension); 812 } 813 814 return status; 815 } 816 817 _IRQL_requires_max_(APC_LEVEL) 818 NTSTATUS 819 DeviceHandleSendChallengeKey( 820 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 821 _In_ WDFREQUEST Request, 822 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 823 _Out_ size_t * DataLength 824 ) 825 /*++ 826 827 Routine Description: 828 This routine is used to process IOCTL: 829 IOCTL_AACS_SEND_CHALLENGE_KEY 830 Arguments: 831 DeviceExtension - device context 832 833 Request - the request that will be formatted 834 835 RequestParameters - request parameter structur 836 837 DataLength - data transferred length 838 839 Return Value: 840 NTSTATUS 841 842 --*/ 843 { 844 //AacsSendChallengeKey 845 846 NTSTATUS status = STATUS_SUCCESS; 847 PAACS_SEND_CHALLENGE_KEY input = NULL; 848 849 PAGED_CODE(); 850 851 *DataLength = 0; 852 853 status = WdfRequestRetrieveInputBuffer(Request, 854 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 855 (PVOID*)&input, 856 NULL); 857 858 if (NT_SUCCESS(status)) 859 { 860 ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CHALLENGE_KEY); 861 CDB cdb; 862 863 ScratchBuffer_BeginUse(DeviceExtension); 864 865 // copy the input buffer to the data buffer for the transfer 866 { 867 PCDVD_KEY_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; 868 ULONG tmp = dataTransferLength; 869 tmp -= RTL_SIZEOF_THROUGH_FIELD(CDVD_KEY_HEADER, DataLength); 870 871 header->DataLength[0] = (UCHAR)(tmp >> (8*1)); 872 header->DataLength[1] = (UCHAR)(tmp >> (8*0)); 873 RtlCopyMemory(header->Data, &(input->ChallengeKey), sizeof(AACS_CHALLENGE_KEY)); 874 } 875 876 RtlZeroMemory(&cdb, sizeof(CDB)); 877 // Set up the CDB 878 cdb.SEND_KEY.OperationCode = SCSIOP_SEND_KEY; 879 cdb.AsByte[7] = 0x02; // AACS key class 880 cdb.SEND_KEY.ParameterListLength[0] = (UCHAR)(dataTransferLength >> (8*1)); 881 cdb.SEND_KEY.ParameterListLength[1] = (UCHAR)(dataTransferLength >> (8*0)); 882 cdb.SEND_KEY.AGID = (UCHAR)( input->SessionId ); 883 cdb.SEND_KEY.KeyFormat = 0x02; // Send Host Challenge Certificate 884 885 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, FALSE, &cdb, 12); 886 887 #ifdef ENABLE_AACS_TESTING 888 status = STATUS_SUCCESS; 889 #endif 890 if (NT_SUCCESS(status)) 891 { 892 *DataLength = 0; 893 } 894 895 ScratchBuffer_EndUse(DeviceExtension); 896 } 897 898 return status; 899 } 900 901 _IRQL_requires_max_(APC_LEVEL) 902 NTSTATUS 903 DeviceHandleReadVolumeId( 904 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 905 _In_ WDFREQUEST Request, 906 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 907 _Out_ size_t * DataLength 908 ) 909 /*++ 910 911 Routine Description: 912 This routine is used to process IOCTL: 913 IOCTL_AACS_READ_VOLUME_ID 914 Arguments: 915 DeviceExtension - device context 916 917 Request - the request that will be formatted 918 919 RequestParameters - request parameter structur 920 921 DataLength - data transferred length 922 923 Return Value: 924 NTSTATUS 925 926 --*/ 927 { 928 //AacsReadVolumeID 929 930 NTSTATUS status = STATUS_SUCCESS; 931 PDVD_SESSION_ID input = NULL; 932 PVOID outputBuffer = NULL; 933 934 PAGED_CODE(); 935 936 *DataLength = 0; 937 938 status = WdfRequestRetrieveInputBuffer(Request, 939 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 940 (PVOID*)&input, 941 NULL); 942 943 if (NT_SUCCESS(status)) 944 { 945 status = WdfRequestRetrieveOutputBuffer(Request, 946 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 947 (PVOID*)&outputBuffer, 948 NULL); 949 } 950 951 if (NT_SUCCESS(status)) 952 { 953 ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_VOLUME_ID); 954 CDB cdb; 955 956 ScratchBuffer_BeginUse(DeviceExtension); 957 958 RtlZeroMemory(&cdb, sizeof(CDB)); 959 // Set up the CDB 960 cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE; 961 cdb.READ_DVD_STRUCTURE.Format = 0x80; // Return the AACS volumeID 962 cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); 963 cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); 964 cdb.READ_DVD_STRUCTURE.AGID = (UCHAR)(*input); 965 966 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); 967 968 #ifdef ENABLE_AACS_TESTING 969 static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 }; 970 static const UCHAR defaultFill = 0x33; // '3' 971 RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill); 972 RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); 973 status = STATUS_SUCCESS; 974 #endif 975 if (NT_SUCCESS(status)) 976 { 977 PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; 978 ULONG dataLengthToCopy = sizeof(AACS_VOLUME_ID); 979 980 // make length field native byte ordering 981 REVERSE_SHORT(&header->Length); 982 983 // exit if getting invalid data from the drive 984 if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) 985 { 986 *DataLength = 0; 987 status = STATUS_IO_DEVICE_ERROR; 988 } 989 990 if (NT_SUCCESS(status)) 991 { 992 // adjust data length to reflect only the addition data 993 header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); 994 995 // exit if the drive is returning an unexpected data size 996 if (header->Length != dataLengthToCopy) 997 { 998 *DataLength = 0; 999 status = STATUS_IO_DEVICE_ERROR; 1000 } 1001 } 1002 1003 if (NT_SUCCESS(status)) 1004 { 1005 // else copy the data to the user's buffer 1006 RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); 1007 *DataLength = dataLengthToCopy; 1008 } 1009 } 1010 1011 ScratchBuffer_EndUse(DeviceExtension); 1012 } 1013 1014 return status; 1015 } 1016 1017 _IRQL_requires_max_(APC_LEVEL) 1018 NTSTATUS 1019 DeviceHandleAacsReadSerialNumber( 1020 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1021 _In_ WDFREQUEST Request, 1022 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1023 _Out_ size_t * DataLength 1024 ) 1025 /*++ 1026 1027 Routine Description: 1028 This routine is used to process IOCTL: 1029 IOCTL_AACS_READ_SERIAL_NUMBER 1030 Arguments: 1031 DeviceExtension - device context 1032 1033 Request - the request that will be formatted 1034 1035 RequestParameters - request parameter structur 1036 1037 DataLength - data transferred length 1038 1039 Return Value: 1040 NTSTATUS 1041 1042 --*/ 1043 { 1044 //AacsReadSerialNumber 1045 1046 NTSTATUS status = STATUS_SUCCESS; 1047 PDVD_SESSION_ID input = NULL; 1048 PVOID outputBuffer = NULL; 1049 1050 PAGED_CODE(); 1051 1052 *DataLength = 0; 1053 1054 status = WdfRequestRetrieveInputBuffer(Request, 1055 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1056 (PVOID*)&input, 1057 NULL); 1058 1059 if (NT_SUCCESS(status)) 1060 { 1061 status = WdfRequestRetrieveOutputBuffer(Request, 1062 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 1063 (PVOID*)&outputBuffer, 1064 NULL); 1065 } 1066 1067 if (NT_SUCCESS(status)) 1068 { 1069 ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_SERIAL_NUMBER); 1070 CDB cdb; 1071 1072 ScratchBuffer_BeginUse(DeviceExtension); 1073 1074 RtlZeroMemory(&cdb, sizeof(CDB)); 1075 // Set up the CDB 1076 cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE; 1077 cdb.READ_DVD_STRUCTURE.Format = 0x81; // Return the AACS volumeID 1078 cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); 1079 cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); 1080 cdb.READ_DVD_STRUCTURE.AGID = (UCHAR)(*input); 1081 1082 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); 1083 1084 #ifdef ENABLE_AACS_TESTING 1085 static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 }; 1086 static const UCHAR defaultFill = 0x34; // '4' 1087 RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill); 1088 RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); 1089 status = STATUS_SUCCESS; 1090 #endif 1091 if (NT_SUCCESS(status)) 1092 { 1093 PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; 1094 ULONG dataLengthToCopy = sizeof(AACS_SERIAL_NUMBER); 1095 1096 // make length field native byte ordering 1097 REVERSE_SHORT(&header->Length); 1098 1099 // exit if getting invalid data from the drive 1100 if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) 1101 { 1102 *DataLength = 0; 1103 status = STATUS_IO_DEVICE_ERROR; 1104 } 1105 1106 if (NT_SUCCESS(status)) 1107 { 1108 // adjust data length to reflect only the addition data 1109 header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); 1110 1111 // exit if the drive is returning an unexpected data size 1112 if (header->Length != dataLengthToCopy) 1113 { 1114 *DataLength = 0; 1115 status = STATUS_IO_DEVICE_ERROR; 1116 } 1117 } 1118 1119 if (NT_SUCCESS(status)) 1120 { 1121 // else copy the data to the user's buffer 1122 RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); 1123 *DataLength = dataLengthToCopy; 1124 } 1125 } 1126 1127 ScratchBuffer_EndUse(DeviceExtension); 1128 } 1129 1130 return status; 1131 } 1132 1133 _IRQL_requires_max_(APC_LEVEL) 1134 NTSTATUS 1135 DeviceHandleAacsReadMediaId( 1136 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1137 _In_ WDFREQUEST Request, 1138 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1139 _Out_ size_t * DataLength 1140 ) 1141 /*++ 1142 1143 Routine Description: 1144 This routine is used to process IOCTL: 1145 IOCTL_AACS_READ_MEDIA_ID 1146 Arguments: 1147 DeviceExtension - device context 1148 1149 Request - the request that will be formatted 1150 1151 RequestParameters - request parameter structur 1152 1153 DataLength - data transferred length 1154 1155 Return Value: 1156 NTSTATUS 1157 1158 --*/ 1159 { 1160 //AacsReadMediaID 1161 1162 NTSTATUS status = STATUS_SUCCESS; 1163 PDVD_SESSION_ID input = NULL; 1164 PVOID outputBuffer = NULL; 1165 1166 PAGED_CODE(); 1167 1168 *DataLength = 0; 1169 1170 status = WdfRequestRetrieveInputBuffer(Request, 1171 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1172 (PVOID*)&input, 1173 NULL); 1174 1175 if (NT_SUCCESS(status)) 1176 { 1177 status = WdfRequestRetrieveOutputBuffer(Request, 1178 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 1179 (PVOID*)&outputBuffer, 1180 NULL); 1181 } 1182 1183 if (NT_SUCCESS(status)) 1184 { 1185 ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_MEDIA_ID); 1186 CDB cdb; 1187 1188 ScratchBuffer_BeginUse(DeviceExtension); 1189 1190 RtlZeroMemory(&cdb, sizeof(CDB)); 1191 // Set up the CDB 1192 cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE; 1193 cdb.READ_DVD_STRUCTURE.Format = 0x82; // Return the AACS volumeID 1194 cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); 1195 cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); 1196 cdb.READ_DVD_STRUCTURE.AGID = (UCHAR)(*input); 1197 1198 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); 1199 1200 #ifdef ENABLE_AACS_TESTING 1201 static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 }; 1202 static const UCHAR defaultFill = 0x35; // '5' 1203 RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill); 1204 RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); 1205 status = STATUS_SUCCESS; 1206 #endif 1207 if (NT_SUCCESS(status)) 1208 { 1209 PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; 1210 ULONG dataLengthToCopy = sizeof(AACS_MEDIA_ID); 1211 1212 // make length field native byte ordering 1213 REVERSE_SHORT(&header->Length); 1214 1215 // exit if getting invalid data from the drive 1216 if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) 1217 { 1218 *DataLength = 0; 1219 status = STATUS_IO_DEVICE_ERROR; 1220 } 1221 1222 if (NT_SUCCESS(status)) 1223 { 1224 // adjust data length to reflect only the addition data 1225 header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); 1226 1227 // exit if the drive is returning an unexpected data size 1228 if (header->Length != dataLengthToCopy) 1229 { 1230 *DataLength = 0; 1231 status = STATUS_IO_DEVICE_ERROR; 1232 } 1233 } 1234 1235 if (NT_SUCCESS(status)) 1236 { 1237 // else copy the data to the user's buffer 1238 RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); 1239 *DataLength = dataLengthToCopy; 1240 } 1241 } 1242 1243 ScratchBuffer_EndUse(DeviceExtension); 1244 } 1245 1246 return status; 1247 } 1248 1249 _IRQL_requires_max_(APC_LEVEL) 1250 NTSTATUS 1251 DeviceHandleAacsReadBindingNonce( 1252 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1253 _In_ WDFREQUEST Request, 1254 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1255 _Out_ size_t * DataLength 1256 ) 1257 /*++ 1258 1259 Routine Description: 1260 This routine is used to process IOCTL: 1261 IOCTL_AACS_READ_BINDING_NONCE 1262 Arguments: 1263 DeviceExtension - device context 1264 1265 Request - the request that will be formatted 1266 1267 RequestParameters - request parameter structur 1268 1269 DataLength - data transferred length 1270 1271 Return Value: 1272 NTSTATUS 1273 1274 --*/ 1275 { 1276 //AacsReadBindingNonce 1277 1278 NTSTATUS status = STATUS_SUCCESS; 1279 PAACS_READ_BINDING_NONCE input = NULL; 1280 PVOID outputBuffer = NULL; 1281 1282 PAGED_CODE(); 1283 1284 *DataLength = 0; 1285 1286 status = WdfRequestRetrieveInputBuffer(Request, 1287 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1288 (PVOID*)&input, 1289 NULL); 1290 1291 if (NT_SUCCESS(status)) 1292 { 1293 status = WdfRequestRetrieveOutputBuffer(Request, 1294 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 1295 (PVOID*)&outputBuffer, 1296 NULL); 1297 } 1298 1299 if (NT_SUCCESS(status)) 1300 { 1301 ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_BINDING_NONCE); 1302 CDB cdb; 1303 1304 ScratchBuffer_BeginUse(DeviceExtension); 1305 1306 RtlZeroMemory(&cdb, sizeof(CDB)); 1307 // Set up the CDB 1308 cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY; 1309 cdb.REPORT_KEY.LogicalBlockAddress[0] = (UCHAR)( input->StartLba >> (3*8) ); 1310 cdb.REPORT_KEY.LogicalBlockAddress[1] = (UCHAR)( input->StartLba >> (2*8) ); 1311 cdb.REPORT_KEY.LogicalBlockAddress[2] = (UCHAR)( input->StartLba >> (1*8) ); 1312 cdb.REPORT_KEY.LogicalBlockAddress[3] = (UCHAR)( input->StartLba >> (0*8) ); 1313 cdb.AsByte[6] = (UCHAR)( input->NumberOfSectors ); 1314 cdb.AsByte[7] = 0x02; // AACS key class 1315 cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1)); 1316 cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0)); 1317 cdb.REPORT_KEY.AGID = (UCHAR)( input->SessionId ); 1318 cdb.REPORT_KEY.KeyFormat = 0x21; // Return an existing binding nonce 1319 1320 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); 1321 1322 #ifdef ENABLE_AACS_TESTING 1323 static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 }; 1324 static const UCHAR defaultFill = 0x36; // '6' 1325 RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill); 1326 RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); 1327 status = STATUS_SUCCESS; 1328 #endif 1329 if (NT_SUCCESS(status)) 1330 { 1331 PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; 1332 ULONG dataLengthToCopy = sizeof(AACS_BINDING_NONCE); 1333 1334 // make length field native byte ordering 1335 REVERSE_SHORT(&header->Length); 1336 1337 // exit if getting invalid data from the drive 1338 if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) 1339 { 1340 *DataLength = 0; 1341 status = STATUS_IO_DEVICE_ERROR; 1342 } 1343 1344 if (NT_SUCCESS(status)) 1345 { 1346 // adjust data length to reflect only the addition data 1347 header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); 1348 1349 // exit if the drive is returning an unexpected data size 1350 if (header->Length != dataLengthToCopy) 1351 { 1352 *DataLength = 0; 1353 status = STATUS_IO_DEVICE_ERROR; 1354 } 1355 } 1356 1357 if (NT_SUCCESS(status)) 1358 { 1359 // else copy the data to the user's buffer 1360 RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); 1361 *DataLength = dataLengthToCopy; 1362 } 1363 } 1364 1365 ScratchBuffer_EndUse(DeviceExtension); 1366 } 1367 1368 return status; 1369 } 1370 1371 _IRQL_requires_max_(APC_LEVEL) 1372 NTSTATUS 1373 DeviceHandleAacsGenerateBindingNonce( 1374 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1375 _In_ WDFREQUEST Request, 1376 _In_ WDF_REQUEST_PARAMETERS RequestParameters, 1377 _Out_ size_t * DataLength 1378 ) 1379 /*++ 1380 1381 Routine Description: 1382 This routine is used to process IOCTL: 1383 IOCTL_AACS_GENERATE_BINDING_NONCE 1384 Arguments: 1385 DeviceExtension - device context 1386 1387 Request - the request that will be formatted 1388 1389 RequestParameters - request parameter structur 1390 1391 DataLength - data transferred length 1392 1393 Return Value: 1394 NTSTATUS 1395 1396 --*/ 1397 { 1398 //AacsGenerateBindingNonce 1399 1400 NTSTATUS status = STATUS_SUCCESS; 1401 PAACS_READ_BINDING_NONCE input = NULL; 1402 PVOID outputBuffer = NULL; 1403 1404 PAGED_CODE(); 1405 1406 *DataLength = 0; 1407 1408 status = WdfRequestRetrieveInputBuffer(Request, 1409 RequestParameters.Parameters.DeviceIoControl.InputBufferLength, 1410 (PVOID*)&input, 1411 NULL); 1412 1413 if (NT_SUCCESS(status)) 1414 { 1415 status = WdfRequestRetrieveOutputBuffer(Request, 1416 RequestParameters.Parameters.DeviceIoControl.OutputBufferLength, 1417 (PVOID*)&outputBuffer, 1418 NULL); 1419 } 1420 1421 if (NT_SUCCESS(status)) 1422 { 1423 ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_BINDING_NONCE); 1424 CDB cdb; 1425 1426 ScratchBuffer_BeginUse(DeviceExtension); 1427 1428 RtlZeroMemory(&cdb, sizeof(CDB)); 1429 // Set up the CDB 1430 1431 status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12); 1432 1433 #ifdef ENABLE_AACS_TESTING 1434 static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 }; 1435 static const UCHAR defaultFill = 0x37; // '7' 1436 RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill); 1437 RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results)); 1438 status = STATUS_SUCCESS; 1439 #endif 1440 if (NT_SUCCESS(status)) 1441 { 1442 PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer; 1443 ULONG dataLengthToCopy = sizeof(AACS_BINDING_NONCE); 1444 1445 // make length field native byte ordering 1446 REVERSE_SHORT(&header->Length); 1447 1448 // exit if getting invalid data from the drive 1449 if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)) 1450 { 1451 *DataLength = 0; 1452 status = STATUS_IO_DEVICE_ERROR; 1453 } 1454 1455 if (NT_SUCCESS(status)) 1456 { 1457 // adjust data length to reflect only the addition data 1458 header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length); 1459 1460 // exit if the drive is returning an unexpected data size 1461 if (header->Length != dataLengthToCopy) 1462 { 1463 *DataLength = 0; 1464 status = STATUS_IO_DEVICE_ERROR; 1465 } 1466 } 1467 1468 if (NT_SUCCESS(status)) 1469 { 1470 // else copy the data to the user's buffer 1471 RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy); 1472 *DataLength = dataLengthToCopy; 1473 } 1474 } 1475 1476 ScratchBuffer_EndUse(DeviceExtension); 1477 } 1478 1479 return status; 1480 } 1481 1482