/* * 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, s->readBuf + s->readBufOff, leftLen); s->readBufOff += leftLen; s->readBufLen -= leftLen; readBytes += leftLen; leftLen = 0; } else { memcpy(mediaBuf, 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; }