xref: /reactos/drivers/storage/class/cdrom/aacs.c (revision 7353af1e)
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