/* * 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; }