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 // Data objects encapsulating the clear key Ecm (Entitlement Control 18 // Message) and related container messages. Deserialization and decryption 19 // are handled externally to reduce build-time dependencies. 20 // 21 // Simplified typical client-side use: 22 // Asset asset; // from the AssetRegistry. 23 // uint8[] ecm_buffer; // received over network, contains an EcmContainer. 24 // EcmContainer ecm_container; 25 // util::Status status = ecm_container.Parse(ecm_buffer); 26 // status = ecm_container.descriptor(1).ecm().Decrypt( 27 // ecm_container.descriptor(1).ecm().buffer(), asset_key); 28 // string content_key; 29 // if (ecm_container.descriptor(1).ecm().has_content_key()) { 30 // content_key = ecm_container.descriptor(1).ecm().content_key(); 31 // } 32 // // use |content_key| to decrypt content. 33 // 34 // Simplified typical server-side use: 35 // EcmContainer container; 36 // string encoded_ecm; 37 // // Use the ecm_generator API to encode and encrypt an ECM from data fields. 38 // util::Status status = ecm_generator::EncodeECM(..., &encoded_ecm); 39 // // Use |encoded_ecm| to initialized the Ecm from this library. 40 // Ecm ecm; 41 // util::Status status = ecm.Parse(encoded_ecm); 42 // EcmDescriptor descriptor(crypto_period_id, ecm); 43 // status = container.Add(descriptor); 44 // string serialized_container; 45 // status = container.Marshall(&serialized_container); 46 // // now |serialized_container| can be sent to the STB. 47 // 48 // Due to past overloading of the term "ECM" this library introduces some 49 // new terminology. 50 // 51 // Ecm: the 32-byte message sent from the head end to a packager that contains 52 // the asset_id, system_id, and content_key (clear). 53 // 54 // EcmDescriptor: contains an Ecm and an id (the crypto period id in the case 55 // of the BroadcastEncryptor). It contains no encrypted fields. 56 // 57 // EcmContainer: sent by the server in the video stream using the ECM pid. 58 // This contains 1 or 2 EcmDescriptors and a count. It contains no 59 // encrypted fields. 60 // 61 // The first EcmContainer sent by the server has only one EcmDescriptor. After 62 // the first crypto period change, an EcmContainer contains 2 EcmDescriptors. 63 // One has an odd id and one has an even id. The decrypted content keys from the 64 // Ecms in the EcmDescriptors are used by the Mpeg2 parser as odd and even 65 // scrambling keys. As the crypto period changes, the oldest EcmDescriptor is 66 // dropped from the EcmContainer and the new EcmDescriptor is added. 67 // 68 // These classes use a simplified protobuf model. For non-repeating fields, 69 // - has_foo() indicates whether the field is populated. 70 // - the accessor foo() returns either a value or a const reference. 71 // - a mutator sets the value. Primitive types and strings use 72 // set_foo(value) while for objects mutable_foo() returns a pointer. 73 // 74 // To prevent null references, objects (like the Asset contained in an Emm) 75 // are allocated as members and can be accessed via foo() even if they have 76 // not been populated. The caller must call has_foo() to make sure that the 77 // object is valid. Calling mutable_foo() to obtain a pointer causes has_foo() 78 // to return true. 79 // 80 // Repeated fields (like the EcmDescriptors contained in an EcmContainer) are 81 // handled differently. 82 // - foo_size() returns the number of instances. 83 // - the accessor foo(index) returns either a value or a const reference to 84 // the instance at index. It is illegal to call with |index| >= the value 85 // returned by foo_size(). |index| is checked with CHECK. 86 // - a mutator to change the value of the instance. Primitive types and 87 // strings use set_foo(index, value) while for objects mutable_foo(index) 88 // returns a pointer. It is illegal to call with |index| >= the value 89 // returned by foo_size(). |index| is checked with CHECK. 90 // 91 // Accessing a repeated field with an invalid index causes CHECK to fail. 92 // Be sure to call EcmContainer::decriptor_size() before calling descriptor() 93 // or mutable_descriptor()! 94 // 95 #ifndef CLEAR_KEY_ECM_H_ 96 #define CLEAR_KEY_ECM_H_ 97 98 #include <stddef.h> 99 #include <string> 100 101 #include "protos/license_protos.pb.h" 102 103 #include <media/stagefright/foundation/ABase.h> 104 #include <media/stagefright/foundation/ABuffer.h> 105 #include <utils/Errors.h> 106 107 using namespace std; 108 109 namespace android { 110 namespace clearkeycas { 111 112 // Entitlement Control Message. It contains clear fields. The asset_id 113 // and system_id as well as the content_key are clear. 114 // 115 // This class is not thread-safe. 116 class Ecm { 117 public: 118 // Wire size of ECM. 119 static constexpr size_t kSizeBytes = 16 + 16; // clear fields + clear key 120 121 // Creates an empty ECM which must be initialized via Parse(). 122 Ecm(); 123 124 ~Ecm(); 125 126 // Parses clear fields of Ecm serialized in |buffer_as_binary| and saves 127 // a copy of |buffer_as_binary| for a future DecryptEcm call. 128 // Returns: 129 // - BAD_VALUE if |buffer_as_binary| is too small. 130 // - CLEARKEY_STATUS_INVALIDASSETID via ecm_generator::DecodeEcmClearFields if 131 // asset_id is 0. 132 // - CLEARKEY_STATUS_INVALIDSYSTEMID via ecm_generator::DecodeEcmClearFields if 133 // system_id is 0. 134 // Postconditions: 135 // - |asset_id_| and |system_id_| are populated with non-zero values. 136 // - |buffer_| contains a copy of the serialized Ecm. 137 status_t Parse(const sp<ABuffer>& buffer_as_binary); 138 139 // Parses and decrypts Ecm serialized in |buffer_as_binary| using 140 // |asset_from_emm|.asset_key().encryption_key(). It is not necessary to call 141 // Parse() first. 142 // Returns BAD_VALUE if |buffer_as_binary| is too small. 143 // Returns CLEARKEY_STATUS_INVALIDASSETID via 144 // ecm_generator::DecodeEcmClearFields if asset_id is 0. 145 // Returns CLEARKEY_STATUS_INVALIDSYSTEMID via 146 // ecm_generator::DecodeEcmClearFields if system_id is 0. 147 // Returns CLEARKEY_STATUS_INVALID_PARAMETER if 148 // - asset_id in |asset_from_emm| does not match asset_id in serialized Ecm. 149 // Preconditions: |asset_from_emm| must contain asset_id and asset_key fields. 150 // Postconditions: asset_id() and system_id() are populated with non-zero 151 // values, content_key() is populated with the clear content key. 152 status_t Decrypt(const sp<ABuffer>& buffer_as_binary, 153 const Asset& asset_from_emm); 154 155 // |buffer_| is a serialized copy of the Ecm used for later decryption or 156 // for marshalling. has_buffer()157 inline bool has_buffer() const { return buffer_ != NULL; } buffer()158 const sp<ABuffer> buffer() const { return buffer_; } set_buffer(const sp<ABuffer> & buffer)159 inline void set_buffer(const sp<ABuffer>& buffer) { 160 buffer_ = ABuffer::CreateAsCopy(buffer->data(), buffer->size()); 161 } 162 163 // |content_key| is the clear, encryption/decryption key generated by the server. has_content_key()164 inline bool has_content_key() const { return content_key_ != NULL; } set_content_key(const sp<ABuffer> & value)165 inline void set_content_key(const sp<ABuffer>& value) { 166 content_key_ = ABuffer::CreateAsCopy(value->data(), value->size()); 167 } content_key()168 inline const sp<ABuffer> content_key() const { return content_key_; } 169 170 // |asset_id| from the server. has_asset_id()171 inline bool has_asset_id() const { return asset_id_set_; } asset_id()172 inline uint64_t asset_id() const { return asset_id_; } set_asset_id(uint64_t value)173 inline void set_asset_id(uint64_t value) { 174 asset_id_ = value; 175 asset_id_set_ = true; 176 } 177 178 // |system_id| from the server. has_system_id()179 inline bool has_system_id() const { return system_id_set_; } system_id()180 inline uint32_t system_id() const { return system_id_; } set_system_id(uint32_t value)181 inline void set_system_id(uint32_t value) { 182 system_id_ = value; 183 system_id_set_ = true; 184 } 185 186 private: 187 uint64_t asset_id_; 188 bool asset_id_set_; 189 sp<ABuffer> buffer_; 190 sp<ABuffer> content_key_; 191 uint32_t system_id_; 192 bool system_id_set_; 193 }; 194 195 // Contains an Ecm and and Id. 196 // This class is not thread-safe. 197 class EcmDescriptor { 198 public: 199 // Wire size of Id field. 200 static constexpr size_t kIdSizeBytes = sizeof(uint16_t); 201 // Wire size of EcmDescriptor. 202 static constexpr size_t kSizeBytes = Ecm::kSizeBytes + kIdSizeBytes; 203 204 // Client-side ctor. Populate from a buffer with Parse(). 205 EcmDescriptor(); 206 207 // Server-side ctor. 208 // Args: 209 // - |id| is the crypto period ID. 210 // - |ecm| is an ECM which must have been intialized with Ecm::Parse(). 211 EcmDescriptor(uint16_t id, const Ecm& ecm); 212 213 ~EcmDescriptor(); 214 215 // Parses EcmDescriptor and its contained Ecm which are serialized in the 216 // binary string |buffer_as_binary|. 217 // Returns 218 // - BAD_VALUE if |buffer_as_binary| is too short to contain a 219 // serialized EcmDescriptor. 220 // - Errors returned by Ecm::Parse. 221 // Postconditions: 222 // - id() is populated. Note that 0 is a legal value. 223 // - the clear fields of the contained Ecm have been populated. 224 status_t Parse(const sp<ABuffer>& buffer_as_binary); 225 226 // |id| of the contained Ecm. Typically the crypto period id. has_id()227 inline bool has_id() const { return id_set_; } set_id(uint16_t value)228 inline void set_id(uint16_t value) { 229 id_ = value; 230 id_set_ = true; 231 } id()232 inline uint16_t id() const { return id_; } 233 234 // The contained |ecm|. has_ecm()235 inline bool has_ecm() const { return ecm_set_; } mutable_ecm()236 inline Ecm* mutable_ecm() { 237 ecm_set_ = true; 238 return &ecm_; 239 } ecm()240 inline const Ecm& ecm() const { return ecm_; } 241 242 private: 243 Ecm ecm_; 244 bool ecm_set_; 245 uint16_t id_; 246 bool id_set_; 247 }; 248 249 // Contains a count and 1 or 2 EcmDescriptors. This is included in the video 250 // stream by the sender in the ECM pid. 251 // This class is not thread-safe. 252 class EcmContainer { 253 public: 254 // Wire size of the count field. 255 static constexpr size_t kCountSizeBytes = sizeof(uint16_t); 256 // Minimum wire size assuming one EcmDescriptor. 257 static constexpr size_t kMinimumSizeBytes = 258 EcmDescriptor::kSizeBytes + kCountSizeBytes; 259 static constexpr size_t kMinDescriptorCount = 1; 260 static constexpr size_t kMaxDescriptorCount = 2; 261 262 // Creates an empty EcmContainer which must be populated via Parse() 263 // (client-side) or Add() (server-side). 264 EcmContainer(); 265 266 ~EcmContainer(); 267 268 // Adds an EcmDescriptor for server-side applications. 269 // If |count_| is 2, |descriptor| replaces the oldest EcmDescriptor. 270 // 271 // Returns: 272 // - INTERNAL if the EcmContainer is in a bad state (count != 0, 1, or 2). 273 // Postconditions: 274 // - count() is within bounds (1 or 2). 275 status_t Add(const EcmDescriptor& descriptor); 276 277 // Parses EcmContainer and its contained EcmDescriptors which are serialized 278 // in |buffer_as_binary|. 279 // Returns 280 // - BAD_VALUE if |buffer_as_binary| is too short to contain a 281 // serialized EcmDescriptor. 282 // - ERROR_OUT_OF_RANGE if the count contained in the serialized EcmContainer 283 // is not 1 or 2. 284 // - Errors returned by EcmDescriptor::Parse. 285 // Postconditions: 286 // - count() is within bounds (1 or 2) and. 287 // - contained EcmDescriptor(s) parsed and populated. 288 status_t Parse(const sp<ABuffer>& buffer_as_binary); 289 has_count()290 inline bool has_count() const { return count_set_; } 291 // Sets the |count| of contained EcmDecriptors. Illegal values are silently 292 // ignored. set_count(size_t count)293 inline void set_count(size_t count) { 294 if (!CountLegal(count)) return; 295 count_ = count; 296 count_set_ = true; 297 } 298 // Number of contained EcmDecriptors. Only 1 and 2 are legal values. count()299 inline size_t count() const { return count_; } 300 301 // Returns the number of allowable descriptors. This is redundant but is 302 // provided for protobuf compatibility. descriptor_size()303 inline size_t descriptor_size() const { return count_; } 304 305 // Returns a pointer to the EcmDescriptor at |index| for valid index values, 306 // otherwise calls CHECK and aborts. Always call descriptor_size() first! mutable_descriptor(size_t index)307 inline EcmDescriptor* mutable_descriptor(size_t index) { 308 //CHECK(IndexValid(index)); 309 return &descriptor_[index]; 310 } 311 312 // Returns a reference to the EcmDescriptor at |index| for valid index 313 // values, otherwise calls CHECK and aborts. Call descriptor_size() first! descriptor(size_t index)314 inline const EcmDescriptor& descriptor(size_t index) const { 315 //CHECK(IndexValid(index)); 316 return descriptor_[index]; 317 } 318 319 private: 320 // Count value must be 1 or 2. CountLegal(size_t count)321 inline bool CountLegal(size_t count) const { 322 return count <= kMaxDescriptorCount && count >= kMinDescriptorCount; 323 } 324 // Index must be 0 or 1. IndexLegal(size_t index)325 inline bool IndexLegal(size_t index) const { 326 return index < kMaxDescriptorCount; 327 } 328 // |index| is valid for this object: it is legal and < count_. IndexValid(size_t index)329 inline bool IndexValid(size_t index) const { 330 if (!IndexLegal(index)) return false; 331 return index < count_; 332 } 333 size_t count_; 334 bool count_set_; 335 EcmDescriptor descriptor_[kMaxDescriptorCount]; 336 337 DISALLOW_EVIL_CONSTRUCTORS(EcmContainer); 338 }; 339 340 } // namespace clearkeycas 341 } // namespace android 342 343 #endif // CLEAR_KEY_ECM_H_ 344