mirror of
https://github.com/reactos/reactos.git
synced 2024-08-24 20:28:57 +00:00
1482 lines
51 KiB
C
1482 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;
|
|
}
|
|
|