1 /*
2 * Copyright (C) 2017 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ClearKeyFetcher"
19
20 #include <algorithm>
21 #include <inttypes.h>
22 #include <string>
23
24 #include "ClearKeyFetcher.h"
25 #include "ecm.h"
26 #include "LicenseFetcher.h"
27
28 #include <media/stagefright/foundation/ADebug.h>
29 #include <utils/Log.h>
30
31 namespace android {
32 namespace clearkeycas {
33
ClearKeyFetcher(std::unique_ptr<LicenseFetcher> license_fetcher)34 ClearKeyFetcher::ClearKeyFetcher(
35 std::unique_ptr<LicenseFetcher> license_fetcher) :
36 initialized_(false),
37 license_fetcher_(std::move(license_fetcher)) {
38 CHECK(license_fetcher_);
39 }
40
~ClearKeyFetcher()41 ClearKeyFetcher::~ClearKeyFetcher() {}
42
43 // This is a no-op but other KeyFetcher subclasses require initialization
44 // so this is necessary to preserve the contract.
Init()45 status_t ClearKeyFetcher::Init() {
46 initialized_ = true;
47 return OK;
48 }
49
ObtainKey(const sp<ABuffer> & buffer,uint64_t * asset_id,std::vector<KeyInfo> * keys)50 status_t ClearKeyFetcher::ObtainKey(const sp<ABuffer>& buffer,
51 uint64_t* asset_id, std::vector<KeyInfo>* keys) {
52 CHECK(asset_id);
53 CHECK(keys);
54 CHECK(initialized_);
55 *asset_id = 0;
56 keys->clear();
57
58 EcmContainer container;
59 status_t status = container.Parse(buffer);
60 if (status != OK) {
61 return status;
62 }
63 ALOGV("descriptor_size=%zu", container.descriptor_size());
64
65 // Sanity check to verify that the BroadcastEncryptor is sending a properly
66 // formed EcmContainer. If it contains two Ecms, the ids should have different
67 // parity (one odd, one even). This does not necessarily affect decryption
68 // but indicates a problem with Ecm generation.
69 if (container.descriptor_size() == 2) {
70 // XOR the least significant bits to verify different parity.
71 bool same_parity = (((container.descriptor(0).id() & 0x01) ^
72 (container.descriptor(1).id() & 0x01)) == 0);
73 if (same_parity) {
74 ALOGW("asset_id=%" PRIu64 ": malformed Ecm, "
75 "content keys have same parity, id0=%d, id1=%d",
76 container.descriptor(0).ecm().asset_id(),
77 container.descriptor(0).id(),
78 container.descriptor(1).id());
79 }
80 }
81
82 *asset_id = container.descriptor(0).ecm().asset_id();
83
84 // Detect asset_id change. This could be caused by a configuration change
85 // in the BroadcastEncryptor. This is unusual so log it in case it is an
86 // operational mistake. This invalidates the current asset_key causing a
87 // new license to be fetched.
88 // TODO(rkint): test against BroadcastEncryptor to verify what BE sends on
89 // asset_id change. If it sends an EcmContainer with 2 Ecms with different
90 // asset_ids (old and new) then it might be best to prefetch the Emm.
91 if ((asset_.id() != 0) && (*asset_id != asset_.id())) {
92 ALOGW("Asset_id change from %" PRIu64 " to %" PRIu64, asset_.id(), *asset_id);
93 asset_.Clear();
94 }
95
96 // Fetch license to get asset_id
97 if (!asset_.has_id()) {
98 status = license_fetcher_->FetchLicense(*asset_id, &asset_);
99 if (status != OK) {
100 *asset_id = 0;
101 return status;
102 }
103 ALOGV("FetchLicense succeeded, has_id=%d", asset_.has_id());
104 }
105 keys->resize(container.descriptor_size());
106
107 for (size_t i = 0; i < container.descriptor_size(); ++i) {
108 status = container.mutable_descriptor(i)->mutable_ecm()->Decrypt(
109 container.descriptor(i).ecm().buffer(), asset_);
110 if (status != OK) {
111 *asset_id = 0;
112 keys->clear();
113 return status;
114 }
115 // TODO: if 2 Ecms have same parity, key from Ecm with higher id
116 // should be keys[1].
117 KeyInfo key;
118 key.key_id = container.descriptor(i).id();
119 key.key_bytes = container.descriptor(i).ecm().content_key();
120
121 keys->at(key.key_id & 1) = key;
122 }
123 return OK;
124 }
125
126 } // namespace clearkeycas
127 } // namespace android
128