1791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang/*
2791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Copyright (C) 2017 The Android Open Source Project
3791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang *
4791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License");
5791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * you may not use this file except in compliance with the License.
6791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * You may obtain a copy of the License at
7791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang *
8791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang *      http://www.apache.org/licenses/LICENSE-2.0
9791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang *
10791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * Unless required by applicable law or agreed to in writing, software
11791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS,
12791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * See the License for the specific language governing permissions and
14791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang * limitations under the License.
15791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang */
16791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
17791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang//#define LOG_NDEBUG 0
18791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#define LOG_TAG "ClearKeyFetcher"
19791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
20791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <algorithm>
21b01fb48fcc755d6bfad9bc94d8c227349155e1b5Chong Zhang#include <inttypes.h>
22791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <string>
23791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
24791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include "ClearKeyFetcher.h"
25791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include "ecm.h"
26791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include "LicenseFetcher.h"
27791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
28791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <media/stagefright/foundation/ADebug.h>
29791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang#include <utils/Log.h>
30791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
31791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangnamespace android {
32791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangnamespace clearkeycas {
33791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
34791a1a206b56be8601a6fffd2614926e67d64790Chong ZhangClearKeyFetcher::ClearKeyFetcher(
35791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        std::unique_ptr<LicenseFetcher> license_fetcher) :
36791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    initialized_(false),
37791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    license_fetcher_(std::move(license_fetcher)) {
38791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    CHECK(license_fetcher_);
39791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang}
40791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
41791a1a206b56be8601a6fffd2614926e67d64790Chong ZhangClearKeyFetcher::~ClearKeyFetcher() {}
42791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
43791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// This is a no-op but other KeyFetcher subclasses require initialization
44791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang// so this is necessary to preserve the contract.
45791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangstatus_t ClearKeyFetcher::Init() {
46791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    initialized_ = true;
47791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    return OK;
48791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang}
49791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
50791a1a206b56be8601a6fffd2614926e67d64790Chong Zhangstatus_t ClearKeyFetcher::ObtainKey(const sp<ABuffer>& buffer,
51791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        uint64_t* asset_id, std::vector<KeyInfo>* keys) {
52791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    CHECK(asset_id);
53791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    CHECK(keys);
54791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    CHECK(initialized_);
55791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    *asset_id = 0;
56791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    keys->clear();
57791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
58791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    EcmContainer container;
59791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    status_t status = container.Parse(buffer);
60791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    if (status != OK) {
61791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        return status;
62791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
63791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    ALOGV("descriptor_size=%zu", container.descriptor_size());
64791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
65791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Sanity check to verify that the BroadcastEncryptor is sending a properly
66791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // formed EcmContainer. If it contains two Ecms, the ids should have different
67791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // parity (one odd, one even). This does not necessarily affect decryption
68791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // but indicates a problem with Ecm generation.
69791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    if (container.descriptor_size() == 2) {
70791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        // XOR the least significant bits to verify different parity.
71791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        bool same_parity = (((container.descriptor(0).id() & 0x01) ^
72791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang                (container.descriptor(1).id() & 0x01)) == 0);
73791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        if (same_parity) {
74b01fb48fcc755d6bfad9bc94d8c227349155e1b5Chong Zhang            ALOGW("asset_id=%" PRIu64 ": malformed Ecm, "
75791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang                    "content keys have same parity, id0=%d, id1=%d",
76791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang                    container.descriptor(0).ecm().asset_id(),
77791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang                    container.descriptor(0).id(),
78791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang                    container.descriptor(1).id());
79791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        }
80791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
81791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
82791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    *asset_id = container.descriptor(0).ecm().asset_id();
83791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
84791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Detect asset_id change. This could be caused by a configuration change
85791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // in the BroadcastEncryptor. This is unusual so log it in case it is an
86791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // operational mistake. This invalidates the current asset_key causing a
87791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // new license to be fetched.
88791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // TODO(rkint): test against BroadcastEncryptor to verify what BE sends on
89791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // asset_id change. If it sends an EcmContainer with 2 Ecms with different
90791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // asset_ids (old and new) then it might be best to prefetch the Emm.
91791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    if ((asset_.id() != 0) && (*asset_id != asset_.id())) {
92843328ff13456dbdfca72e3825222bcc65f4fac3George Burgess IV        ALOGW("Asset_id change from %llu to %" PRIu64, asset_.id(), *asset_id);
93791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        asset_.Clear();
94791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
95791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
96791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    // Fetch license to get asset_id
97791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    if (!asset_.has_id()) {
98791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        status = license_fetcher_->FetchLicense(*asset_id, &asset_);
99791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        if (status != OK) {
100791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang            *asset_id = 0;
101791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang            return status;
102791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        }
103791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        ALOGV("FetchLicense succeeded, has_id=%d", asset_.has_id());
104791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
105791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    keys->resize(container.descriptor_size());
106791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
107791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    for (size_t i = 0; i < container.descriptor_size(); ++i) {
108791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        status = container.mutable_descriptor(i)->mutable_ecm()->Decrypt(
109791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang                container.descriptor(i).ecm().buffer(), asset_);
110791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        if (status != OK) {
111791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang            *asset_id = 0;
112791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang            keys->clear();
113791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang            return status;
114791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        }
115791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        // TODO: if 2 Ecms have same parity, key from Ecm with higher id
116791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        // should be keys[1].
117791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        KeyInfo key;
118791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        key.key_id = container.descriptor(i).id();
119791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        key.key_bytes = container.descriptor(i).ecm().content_key();
120791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
121791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang        keys->at(key.key_id & 1) = key;
122791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    }
123791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang    return OK;
124791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang}
125791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang
126791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang}  // namespace clearkeycas
127791a1a206b56be8601a6fffd2614926e67d64790Chong Zhang}  // namespace android
128