• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
25 typedef 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 
drm_strnicmp(const uint8_t * s1,const uint8_t * s2,int32_t n)32 static 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 
drm_strnstr(const uint8_t * str,const uint8_t * strSearch,int32_t len)51 const 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 */
drm_parseDM(const uint8_t * buffer,int32_t bufferLen,T_DRM_DM_Info * pDmInfo)67 int32_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                         ALOGD("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