blob: 232d9f44a1c3b6943063caecca4d21659aa228a5 [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <svc_drm.h>
#include <drm_inner.h>
#include <parser_dm.h>
#include <parser_dcf.h>
#include <parser_rel.h>
#include <drm_rights_manager.h>
#include <drm_time.h>
#include <drm_decoder.h>
#include "log.h"
/**
* Current id.
*/
static int32_t curID = 0;
/**
* The header pointer for the session list.
*/
static T_DRM_Session_Node* sessionTable = NULL;
/**
* New a session.
*/
static T_DRM_Session_Node* newSession(T_DRM_Input_Data data)
{
T_DRM_Session_Node* s = (T_DRM_Session_Node *)malloc(sizeof(T_DRM_Session_Node));
if (NULL != s) {
memset(s, 0, sizeof(T_DRM_Session_Node));
s->sessionId = curID++;
s->inputHandle = data.inputHandle;
s->mimeType = data.mimeType;
s->getInputDataLengthFunc = data.getInputDataLength;
s->readInputDataFunc = data.readInputData;
s->seekInputDataFunc = data.seekInputData;
}
return s;
}
/**
* Free a session.
*/
static void freeSession(T_DRM_Session_Node* s)
{
if (NULL == s)
return;
if (NULL != s->rawContent)
free(s->rawContent);
if (NULL != s->readBuf)
free(s->readBuf);
if (NULL != s->infoStruct)
free(s->infoStruct);
free(s);
}
/**
* Add a session to list.
*/
static int32_t addSession(T_DRM_Session_Node* s)
{
if (NULL == s)
return -1;
s->next = sessionTable;
sessionTable = s;
return s->sessionId;
}
/**
* Get a session from the list.
*/
static T_DRM_Session_Node* getSession(int32_t sessionId)
{
T_DRM_Session_Node* s;
if (sessionId < 0 || NULL == sessionTable)
return NULL;
for (s = sessionTable; s != NULL; s = s->next) {
if (sessionId == s->sessionId)
return s;
}
return NULL;
}
/**
* Remove a session from the list.
*/
static void removeSession(int32_t sessionId)
{
T_DRM_Session_Node *curS, *preS;
if (sessionId < 0 || NULL == sessionTable)
return;
if (sessionId == sessionTable->sessionId) {
curS = sessionTable;
sessionTable = curS->next;
freeSession(curS);
return;
}
for (preS = sessionTable; preS->next != NULL; preS = preS->next) {
if (preS->next->sessionId == sessionId)
curS = preS->next;
}
if (NULL == preS->next)
return;
preS->next = curS->next;
freeSession(curS);
}
/**
* Try to identify the mimetype according the input DRM data.
*/
static int32_t getMimeType(const uint8_t *buf, int32_t bufLen)
{
const uint8_t *p;
if (NULL == buf || bufLen <= 0)
return TYPE_DRM_UNKNOWN;
p = buf;
/* check if it is DRM Content Format, only check the first field of Version, it must be "0x01" */
if (0x01 == *p)
return TYPE_DRM_CONTENT;
/* check if it is DRM Message, only check the first two bytes, it must be the start flag of boundary: "--" */
if (bufLen >= 2 && '-' == *p && '-' == *(p + 1))
return TYPE_DRM_MESSAGE;
/* check if it is DRM Rights XML format, only check the first several bytes, it must be: "<o-ex:rights" */
if (bufLen >= 12 && 0 == strncmp("<o-ex:rights", (char *)p, 12))
return TYPE_DRM_RIGHTS_XML;
/* check if it is DRM Rights WBXML format, only check the first two bytes, it must be: 0x03, 0x0e */
if (bufLen >= 2 && 0x03 == *p && 0x0e == *(p + 1))
return TYPE_DRM_RIGHTS_WBXML;
return TYPE_DRM_UNKNOWN;
}
static int32_t drm_skipCRLFinB64(const uint8_t* b64Data, int32_t len)
{
const uint8_t* p;
int32_t skipLen = 0;
if (NULL == b64Data || len <= 0)
return -1;
p = b64Data;
while (p - b64Data < len) {
if ('\r' == *p || '\n'== *p)
skipLen++;
p++;
}
return skipLen;
}
static int32_t drm_scanEndBoundary(const uint8_t* pBuf, int32_t len, uint8_t* const boundary)
{
const uint8_t* p;
int32_t leftLen;
int32_t boundaryLen;
if (NULL == pBuf || len <=0 || NULL == boundary)
return -1;
p = pBuf;
boundaryLen = strlen((char *)boundary) + 2; /* 2 means: '\r' and '\n' */
leftLen = len - (p - pBuf);
while (leftLen > 0) {
if (NULL == (p = memchr(p, '\r', leftLen)))
break;
leftLen = len - (p - pBuf);
if (leftLen < boundaryLen)
return -2; /* here means may be the boundary has been split */
if (('\n' == *(p + 1)) && (0 == memcmp(p + 2, boundary, strlen((char *)boundary))))
return p - pBuf; /* find the boundary here */
p++;
leftLen--;
}
return len; /* no boundary found */
}
static int32_t drm_getLicenseInfo(T_DRM_Rights* pRights, T_DRM_Rights_Info* licenseInfo)
{
if (NULL != licenseInfo && NULL != pRights) {
strcpy((char *)licenseInfo->roId, (char *)pRights->uid);
if (1 == pRights->bIsDisplayable) {
licenseInfo->displayRights.indicator = pRights->DisplayConstraint.Indicator;
licenseInfo->displayRights.count =
pRights->DisplayConstraint.Count;
licenseInfo->displayRights.startDate =
pRights->DisplayConstraint.StartTime.date;
licenseInfo->displayRights.startTime =
pRights->DisplayConstraint.StartTime.time;
licenseInfo->displayRights.endDate =
pRights->DisplayConstraint.EndTime.date;
licenseInfo->displayRights.endTime =
pRights->DisplayConstraint.EndTime.time;
licenseInfo->displayRights.intervalDate =
pRights->DisplayConstraint.Interval.date;
licenseInfo->displayRights.intervalTime =
pRights->DisplayConstraint.Interval.time;
}
if (1 == pRights->bIsPlayable) {
licenseInfo->playRights.indicator = pRights->PlayConstraint.Indicator;
licenseInfo->playRights.count = pRights->PlayConstraint.Count;
licenseInfo->playRights.startDate =
pRights->PlayConstraint.StartTime.date;
licenseInfo->playRights.startTime =
pRights->PlayConstraint.StartTime.time;
licenseInfo->playRights.endDate =
pRights->PlayConstraint.EndTime.date;
licenseInfo->playRights.endTime =
pRights->PlayConstraint.EndTime.time;
licenseInfo->playRights.intervalDate =
pRights->PlayConstraint.Interval.date;
licenseInfo->playRights.intervalTime =
pRights->PlayConstraint.Interval.time;
}
if (1 == pRights->bIsExecuteable) {
licenseInfo->executeRights.indicator = pRights->ExecuteConstraint.Indicator;
licenseInfo->executeRights.count =
pRights->ExecuteConstraint.Count;
licenseInfo->executeRights.startDate =
pRights->ExecuteConstraint.StartTime.date;
licenseInfo->executeRights.startTime =
pRights->ExecuteConstraint.StartTime.time;
licenseInfo->executeRights.endDate =
pRights->ExecuteConstraint.EndTime.date;
licenseInfo->executeRights.endTime =
pRights->ExecuteConstraint.EndTime.time;
licenseInfo->executeRights.intervalDate =
pRights->ExecuteConstraint.Interval.date;
licenseInfo->executeRights.intervalTime =
pRights->ExecuteConstraint.Interval.time;
}
if (1 == pRights->bIsPrintable) {
licenseInfo->printRights.indicator = pRights->PrintConstraint.Indicator;
licenseInfo->printRights.count =
pRights->PrintConstraint.Count;
licenseInfo->printRights.startDate =
pRights->PrintConstraint.StartTime.date;
licenseInfo->printRights.startTime =
pRights->PrintConstraint.StartTime.time;
licenseInfo->printRights.endDate =
pRights->PrintConstraint.EndTime.date;
licenseInfo->printRights.endTime =
pRights->PrintConstraint.EndTime.time;
licenseInfo->printRights.intervalDate =
pRights->PrintConstraint.Interval.date;
licenseInfo->printRights.intervalTime =
pRights->PrintConstraint.Interval.time;
}
return TRUE;
}
return FALSE;
}
static int32_t drm_addRightsNodeToList(T_DRM_Rights_Info_Node **ppRightsHeader,
T_DRM_Rights_Info_Node *pInputRightsNode)
{
T_DRM_Rights_Info_Node *pRightsNode;
if (NULL == ppRightsHeader || NULL == pInputRightsNode)
return FALSE;
pRightsNode = (T_DRM_Rights_Info_Node *)malloc(sizeof(T_DRM_Rights_Info_Node));
if (NULL == pRightsNode)
return FALSE;
memcpy(pRightsNode, pInputRightsNode, sizeof(T_DRM_Rights_Info_Node));
pRightsNode->next = NULL;
/* this means it is the first node */
if (NULL == *ppRightsHeader)
*ppRightsHeader = pRightsNode;
else {
T_DRM_Rights_Info_Node *pTmp;
pTmp = *ppRightsHeader;
while (NULL != pTmp->next)
pTmp = pTmp->next;
pTmp->next = pRightsNode;
}
return TRUE;
}
static int32_t drm_startConsumeRights(int32_t * bIsXXable,
T_DRM_Rights_Constraint * XXConstraint,
int32_t * writeFlag)
{
T_DB_TIME_SysTime curDateTime;
T_DRM_DATETIME CurrentTime;
uint8_t countFlag = 0;
memset(&CurrentTime, 0, sizeof(T_DRM_DATETIME));
if (NULL == bIsXXable || 0 == *bIsXXable || NULL == XXConstraint || NULL == writeFlag)
return DRM_FAILURE;
if (0 != (uint8_t)(XXConstraint->Indicator & DRM_NO_CONSTRAINT)) /* Have utter right? */
return DRM_SUCCESS;
*bIsXXable = 0; /* Assume have invalid rights at first */
*writeFlag = 0;
if (0 != (XXConstraint->Indicator & (DRM_START_TIME_CONSTRAINT | DRM_END_TIME_CONSTRAINT | DRM_INTERVAL_CONSTRAINT))) {
DRM_time_getSysTime(&curDateTime);
if (-1 == drm_checkDate(curDateTime.year, curDateTime.month, curDateTime.day,
curDateTime.hour, curDateTime.min, curDateTime.sec))
return DRM_FAILURE;
YMD_HMS_2_INT(curDateTime.year, curDateTime.month, curDateTime.day,
CurrentTime.date, curDateTime.hour, curDateTime.min,
curDateTime.sec, CurrentTime.time);
}
if (0 != (uint8_t)(XXConstraint->Indicator & DRM_COUNT_CONSTRAINT)) { /* Have count restrict? */
*writeFlag = 1;
/* If it has only one time for use, after use this function, we will delete this rights */
if (XXConstraint->Count <= 0) {
XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT;
return DRM_RIGHTS_EXPIRED;
}
if (XXConstraint->Count-- <= 1) {
XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT;
countFlag = 1;
}
}
if (0 != (uint8_t)(XXConstraint->Indicator & DRM_START_TIME_CONSTRAINT)) {
if (XXConstraint->StartTime.date > CurrentTime.date ||
(XXConstraint->StartTime.date == CurrentTime.date &&
XXConstraint->StartTime.time >= CurrentTime.time)) {
*bIsXXable = 1;
return DRM_RIGHTS_PENDING;
}
}
if (0 != (uint8_t)(XXConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) { /* Have end time restrict? */
if (XXConstraint->EndTime.date < CurrentTime.date ||
(XXConstraint->EndTime.date == CurrentTime.date &&
XXConstraint->EndTime.time <= CurrentTime.time)) {
*writeFlag = 1;
XXConstraint->Indicator &= ~DRM_END_TIME_CONSTRAINT;
return DRM_RIGHTS_EXPIRED;
}
}
if (0 != (uint8_t)(XXConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) { /* Have interval time restrict? */
int32_t year, mon, day, hour, min, sec, date, time;
int32_t ret;
XXConstraint->Indicator |= DRM_END_TIME_CONSTRAINT;
XXConstraint->Indicator &= ~DRM_INTERVAL_CONSTRAINT; /* Write off interval right */
*writeFlag = 1;
if (XXConstraint->Interval.date == 0
&& XXConstraint->Interval.time == 0) {
return DRM_RIGHTS_EXPIRED;
}
date = CurrentTime.date + XXConstraint->Interval.date;
time = CurrentTime.time + XXConstraint->Interval.time;
INT_2_YMD_HMS(year, mon, day, date, hour, min, sec, time);
if (sec > 59) {
min += sec / 60;
sec %= 60;
}
if (min > 59) {
hour += min / 60;
min %= 60;
}
if (hour > 23) {
day += hour / 24;
hour %= 24;
}
if (day > 31) {
mon += day / 31;
day %= 31;
}
if (mon > 12) {
year += mon / 12;
mon %= 12;
}
if (day > (ret = drm_monthDays(year, mon))) {
day -= ret;
mon++;
if (mon > 12) {
mon -= 12;
year++;
}
}
YMD_HMS_2_INT(year, mon, day, XXConstraint->EndTime.date, hour,
min, sec, XXConstraint->EndTime.time);
}
if (1 != countFlag)
*bIsXXable = 1; /* Can go here ,so right must be valid */
return DRM_SUCCESS;
}
static int32_t drm_startCheckRights(int32_t * bIsXXable,
T_DRM_Rights_Constraint * XXConstraint)
{
T_DB_TIME_SysTime curDateTime;
T_DRM_DATETIME CurrentTime;
memset(&CurrentTime, 0, sizeof(T_DRM_DATETIME));
if (NULL == bIsXXable || 0 == *bIsXXable || NULL == XXConstraint)
return DRM_FAILURE;
if (0 != (uint8_t)(XXConstraint->Indicator & DRM_NO_CONSTRAINT)) /* Have utter right? */
return DRM_SUCCESS;
*bIsXXable = 0; /* Assume have invalid rights at first */
if (0 != (XXConstraint->Indicator & (DRM_START_TIME_CONSTRAINT | DRM_END_TIME_CONSTRAINT))) {
DRM_time_getSysTime(&curDateTime);
if (-1 == drm_checkDate(curDateTime.year, curDateTime.month, curDateTime.day,
curDateTime.hour, curDateTime.min, curDateTime.sec))
return DRM_FAILURE;
YMD_HMS_2_INT(curDateTime.year, curDateTime.month, curDateTime.day,
CurrentTime.date, curDateTime.hour, curDateTime.min,
curDateTime.sec, CurrentTime.time);
}
if (0 != (uint8_t)(XXConstraint->Indicator & DRM_COUNT_CONSTRAINT)) { /* Have count restrict? */
if (XXConstraint->Count <= 0) {
XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT;
return DRM_RIGHTS_EXPIRED;
}
}
if (0 != (uint8_t)(XXConstraint->Indicator & DRM_START_TIME_CONSTRAINT)) {
if (XXConstraint->StartTime.date > CurrentTime.date ||
(XXConstraint->StartTime.date == CurrentTime.date &&
XXConstraint->StartTime.time >= CurrentTime.time)) {
*bIsXXable = 1;
return DRM_RIGHTS_PENDING;
}
}
if (0 != (uint8_t)(XXConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) { /* Have end time restrict? */
if (XXConstraint->EndTime.date < CurrentTime.date ||
(XXConstraint->EndTime.date == CurrentTime.date &&
XXConstraint->EndTime.time <= CurrentTime.time)) {
XXConstraint->Indicator &= ~DRM_END_TIME_CONSTRAINT;
return DRM_RIGHTS_EXPIRED;
}
}
if (0 != (uint8_t)(XXConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) { /* Have interval time restrict? */
if (XXConstraint->Interval.date == 0 && XXConstraint->Interval.time == 0) {
XXConstraint->Indicator &= ~DRM_INTERVAL_CONSTRAINT;
return DRM_RIGHTS_EXPIRED;
}
}
*bIsXXable = 1;
return DRM_SUCCESS;
}
int32_t drm_checkRoAndUpdate(int32_t id, int32_t permission)
{
int32_t writeFlag = 0;
int32_t roAmount;
int32_t validRoAmount = 0;
int32_t flag = DRM_FAILURE;
int32_t i, j;
T_DRM_Rights *pRo;
T_DRM_Rights *pCurRo;
int32_t * pNumOfPriority;
int32_t iNum;
T_DRM_Rights_Constraint * pCurConstraint;
T_DRM_Rights_Constraint * pCompareConstraint;
int priority[8] = {1, 2, 4, 3, 8, 6, 7, 5};
if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT))
return DRM_FAILURE;
validRoAmount = roAmount;
if (roAmount < 1)
return DRM_NO_RIGHTS;
pRo = malloc(roAmount * sizeof(T_DRM_Rights));
pCurRo = pRo;
if (NULL == pRo)
return DRM_FAILURE;
if (FALSE == drm_writeOrReadInfo(id, pRo, &roAmount, GET_ALL_RO)) {
free(pRo);
return DRM_FAILURE;
}
/** check the right priority */
pNumOfPriority = malloc(sizeof(int32_t) * roAmount);
for(i = 0; i < roAmount; i++) {
iNum = roAmount - 1;
for(j = 0; j < roAmount; j++) {
if(i == j)
continue;
switch(permission) {
case DRM_PERMISSION_PLAY:
pCurConstraint = &pRo[i].PlayConstraint;
pCompareConstraint = &pRo[j].PlayConstraint;
break;
case DRM_PERMISSION_DISPLAY:
pCurConstraint = &pRo[i].DisplayConstraint;
pCompareConstraint = &pRo[j].DisplayConstraint;
break;
case DRM_PERMISSION_EXECUTE:
pCurConstraint = &pRo[i].ExecuteConstraint;
pCompareConstraint = &pRo[j].ExecuteConstraint;
break;
case DRM_PERMISSION_PRINT:
pCurConstraint = &pRo[i].PrintConstraint;
pCompareConstraint = &pRo[j].PrintConstraint;
break;
default:
free(pRo);
free(pNumOfPriority);
return DRM_FAILURE;
}
/**get priority by Indicator*/
if(0 == (pCurConstraint->Indicator & DRM_NO_CONSTRAINT) &&
0 == (pCompareConstraint->Indicator & DRM_NO_CONSTRAINT)) {
int num1, num2;
num1 = (pCurConstraint->Indicator & 0x0e) >> 1;
num2 = (pCompareConstraint->Indicator & 0x0e) >> 1;
if(priority[num1] > priority[num2]) {
iNum--;
continue;
} else if(priority[pCurConstraint->Indicator] < priority[pCompareConstraint->Indicator])
continue;
} else if(pCurConstraint->Indicator > pCompareConstraint->Indicator) {
iNum--;
continue;
} else if(pCurConstraint->Indicator < pCompareConstraint->Indicator)
continue;
if(0 != (pCurConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) {
if(pCurConstraint->EndTime.date < pCompareConstraint->EndTime.date) {
iNum--;
continue;
} else if(pCurConstraint->EndTime.date > pCompareConstraint->EndTime.date)
continue;
if(pCurConstraint->EndTime.time < pCompareConstraint->EndTime.time) {
iNum--;
continue;
} else if(pCurConstraint->EndTime.date > pCompareConstraint->EndTime.date)
continue;
}
if(0 != (pCurConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) {
if(pCurConstraint->Interval.date < pCompareConstraint->Interval.date) {
iNum--;
continue;
} else if(pCurConstraint->Interval.date > pCompareConstraint->Interval.date)
continue;
if(pCurConstraint->Interval.time < pCompareConstraint->Interval.time) {
iNum--;
continue;
} else if(pCurConstraint->Interval.time > pCompareConstraint->Interval.time)
continue;
}
if(0 != (pCurConstraint->Indicator & DRM_COUNT_CONSTRAINT)) {
if(pCurConstraint->Count < pCompareConstraint->Count) {
iNum--;
continue;
} else if(pCurConstraint->Count > pCompareConstraint->Count)
continue;
}
if(i < j)
iNum--;
}
pNumOfPriority[iNum] = i;
}
for (i = 0; i < validRoAmount; i++) {
/** check the right priority */
if (pNumOfPriority[i] >= validRoAmount)
break;
pCurRo = pRo + pNumOfPriority[i];
switch (permission) {
case DRM_PERMISSION_PLAY:
flag =
drm_startConsumeRights(&pCurRo->bIsPlayable,
&pCurRo->PlayConstraint, &writeFlag);
break;
case DRM_PERMISSION_DISPLAY:
flag =
drm_startConsumeRights(&pCurRo->bIsDisplayable,
&pCurRo->DisplayConstraint,
&writeFlag);
break;
case DRM_PERMISSION_EXECUTE:
flag =
drm_startConsumeRights(&pCurRo->bIsExecuteable,
&pCurRo->ExecuteConstraint,
&writeFlag);
break;
case DRM_PERMISSION_PRINT:
flag =
drm_startConsumeRights(&pCurRo->bIsPrintable,
&pCurRo->PrintConstraint, &writeFlag);
break;
default:
free(pNumOfPriority);
free(pRo);
return DRM_FAILURE;
}
/* Here confirm the valid RO amount and set the writeFlag */
if (0 == pCurRo->bIsPlayable && 0 == pCurRo->bIsDisplayable &&
0 == pCurRo->bIsExecuteable && 0 == pCurRo->bIsPrintable) {
int32_t iCurPri;
/** refresh the right priority */
iCurPri = pNumOfPriority[i];
for(j = i; j < validRoAmount - 1; j++)
pNumOfPriority[j] = pNumOfPriority[j + 1];
if(iCurPri != validRoAmount - 1) {
memcpy(pCurRo, pRo + validRoAmount - 1,
sizeof(T_DRM_Rights));
for(j = 0; j < validRoAmount -1; j++) {
if(validRoAmount - 1 == pNumOfPriority[j])
pNumOfPriority[j] = iCurPri;
}
}
/* Here means it is not the last one RO, so the invalid RO should be deleted */
writeFlag = 1;
validRoAmount--; /* If current right is invalid */
i--;
}
/* If the flag is TRUE, this means: we have found a valid RO, so break, no need to check other RO */
if (DRM_SUCCESS == flag)
break;
}
if (1 == writeFlag) {
/* Delete the *.info first */
//drm_removeIdInfoFile(id);
if (FALSE == drm_writeOrReadInfo(id, pRo, &validRoAmount, SAVE_ALL_RO))
flag = DRM_FAILURE;
}
free(pNumOfPriority);
free(pRo);
return flag;
}
/* see svc_drm.h */
int32_t SVC_drm_installRights(T_DRM_Input_Data data, T_DRM_Rights_Info* pRightsInfo)
{
uint8_t *buf;
int32_t dataLen, bufLen;
T_DRM_Rights rights;
if (0 == data.inputHandle)
return DRM_RIGHTS_DATA_INVALID;
/* Get input rights data length */
dataLen = data.getInputDataLength(data.inputHandle);
if (dataLen <= 0)
return DRM_RIGHTS_DATA_INVALID;
/* Check if the length is larger than DRM max malloc length */
if (dataLen > DRM_MAX_MALLOC_LEN)
bufLen = DRM_MAX_MALLOC_LEN;
else
bufLen = dataLen;
buf = (uint8_t *)malloc(bufLen);
if (NULL == buf)
return DRM_FAILURE;
/* Read input data to buffer */
if (0 >= data.readInputData(data.inputHandle, buf, bufLen)) {
free(buf);
return DRM_RIGHTS_DATA_INVALID;
}
/* if the input mime type is unknown, DRM engine will try to recognize it. */
if (TYPE_DRM_UNKNOWN == data.mimeType)
data.mimeType = getMimeType(buf, bufLen);
switch(data.mimeType) {
case TYPE_DRM_MESSAGE: /* in case of Combined Delivery, extract the rights part to install */
{
T_DRM_DM_Info dmInfo;
memset(&dmInfo, 0, sizeof(T_DRM_DM_Info));
if (FALSE == drm_parseDM(buf, bufLen, &dmInfo)) {
free(buf);
return DRM_RIGHTS_DATA_INVALID;
}
/* if it is not Combined Delivery, it can not use to "SVC_drm_installRights" */
if (COMBINED_DELIVERY != dmInfo.deliveryType || dmInfo.rightsOffset <= 0 || dmInfo.rightsLen <= 0) {
free(buf);
return DRM_RIGHTS_DATA_INVALID;
}
memset(&rights, 0, sizeof(T_DRM_Rights));
if (FALSE == drm_relParser(buf + dmInfo.rightsOffset, dmInfo.rightsLen, TYPE_DRM_RIGHTS_XML, &rights)) {
free(buf);
return DRM_RIGHTS_DATA_INVALID;
}
}
break;
case TYPE_DRM_RIGHTS_XML:
case TYPE_DRM_RIGHTS_WBXML:
memset(&rights, 0, sizeof(T_DRM_Rights));
if (FALSE == drm_relParser(buf, bufLen, data.mimeType, &rights)) {
free(buf);
return DRM_RIGHTS_DATA_INVALID;
}
break;
case TYPE_DRM_CONTENT: /* DCF should not using "SVC_drm_installRights", it should be used to open a session. */
case TYPE_DRM_UNKNOWN:
default:
free(buf);
return DRM_MEDIA_DATA_INVALID;
}
free(buf);
/* append the rights information to DRM engine storage */
if (FALSE == drm_appendRightsInfo(&rights))
return DRM_FAILURE;
memset(pRightsInfo, 0, sizeof(T_DRM_Rights_Info));
drm_getLicenseInfo(&rights, pRightsInfo);
return DRM_SUCCESS;
}
/* see svc_drm.h */
int32_t SVC_drm_openSession(T_DRM_Input_Data data)
{
int32_t session;
int32_t dataLen;
T_DRM_Session_Node* s;
if (0 == data.inputHandle)
return DRM_MEDIA_DATA_INVALID;
/* Get input data length */
dataLen = data.getInputDataLength(data.inputHandle);
if (dataLen <= 0)
return DRM_MEDIA_DATA_INVALID;
s = newSession(data);
if (NULL == s)
return DRM_FAILURE;
/* Check if the length is larger than DRM max malloc length */
if (dataLen > DRM_MAX_MALLOC_LEN)
s->rawContentLen = DRM_MAX_MALLOC_LEN;
else
s->rawContentLen = dataLen;
s->rawContent = (uint8_t *)malloc(s->rawContentLen);
if (NULL == s->rawContent)
return DRM_FAILURE;
/* Read input data to buffer */
if (0 >= data.readInputData(data.inputHandle, s->rawContent, s->rawContentLen)) {
freeSession(s);
return DRM_MEDIA_DATA_INVALID;
}
/* if the input mime type is unknown, DRM engine will try to recognize it. */
if (TYPE_DRM_UNKNOWN == data.mimeType)
data.mimeType = getMimeType(s->rawContent, s->rawContentLen);
switch(data.mimeType) {
case TYPE_DRM_MESSAGE:
{
T_DRM_DM_Info dmInfo;
memset(&dmInfo, 0, sizeof(T_DRM_DM_Info));
if (FALSE == drm_parseDM(s->rawContent, s->rawContentLen, &dmInfo)) {
freeSession(s);
return DRM_MEDIA_DATA_INVALID;
}
s->deliveryMethod = dmInfo.deliveryType;
if (SEPARATE_DELIVERY_FL == s->deliveryMethod)
s->contentLength = DRM_UNKNOWN_DATA_LEN;
else
s->contentLength = dmInfo.contentLen;
s->transferEncoding = dmInfo.transferEncoding;
s->contentOffset = dmInfo.contentOffset;
s->bEndData = FALSE;
strcpy((char *)s->contentType, (char *)dmInfo.contentType);
strcpy((char *)s->contentID, (char *)dmInfo.contentID);
if (SEPARATE_DELIVERY_FL == s->deliveryMethod) {
s->infoStruct = (T_DRM_Dcf_Node *)malloc(sizeof(T_DRM_Dcf_Node));
if (NULL == s->infoStruct)
return DRM_FAILURE;
memset(s->infoStruct, 0, sizeof(T_DRM_Dcf_Node));
((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength = dmInfo.contentLen;
strcpy((char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer, (char *)dmInfo.rightsIssuer);
break;
}
if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) {
s->infoStruct = (T_DRM_DM_Base64_Node *)malloc(sizeof(T_DRM_DM_Base64_Node));
if (NULL == s->infoStruct)
return DRM_FAILURE;
memset(s->infoStruct, 0, sizeof(T_DRM_DM_Base64_Node));
strcpy((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary, (char *)dmInfo.boundary);
} else {
s->infoStruct = (T_DRM_DM_Binary_Node *)malloc(sizeof(T_DRM_DM_Binary_Node));
if (NULL == s->infoStruct)
return DRM_FAILURE;
memset(s->infoStruct, 0, sizeof(T_DRM_DM_Binary_Node));
strcpy((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary, (char *)dmInfo.boundary);
}
if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) {
if (s->contentLength > 0) {
int32_t encLen, decLen;
encLen = s->contentLength;
decLen = encLen / DRM_B64_ENC_BLOCK * DRM_B64_DEC_BLOCK;
decLen = drm_decodeBase64(s->rawContent, decLen, s->rawContent + s->contentOffset, &encLen);
s->contentLength = decLen;
} else {
int32_t encLen = DRM_MAX_MALLOC_LEN - s->contentOffset, decLen;
int32_t skipLen, needBytes, i;
uint8_t *pStart;
int32_t res, bFoundBoundary = FALSE;
pStart = s->rawContent + s->contentOffset;
if (-1 == (skipLen = drm_skipCRLFinB64(pStart, encLen))) {
freeSession(s);
return DRM_FAILURE;
}
needBytes = DRM_B64_ENC_BLOCK - ((encLen - skipLen) % DRM_B64_ENC_BLOCK);
if (needBytes < DRM_B64_ENC_BLOCK) {
s->rawContent = (uint8_t *)realloc(s->rawContent, DRM_MAX_MALLOC_LEN + needBytes);
if (NULL == s->rawContent) {
freeSession(s);
return DRM_FAILURE;
}
i = 0;
while (i < needBytes) {
if (-1 != data.readInputData(data.inputHandle, s->rawContent + DRM_MAX_MALLOC_LEN + i, 1)) {
if ('\r' == *(s->rawContent + DRM_MAX_MALLOC_LEN + i) || '\n' == *(s->rawContent + DRM_MAX_MALLOC_LEN + i))
continue;
i++;
} else
break;
}
encLen += i;
}
res = drm_scanEndBoundary(pStart, encLen, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary);
if (-1 == res) {
freeSession(s);
return DRM_FAILURE;
}
if (-2 == res) { /* may be there is a boundary */
int32_t boundaryLen, leftLen, readBytes;
char* pTmp = memrchr(pStart, '\r', encLen);
if (NULL == pTmp) {
freeSession(s);
return DRM_FAILURE; /* conflict */
}
boundaryLen = strlen((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */
s->readBuf = (uint8_t *)malloc(boundaryLen);
if (NULL == s->readBuf) {
freeSession(s);
return DRM_FAILURE;
}
s->readBufOff = encLen - ((uint8_t *)pTmp - pStart);
s->readBufLen = boundaryLen - s->readBufOff;
memcpy(s->readBuf, pTmp, s->readBufOff);
readBytes = data.readInputData(data.inputHandle, s->readBuf + s->readBufOff, s->readBufLen);
if (-1 == readBytes || readBytes < s->readBufLen) {
freeSession(s);
return DRM_MEDIA_DATA_INVALID;
}
if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary)) {
encLen = (uint8_t *)pTmp - pStart; /* yes, it is the end boundary */
bFoundBoundary = TRUE;
}
} else {
if (res >= 0 && res < encLen) {
encLen = res;
bFoundBoundary = TRUE;
}
}
decLen = encLen / DRM_B64_ENC_BLOCK * DRM_B64_DEC_BLOCK;
decLen = drm_decodeBase64(s->rawContent, decLen, s->rawContent + s->contentOffset, &encLen);
((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen = decLen;
if (bFoundBoundary)
s->contentLength = decLen;
}
} else {
/* binary data */
if (DRM_UNKNOWN_DATA_LEN == s->contentLength) {
/* try to check whether there is boundary may be split */
int32_t res, binContentLen;
uint8_t* pStart;
int32_t bFoundBoundary = FALSE;
pStart = s->rawContent + s->contentOffset;
binContentLen = s->rawContentLen - s->contentOffset;
res = drm_scanEndBoundary(pStart, binContentLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary);
if (-1 == res) {
freeSession(s);
return DRM_FAILURE;
}
if (-2 == res) { /* may be the boundary is split */
int32_t boundaryLen, leftLen, readBytes;
char* pTmp = memrchr(pStart, '\r', binContentLen);
if (NULL == pTmp) {
freeSession(s);
return DRM_FAILURE; /* conflict */
}
boundaryLen = strlen((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */
s->readBuf = (uint8_t *)malloc(boundaryLen);
if (NULL == s->readBuf) {
freeSession(s);
return DRM_FAILURE;
}
s->readBufOff = binContentLen - ((uint8_t *)pTmp - pStart);
s->readBufLen = boundaryLen - s->readBufOff;
memcpy(s->readBuf, pTmp, s->readBufOff);
readBytes = data.readInputData(data.inputHandle, s->readBuf + s->readBufOff, s->readBufLen);
if (-1 == readBytes || readBytes < s->readBufLen) {
freeSession(s);
return DRM_MEDIA_DATA_INVALID;
}
if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary)) {
binContentLen = (uint8_t *)pTmp - pStart; /* yes, it is the end boundary */
bFoundBoundary = TRUE;
}
} else {
if (res >= 0 && res < binContentLen) {
binContentLen = res;
bFoundBoundary = TRUE;
}
}
if (bFoundBoundary)
s->contentLength = binContentLen;
}
}
}
break;
case TYPE_DRM_CONTENT:
{
T_DRM_DCF_Info dcfInfo;
uint8_t* pEncData = NULL;
memset(&dcfInfo, 0, sizeof(T_DRM_DCF_Info));
if (FALSE == drm_dcfParser(s->rawContent, s->rawContentLen, &dcfInfo, &pEncData)) {
freeSession(s);
return DRM_MEDIA_DATA_INVALID;
}
s->infoStruct = (T_DRM_Dcf_Node *)malloc(sizeof(T_DRM_Dcf_Node));
if (NULL == s->infoStruct)
return DRM_FAILURE;
memset(s->infoStruct, 0, sizeof(T_DRM_Dcf_Node));
s->deliveryMethod = SEPARATE_DELIVERY;
s->contentLength = dcfInfo.DecryptedDataLen;
((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength = dcfInfo.EncryptedDataLen;
s->contentOffset = pEncData - s->rawContent;
strcpy((char *)s->contentType, (char *)dcfInfo.ContentType);
strcpy((char *)s->contentID, (char *)dcfInfo.ContentURI);
strcpy((char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer, (char *)dcfInfo.Rights_Issuer);
}
break;
case TYPE_DRM_RIGHTS_XML: /* rights object should using "SVC_drm_installRights", it can not open a session */
case TYPE_DRM_RIGHTS_WBXML: /* rights object should using "SVC_drm_installRights", it can not open a session */
case TYPE_DRM_UNKNOWN:
default:
freeSession(s);
return DRM_MEDIA_DATA_INVALID;
}
if ((SEPARATE_DELIVERY_FL == s->deliveryMethod || SEPARATE_DELIVERY == s->deliveryMethod) &&
s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength <= DRM_MAX_MALLOC_LEN) {
uint8_t keyValue[DRM_KEY_LEN];
uint8_t lastDcfBuf[DRM_TWO_AES_BLOCK_LEN];
int32_t seekPos, moreBytes;
if (TRUE == drm_getKey(s->contentID, keyValue)) {
seekPos = s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN;
memcpy(lastDcfBuf, s->rawContent + seekPos, DRM_TWO_AES_BLOCK_LEN);
if (TRUE == drm_updateDcfDataLen(lastDcfBuf, keyValue, &moreBytes)) {
s->contentLength = ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength;
s->contentLength -= moreBytes;
}
}
}
session = addSession(s);
if (-1 == session)
return DRM_FAILURE;
return session;
}
/* see svc_drm.h */
int32_t SVC_drm_getDeliveryMethod(int32_t session)
{
T_DRM_Session_Node* s;
if (session < 0)
return DRM_FAILURE;
s = getSession(session);
if (NULL == s)
return DRM_SESSION_NOT_OPENED;
return s->deliveryMethod;
}
/* see svc_drm.h */
int32_t SVC_drm_getContentType(int32_t session, uint8_t* mediaType)
{
T_DRM_Session_Node* s;
if (session < 0 || NULL == mediaType)
return DRM_FAILURE;
s = getSession(session);
if (NULL == s)
return DRM_SESSION_NOT_OPENED;
strcpy((char *)mediaType, (char *)s->contentType);
return DRM_SUCCESS;
}
/* see svc_drm.h */
int32_t SVC_drm_checkRights(int32_t session, int32_t permission)
{
T_DRM_Session_Node* s;
int32_t id;
T_DRM_Rights *pRo, *pCurRo;
int32_t roAmount;
int32_t i;
int32_t res = DRM_FAILURE;
if (session < 0)
return DRM_FAILURE;
s = getSession(session);
if (NULL == s)
return DRM_SESSION_NOT_OPENED;
/* if it is Forward-Lock cases, check it and return directly */
if (FORWARD_LOCK == s->deliveryMethod) {
if (DRM_PERMISSION_PLAY == permission ||
DRM_PERMISSION_DISPLAY == permission ||
DRM_PERMISSION_EXECUTE == permission ||
DRM_PERMISSION_PRINT == permission)
return DRM_SUCCESS;
return DRM_FAILURE;
}
/* if try to forward, only DCF can be forwarded */
if (DRM_PERMISSION_FORWARD == permission) {
if (SEPARATE_DELIVERY == s->deliveryMethod)
return DRM_SUCCESS;
return DRM_FAILURE;
}
/* The following will check CD or SD other permissions */
if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID))
return DRM_FAILURE;
drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT);
if (roAmount <= 0)
return DRM_FAILURE;
pRo = malloc(roAmount * sizeof(T_DRM_Rights));
if (NULL == pRo)
return DRM_FAILURE;
drm_writeOrReadInfo(id, pRo, &roAmount, GET_ALL_RO);
pCurRo = pRo;
for (i = 0; i < roAmount; i++) {
switch (permission) {
case DRM_PERMISSION_PLAY:
res = drm_startCheckRights(&(pCurRo->bIsPlayable), &(pCurRo->PlayConstraint));
break;
case DRM_PERMISSION_DISPLAY:
res = drm_startCheckRights(&(pCurRo->bIsDisplayable), &(pCurRo->DisplayConstraint));
break;
case DRM_PERMISSION_EXECUTE:
res = drm_startCheckRights(&(pCurRo->bIsExecuteable), &(pCurRo->ExecuteConstraint));
break;
case DRM_PERMISSION_PRINT:
res = drm_startCheckRights(&(pCurRo->bIsPrintable), &(pCurRo->PrintConstraint));
break;
default:
free(pRo);
return DRM_FAILURE;
}
if (DRM_SUCCESS == res) {
free(pRo);
return DRM_SUCCESS;
}
pCurRo++;
}
free(pRo);
return res;
}
/* see svc_drm.h */
int32_t SVC_drm_consumeRights(int32_t session, int32_t permission)
{
T_DRM_Session_Node* s;
int32_t id;
if (session < 0)
return DRM_FAILURE;
s = getSession(session);
if (NULL == s)
return DRM_SESSION_NOT_OPENED;
if (DRM_PERMISSION_FORWARD == permission) {
if (SEPARATE_DELIVERY == s->deliveryMethod)
return DRM_SUCCESS;
return DRM_FAILURE;
}
if (FORWARD_LOCK == s->deliveryMethod) /* Forwardlock type have utter rights */
return DRM_SUCCESS;
if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID))
return DRM_FAILURE;
return drm_checkRoAndUpdate(id, permission);
}
/* see svc_drm.h */
int32_t SVC_drm_getContentLength(int32_t session)
{
T_DRM_Session_Node* s;
if (session < 0)
return DRM_FAILURE;
s = getSession(session);
if (NULL == s)
return DRM_SESSION_NOT_OPENED;
if (DRM_UNKNOWN_DATA_LEN == s->contentLength && s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength <= DRM_MAX_MALLOC_LEN &&
(SEPARATE_DELIVERY == s->deliveryMethod || SEPARATE_DELIVERY_FL == s->deliveryMethod)) {
uint8_t keyValue[DRM_KEY_LEN];
uint8_t lastDcfBuf[DRM_TWO_AES_BLOCK_LEN];
int32_t seekPos, moreBytes;
if (TRUE == drm_getKey(s->contentID, keyValue)) {
seekPos = s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN;
memcpy(lastDcfBuf, s->rawContent + seekPos, DRM_TWO_AES_BLOCK_LEN);
if (TRUE == drm_updateDcfDataLen(lastDcfBuf, keyValue, &moreBytes)) {
s->contentLength = ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength;
s->contentLength -= moreBytes;
}
}
}
return s->contentLength;
}
static int32_t drm_readAesData(uint8_t* buf, T_DRM_Session_Node* s, int32_t aesStart, int32_t bufLen)
{
if (NULL == buf || NULL == s || aesStart < 0 || bufLen < 0)
return -1;
if (aesStart - s->contentOffset + bufLen > ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength)
return -2;
if (aesStart < DRM_MAX_MALLOC_LEN) {
if (aesStart + bufLen <= DRM_MAX_MALLOC_LEN) { /* read from buffer */
memcpy(buf, s->rawContent + aesStart, bufLen);
return bufLen;
} else { /* first read from buffer and then from InputStream */
int32_t point = DRM_MAX_MALLOC_LEN - aesStart;
int32_t res;
if (((T_DRM_Dcf_Node *)(s->infoStruct))->bAesBackupBuf) {
memcpy(buf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, DRM_ONE_AES_BLOCK_LEN);
res = s->readInputDataFunc(s->inputHandle, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN);
if (0 == res || -1 == res)
return -1;
res += DRM_ONE_AES_BLOCK_LEN;
} else {
memcpy(buf, s->rawContent + aesStart, point);
res = s->readInputDataFunc(s->inputHandle, buf + point, bufLen - point);
if (0 == res || -1 == res)
return -1;
res += point;
}
memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN);
((T_DRM_Dcf_Node *)(s->infoStruct))->bAesBackupBuf = TRUE;
return res;
}
} else { /* read from InputStream */
int32_t res;
memcpy(buf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, DRM_ONE_AES_BLOCK_LEN);
res = s->readInputDataFunc(s->inputHandle, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN);
if (0 == res || -1 == res)
return -1;
memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN);
return DRM_ONE_AES_BLOCK_LEN + res;
}
}
static int32_t drm_readContentFromBuf(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
{
int32_t readBytes;
if (offset > s->contentLength)
return DRM_FAILURE;
if (offset == s->contentLength)
return DRM_MEDIA_EOF;
if (offset + mediaBufLen > s->contentLength)
readBytes = s->contentLength - offset;
else
readBytes = mediaBufLen;
if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding)
memcpy(mediaBuf, s->rawContent + offset, readBytes);
else
memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes);
return readBytes;
}
static int32_t drm_readB64ContentFromInputStream(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
{
uint8_t encBuf[DRM_B64_ENC_BLOCK], decBuf[DRM_B64_DEC_BLOCK];
int32_t encLen, decLen;
int32_t i, j, piece, leftLen, firstBytes;
int32_t readBytes = 0;
if (offset < ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen) {
readBytes = ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen - offset;
memcpy(mediaBuf, s->rawContent + offset, readBytes);
} else {
if (s->bEndData)
return DRM_MEDIA_EOF;
firstBytes = offset % DRM_B64_DEC_BLOCK;
if (firstBytes > 0) {
if (DRM_B64_DEC_BLOCK - firstBytes >= mediaBufLen) {
readBytes = mediaBufLen;
memcpy(mediaBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData + firstBytes, readBytes);
return readBytes;
}
readBytes = DRM_B64_DEC_BLOCK - firstBytes;
memcpy(mediaBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData + firstBytes, readBytes);
}
}
leftLen = mediaBufLen - readBytes;
encLen = (leftLen - 1) / DRM_B64_DEC_BLOCK * DRM_B64_ENC_BLOCK + DRM_B64_ENC_BLOCK;
piece = encLen / DRM_B64_ENC_BLOCK;
for (i = 0; i < piece; i++) {
j = 0;
while (j < DRM_B64_ENC_BLOCK) {
if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */
*(encBuf + j) = s->readBuf[s->readBufOff];
s->readBufOff++;
s->readBufLen--;
} else { /* read from InputStream */
if (0 == s->readInputDataFunc(s->inputHandle, encBuf + j, 1))
return DRM_MEDIA_DATA_INVALID;
}
if ('\r' == *(encBuf + j) || '\n' == *(encBuf + j))
continue; /* skip CRLF */
if ('-' == *(encBuf + j)) {
int32_t k, len;
/* invalid base64 data, it comes to end boundary */
if (0 != j)
return DRM_MEDIA_DATA_INVALID;
/* check whether it is really the boundary */
len = strlen((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary);
if (NULL == s->readBuf) {
s->readBuf = (uint8_t *)malloc(len);
if (NULL == s->readBuf)
return DRM_FAILURE;
}
s->readBuf[0] = '-';
for (k = 0; k < len - 1; k++) {
if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */
*(s->readBuf + k + 1) = s->readBuf[s->readBufOff];
s->readBufOff++;
s->readBufLen--;
} else { /* read from InputStream */
if (-1 == s->readInputDataFunc(s->inputHandle, s->readBuf + k + 1, 1))
return DRM_MEDIA_DATA_INVALID;
}
}
if (0 == memcmp(s->readBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary, len))
s->bEndData = TRUE;
else
return DRM_MEDIA_DATA_INVALID;
break;
}
j++;
}
if (TRUE == s->bEndData) { /* it means come to the end of base64 data */
if (0 == readBytes)
return DRM_MEDIA_EOF;
break;
}
encLen = DRM_B64_ENC_BLOCK;
decLen = DRM_B64_DEC_BLOCK;
if (-1 == (decLen = drm_decodeBase64(decBuf, decLen, encBuf, &encLen)))
return DRM_MEDIA_DATA_INVALID;
if (leftLen >= decLen) {
memcpy(mediaBuf + readBytes, decBuf, decLen);
readBytes += decLen;
leftLen -= decLen;
} else {
if (leftLen > 0) {
memcpy(mediaBuf + readBytes, decBuf, leftLen);
readBytes += leftLen;
}
break;
}
}
memcpy(((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData, decBuf, DRM_B64_DEC_BLOCK);
return readBytes;
}
static int32_t drm_readBase64Content(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
{
int32_t readBytes;
/* when the content length has been well-known */
if (s->contentLength >= 0)
readBytes = drm_readContentFromBuf(s, offset, mediaBuf, mediaBufLen);
else /* else when the content length has not been well-known yet */
if (offset < ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen)
if (offset + mediaBufLen <= ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen) {
readBytes = mediaBufLen;
memcpy(mediaBuf, s->rawContent + offset, readBytes);
} else
readBytes = drm_readB64ContentFromInputStream(s, offset, mediaBuf, mediaBufLen);
else
readBytes = drm_readB64ContentFromInputStream(s, offset, mediaBuf, mediaBufLen);
return readBytes;
}
static int32_t drm_readBinaryContentFromInputStream(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
{
int32_t res = 0, readBytes = 0;
int32_t leftLen;
if (s->contentOffset + offset < DRM_MAX_MALLOC_LEN) {
readBytes = DRM_MAX_MALLOC_LEN - s->contentOffset - offset;
memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes);
} else
if (s->bEndData)
return DRM_MEDIA_EOF;
leftLen = mediaBufLen - readBytes;
if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */
if (leftLen <= s->readBufLen) {
memcpy(mediaBuf + readBytes, s->readBuf + s->readBufOff, leftLen);
s->readBufOff += leftLen;
s->readBufLen -= leftLen;
readBytes += leftLen;
leftLen = 0;
} else {
memcpy(mediaBuf + readBytes, s->readBuf + s->readBufOff, s->readBufLen);
s->readBufOff += s->readBufLen;
leftLen -= s->readBufLen;
readBytes += s->readBufLen;
s->readBufLen = 0;
}
}
if (leftLen > 0) {
res = s->readInputDataFunc(s->inputHandle, mediaBuf + readBytes, mediaBufLen - readBytes);
if (-1 == res)
return DRM_MEDIA_DATA_INVALID;
}
readBytes += res;
res = drm_scanEndBoundary(mediaBuf, readBytes, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary);
if (-1 == res)
return DRM_MEDIA_DATA_INVALID;
if (-2 == res) { /* may be the boundary is split */
int32_t boundaryLen, len, off, k;
char* pTmp = memrchr(mediaBuf, '\r', readBytes);
if (NULL == pTmp)
return DRM_FAILURE; /* conflict */
boundaryLen = strlen((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */
if (NULL == s->readBuf) {
s->readBuf = (uint8_t *)malloc(boundaryLen);
if (NULL == s->readBuf)
return DRM_FAILURE;
}
off = readBytes - ((uint8_t *)pTmp - mediaBuf);
len = boundaryLen - off;
memcpy(s->readBuf, pTmp, off);
for (k = 0; k < boundaryLen - off; k++) {
if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */
*(s->readBuf + k + off) = s->readBuf[s->readBufOff];
s->readBufOff++;
s->readBufLen--;
} else { /* read from InputStream */
if (-1 == s->readInputDataFunc(s->inputHandle, s->readBuf + k + off, 1))
return DRM_MEDIA_DATA_INVALID;
}
}
s->readBufOff = off;
s->readBufLen = len;
if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary)) {
readBytes = (uint8_t *)pTmp - mediaBuf; /* yes, it is the end boundary */
s->bEndData = TRUE;
}
} else {
if (res >= 0 && res < readBytes) {
readBytes = res;
s->bEndData = TRUE;
}
}
if (s->bEndData) {
if (0 == readBytes)
return DRM_MEDIA_EOF;
}
return readBytes;
}
static int32_t drm_readBinaryContent(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
{
int32_t readBytes;
if (s->contentLength >= 0)
readBytes = drm_readContentFromBuf(s, offset, mediaBuf, mediaBufLen);
else /* else when the content length has not been well-known yet */
if (s->contentOffset + offset < DRM_MAX_MALLOC_LEN)
if (s->contentOffset + offset + mediaBufLen <= DRM_MAX_MALLOC_LEN) {
readBytes = mediaBufLen;
memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes);
} else
readBytes = drm_readBinaryContentFromInputStream(s, offset, mediaBuf, mediaBufLen);
else
readBytes = drm_readBinaryContentFromInputStream(s, offset, mediaBuf, mediaBufLen);
return readBytes;
}
static int32_t drm_readAesContent(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
{
uint8_t keyValue[DRM_KEY_LEN];
uint8_t buf[DRM_TWO_AES_BLOCK_LEN];
int32_t readBytes = 0;
int32_t bufLen, piece, i, copyBytes, leftBytes;
int32_t aesStart, mediaStart, mediaBufOff;
AES_KEY key;
if (FALSE == drm_getKey(s->contentID, keyValue))
return DRM_NO_RIGHTS;
/* when the content length has been well-known */
if (s->contentLength > 0) {
if (offset > s->contentLength)
return DRM_FAILURE;
if (offset == s->contentLength)
return DRM_MEDIA_EOF;
if (offset + mediaBufLen > s->contentLength)
readBytes = s->contentLength - offset;
else
readBytes = mediaBufLen;
aesStart = s->contentOffset + (offset / DRM_ONE_AES_BLOCK_LEN * DRM_ONE_AES_BLOCK_LEN);
piece = (offset + readBytes - 1) / DRM_ONE_AES_BLOCK_LEN - offset / DRM_ONE_AES_BLOCK_LEN + 2;
mediaStart = offset % DRM_ONE_AES_BLOCK_LEN;
AES_set_decrypt_key(keyValue, DRM_KEY_LEN * 8, &key);
mediaBufOff = 0;
leftBytes = readBytes;
for (i = 0; i < piece - 1; i++) {
memcpy(buf, s->rawContent + aesStart + i * DRM_ONE_AES_BLOCK_LEN, DRM_TWO_AES_BLOCK_LEN);
bufLen = DRM_TWO_AES_BLOCK_LEN;
if (drm_aesDecBuffer(buf, &bufLen, &key) < 0)
return DRM_MEDIA_DATA_INVALID;
if (0 != i)
mediaStart = 0;
if (bufLen - mediaStart <= leftBytes)
copyBytes = bufLen - mediaStart;
else
copyBytes = leftBytes;
memcpy(mediaBuf + mediaBufOff, buf + mediaStart, copyBytes);
leftBytes -= copyBytes;
mediaBufOff += copyBytes;
}
} else {
int32_t res;
if (s->bEndData)
return DRM_MEDIA_EOF;
if (((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen > ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff) {
if (mediaBufLen < ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen - ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff)
copyBytes = mediaBufLen;
else
copyBytes = ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen - ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff;
memcpy(mediaBuf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecData + ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff, copyBytes);
((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff += copyBytes;
readBytes += copyBytes;
}
leftBytes = mediaBufLen - readBytes;
if (0 == leftBytes)
return readBytes;
if (leftBytes < 0)
return DRM_FAILURE;
offset += readBytes;
aesStart = s->contentOffset + (offset / DRM_ONE_AES_BLOCK_LEN * DRM_ONE_AES_BLOCK_LEN);
piece = (offset + leftBytes - 1) / DRM_ONE_AES_BLOCK_LEN - offset / DRM_ONE_AES_BLOCK_LEN + 2;
mediaBufOff = readBytes;
AES_set_decrypt_key(keyValue, DRM_KEY_LEN * 8, &key);
for (i = 0; i < piece - 1; i++) {
if (-1 == (res = drm_readAesData(buf, s, aesStart, DRM_TWO_AES_BLOCK_LEN)))
return DRM_MEDIA_DATA_INVALID;
if (-2 == res)
break;
bufLen = DRM_TWO_AES_BLOCK_LEN;
aesStart += DRM_ONE_AES_BLOCK_LEN;
if (drm_aesDecBuffer(buf, &bufLen, &key) < 0)
return DRM_MEDIA_DATA_INVALID;
drm_discardPaddingByte(buf, &bufLen);
if (bufLen <= leftBytes)
copyBytes = bufLen;
else
copyBytes = leftBytes;
memcpy(mediaBuf + mediaBufOff, buf, copyBytes);
leftBytes -= copyBytes;
mediaBufOff += copyBytes;
readBytes += copyBytes;
}
memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecData, buf, DRM_ONE_AES_BLOCK_LEN);
((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen = bufLen;
((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff = copyBytes;
if (aesStart - s->contentOffset > ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN && ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff == ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen) {
s->bEndData = TRUE;
if (0 == readBytes)
return DRM_MEDIA_EOF;
}
}
return readBytes;
}
/* see svc_drm.h */
int32_t SVC_drm_getContent(int32_t session, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen)
{
T_DRM_Session_Node* s;
int32_t readBytes;
if (session < 0 || offset < 0 || NULL == mediaBuf || mediaBufLen <= 0)
return DRM_FAILURE;
s = getSession(session);
if (NULL == s)
return DRM_SESSION_NOT_OPENED;
if (0 >= s->getInputDataLengthFunc(s->inputHandle))
return DRM_MEDIA_DATA_INVALID;
switch(s->deliveryMethod) {
case FORWARD_LOCK:
case COMBINED_DELIVERY:
if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding)
readBytes = drm_readBase64Content(s, offset, mediaBuf, mediaBufLen);
else /* binary */
readBytes = drm_readBinaryContent(s, offset, mediaBuf, mediaBufLen);
break;
case SEPARATE_DELIVERY:
case SEPARATE_DELIVERY_FL:
readBytes = drm_readAesContent(s, offset, mediaBuf, mediaBufLen);
break;
default:
return DRM_FAILURE;
}
return readBytes;
}
/* see svc_drm.h */
int32_t SVC_drm_getRightsIssuer(int32_t session, uint8_t* rightsIssuer)
{
T_DRM_Session_Node* s;
if (session < 0 || NULL == rightsIssuer)
return DRM_FAILURE;
s = getSession(session);
if (NULL == s)
return DRM_SESSION_NOT_OPENED;
if (SEPARATE_DELIVERY == s->deliveryMethod || SEPARATE_DELIVERY_FL == s->deliveryMethod) {
strcpy((char *)rightsIssuer, (char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer);
return DRM_SUCCESS;
}
return DRM_NOT_SD_METHOD;
}
/* see svc_drm.h */
int32_t SVC_drm_getRightsInfo(int32_t session, T_DRM_Rights_Info* rights)
{
T_DRM_Session_Node* s;
T_DRM_Rights rightsInfo;
int32_t roAmount, id;
if (session < 0 || NULL == rights)
return DRM_FAILURE;
s = getSession(session);
if (NULL == s)
return DRM_SESSION_NOT_OPENED;
if (FORWARD_LOCK == s->deliveryMethod) {
strcpy((char *)rights->roId, "ForwardLock");
rights->displayRights.indicator = DRM_NO_CONSTRAINT;
rights->playRights.indicator = DRM_NO_CONSTRAINT;
rights->executeRights.indicator = DRM_NO_CONSTRAINT;
rights->printRights.indicator = DRM_NO_CONSTRAINT;
return DRM_SUCCESS;
}
if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID))
return DRM_NO_RIGHTS;
if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT))
return DRM_FAILURE;
if (roAmount < 0)
return DRM_NO_RIGHTS;
/* some rights has been installed, but now there is no valid rights */
if (0 == roAmount) {
strcpy((char *)rights->roId, s->contentID);
rights->displayRights.indicator = DRM_NO_PERMISSION;
rights->playRights.indicator = DRM_NO_PERMISSION;
rights->executeRights.indicator = DRM_NO_PERMISSION;
rights->printRights.indicator = DRM_NO_PERMISSION;
return DRM_SUCCESS;
}
roAmount = 1;
memset(&rightsInfo, 0, sizeof(T_DRM_Rights));
if (FALSE == drm_writeOrReadInfo(id, &rightsInfo, &roAmount, GET_A_RO))
return DRM_FAILURE;
memset(rights, 0, sizeof(T_DRM_Rights_Info));
drm_getLicenseInfo(&rightsInfo, rights);
return DRM_SUCCESS;
}
/* see svc_drm.h */
int32_t SVC_drm_closeSession(int32_t session)
{
if (session < 0)
return DRM_FAILURE;
if (NULL == getSession(session))
return DRM_SESSION_NOT_OPENED;
removeSession(session);
return DRM_SUCCESS;
}
/* see svc_drm.h */
int32_t SVC_drm_updateRights(uint8_t* contentID, int32_t permission)
{
int32_t id;
if (NULL == contentID)
return DRM_FAILURE;
if (FALSE == drm_readFromUidTxt(contentID, &id, GET_ID))
return DRM_FAILURE;
return drm_checkRoAndUpdate(id, permission);
}
/* see svc_drm.h */
int32_t SVC_drm_viewAllRights(T_DRM_Rights_Info_Node **ppRightsInfo)
{
T_DRM_Rights_Info_Node rightsNode;
int32_t maxId, id, roAmount, j;
T_DRM_Rights rights;
memset(&rights, 0, sizeof(T_DRM_Rights));
if (NULL == ppRightsInfo)
return DRM_FAILURE;
*ppRightsInfo = NULL;
maxId = drm_getMaxIdFromUidTxt();
if (-1 == maxId)
return DRM_FAILURE;
for (id = 1; id <= maxId; id++) {
drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT);
if (roAmount <= 0) /* this means there is not any rights */
continue;
for (j = 1; j <= roAmount; j++) {
if (FALSE == drm_writeOrReadInfo(id, &rights, &j, GET_A_RO))
continue;
memset(&rightsNode, 0, sizeof(T_DRM_Rights_Info_Node));
drm_getLicenseInfo(&rights, &(rightsNode.roInfo));
if (FALSE == drm_addRightsNodeToList(ppRightsInfo, &rightsNode))
continue;
}
}
return DRM_SUCCESS;
}
/* see svc_drm.h */
int32_t SVC_drm_freeRightsInfoList(T_DRM_Rights_Info_Node *pRightsHeader)
{
T_DRM_Rights_Info_Node *pNode, *pTmp;
if (NULL == pRightsHeader)
return DRM_FAILURE;
pNode = pRightsHeader;
while (NULL != pNode) {
pTmp = pNode;
pNode = pNode->next;
free(pTmp);
}
return DRM_SUCCESS;
}
/* see svc_drm.h */
int32_t SVC_drm_deleteRights(uint8_t* roId)
{
int32_t maxId, id, roAmount, j;
T_DRM_Rights rights;
memset(&rights, 0, sizeof(T_DRM_Rights));
if (NULL == roId)
return DRM_FAILURE;
maxId = drm_getMaxIdFromUidTxt();
if (-1 == maxId)
return DRM_NO_RIGHTS;
for (id = 1; id <= maxId; id++) {
drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT);
if (roAmount <= 0) /* this means there is not any rights */
continue;
for (j = 1; j <= roAmount; j++) {
if (FALSE == drm_writeOrReadInfo(id, &rights, &j, GET_A_RO))
continue;
/* here find the RO which will be deleted */
if (0 == strcmp((char *)rights.uid, (char *)roId)) {
T_DRM_Rights *pAllRights;
pAllRights = (T_DRM_Rights *)malloc(roAmount * sizeof(T_DRM_Rights));
if (NULL == pAllRights)
return DRM_FAILURE;
drm_writeOrReadInfo(id, pAllRights, &roAmount, GET_ALL_RO);
roAmount--;
if (0 == roAmount) { /* this means it is the last one rights */
drm_removeIdInfoFile(id); /* delete the id.info file first */
drm_updateUidTxtWhenDelete(id); /* update uid.txt file */
free(pAllRights);
return DRM_SUCCESS;
} else /* using the last one rights instead of the deleted one */
memcpy(pAllRights + (j - 1), pAllRights + roAmount, sizeof(T_DRM_Rights));
/* delete the id.info file first */
// drm_removeIdInfoFile(id);
if (FALSE == drm_writeOrReadInfo(id, pAllRights, &roAmount, SAVE_ALL_RO)) {
free(pAllRights);
return DRM_FAILURE;
}
free(pAllRights);
return DRM_SUCCESS;
}
}
}
return DRM_FAILURE;
}