1791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 2791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang/* 3791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Copyright (C) 2017 The Android Open Source Project 4791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * 5791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License"); 6791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * you may not use this file except in compliance with the License. 7791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * You may obtain a copy of the License at 8791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * 9791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * http://www.apache.org/licenses/LICENSE-2.0 10791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * 11791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Unless required by applicable law or agreed to in writing, software 12791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS, 13791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * See the License for the specific language governing permissions and 15791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * limitations under the License. 16791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang */ 17791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//#define LOG_NDEBUG 0 18791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#define LOG_TAG "JsonAssetLoader" 19791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 20791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <media/stagefright/foundation/ABuffer.h> 21791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <media/stagefright/foundation/AString.h> 22791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <media/stagefright/foundation/base64.h> 23791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <media/stagefright/MediaErrors.h> 24791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <utils/Log.h> 25791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 26791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include "JsonAssetLoader.h" 27791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include "protos/license_protos.pb.h" 28791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 29791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangnamespace android { 30791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangnamespace clearkeycas { 31791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 32791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangconst String8 kIdTag("id"); 33791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangconst String8 kNameTag("name"); 34791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangconst String8 kLowerCaseOgranizationNameTag("lowercase_organization_name"); 35791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangconst String8 kEncryptionKeyTag("encryption_key"); 36791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangconst String8 kCasTypeTag("cas_type"); 37791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangconst String8 kBase64Padding("="); 38791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 39791a1a206b56be8601a6fffd2614926e67d64790Chong ZhangJsonAssetLoader::JsonAssetLoader() { 40791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang} 41791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 42791a1a206b56be8601a6fffd2614926e67d64790Chong ZhangJsonAssetLoader::~JsonAssetLoader() { 43791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang} 44791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 45791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang/* 46791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Extract a clear key asset from a JSON string. 47791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * 48791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Returns OK if a clear key asset is extracted successfully, 49d5a416a49d5074e2966f5fe255561cbaaf31a325Chong Zhang * or ERROR_CAS_NO_LICENSE if the string doesn't contain a valid 50791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * clear key asset. 51791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang */ 52791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangstatus_t JsonAssetLoader::extractAssetFromString( 53791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang const String8& jsonAssetString, Asset *asset) { 54791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (!parseJsonAssetString(jsonAssetString, &mJsonObjects)) { 55d5a416a49d5074e2966f5fe255561cbaaf31a325Chong Zhang return ERROR_CAS_NO_LICENSE; 56791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 57791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 58791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (mJsonObjects.size() < 1) { 59d5a416a49d5074e2966f5fe255561cbaaf31a325Chong Zhang return ERROR_CAS_NO_LICENSE; 60791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 61791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 62791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (!parseJsonObject(mJsonObjects[0], &mTokens)) 63d5a416a49d5074e2966f5fe255561cbaaf31a325Chong Zhang return ERROR_CAS_NO_LICENSE; 64791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 65791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (!findKey(mJsonObjects[0], asset)) { 66d5a416a49d5074e2966f5fe255561cbaaf31a325Chong Zhang return ERROR_CAS_NO_LICENSE; 67791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 68791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return OK; 69791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang} 70791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 71791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//static 72791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangsp<ABuffer> JsonAssetLoader::decodeBase64String(const String8& encodedText) { 73791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang // Since android::decodeBase64() requires padding characters, 74791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang // add them so length of encodedText is exactly a multiple of 4. 75791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang int remainder = encodedText.length() % 4; 76791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang String8 paddedText(encodedText); 77791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (remainder > 0) { 78791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang for (int i = 0; i < 4 - remainder; ++i) { 79791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang paddedText.append(kBase64Padding); 80791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 81791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 82791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 83791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return decodeBase64(AString(paddedText.string())); 84791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang} 85791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 86791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangbool JsonAssetLoader::findKey(const String8& jsonObject, Asset *asset) { 87791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 88791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang String8 value; 89791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 90791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (jsonObject.find(kIdTag) < 0) { 91791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return false; 92791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 93791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang findValue(kIdTag, &value); 94791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang ALOGV("found %s=%s", kIdTag.string(), value.string()); 95791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang asset->set_id(atoi(value.string())); 96791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 97791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (jsonObject.find(kNameTag) < 0) { 98791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return false; 99791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 100791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang findValue(kNameTag, &value); 101791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang ALOGV("found %s=%s", kNameTag.string(), value.string()); 102791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang asset->set_name(value.string()); 103791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 104791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (jsonObject.find(kLowerCaseOgranizationNameTag) < 0) { 105791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return false; 106791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 107791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang findValue(kLowerCaseOgranizationNameTag, &value); 108791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang ALOGV("found %s=%s", kLowerCaseOgranizationNameTag.string(), value.string()); 109791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang asset->set_lowercase_organization_name(value.string()); 110791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 111791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (jsonObject.find(kCasTypeTag) < 0) { 112791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return false; 113791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 114791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang findValue(kCasTypeTag, &value); 115791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang ALOGV("found %s=%s", kCasTypeTag.string(), value.string()); 116791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang // Asset_CasType_CLEARKEY_CAS = 1 117791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang asset->set_cas_type((Asset_CasType)atoi(value.string())); 118791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 119791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return true; 120791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang} 121791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 122791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangvoid JsonAssetLoader::findValue(const String8 &key, String8* value) { 123791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang value->clear(); 124791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang const char* valueToken; 125791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang for (Vector<String8>::const_iterator nextToken = mTokens.begin(); 126791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang nextToken != mTokens.end(); ++nextToken) { 127791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (0 == (*nextToken).compare(key)) { 128791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (nextToken + 1 == mTokens.end()) 129791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang break; 130791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang valueToken = (*(nextToken + 1)).string(); 131791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang value->setTo(valueToken); 132791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang nextToken++; 133791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang break; 134791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 135791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 136791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang} 137791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 138791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang/* 139791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Parses a JSON objects string and initializes a vector of tokens. 140791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * 141791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * @return Returns false for errors, true for success. 142791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang */ 143791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangbool JsonAssetLoader::parseJsonObject(const String8& jsonObject, 144791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang Vector<String8>* tokens) { 145791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang jsmn_parser parser; 146791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 147791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang jsmn_init(&parser); 148791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang int numTokens = jsmn_parse(&parser, 149791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang jsonObject.string(), jsonObject.size(), NULL, 0); 150791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (numTokens < 0) { 151791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang ALOGE("Parser returns error code=%d", numTokens); 152791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return false; 153791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 154791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 155791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang unsigned int jsmnTokensSize = numTokens * sizeof(jsmntok_t); 156791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang mJsmnTokens.clear(); 157791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang mJsmnTokens.setCapacity(jsmnTokensSize); 158791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 159791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang jsmn_init(&parser); 160791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang int status = jsmn_parse(&parser, jsonObject.string(), 161791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang jsonObject.size(), mJsmnTokens.editArray(), numTokens); 162791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (status < 0) { 163791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang ALOGE("Parser returns error code=%d", status); 164791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return false; 165791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 166791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 167791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang tokens->clear(); 168791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang String8 token; 169791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang const char *pjs; 170791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang ALOGV("numTokens: %d", numTokens); 171791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang for (int j = 0; j < numTokens; ++j) { 172791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang pjs = jsonObject.string() + mJsmnTokens[j].start; 173791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (mJsmnTokens[j].type == JSMN_STRING || 174791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang mJsmnTokens[j].type == JSMN_PRIMITIVE) { 175791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang token.setTo(pjs, mJsmnTokens[j].end - mJsmnTokens[j].start); 176791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang tokens->add(token); 177791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang ALOGV("add token: %s", token.string()); 178791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 179791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 180791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return true; 181791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang} 182791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 183791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang/* 184791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Parses JSON asset string and initializes a vector of JSON objects. 185791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * 186791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * @return Returns false for errors, true for success. 187791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang */ 188791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangbool JsonAssetLoader::parseJsonAssetString(const String8& jsonAsset, 189791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang Vector<String8>* jsonObjects) { 190791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (jsonAsset.isEmpty()) { 191791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang ALOGE("Empty JSON Web Key"); 192791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return false; 193791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 194791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 195791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang // The jsmn parser only supports unicode encoding. 196791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang jsmn_parser parser; 197791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 198791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang // Computes number of tokens. A token marks the type, offset in 199791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang // the original string. 200791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang jsmn_init(&parser); 201791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang int numTokens = jsmn_parse(&parser, 202791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang jsonAsset.string(), jsonAsset.size(), NULL, 0); 203791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (numTokens < 0) { 204791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang ALOGE("Parser returns error code=%d", numTokens); 205791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return false; 206791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 207791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 208791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang unsigned int jsmnTokensSize = numTokens * sizeof(jsmntok_t); 209791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang mJsmnTokens.setCapacity(jsmnTokensSize); 210791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 211791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang jsmn_init(&parser); 212791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang int status = jsmn_parse(&parser, jsonAsset.string(), 213791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang jsonAsset.size(), mJsmnTokens.editArray(), numTokens); 214791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (status < 0) { 215791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang ALOGE("Parser returns error code=%d", status); 216791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return false; 217791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 218791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 219791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang String8 token; 220791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang const char *pjs; 221791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang for (int i = 0; i < numTokens; ++i) { 222791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang pjs = jsonAsset.string() + mJsmnTokens[i].start; 223791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang if (mJsmnTokens[i].type == JSMN_OBJECT) { 224791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang token.setTo(pjs, mJsmnTokens[i].end - mJsmnTokens[i].start); 225791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang jsonObjects->add(token); 226791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 227791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang } 228791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang return true; 229791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang} 230791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang 231791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang} // namespace clearkeycas 232791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang} // namespace android 233