/*
* 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 <parser_rel.h>
#include <parser_dm.h>
#include <xml_tinyParser.h>
#include <wbxml_tinyparser.h>
#include <drm_decoder.h>
#include <svc_drm.h>
/* See parser_rel.h */
int32_t drm_monthDays(int32_t year, int32_t month)
{
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return 31;
case 4:
case 6:
case 9:
case 11:
return 30;
case 2:
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
return 29;
else
return 28;
default:
return -1;
}
}
int32_t drm_checkDate(int32_t year, int32_t month, int32_t day,
int32_t hour, int32_t min, int32_t sec)
{
if (month >= 1 && month <= 12 &&
day >= 1 && day <= drm_monthDays(year, month) &&
hour >= 0 && hour <= 23 &&
min >= 0 && min <= 59 && sec >= 0 && sec <= 59)
return 0;
else
return -1;
}
static int32_t drm_getStartEndTime(uint8_t * pValue, int32_t valueLen,
T_DRM_DATETIME * dateTime)
{
int32_t year, mon, day, hour, min, sec;
uint8_t pTmp[64] = {0};
strncpy((char *)pTmp, (char *)pValue, valueLen);
{
uint8_t * pHead = pTmp;
uint8_t * pEnd = NULL;
uint8_t tmpByte;
/** get year */
pEnd = (uint8_t *)strstr((char *)pHead, "-");
if(NULL == pEnd)
return FALSE;
tmpByte = *pEnd;
*pEnd = '\0';
year = atoi((char *)pHead);
pHead = pEnd + 1;
*pEnd = tmpByte;
/** get month */
pEnd = (uint8_t *)strstr((char *)pHead, "-");
if(NULL == pEnd)
return FALSE;
tmpByte = *pEnd;
*pEnd = '\0';
mon = atoi((char *)pHead);
pHead = pEnd + 1;
*pEnd = tmpByte;
/** get day */
pEnd = (uint8_t *)strstr((char *)pHead, "T");
if(NULL == pEnd)
return FALSE;
tmpByte = *pEnd;
*pEnd = '\0';
day = atoi((char *)pHead);
pHead = pEnd + 1;
*pEnd = tmpByte;
/** get hour */
pEnd = (uint8_t *)strstr((char *)pHead, ":");
if(NULL == pEnd)
return FALSE;
tmpByte = *pEnd;
*pEnd = '\0';
hour = atoi((char *)pHead);
pHead = pEnd + 1;
*pEnd = tmpByte;
/** get minute */
pEnd = (uint8_t *)strstr((char *)pHead, ":");
if(NULL == pEnd)
return FALSE;
tmpByte = *pEnd;
*pEnd = '\0';
min = atoi((char *)pHead);
pHead = pEnd + 1;
*pEnd = tmpByte;
/** get second */
sec = atoi((char *)pHead);
}
if (0 != drm_checkDate(year, mon, day, hour, min, sec))
return FALSE;
YMD_HMS_2_INT(year, mon, day, dateTime->date, hour, min, sec,
dateTime->time);
return TRUE;
}
static int32_t drm_checkWhetherHasUnknowConstraint(uint8_t* drm_constrain)
{
char* begin_constrain = "<o-ex:constraint>";
char* end_constrain = "</o-ex:constraint>";
char* constrain_begin = strstr((char*)drm_constrain,begin_constrain);
char* constrain_end = strstr((char*)drm_constrain,end_constrain);
uint32_t constrain_len = 0;
if(NULL == constrain_begin)
return FALSE;
if(NULL == constrain_end)
return TRUE;
/* compute valid characters length */
{
uint32_t constrain_begin_len = strlen(begin_constrain);
char* cur_pos = constrain_begin + constrain_begin_len;
constrain_len = (constrain_end - constrain_begin) - constrain_begin_len;
while(cur_pos < constrain_end){
if(isspace(*cur_pos))
constrain_len--;
cur_pos++;
}
}
/* check all constraints */
{
#define DRM_ALL_CONSTRAINT_COUNT 5
int32_t i = 0;
int32_t has_datetime = FALSE;
int32_t has_start_or_end = FALSE;
char* all_vaild_constraints[DRM_ALL_CONSTRAINT_COUNT][2] = {
{"<o-dd:count>","</o-dd:count>"},
{"<o-dd:interval>","</o-dd:interval>"},
{"<o-dd:datetime>","</o-dd:datetime>"},
{"<o-dd:start>","</o-dd:start>"},
{"<o-dd:end>","</o-dd:end>"}
};
for(i = 0; i < DRM_ALL_CONSTRAINT_COUNT; i++){
char*start = strstr((char*)drm_constrain,all_vaild_constraints[i][0]);
if(start && (start < constrain_end)){
char* end = strstr((char*)drm_constrain,all_vaild_constraints[i][1]);
if(end && (end < constrain_end)){
if(0 == strncmp(all_vaild_constraints[i][0],"<o-dd:datetime>",strlen("<o-dd:datetime>"))){
constrain_len -= strlen(all_vaild_constraints[i][0]);
constrain_len -= strlen(all_vaild_constraints[i][1]);
if(0 == constrain_len)
return TRUE;
has_datetime = TRUE;
continue;
}
if((0 == strncmp(all_vaild_constraints[i][0],"<o-dd:start>",strlen("<o-dd:start>")))
|| (0 == strncmp(all_vaild_constraints[i][0],"<o-dd:end>",strlen("<o-dd:end>")))){
if(FALSE == has_datetime)
return TRUE;
else
has_start_or_end = TRUE;
}
constrain_len -= (end - start);
constrain_len -= strlen(all_vaild_constraints[i][1]);
if(0 == constrain_len)
if(has_datetime != has_start_or_end)
return TRUE;
else
return FALSE;
}
else
return TRUE;
}
}
if(has_datetime != has_start_or_end)
return TRUE;
if(constrain_len)
return TRUE;
else
return FALSE;
}
}
static int32_t drm_getRightValue(uint8_t * buffer, int32_t bufferLen,
T_DRM_Rights * ro, uint8_t * operation,
uint8_t oper_char)
{
uint8_t *pBuf, *pValue;
uint8_t sProperty[256];
int32_t valueLen;
int32_t year, mon, day, hour, min, sec;
T_DRM_Rights_Constraint *pConstraint;
int32_t *bIsAble;
uint8_t *ret = NULL;
int32_t flag = 0;
if (operation == NULL) {
switch (oper_char) {
case REL_TAG_PLAY:
pConstraint = &(ro->PlayConstraint);
bIsAble = &(ro->bIsPlayable);
break;
case REL_TAG_DISPLAY:
pConstraint = &(ro->DisplayConstraint);
bIsAble = &(ro->bIsDisplayable);
break;
case REL_TAG_EXECUTE:
pConstraint = &(ro->ExecuteConstraint);
bIsAble = &(ro->bIsExecuteable);
break;
case REL_TAG_PRINT:
pConstraint = &(ro->PrintConstraint);
bIsAble = &(ro->bIsPrintable);
break;
default:
return FALSE; /* The input parm is err */
}
} else {
if (strcmp((char *)operation, "play") == 0) {
pConstraint = &(ro->PlayConstraint);
bIsAble = &(ro->bIsPlayable);
} else if (strcmp((char *)operation, "display") == 0) {
pConstraint = &(ro->DisplayConstraint);
bIsAble = &(ro->bIsDisplayable);
} else if (strcmp((char *)operation, "execute") == 0) {
pConstraint = &(ro->ExecuteConstraint);
bIsAble = &(ro->bIsExecuteable);
} else if (strcmp((char *)operation, "print") == 0) {
pConstraint = &(ro->PrintConstraint);
bIsAble = &(ro->bIsPrintable);
} else
return FALSE; /* The input parm is err */
}
if (operation == NULL) {
sprintf((char *)sProperty, "%c%c%c%c", REL_TAG_RIGHTS,
REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char);
ret = WBXML_DOM_getNode(buffer, bufferLen, sProperty);
} else {
sprintf((char *)sProperty,
"o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s",
operation);
ret = XML_DOM_getNode(buffer, sProperty);
}
CHECK_VALIDITY(ret);
if (NULL == ret)
return TRUE;
WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_NO_CONSTRAINT); /* If exit first assume have utter rights */
flag = 1;
if (operation == NULL) { /* If father element node is not exit then return */
sprintf((char *)sProperty, "%c%c%c%c%c", REL_TAG_RIGHTS,
REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char,
REL_TAG_CONSTRAINT);
ret = WBXML_DOM_getNode(buffer, bufferLen, sProperty);
} else {
sprintf((char *)sProperty,
"o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint",
operation);
ret = XML_DOM_getNode(buffer, sProperty);
}
CHECK_VALIDITY(ret);
if (ret == NULL)
return TRUE;
if(TRUE == drm_checkWhetherHasUnknowConstraint(ret))
return FALSE;
*bIsAble = 0;
pConstraint->Indicator = DRM_NO_PERMISSION; /* If exit constraint assume have no rights */
flag = 2;
if (operation == NULL) {
sprintf((char *)sProperty, "%c%c%c%c%c%c", REL_TAG_RIGHTS,
REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char,
REL_TAG_CONSTRAINT, REL_TAG_INTERVAL);
pBuf =
WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
&valueLen);
} else {
sprintf((char *)sProperty,
"o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:interval",
operation);
pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen);
}
CHECK_VALIDITY(pBuf);
if (pBuf) { /* If interval element exit then get the value */
uint8_t pTmp[64] = {0};
strncpy((char *)pTmp, (char *)pValue, valueLen);
{
uint8_t * pHead = pTmp + 1;
uint8_t * pEnd = NULL;
uint8_t tmpChar;
/** get year */
pEnd = (uint8_t *)strstr((char *)pHead, "Y");
if(NULL == pEnd)
return FALSE;
tmpChar = *pEnd;
*pEnd = '\0';
year = atoi((char *)pHead);
pHead = pEnd + 1;
*pEnd = tmpChar;
/** get month */
pEnd = (uint8_t *)strstr((char *)pHead, "M");
if(NULL == pEnd)
return FALSE;
tmpChar = *pEnd;
*pEnd = '\0';
mon = atoi((char *)pHead);
pHead = pEnd + 1;
*pEnd = tmpChar;
/** get day */
pEnd = (uint8_t *)strstr((char *)pHead, "D");
if(NULL == pEnd)
return FALSE;
tmpChar = *pEnd;
*pEnd = '\0';
day = atoi((char *)pHead);
pHead = pEnd + 2;
*pEnd = tmpChar;
/** get hour */
pEnd = (uint8_t *)strstr((char *)pHead, "H");
if(NULL == pEnd)
return FALSE;
tmpChar = *pEnd;
*pEnd = '\0';
hour = atoi((char *)pHead);
pHead = pEnd + 1;
*pEnd = tmpChar;
/** get minute */
pEnd = (uint8_t *)strstr((char *)pHead, "M");
if(NULL == pEnd)
return FALSE;
tmpChar = *pEnd;
*pEnd = '\0';
min = atoi((char *)pHead);
pHead = pEnd + 1;
*pEnd = tmpChar;
/** get second */
pEnd = (uint8_t *)strstr((char *)pHead, "S");
if(NULL == pEnd)
return FALSE;
tmpChar = *pEnd;
*pEnd = '\0';
sec = atoi((char *)pHead);
pHead = pEnd + 1;
*pEnd = tmpChar;
}
if (year < 0 || mon < 0 || day < 0 || hour < 0
|| min < 0 || sec < 0)
return FALSE;
YMD_HMS_2_INT(year, mon, day, pConstraint->Interval.date, hour,
min, sec, pConstraint->Interval.time);
WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator,
DRM_INTERVAL_CONSTRAINT);
flag = 3;
}
if (operation == NULL) {
sprintf((char *)sProperty, "%c%c%c%c%c%c", REL_TAG_RIGHTS,
REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char,
REL_TAG_CONSTRAINT, REL_TAG_COUNT);
pBuf =
WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
&valueLen);
} else {
sprintf((char *)sProperty,
"o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:count",
operation);
pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen);
}
CHECK_VALIDITY(pBuf);
if (pBuf) { /* If count element exit the get the value */
uint8_t pTmp[16] = {0};
int32_t i;
for (i = 0; i < valueLen; i++) { /* Check the count format */
if (0 == isdigit(*(pValue + i)))
return FALSE;
}
strncpy((char *)pTmp, (char *)pValue, valueLen);
pConstraint->Count = atoi((char *)pTmp);
if(0 == pConstraint->Count)
{
WRITE_RO_FLAG(*bIsAble, 0, pConstraint->Indicator, DRM_NO_PERMISSION);
}
else if( pConstraint->Count > 0)
{
WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_COUNT_CONSTRAINT);
}
else /* < 0 */
{
return FALSE;
}
flag = 3;
}
if (operation == NULL) {
sprintf((char *)sProperty, "%c%c%c%c%c%c%c", REL_TAG_RIGHTS,
REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char,
REL_TAG_CONSTRAINT, REL_TAG_DATETIME, REL_TAG_START);
pBuf =
WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
&valueLen);
} else {
sprintf((char *)sProperty,
"o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:datetime\\o-dd:start",
operation);
pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen);
}
CHECK_VALIDITY(pBuf);
if (pBuf) { /* If start element exit then get the value */
if (FALSE ==
drm_getStartEndTime(pValue, valueLen, &pConstraint->StartTime))
return FALSE;
WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_START_TIME_CONSTRAINT);
flag = 3;
}
if (operation == NULL) {
sprintf((char *)sProperty, "%c%c%c%c%c%c%c", REL_TAG_RIGHTS,
REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char,
REL_TAG_CONSTRAINT, REL_TAG_DATETIME, REL_TAG_END);
pBuf =
WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
&valueLen);
} else {
sprintf((char *)sProperty,
"o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:datetime\\o-dd:end",
operation);
pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen);
}
CHECK_VALIDITY(pBuf);
if (pBuf) {
if (FALSE ==
drm_getStartEndTime(pValue, valueLen, &pConstraint->EndTime))
return FALSE;
WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_END_TIME_CONSTRAINT);
flag = 3;
}
if (2 == flag)
WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_NO_CONSTRAINT); /* If exit first assume have utter rights */
return TRUE;
}
/* See parser_rel.h */
int32_t drm_relParser(uint8_t* buffer, int32_t bufferLen, int32_t Format, T_DRM_Rights* pRights)
{
uint8_t *pBuf, *pValue;
uint8_t sProperty[256];
int32_t valueLen;
if (TYPE_DRM_RIGHTS_WBXML != Format && TYPE_DRM_RIGHTS_XML != Format) /* It is not the support parse format */
return FALSE;
if (TYPE_DRM_RIGHTS_XML == Format) {
/* Check whether it is a CD, and parse it using TYPE_DRM_RIGHTS_XML */
if (NULL != drm_strnstr(buffer, (uint8_t *)HEADERS_CONTENT_ID, bufferLen))
return FALSE;
pBuf =
XML_DOM_getNodeValue(buffer,
(uint8_t *)"o-ex:rights\\o-ex:context\\o-dd:version",
&pValue, &valueLen);
CHECK_VALIDITY(pBuf);
if (pBuf) {
if (valueLen > 8) /* Check version lenth */
return FALSE;
/* error version */
if(strncmp(pValue,"1.0",valueLen))
return FALSE;
strncpy((char *)pRights->Version, (char *)pValue, valueLen);
} else
return FALSE;
/* this means there is more than one version label in rights */
if(strstr((char*)pBuf, "<o-dd:version>"))
return FALSE;
pBuf =
XML_DOM_getNodeValue(buffer,
(uint8_t *)"o-ex:rights\\o-ex:agreement\\o-ex:asset\\ds:KeyInfo\\ds:KeyValue",
&pValue, &valueLen);
CHECK_VALIDITY(pBuf);
if (pBuf) { /* Get keyvalue */
int32_t keyLen;
if (24 != valueLen)
return FALSE;
keyLen = drm_decodeBase64(NULL, 0, pValue, &valueLen);
if (keyLen < 0)
return FALSE;
if (DRM_KEY_LEN != drm_decodeBase64(pRights->KeyValue, keyLen, pValue, &valueLen))
return FALSE;
}
pBuf =
XML_DOM_getNodeValue(buffer,
(uint8_t *)"o-ex:rights\\o-ex:agreement\\o-ex:asset\\o-ex:context\\o-dd:uid",
&pValue, &valueLen);
CHECK_VALIDITY(pBuf);
if (pBuf) {
if (valueLen > DRM_UID_LEN)
return FALSE;
strncpy((char *)pRights->uid, (char *)pValue, valueLen);
pRights->uid[valueLen] = '\0';
} else
return FALSE;
/* this means there is more than one uid label in rights */
if(strstr((char*)pBuf, "<o-dd:uid>"))
return FALSE;
if (FALSE ==
drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"play", 0))
return FALSE;
if (FALSE ==
drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"display", 0))
return FALSE;
if (FALSE ==
drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"execute", 0))
return FALSE;
if (FALSE ==
drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"print", 0))
return FALSE;
} else if (TYPE_DRM_RIGHTS_WBXML == Format) {
if (!REL_CHECK_WBXML_HEADER(buffer))
return FALSE;
sprintf((char *)sProperty, "%c%c%c", REL_TAG_RIGHTS, REL_TAG_CONTEXT,
REL_TAG_VERSION);
pBuf =
WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
&valueLen);
CHECK_VALIDITY(pBuf);
if (pBuf) {
if (valueLen > 8) /* Check version lenth */
return FALSE;
strncpy((char *)pRights->Version, (char *)pValue, valueLen);
} else
return FALSE;
sprintf((char *)sProperty, "%c%c%c%c%c",
REL_TAG_RIGHTS, REL_TAG_AGREEMENT, REL_TAG_ASSET,
REL_TAG_KEYINFO, REL_TAG_KEYVALUE);
pBuf =
WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
&valueLen);
CHECK_VALIDITY(pBuf);
if (pBuf) {
if (DRM_KEY_LEN != valueLen)
return FALSE;
memcpy(pRights->KeyValue, pValue, DRM_KEY_LEN);
memset(pValue, 0, DRM_KEY_LEN); /* Clean the KeyValue */
}
sprintf((char *)sProperty, "%c%c%c%c%c",
REL_TAG_RIGHTS, REL_TAG_AGREEMENT, REL_TAG_ASSET,
REL_TAG_CONTEXT, REL_TAG_UID);
pBuf =
WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue,
&valueLen);
CHECK_VALIDITY(pBuf);
if (pBuf) {
if (valueLen > DRM_UID_LEN)
return FALSE;
strncpy((char *)pRights->uid, (char *)pValue, valueLen);
pRights->uid[valueLen] = '\0';
} else
return FALSE;
if (FALSE ==
drm_getRightValue(buffer, bufferLen, pRights, NULL,
REL_TAG_PLAY))
return FALSE;
if (FALSE ==
drm_getRightValue(buffer, bufferLen, pRights, NULL,
REL_TAG_DISPLAY))
return FALSE;
if (FALSE ==
drm_getRightValue(buffer, bufferLen, pRights, NULL,
REL_TAG_EXECUTE))
return FALSE;
if (FALSE ==
drm_getRightValue(buffer, bufferLen, pRights, NULL,
REL_TAG_PRINT))
return FALSE;
}
return TRUE;
}