1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <parser_dm.h> 18#include <parser_dcf.h> 19#include <svc_drm.h> 20#include "log.h" 21 22#define DRM_SKIP_SPACE_TAB(p) while( (*(p) == ' ') || (*(p) == '\t') ) \ 23 p++ 24 25typedef enum _DM_PARSE_STATUS { 26 DM_PARSE_START, 27 DM_PARSING_RIGHTS, 28 DM_PARSING_CONTENT, 29 DM_PARSE_END 30} DM_PARSE_STATUS; 31 32static int drm_strnicmp(const uint8_t* s1, const uint8_t* s2, int32_t n) 33{ 34 if (n < 0 || NULL == s1 || NULL == s2) 35 return -1; 36 37 if (n == 0) 38 return 0; 39 40 while (n-- != 0 && tolower(*s1) == tolower(*s2)) 41 { 42 if (n == 0 || *s1 == '\0' || *s2 == '\0') 43 break; 44 s1++; 45 s2++; 46 } 47 48 return tolower(*s1) - tolower(*s2); 49} 50 51const uint8_t * drm_strnstr(const uint8_t * str, const uint8_t * strSearch, int32_t len) 52{ 53 int32_t i, stringLen; 54 55 if (NULL == str || NULL == strSearch || len <= 0) 56 return NULL; 57 58 stringLen = strlen((char *)strSearch); 59 for (i = 0; i < len - stringLen + 1; i++) { 60 if (str[i] == *strSearch && 0 == memcmp(str + i, strSearch, stringLen)) 61 return str + i; 62 } 63 return NULL; 64} 65 66/* See parser_dm.h */ 67int32_t drm_parseDM(const uint8_t *buffer, int32_t bufferLen, T_DRM_DM_Info *pDmInfo) 68{ 69 const uint8_t *pStart = NULL, *pEnd = NULL; 70 const uint8_t *pBufferEnd; 71 int32_t contentLen, leftLen; 72 DM_PARSE_STATUS status = DM_PARSE_START; 73 int32_t boundaryLen; 74 75 if (NULL == buffer || bufferLen <= 0 || NULL == pDmInfo) 76 return FALSE; 77 78 /* Find the end of the input buffer */ 79 pBufferEnd = buffer + bufferLen; 80 leftLen = bufferLen; 81 82 /* Find out the boundary */ 83 pStart = drm_strnstr(buffer, (uint8_t *)"--", bufferLen); 84 if (NULL == pStart) 85 return FALSE; /* No boundary error */ 86 pEnd = pStart; 87 88 /* Record the boundary */ 89 pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen); 90 /* if can not find the CRLF, return FALSE */ 91 if (NULL == pEnd) 92 return FALSE; 93 strncpy((char *)pDmInfo->boundary, (char *)pStart, pEnd - pStart); 94 boundaryLen = strlen((char *)pDmInfo->boundary) + 2; /* 2 means: '\r' and '\n' */ 95 96 pEnd += 2; /* skip the '\r' and '\n' */ 97 pStart = pEnd; 98 leftLen = pBufferEnd - pStart; 99 do { 100 pDmInfo->transferEncoding = DRM_MESSAGE_CODING_7BIT; /* According RFC2045 chapter 6.1, the default value should be 7bit.*/ 101 strcpy((char *)pDmInfo->contentType, "text/plain"); /* According RFC2045 chapter 5.2, the default value should be "text/plain". */ 102 103 /* Deal the header information */ 104 while ((('\r' != *pStart) || ('\n' != *(pStart + 1))) && pStart < pBufferEnd) { 105 pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen); 106 if (NULL == pEnd) 107 return FALSE; 108 109 if (0 != pDmInfo->deliveryType) { /* This means the delivery type has been confirmed */ 110 if (0 == strncmp((char *)pStart, HEADERS_TRANSFER_CODING, HEADERS_TRANSFER_CODING_LEN)) { 111 pStart += HEADERS_TRANSFER_CODING_LEN; 112 DRM_SKIP_SPACE_TAB(pStart); 113 114 if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_7BIT, pEnd - pStart)) 115 pDmInfo->transferEncoding = DRM_MESSAGE_CODING_7BIT; 116 else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_8BIT, pEnd - pStart)) 117 pDmInfo->transferEncoding = DRM_MESSAGE_CODING_8BIT; 118 else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_BINARY, pEnd - pStart)) 119 pDmInfo->transferEncoding = DRM_MESSAGE_CODING_BINARY; 120 else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_BASE64, pEnd - pStart)) 121 pDmInfo->transferEncoding = DRM_MESSAGE_CODING_BASE64; 122 else 123 return FALSE; /* Unknown transferCoding error */ 124 } else if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_TYPE, HEADERS_CONTENT_TYPE_LEN)) { 125 pStart += HEADERS_CONTENT_TYPE_LEN; 126 DRM_SKIP_SPACE_TAB(pStart); 127 128 if (pEnd - pStart > 0) { 129 strncpy((char *)pDmInfo->contentType, (char *)pStart, pEnd - pStart); 130 pDmInfo->contentType[pEnd - pStart] = '\0'; 131 } 132 } else if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_ID, HEADERS_CONTENT_ID_LEN)) { 133 uint8_t tmpBuf[MAX_CONTENT_ID] = {0}; 134 uint8_t *pTmp; 135 136 pStart += HEADERS_CONTENT_ID_LEN; 137 DRM_SKIP_SPACE_TAB(pStart); 138 139 /* error: more than one content id */ 140 if(drm_strnstr(pStart, (uint8_t*)HEADERS_CONTENT_ID, pBufferEnd - pStart)){ 141 LOGD("drm_dmParser: error: more than one content id\r\n"); 142 return FALSE; 143 } 144 145 status = DM_PARSING_CONTENT; /* can go here means that the rights object has been parsed. */ 146 147 /* Change the format from <...> to cid:... */ 148 if (NULL != (pTmp = (uint8_t *)memchr((char *)pStart, '<', pEnd - pStart))) { 149 strncpy((char *)tmpBuf, (char *)(pTmp + 1), pEnd - pTmp - 1); 150 151 if (NULL != (pTmp = (uint8_t *)memchr((char *)tmpBuf, '>', pEnd - pTmp - 1))) { 152 *pTmp = '\0'; 153 154 memset(pDmInfo->contentID, 0, MAX_CONTENT_ID); 155 sprintf((char *)pDmInfo->contentID, "%s%s", "cid:", (int8_t *)tmpBuf); 156 } 157 } 158 } 159 } else { /* First confirm delivery type, Forward_Lock, Combined Delivery or Separate Delivery */ 160 if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_TYPE, HEADERS_CONTENT_TYPE_LEN)) { 161 pStart += HEADERS_CONTENT_TYPE_LEN; 162 DRM_SKIP_SPACE_TAB(pStart); 163 164 if (pEnd - pStart > 0) { 165 strncpy((char *)pDmInfo->contentType, (char *)pStart, pEnd - pStart); 166 pDmInfo->contentType[pEnd - pStart] = '\0'; 167 } 168 169 if (0 == strcmp((char *)pDmInfo->contentType, DRM_MIME_TYPE_RIGHTS_XML)) { 170 pDmInfo->deliveryType = COMBINED_DELIVERY; 171 status = DM_PARSING_RIGHTS; 172 } 173 else if (0 == strcmp((char *)pDmInfo->contentType, DRM_MIME_TYPE_CONTENT)) { 174 pDmInfo->deliveryType = SEPARATE_DELIVERY_FL; 175 status = DM_PARSING_CONTENT; 176 } 177 else if (0 == pDmInfo->deliveryType) { 178 pDmInfo->deliveryType = FORWARD_LOCK; 179 status = DM_PARSING_CONTENT; 180 } 181 } 182 } 183 pEnd += 2; /* skip the '\r' and '\n' */ 184 pStart = pEnd; 185 leftLen = pBufferEnd - pStart; 186 } 187 pStart += 2; /* skip the second CRLF: "\r\n" */ 188 pEnd = pStart; 189 190 /* Deal the content part, including rel or real content */ 191 while (leftLen > 0) { 192 if (NULL == (pEnd = memchr(pEnd, '\r', leftLen))) { 193 pEnd = pBufferEnd; 194 break; /* no boundary found */ 195 } 196 197 leftLen = pBufferEnd - pEnd; 198 if (leftLen < boundaryLen) { 199 pEnd = pBufferEnd; 200 break; /* here means may be the boundary has been split */ 201 } 202 203 if (('\n' == *(pEnd + 1)) && (0 == memcmp(pEnd + 2, pDmInfo->boundary, strlen((char *)pDmInfo->boundary)))) 204 break; /* find the boundary here */ 205 206 pEnd++; 207 leftLen--; 208 } 209 210 if (pEnd >= pBufferEnd) 211 contentLen = DRM_UNKNOWN_DATA_LEN; 212 else 213 contentLen = pEnd - pStart; 214 215 switch(pDmInfo->deliveryType) { 216 case FORWARD_LOCK: 217 pDmInfo->contentLen = contentLen; 218 pDmInfo->contentOffset = pStart - buffer; 219 status = DM_PARSE_END; 220 break; 221 case COMBINED_DELIVERY: 222 if (DM_PARSING_RIGHTS == status) { 223 pDmInfo->rightsLen = contentLen; 224 pDmInfo->rightsOffset = pStart - buffer; 225 } else { 226 pDmInfo->contentLen = contentLen; 227 pDmInfo->contentOffset = pStart - buffer; 228 status = DM_PARSE_END; 229 } 230 break; 231 case SEPARATE_DELIVERY_FL: 232 { 233 T_DRM_DCF_Info dcfInfo; 234 uint8_t* pEncData = NULL; 235 236 memset(&dcfInfo, 0, sizeof(T_DRM_DCF_Info)); 237 if (DRM_UNKNOWN_DATA_LEN == contentLen) 238 contentLen = pEnd - pStart; 239 if (FALSE == drm_dcfParser(pStart, contentLen, &dcfInfo, &pEncData)) 240 return FALSE; 241 242 pDmInfo->contentLen = dcfInfo.EncryptedDataLen; 243 pDmInfo->contentOffset = pEncData - buffer; 244 strcpy((char *)pDmInfo->contentType, (char *)dcfInfo.ContentType); 245 strcpy((char *)pDmInfo->contentID, (char *)dcfInfo.ContentURI); 246 strcpy((char *)pDmInfo->rightsIssuer, (char *)dcfInfo.Rights_Issuer); 247 status = DM_PARSE_END; 248 } 249 break; 250 default: 251 return FALSE; 252 } 253 254 if (DM_PARSING_RIGHTS == status) { 255 /* Here means the rights object data has been completed, boundary must exist */ 256 leftLen = pBufferEnd - pEnd; 257 pStart = drm_strnstr(pEnd, pDmInfo->boundary, leftLen); 258 if (NULL == pStart) 259 return FALSE; 260 leftLen = pBufferEnd - pStart; 261 pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen); 262 if (NULL == pEnd) 263 return FALSE; /* only rights object, no media object, error */ 264 265 pEnd += 2; /* skip the "\r\n" */ 266 pStart = pEnd; 267 } 268 } while (DM_PARSE_END != status); 269 270 return TRUE; 271} 272