The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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_dcf.h> |
| 18 | #include <svc_drm.h> |
| 19 | |
| 20 | static int32_t drm_parseUintVar(uint8_t * buffer, uint8_t * len) |
| 21 | { |
| 22 | int32_t i; |
| 23 | int32_t byteLen; |
| 24 | int32_t sum; |
| 25 | |
| 26 | if (NULL == buffer) |
| 27 | return DRM_UINT_VAR_ERR; |
| 28 | |
| 29 | byteLen = 0; |
| 30 | while ((buffer[byteLen] & UINT_VAR_FLAG) > 0 && byteLen < MAX_UINT_VAR_BYTE) /* UINT_VAR_FLAG == 0x80 */ |
| 31 | byteLen++; |
| 32 | |
| 33 | if (byteLen >= MAX_UINT_VAR_BYTE) /* MAX_UINT_VAR_BYTE == 5 */ |
| 34 | return DRM_UINT_VAR_ERR; /* The var int is too large, and that is impossible */ |
| 35 | |
| 36 | *len = (uint8_t)(byteLen + 1); |
| 37 | sum = buffer[byteLen]; |
| 38 | for (i = byteLen - 1; i >= 0; i--) |
| 39 | sum += ((buffer[i] & UINT_VAR_DATA) << 7 * (byteLen - i)); /* UINT_VAR_DATA == 0x7F */ |
| 40 | |
| 41 | return sum; |
| 42 | } |
| 43 | |
| 44 | /* See parser_dcf.h */ |
| 45 | int32_t drm_dcfParser(uint8_t *buffer, int32_t bufferLen, T_DRM_DCF_Info *pDcfInfo, |
| 46 | uint8_t **ppEncryptedData) |
| 47 | { |
| 48 | uint8_t *tmpBuf; |
| 49 | uint8_t *pStart, *pEnd; |
| 50 | uint8_t *pHeader, *pData; |
| 51 | uint8_t varLen; |
| 52 | |
| 53 | if (NULL == buffer || bufferLen <= 0 || NULL == pDcfInfo) |
| 54 | return FALSE; |
| 55 | |
| 56 | tmpBuf = buffer; |
| 57 | /* 1. Parse the version, content-type and content-url */ |
| 58 | pDcfInfo->Version = *(tmpBuf++); |
| 59 | if (0x01 != pDcfInfo->Version) /* Because it is OMA DRM v1.0, the vension must be 1 */ |
| 60 | return FALSE; |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 61 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 62 | pDcfInfo->ContentTypeLen = *(tmpBuf++); |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 63 | if (pDcfInfo->ContentTypeLen >= MAX_CONTENT_TYPE_LEN) |
| 64 | return FALSE; |
| 65 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 66 | pDcfInfo->ContentURILen = *(tmpBuf++); |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 67 | if (pDcfInfo->ContentURILen >= MAX_CONTENT_URI_LEN) |
| 68 | return FALSE; |
| 69 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 70 | strncpy((char *)pDcfInfo->ContentType, (char *)tmpBuf, pDcfInfo->ContentTypeLen); |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 71 | pDcfInfo->ContentType[MAX_CONTENT_TYPE_LEN - 1] = 0; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 72 | tmpBuf += pDcfInfo->ContentTypeLen; |
| 73 | strncpy((char *)pDcfInfo->ContentURI, (char *)tmpBuf, pDcfInfo->ContentURILen); |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 74 | pDcfInfo->ContentURI[MAX_CONTENT_URI_LEN - 1] = 0; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 75 | tmpBuf += pDcfInfo->ContentURILen; |
| 76 | |
| 77 | /* 2. Get the headers length and data length */ |
| 78 | pDcfInfo->HeadersLen = drm_parseUintVar(tmpBuf, &varLen); |
| 79 | if (DRM_UINT_VAR_ERR == pDcfInfo->HeadersLen) |
| 80 | return FALSE; |
| 81 | tmpBuf += varLen; |
| 82 | pDcfInfo->DecryptedDataLen = DRM_UNKNOWN_DATA_LEN; |
| 83 | pDcfInfo->EncryptedDataLen = drm_parseUintVar(tmpBuf, &varLen); |
| 84 | if (DRM_UINT_VAR_ERR == pDcfInfo->EncryptedDataLen) |
| 85 | return FALSE; |
| 86 | tmpBuf += varLen; |
| 87 | pHeader = tmpBuf; |
| 88 | tmpBuf += pDcfInfo->HeadersLen; |
| 89 | pData = tmpBuf; |
| 90 | |
| 91 | /* 3. Parse the headers */ |
| 92 | pStart = pHeader; |
| 93 | while (pStart < pData) { |
| 94 | pEnd = pStart; |
| 95 | while ('\r' != *pEnd && pEnd < pData) |
| 96 | pEnd++; |
| 97 | |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 98 | if (0 == strncmp((char *)pStart, HEADER_ENCRYPTION_METHOD, HEADER_ENCRYPTION_METHOD_LEN)) { |
| 99 | if ((pEnd - pStart - HEADER_ENCRYPTION_METHOD_LEN) >= MAX_ENCRYPTION_METHOD_LEN) |
| 100 | return FALSE; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 101 | strncpy((char *)pDcfInfo->Encryption_Method, |
| 102 | (char *)(pStart + HEADER_ENCRYPTION_METHOD_LEN), |
| 103 | pEnd - pStart - HEADER_ENCRYPTION_METHOD_LEN); |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 104 | pDcfInfo->Encryption_Method[MAX_ENCRYPTION_METHOD_LEN - 1] = 0; |
| 105 | } else if (0 == strncmp((char *)pStart, HEADER_RIGHTS_ISSUER, HEADER_RIGHTS_ISSUER_LEN)) { |
| 106 | if ((pEnd - pStart - HEADER_RIGHTS_ISSUER_LEN) >= MAX_RIGHTS_ISSUER_LEN) |
| 107 | return FALSE; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 108 | strncpy((char *)pDcfInfo->Rights_Issuer, |
| 109 | (char *)(pStart + HEADER_RIGHTS_ISSUER_LEN), |
| 110 | pEnd - pStart - HEADER_RIGHTS_ISSUER_LEN); |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 111 | pDcfInfo->Rights_Issuer[MAX_RIGHTS_ISSUER_LEN - 1] = 0; |
| 112 | } else if (0 == strncmp((char *)pStart, HEADER_CONTENT_NAME, HEADER_CONTENT_NAME_LEN)) { |
| 113 | if ((pEnd - pStart - HEADER_CONTENT_NAME_LEN) >= MAX_CONTENT_NAME_LEN) |
| 114 | return FALSE; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 115 | strncpy((char *)pDcfInfo->Content_Name, |
| 116 | (char *)(pStart + HEADER_CONTENT_NAME_LEN), |
| 117 | pEnd - pStart - HEADER_CONTENT_NAME_LEN); |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 118 | pDcfInfo->Content_Name[MAX_CONTENT_NAME_LEN - 1] = 0; |
| 119 | } else if (0 == strncmp((char *)pStart, HEADER_CONTENT_DESCRIPTION, HEADER_CONTENT_DESCRIPTION_LEN)) { |
| 120 | if ((pEnd - pStart - HEADER_CONTENT_DESCRIPTION_LEN) >= MAX_CONTENT_DESCRIPTION_LEN) |
| 121 | return FALSE; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 122 | strncpy((char *)pDcfInfo->ContentDescription, |
| 123 | (char *)(pStart + HEADER_CONTENT_DESCRIPTION_LEN), |
| 124 | pEnd - pStart - HEADER_CONTENT_DESCRIPTION_LEN); |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 125 | pDcfInfo->ContentDescription[MAX_CONTENT_DESCRIPTION_LEN - 1] = 0; |
| 126 | } else if (0 == strncmp((char *)pStart, HEADER_CONTENT_VENDOR, HEADER_CONTENT_VENDOR_LEN)) { |
| 127 | if ((pEnd - pStart - HEADER_CONTENT_VENDOR_LEN) >= MAX_CONTENT_VENDOR_LEN) |
| 128 | return FALSE; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 129 | strncpy((char *)pDcfInfo->ContentVendor, |
| 130 | (char *)(pStart + HEADER_CONTENT_VENDOR_LEN), |
| 131 | pEnd - pStart - HEADER_CONTENT_VENDOR_LEN); |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 132 | pDcfInfo->ContentVendor[MAX_CONTENT_VENDOR_LEN - 1] = 0; |
| 133 | } else if (0 == strncmp((char *)pStart, HEADER_ICON_URI, HEADER_ICON_URI_LEN)) { |
| 134 | if ((pEnd - pStart - HEADER_ICON_URI_LEN) >= MAX_ICON_URI_LEN) |
| 135 | return FALSE; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 136 | strncpy((char *)pDcfInfo->Icon_URI, |
| 137 | (char *)(pStart + HEADER_ICON_URI_LEN), |
| 138 | pEnd - pStart - HEADER_ICON_URI_LEN); |
Nick Kralevich | 25619b2 | 2013-04-29 10:49:47 -0700 | [diff] [blame] | 139 | pDcfInfo->Icon_URI[MAX_ICON_URI_LEN - 1] = 0; |
| 140 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 141 | |
| 142 | if ('\n' == *(pEnd + 1)) |
| 143 | pStart = pEnd + 2; /* Two bytes: a '\r' and a '\n' */ |
| 144 | else |
| 145 | pStart = pEnd + 1; |
| 146 | } |
| 147 | |
| 148 | /* 4. Give out the location of encrypted data */ |
| 149 | if (NULL != ppEncryptedData) |
| 150 | *ppEncryptedData = pData; |
| 151 | |
| 152 | return TRUE; |
| 153 | } |