reactos/drivers/storage/class/cdrom/aacs.c

1481 lines
51 KiB
C

/*--
Copyright (C) Microsoft Corporation. All rights reserved.
Module Name:
aacs.c
Abstract:
The CDROM class driver implementation of handling AACS IOCTLs.
Environment:
kernel mode only
Notes:
Revision History:
--*/
#include "stddef.h"
#include "string.h"
#include "ntddk.h"
#include "ntddstor.h"
#include "cdrom.h"
#include "ioctl.h"
#include "scratch.h"
#ifdef DEBUG_USE_WPP
#include "aacs.tmh"
#endif
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, DeviceHandleAacsReadMediaKeyBlock)
#pragma alloc_text(PAGE, DeviceHandleAacsStartSession)
#pragma alloc_text(PAGE, DeviceHandleAacsEndSession)
#pragma alloc_text(PAGE, DeviceHandleAacsSendCertificate)
#pragma alloc_text(PAGE, DeviceHandleAacsGetCertificate)
#pragma alloc_text(PAGE, DeviceHandleAacsGetChallengeKey)
#pragma alloc_text(PAGE, DeviceHandleAacsReadSerialNumber)
#pragma alloc_text(PAGE, DeviceHandleAacsReadMediaId)
#pragma alloc_text(PAGE, DeviceHandleAacsReadBindingNonce)
#pragma alloc_text(PAGE, DeviceHandleAacsGenerateBindingNonce)
#pragma alloc_text(PAGE, DeviceHandleReadVolumeId)
#pragma alloc_text(PAGE, DeviceHandleSendChallengeKey)
#endif
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleAacsReadMediaKeyBlock(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTLs:
IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE
IOCTL_AACS_READ_MEDIA_KEY_BLOCK
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PAACS_LAYER_NUMBER layerNumber = NULL;
PVOID outputBuffer = NULL;
ULONG transferSize = sizeof(READ_DVD_STRUCTURES_HEADER);
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveInputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
(PVOID*)&layerNumber,
NULL);
if (NT_SUCCESS(status))
{
status = WdfRequestRetrieveOutputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
(PVOID*)&outputBuffer,
NULL);
}
if (NT_SUCCESS(status))
{
if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK)
{
// maximum size for this transfer is one pack + header
transferSize += AACS_MKB_PACK_SIZE;
}
if (transferSize > DeviceExtension->ScratchContext.ScratchBufferSize)
{
// rare case. normally the size of scratch buffer is 64k.
status = STATUS_INTERNAL_ERROR;
}
}
if (NT_SUCCESS(status))
{
UCHAR rmdBlockNumber = 0;
BOOLEAN sendChangedCommand = TRUE;
BOOLEAN shouldRetry = TRUE;
CDB cdb;
ScratchBuffer_BeginUse(DeviceExtension);
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE;
// cdb->AsByte[1] = 0x01; // AACS sub-command not required for this
cdb.READ_DVD_STRUCTURE.LayerNumber = (UCHAR)(*layerNumber);
cdb.READ_DVD_STRUCTURE.Format = 0x83; // MKB
cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(transferSize >> (8*1));
cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(transferSize >> (8*0));
while (sendChangedCommand)
{
// RMDBlockNumber is set to zero....
// RMDBlockNumber[3] maybe changed for other blocks.
cdb.READ_DVD_STRUCTURE.RMDBlockNumber[3] = rmdBlockNumber;
if (shouldRetry)
{
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, TRUE, &cdb, 12);
}
#ifdef ENABLE_AACS_TESTING
if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE)
{
static const UCHAR results[] = { 0x80, 0x02, 0x00, 0x02 };
RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results));
status = STATUS_SUCCESS;
}
else if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK)
{
static const UCHAR results[] = { 0x80, 0x02, 0x00, 0x02 };
static const UCHAR defaultFill = 0x30; // '0'
RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x8004, defaultFill);
RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results));
status = STATUS_SUCCESS;
}
#endif //ENABLE_AACS_TESTING
if (NT_SUCCESS(status))
{
// command succeeded, process data...
PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer;
UCHAR thisPackNumber = cdb.READ_DVD_STRUCTURE.RMDBlockNumber[3];
UCHAR otherPacks = header->Reserved[1];
// validate and zero-base the otherPacks
if (otherPacks == 0)
{
TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_INIT,
"AACS: Device is reporting zero total packs (invalid)\n"));
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
else
{
otherPacks--;
if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK_SIZE)
{
// if not already requested last pack, do so now
if (otherPacks != thisPackNumber)
{
// re-send the command for the other pack number.
// this is safe here because NT_SUCCESS() is TRUE,
// and all the rest of this routine does is SetHardError()
// and release of resources we're still about to use.
// re-zero the output buffer
RtlZeroMemory(DeviceExtension->ScratchContext.ScratchBuffer, sizeof(READ_DVD_STRUCTURES_HEADER));
// modify the CDB to get the very last pack of the MKB
rmdBlockNumber = otherPacks;
transferSize = sizeof(READ_DVD_STRUCTURES_HEADER);
// keep items clean
ScratchBuffer_ResetItems(DeviceExtension, TRUE);
// make sure the loop will be executed for modified command.
sendChangedCommand = TRUE;
shouldRetry = TRUE;
}
else
{
// this request already got the last pack
// so just interpret the data
REVERSE_SHORT(&header->Length);
if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length))
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
else
{
ULONG totalSize = header->Length;
// subtract out any remaining bytes in the header
// to get the number of usable bytes in this pack
totalSize -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length);
totalSize += otherPacks * AACS_MKB_PACK_SIZE;
// save the result and complete the request
*((PULONG)outputBuffer) = totalSize;
*DataLength = sizeof(ULONG);
status = STATUS_SUCCESS;
}
// This will exit the loop of sendChangedCommand
sendChangedCommand = FALSE;
shouldRetry = FALSE;
}
}
else if (RequestParameters.Parameters.DeviceIoControl.IoControlCode == IOCTL_AACS_READ_MEDIA_KEY_BLOCK)
{
// make length field native byte ordering
REVERSE_SHORT(&header->Length);
// exit if getting invalid data from the drive
if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length))
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
else
{
// success, how many bytes to copy for this pack?
ULONG totalSize = header->Length;
size_t originalBufferSize;
// subtract out any remaining bytes in the header
// to get the number of usable bytes in this pack
totalSize -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length);
// if not the final pack, this should be a full transfer per spec
NT_ASSERT( (totalSize == AACS_MKB_PACK_SIZE) || (thisPackNumber == otherPacks) );
// validate the user's buffer is large enough to accept the full data
originalBufferSize = RequestParameters.Parameters.DeviceIoControl.OutputBufferLength;
if (originalBufferSize < (totalSize + (AACS_MKB_PACK_SIZE*thisPackNumber)))
{
// just return a slightly bigger-than-normal size
*DataLength = (otherPacks + 1)*AACS_MKB_PACK_SIZE;
status = STATUS_BUFFER_TOO_SMALL;
}
else
{
PUCHAR whereToCopy;
// determine where to copy to the user's memory
whereToCopy = outputBuffer;
whereToCopy += AACS_MKB_PACK_SIZE * thisPackNumber;
RtlCopyMemory(whereToCopy, header->Data, totalSize);
// update the Information field here because we already
// have calculated the size of the block
*DataLength = totalSize + (AACS_MKB_PACK_SIZE * thisPackNumber);
status = STATUS_SUCCESS;
// if there are more packs to get from the device, send it again....
if (thisPackNumber != otherPacks)
{
// re-send the command for the next pack number.
// this is safe here because NT_SUCCESS() is TRUE,
// and all the rest of this routine does is SetHardError()
// and release of resources we're still about to use.
// re-zero the output buffer
RtlZeroMemory(DeviceExtension->ScratchContext.ScratchBuffer, sizeof(READ_DVD_STRUCTURES_HEADER));
// modify the CDB to get the next pack of the MKB
rmdBlockNumber = cdb.READ_DVD_STRUCTURE.RMDBlockNumber[3]++;
// modify the SRB to be resent
//
transferSize = AACS_MKB_PACK_SIZE + sizeof(READ_DVD_STRUCTURES_HEADER);
// keep items clean
ScratchBuffer_ResetItems(DeviceExtension, FALSE);
// make sure the loop will be executed for modified command.
sendChangedCommand = TRUE;
shouldRetry = TRUE;
}
else
{
// else, that was the end of the transfer, so just complete the request
sendChangedCommand = FALSE;
}
}
}
} // end of IOCTL_AACS_READ_MEDIA_KEY_BLOCK
}
} // end of NT_SUCCESS(status)
if (!NT_SUCCESS(status))
{
// command failed.
sendChangedCommand = FALSE;
}
} //end of while (sendChangedCommand)
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleAacsStartSession(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTL:
IOCTL_AACS_START_SESSION
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
//AacsGetAgid
NTSTATUS status = STATUS_SUCCESS;
PDVD_SESSION_ID sessionId = NULL;
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveOutputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
(PVOID*)&sessionId,
NULL);
if (NT_SUCCESS(status))
{
ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(CDVD_REPORT_AGID_DATA);
CDB cdb;
ScratchBuffer_BeginUse(DeviceExtension);
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY;
cdb.AsByte[7] = 0x02; // AACS key class
cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1));
cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0));
cdb.REPORT_KEY.KeyFormat = 0x00; // DVD_REPORT_AGID?
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12);
#ifdef ENABLE_AACS_TESTING
static const UCHAR results[] = { 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0 };
RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results));
status = STATUS_SUCCESS;
#endif
if (NT_SUCCESS(status))
{
PCDVD_KEY_HEADER keyHeader = DeviceExtension->ScratchContext.ScratchBuffer;
PCDVD_REPORT_AGID_DATA keyData = (PCDVD_REPORT_AGID_DATA)keyHeader->Data;
*sessionId = (DVD_SESSION_ID)(keyData->AGID);
*DataLength = sizeof(DVD_SESSION_ID);
}
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleAacsEndSession(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTL:
IOCTL_AACS_END_SESSION
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
//AacsReleaseAgid
NTSTATUS status = STATUS_SUCCESS;
PDVD_SESSION_ID sessionId = NULL;
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveInputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
(PVOID*)&sessionId,
NULL);
if (NT_SUCCESS(status))
{
ULONG transferSize = 0;
CDB cdb;
DVD_SESSION_ID currentSession = 0;
DVD_SESSION_ID limitSession = 0;
if(*sessionId == DVD_END_ALL_SESSIONS)
{
currentSession = 0;
limitSession = MAX_COPY_PROTECT_AGID - 1;
}
else
{
currentSession = *sessionId;
limitSession = *sessionId;
}
ScratchBuffer_BeginUse(DeviceExtension);
do
{
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
cdb.SEND_KEY.OperationCode = SCSIOP_SEND_KEY;
cdb.AsByte[7] = 0x02; // AACS key class
cdb.SEND_KEY.AGID = (UCHAR)(currentSession);
cdb.SEND_KEY.KeyFormat = DVD_INVALIDATE_AGID;
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, transferSize, FALSE, &cdb, 12);
currentSession++;
} while ((currentSession <= limitSession) && NT_SUCCESS(status));
#ifdef ENABLE_AACS_TESTING
status = STATUS_SUCCESS;
#endif
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleAacsSendCertificate(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTL:
IOCTL_AACS_SEND_CERTIFICATE
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
//AacsSendHostCertificate
NTSTATUS status = STATUS_SUCCESS;
PAACS_SEND_CERTIFICATE input = NULL;
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveInputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
(PVOID*)&input,
NULL);
if (NT_SUCCESS(status))
{
ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CERTIFICATE);
CDB cdb;
ScratchBuffer_BeginUse(DeviceExtension);
// copy the input buffer to the data buffer for the transfer
{
PCDVD_KEY_HEADER header = (PCDVD_KEY_HEADER)DeviceExtension->ScratchContext.ScratchBuffer;
ULONG tmp = dataTransferLength;
tmp -= RTL_SIZEOF_THROUGH_FIELD(CDVD_KEY_HEADER, DataLength);
header->DataLength[0] = (UCHAR)(tmp >> (8*1));
header->DataLength[1] = (UCHAR)(tmp >> (8*0));
RtlCopyMemory(header->Data, &(input->Certificate), sizeof(AACS_CERTIFICATE));
}
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
cdb.SEND_KEY.OperationCode = SCSIOP_SEND_KEY;
cdb.AsByte[7] = 0x02; // AACS key class
cdb.SEND_KEY.ParameterListLength[0] = (UCHAR)(dataTransferLength >> (8*1));
cdb.SEND_KEY.ParameterListLength[1] = (UCHAR)(dataTransferLength >> (8*0));
cdb.SEND_KEY.AGID = (UCHAR)( input->SessionId );
cdb.SEND_KEY.KeyFormat = 0x01; // Send Host Challenge Certificate
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, FALSE, &cdb, 12);
#ifdef ENABLE_AACS_TESTING
status = STATUS_SUCCESS;
#endif
if (NT_SUCCESS(status))
{
*DataLength = 0;
}
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleAacsGetCertificate(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTL:
IOCTL_AACS_GET_CERTIFICATE
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
//AacsGetDriveCertificate
NTSTATUS status = STATUS_SUCCESS;
PDVD_SESSION_ID input = NULL;
PVOID outputBuffer = NULL;
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveInputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
(PVOID*)&input,
NULL);
if (NT_SUCCESS(status))
{
status = WdfRequestRetrieveOutputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
(PVOID*)&outputBuffer,
NULL);
}
if (NT_SUCCESS(status))
{
ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CERTIFICATE);
CDB cdb;
ScratchBuffer_BeginUse(DeviceExtension);
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY;
cdb.AsByte[7] = 0x02; // AACS key class
cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1));
cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0));
cdb.REPORT_KEY.AGID = (UCHAR)(*input);
cdb.REPORT_KEY.KeyFormat = 0x01; // Return a drive certificate challenge
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12);
#ifdef ENABLE_AACS_TESTING
static const UCHAR results[] = { 0x00, 0x72, 0x00, 0x00 };
static const UCHAR defaultFill = 0x31; // '1'
RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0074, defaultFill);
RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results));
status = STATUS_SUCCESS;
#endif
if (NT_SUCCESS(status))
{
PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer;
ULONG dataLengthToCopy = sizeof(AACS_CERTIFICATE);
// make length field native byte ordering
REVERSE_SHORT(&header->Length);
// exit if getting invalid data from the drive
if (header->Length < (sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length)))
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
if (NT_SUCCESS(status))
{
// adjust data length to reflect only the addition data
header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length);
// exit if the drive is returning an unexpected data size
if (header->Length != dataLengthToCopy)
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
}
if (NT_SUCCESS(status))
{
// else copy the data to the user's buffer
RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy);
*DataLength = dataLengthToCopy;
}
}
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleAacsGetChallengeKey(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTL:
IOCTL_AACS_GET_CHALLENGE_KEY
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
//AacsGetChallengeKey
NTSTATUS status = STATUS_SUCCESS;
PDVD_SESSION_ID input = NULL;
PVOID outputBuffer = NULL;
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveInputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
(PVOID*)&input,
NULL);
if (NT_SUCCESS(status))
{
status = WdfRequestRetrieveOutputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
(PVOID*)&outputBuffer,
NULL);
}
if (NT_SUCCESS(status))
{
ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CHALLENGE_KEY);
CDB cdb;
ScratchBuffer_BeginUse(DeviceExtension);
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY;
cdb.AsByte[7] = 0x02; // AACS key class
cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1));
cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0));
cdb.REPORT_KEY.AGID = (UCHAR)(*input);
cdb.REPORT_KEY.KeyFormat = 0x02; // Return a drive certificate challenge
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12);
#ifdef ENABLE_AACS_TESTING
static const UCHAR results[] = { 0x00, 0x52, 0x00, 0x00 };
static const UCHAR defaultFill = 0x32; // '2'
RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0054, defaultFill);
RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results));
status = STATUS_SUCCESS;
#endif
if (NT_SUCCESS(status))
{
PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer;
ULONG dataLengthToCopy = sizeof(AACS_CHALLENGE_KEY);
// make length field native byte ordering
REVERSE_SHORT(&header->Length);
// exit if getting invalid data from the drive
if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length))
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
if (NT_SUCCESS(status))
{
// adjust data length to reflect only the addition data
header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length);
// exit if the drive is returning an unexpected data size
if (header->Length != dataLengthToCopy)
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
}
if (NT_SUCCESS(status))
{
// else copy the data to the user's buffer
RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy);
*DataLength = dataLengthToCopy;
}
}
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleSendChallengeKey(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTL:
IOCTL_AACS_SEND_CHALLENGE_KEY
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
//AacsSendChallengeKey
NTSTATUS status = STATUS_SUCCESS;
PAACS_SEND_CHALLENGE_KEY input = NULL;
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveInputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
(PVOID*)&input,
NULL);
if (NT_SUCCESS(status))
{
ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_CHALLENGE_KEY);
CDB cdb;
ScratchBuffer_BeginUse(DeviceExtension);
// copy the input buffer to the data buffer for the transfer
{
PCDVD_KEY_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer;
ULONG tmp = dataTransferLength;
tmp -= RTL_SIZEOF_THROUGH_FIELD(CDVD_KEY_HEADER, DataLength);
header->DataLength[0] = (UCHAR)(tmp >> (8*1));
header->DataLength[1] = (UCHAR)(tmp >> (8*0));
RtlCopyMemory(header->Data, &(input->ChallengeKey), sizeof(AACS_CHALLENGE_KEY));
}
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
cdb.SEND_KEY.OperationCode = SCSIOP_SEND_KEY;
cdb.AsByte[7] = 0x02; // AACS key class
cdb.SEND_KEY.ParameterListLength[0] = (UCHAR)(dataTransferLength >> (8*1));
cdb.SEND_KEY.ParameterListLength[1] = (UCHAR)(dataTransferLength >> (8*0));
cdb.SEND_KEY.AGID = (UCHAR)( input->SessionId );
cdb.SEND_KEY.KeyFormat = 0x02; // Send Host Challenge Certificate
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, FALSE, &cdb, 12);
#ifdef ENABLE_AACS_TESTING
status = STATUS_SUCCESS;
#endif
if (NT_SUCCESS(status))
{
*DataLength = 0;
}
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleReadVolumeId(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTL:
IOCTL_AACS_READ_VOLUME_ID
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
//AacsReadVolumeID
NTSTATUS status = STATUS_SUCCESS;
PDVD_SESSION_ID input = NULL;
PVOID outputBuffer = NULL;
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveInputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
(PVOID*)&input,
NULL);
if (NT_SUCCESS(status))
{
status = WdfRequestRetrieveOutputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
(PVOID*)&outputBuffer,
NULL);
}
if (NT_SUCCESS(status))
{
ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_VOLUME_ID);
CDB cdb;
ScratchBuffer_BeginUse(DeviceExtension);
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE;
cdb.READ_DVD_STRUCTURE.Format = 0x80; // Return the AACS volumeID
cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1));
cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0));
cdb.READ_DVD_STRUCTURE.AGID = (UCHAR)(*input);
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12);
#ifdef ENABLE_AACS_TESTING
static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 };
static const UCHAR defaultFill = 0x33; // '3'
RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill);
RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results));
status = STATUS_SUCCESS;
#endif
if (NT_SUCCESS(status))
{
PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer;
ULONG dataLengthToCopy = sizeof(AACS_VOLUME_ID);
// make length field native byte ordering
REVERSE_SHORT(&header->Length);
// exit if getting invalid data from the drive
if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length))
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
if (NT_SUCCESS(status))
{
// adjust data length to reflect only the addition data
header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length);
// exit if the drive is returning an unexpected data size
if (header->Length != dataLengthToCopy)
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
}
if (NT_SUCCESS(status))
{
// else copy the data to the user's buffer
RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy);
*DataLength = dataLengthToCopy;
}
}
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleAacsReadSerialNumber(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTL:
IOCTL_AACS_READ_SERIAL_NUMBER
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
//AacsReadSerialNumber
NTSTATUS status = STATUS_SUCCESS;
PDVD_SESSION_ID input = NULL;
PVOID outputBuffer = NULL;
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveInputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
(PVOID*)&input,
NULL);
if (NT_SUCCESS(status))
{
status = WdfRequestRetrieveOutputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
(PVOID*)&outputBuffer,
NULL);
}
if (NT_SUCCESS(status))
{
ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_SERIAL_NUMBER);
CDB cdb;
ScratchBuffer_BeginUse(DeviceExtension);
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE;
cdb.READ_DVD_STRUCTURE.Format = 0x81; // Return the AACS volumeID
cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1));
cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0));
cdb.READ_DVD_STRUCTURE.AGID = (UCHAR)(*input);
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12);
#ifdef ENABLE_AACS_TESTING
static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 };
static const UCHAR defaultFill = 0x34; // '4'
RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill);
RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results));
status = STATUS_SUCCESS;
#endif
if (NT_SUCCESS(status))
{
PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer;
ULONG dataLengthToCopy = sizeof(AACS_SERIAL_NUMBER);
// make length field native byte ordering
REVERSE_SHORT(&header->Length);
// exit if getting invalid data from the drive
if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length))
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
if (NT_SUCCESS(status))
{
// adjust data length to reflect only the addition data
header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length);
// exit if the drive is returning an unexpected data size
if (header->Length != dataLengthToCopy)
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
}
if (NT_SUCCESS(status))
{
// else copy the data to the user's buffer
RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy);
*DataLength = dataLengthToCopy;
}
}
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleAacsReadMediaId(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTL:
IOCTL_AACS_READ_MEDIA_ID
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
//AacsReadMediaID
NTSTATUS status = STATUS_SUCCESS;
PDVD_SESSION_ID input = NULL;
PVOID outputBuffer = NULL;
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveInputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
(PVOID*)&input,
NULL);
if (NT_SUCCESS(status))
{
status = WdfRequestRetrieveOutputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
(PVOID*)&outputBuffer,
NULL);
}
if (NT_SUCCESS(status))
{
ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_MEDIA_ID);
CDB cdb;
ScratchBuffer_BeginUse(DeviceExtension);
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
cdb.READ_DVD_STRUCTURE.OperationCode = SCSIOP_READ_DVD_STRUCTURE;
cdb.READ_DVD_STRUCTURE.Format = 0x82; // Return the AACS volumeID
cdb.READ_DVD_STRUCTURE.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1));
cdb.READ_DVD_STRUCTURE.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0));
cdb.READ_DVD_STRUCTURE.AGID = (UCHAR)(*input);
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12);
#ifdef ENABLE_AACS_TESTING
static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 };
static const UCHAR defaultFill = 0x35; // '5'
RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill);
RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results));
status = STATUS_SUCCESS;
#endif
if (NT_SUCCESS(status))
{
PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer;
ULONG dataLengthToCopy = sizeof(AACS_MEDIA_ID);
// make length field native byte ordering
REVERSE_SHORT(&header->Length);
// exit if getting invalid data from the drive
if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length))
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
if (NT_SUCCESS(status))
{
// adjust data length to reflect only the addition data
header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length);
// exit if the drive is returning an unexpected data size
if (header->Length != dataLengthToCopy)
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
}
if (NT_SUCCESS(status))
{
// else copy the data to the user's buffer
RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy);
*DataLength = dataLengthToCopy;
}
}
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleAacsReadBindingNonce(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTL:
IOCTL_AACS_READ_BINDING_NONCE
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
//AacsReadBindingNonce
NTSTATUS status = STATUS_SUCCESS;
PAACS_READ_BINDING_NONCE input = NULL;
PVOID outputBuffer = NULL;
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveInputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
(PVOID*)&input,
NULL);
if (NT_SUCCESS(status))
{
status = WdfRequestRetrieveOutputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
(PVOID*)&outputBuffer,
NULL);
}
if (NT_SUCCESS(status))
{
ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_BINDING_NONCE);
CDB cdb;
ScratchBuffer_BeginUse(DeviceExtension);
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
cdb.REPORT_KEY.OperationCode = SCSIOP_REPORT_KEY;
cdb.REPORT_KEY.LogicalBlockAddress[0] = (UCHAR)( input->StartLba >> (3*8) );
cdb.REPORT_KEY.LogicalBlockAddress[1] = (UCHAR)( input->StartLba >> (2*8) );
cdb.REPORT_KEY.LogicalBlockAddress[2] = (UCHAR)( input->StartLba >> (1*8) );
cdb.REPORT_KEY.LogicalBlockAddress[3] = (UCHAR)( input->StartLba >> (0*8) );
cdb.AsByte[6] = (UCHAR)( input->NumberOfSectors );
cdb.AsByte[7] = 0x02; // AACS key class
cdb.REPORT_KEY.AllocationLength[0] = (UCHAR)(dataTransferLength >> (8*1));
cdb.REPORT_KEY.AllocationLength[1] = (UCHAR)(dataTransferLength >> (8*0));
cdb.REPORT_KEY.AGID = (UCHAR)( input->SessionId );
cdb.REPORT_KEY.KeyFormat = 0x21; // Return an existing binding nonce
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12);
#ifdef ENABLE_AACS_TESTING
static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 };
static const UCHAR defaultFill = 0x36; // '6'
RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill);
RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results));
status = STATUS_SUCCESS;
#endif
if (NT_SUCCESS(status))
{
PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer;
ULONG dataLengthToCopy = sizeof(AACS_BINDING_NONCE);
// make length field native byte ordering
REVERSE_SHORT(&header->Length);
// exit if getting invalid data from the drive
if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length))
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
if (NT_SUCCESS(status))
{
// adjust data length to reflect only the addition data
header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length);
// exit if the drive is returning an unexpected data size
if (header->Length != dataLengthToCopy)
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
}
if (NT_SUCCESS(status))
{
// else copy the data to the user's buffer
RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy);
*DataLength = dataLengthToCopy;
}
}
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}
_IRQL_requires_max_(APC_LEVEL)
NTSTATUS
DeviceHandleAacsGenerateBindingNonce(
_In_ PCDROM_DEVICE_EXTENSION DeviceExtension,
_In_ WDFREQUEST Request,
_In_ WDF_REQUEST_PARAMETERS RequestParameters,
_Out_ size_t * DataLength
)
/*++
Routine Description:
This routine is used to process IOCTL:
IOCTL_AACS_GENERATE_BINDING_NONCE
Arguments:
DeviceExtension - device context
Request - the request that will be formatted
RequestParameters - request parameter structur
DataLength - data transferred length
Return Value:
NTSTATUS
--*/
{
//AacsGenerateBindingNonce
NTSTATUS status = STATUS_SUCCESS;
PAACS_READ_BINDING_NONCE input = NULL;
PVOID outputBuffer = NULL;
PAGED_CODE();
*DataLength = 0;
status = WdfRequestRetrieveInputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.InputBufferLength,
(PVOID*)&input,
NULL);
if (NT_SUCCESS(status))
{
status = WdfRequestRetrieveOutputBuffer(Request,
RequestParameters.Parameters.DeviceIoControl.OutputBufferLength,
(PVOID*)&outputBuffer,
NULL);
}
if (NT_SUCCESS(status))
{
ULONG dataTransferLength = sizeof(CDVD_KEY_HEADER) + sizeof(AACS_BINDING_NONCE);
CDB cdb;
ScratchBuffer_BeginUse(DeviceExtension);
RtlZeroMemory(&cdb, sizeof(CDB));
// Set up the CDB
status = ScratchBuffer_ExecuteCdb(DeviceExtension, Request, dataTransferLength, TRUE, &cdb, 12);
#ifdef ENABLE_AACS_TESTING
static const UCHAR results[] = { 0x00, 0x22, 0x00, 0x00 };
static const UCHAR defaultFill = 0x37; // '7'
RtlFillMemory(DeviceExtension->ScratchContext.ScratchBuffer, 0x0024, defaultFill);
RtlCopyMemory(DeviceExtension->ScratchContext.ScratchBuffer, results, SIZEOF_ARRAY(results));
status = STATUS_SUCCESS;
#endif
if (NT_SUCCESS(status))
{
PDVD_DESCRIPTOR_HEADER header = DeviceExtension->ScratchContext.ScratchBuffer;
ULONG dataLengthToCopy = sizeof(AACS_BINDING_NONCE);
// make length field native byte ordering
REVERSE_SHORT(&header->Length);
// exit if getting invalid data from the drive
if (header->Length < sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length))
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
if (NT_SUCCESS(status))
{
// adjust data length to reflect only the addition data
header->Length -= sizeof(DVD_DESCRIPTOR_HEADER) - RTL_SIZEOF_THROUGH_FIELD(DVD_DESCRIPTOR_HEADER, Length);
// exit if the drive is returning an unexpected data size
if (header->Length != dataLengthToCopy)
{
*DataLength = 0;
status = STATUS_IO_DEVICE_ERROR;
}
}
if (NT_SUCCESS(status))
{
// else copy the data to the user's buffer
RtlCopyMemory(outputBuffer, header->Data, dataLengthToCopy);
*DataLength = dataLengthToCopy;
}
}
ScratchBuffer_EndUse(DeviceExtension);
}
return status;
}