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 "ecm"
19
20 #include "ecm.h"
21 #include "ecm_generator.h"
22 #include "protos/license_protos.pb.h"
23
24 #include <media/stagefright/foundation/ADebug.h>
25 #include <media/stagefright/MediaErrors.h>
26 #include <utils/Log.h>
27
28 namespace android {
29 namespace clearkeycas {
30
Ecm()31 Ecm::Ecm()
32 : asset_id_(0),
33 asset_id_set_(false),
34 system_id_(0),
35 system_id_set_(false) {}
36
~Ecm()37 Ecm::~Ecm() {}
38
Parse(const sp<ABuffer> & buffer_as_binary)39 status_t Ecm::Parse(const sp<ABuffer>& buffer_as_binary) {
40 if (buffer_as_binary->size() < kSizeBytes) {
41 ALOGE("Short Ecm buffer: expected %zu, received %zu.",
42 kSizeBytes, buffer_as_binary->size());
43 return BAD_VALUE;
44 }
45
46 Asset asset;
47 ecm_generator::DefaultEcmFields default_fields;
48 status_t status = ecm_generator::DecodeECMClearFields(
49 buffer_as_binary, &asset, &default_fields);
50 if (status != OK) {
51 ALOGE("DecodeECMClearFields failed with status %d", status);
52 return status;
53 }
54 set_asset_id(asset.id());
55 set_system_id(default_fields.system_id);
56
57 // Save a copy of the buffer_as_binary for a future DecryptEcm call.
58 set_buffer(buffer_as_binary);
59 return OK;
60 }
61
Decrypt(const sp<ABuffer> & buffer_as_binary,const Asset & asset_from_emm)62 status_t Ecm::Decrypt(
63 const sp<ABuffer>& buffer_as_binary,
64 const Asset& asset_from_emm) {
65 // Invariant: asset has id. These are postconditions for Emm::Decrypt().
66 CHECK(asset_from_emm.has_id());
67
68 // DecodeEcm fills in |asset|.id() with the asset_id from the encoded Ecm.
69 Asset asset(asset_from_emm);
70 ecm_generator::DefaultEcmFields default_fields;
71 sp<ABuffer> content_key;
72 status_t status = ecm_generator::DecodeECM(
73 buffer_as_binary, &asset, &content_key, &default_fields);
74 if (status != OK) {
75 ALOGE("DecodeECM failed with status %d", status);
76 return status;
77 }
78 if (asset.id() != asset_from_emm.id()) {
79 ALOGE("Asset_id from Emm (%llu) does not match asset_id from Ecm (%llu).",
80 asset_from_emm.id(), asset.id());
81 return CLEARKEY_STATUS_INVALID_PARAMETER;
82 }
83 set_asset_id(asset.id());
84 set_system_id(default_fields.system_id);
85 set_content_key(content_key);
86 return status;
87 }
88
EcmDescriptor()89 EcmDescriptor::EcmDescriptor() : ecm_set_(false), id_(0), id_set_(false) {}
90
EcmDescriptor(uint16_t id,const Ecm & ecm)91 EcmDescriptor::EcmDescriptor(uint16_t id, const Ecm& ecm)
92 : ecm_(ecm), ecm_set_(true), id_(id), id_set_(true) {}
93
~EcmDescriptor()94 EcmDescriptor::~EcmDescriptor() {}
95
Parse(const sp<ABuffer> & buffer_as_binary)96 status_t EcmDescriptor::Parse(const sp<ABuffer>& buffer_as_binary) {
97 if (buffer_as_binary->size() < kSizeBytes) {
98 ALOGE("Short EcmDescriptor buffer: expected %zu, received %zu.",
99 kSizeBytes, buffer_as_binary->size());
100 return BAD_VALUE;
101 }
102 sp<ABuffer> id_buffer = new ABuffer(buffer_as_binary->data(), kIdSizeBytes);
103 const uint8_t *id_bytes = id_buffer->data();
104 uint16_t id = (id_bytes[0] << 8) | id_bytes[1];
105 set_id(id);
106
107 // Unmarshall the contained Ecm.
108 sp<ABuffer> ecm_buffer = new ABuffer(
109 buffer_as_binary->data() + kIdSizeBytes, Ecm::kSizeBytes);
110 status_t status = mutable_ecm()->Parse(ecm_buffer);
111 if (status != OK) {
112 return status;
113 }
114 return OK;
115 }
116
EcmContainer()117 EcmContainer::EcmContainer() : count_(0), count_set_(false) {}
118
~EcmContainer()119 EcmContainer::~EcmContainer() {}
120
Add(const EcmDescriptor & descriptor)121 status_t EcmContainer::Add(const EcmDescriptor& descriptor) {
122 switch (count_) {
123 case 0:
124 descriptor_[0] = descriptor;
125 count_ = 1;
126 break;
127 case 1:
128 descriptor_[1] = descriptor;
129 count_ = 2;
130 break;
131 case 2:
132 descriptor_[0] = descriptor_[1];
133 descriptor_[1] = descriptor;
134 break;
135 default:
136 ALOGE("Bad state.");
137 return INVALID_OPERATION;
138 }
139 count_set_ = true;
140 return OK;
141 }
142
Parse(const sp<ABuffer> & buffer_as_binary)143 status_t EcmContainer::Parse(const sp<ABuffer>& buffer_as_binary) {
144 // EcmContainer can contain 1 or 2 EcmDescriptors so this is a check for
145 // minimum size.
146 if (buffer_as_binary->size() < kMinimumSizeBytes) {
147 ALOGE("Short EcmContainer buffer: expected >= %zu, received %zu.",
148 kMinimumSizeBytes, buffer_as_binary->size());
149 return BAD_VALUE;
150 }
151
152 sp<ABuffer> count_buffer = new ABuffer(
153 buffer_as_binary->data(), kCountSizeBytes);
154 const uint8_t *count_bytes = count_buffer->data();
155 size_t count = (count_bytes[0] << 8) | count_bytes[1];
156 // Check that count is a legal value.
157 if (!CountLegal(count)) {
158 ALOGE("Invalid descriptor count: expected %zu <= count <= %zu, received %zu.",
159 kMinDescriptorCount, kMaxDescriptorCount, count);
160 return ERROR_OUT_OF_RANGE;
161 }
162 // If needed, check that buffer_as_binary can hold 2 EcmDescriptors.
163 if (count > kMinDescriptorCount) {
164 size_t expected_bytes =
165 kCountSizeBytes + (count * EcmDescriptor::kSizeBytes);
166 if (buffer_as_binary->size() < expected_bytes) {
167 ALOGE("Short EcmContainer buffer: expected %zu, received %zu.",
168 expected_bytes, buffer_as_binary->size());
169 return BAD_VALUE;
170 }
171 }
172 set_count(count);
173 // Unmarshall the contained EcmDescriptors.
174 size_t offset = kCountSizeBytes;
175 for (size_t i = 0; i < count_; ++i) {
176 sp<ABuffer> descriptor_buffer = new ABuffer(
177 buffer_as_binary->data() + offset, EcmDescriptor::kSizeBytes);
178 status_t status = mutable_descriptor(i)->Parse(descriptor_buffer);
179 if (status != OK) {
180 return status;
181 }
182 offset += EcmDescriptor::kSizeBytes;
183 }
184 return OK;
185 }
186
187 } // namespace clearkeycas
188 } // namespace android
189