Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / media / cdm / aes_decryptor.cc
blob77783e3319c9c0fd63eea5543abbcf9bec1348a4
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/cdm/aes_decryptor.h"
7 #include <list>
8 #include <vector>
10 #include "base/logging.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "crypto/encryptor.h"
14 #include "crypto/symmetric_key.h"
15 #include "media/base/audio_decoder_config.h"
16 #include "media/base/cdm_key_information.h"
17 #include "media/base/cdm_promise.h"
18 #include "media/base/decoder_buffer.h"
19 #include "media/base/decrypt_config.h"
20 #include "media/base/video_decoder_config.h"
21 #include "media/base/video_frame.h"
22 #include "media/cdm/cenc_utils.h"
23 #include "media/cdm/json_web_key.h"
25 namespace media {
27 // Keeps track of the session IDs and DecryptionKeys. The keys are ordered by
28 // insertion time (last insertion is first). It takes ownership of the
29 // DecryptionKeys.
30 class AesDecryptor::SessionIdDecryptionKeyMap {
31 // Use a std::list to actually hold the data. Insertion is always done
32 // at the front, so the "latest" decryption key is always the first one
33 // in the list.
34 typedef std::list<std::pair<std::string, DecryptionKey*> > KeyList;
36 public:
37 SessionIdDecryptionKeyMap() {}
38 ~SessionIdDecryptionKeyMap() { STLDeleteValues(&key_list_); }
40 // Replaces value if |session_id| is already present, or adds it if not.
41 // This |decryption_key| becomes the latest until another insertion or
42 // |session_id| is erased.
43 void Insert(const std::string& session_id,
44 scoped_ptr<DecryptionKey> decryption_key);
46 // Deletes the entry for |session_id| if present.
47 void Erase(const std::string& session_id);
49 // Returns whether the list is empty
50 bool Empty() const { return key_list_.empty(); }
52 // Returns the last inserted DecryptionKey.
53 DecryptionKey* LatestDecryptionKey() {
54 DCHECK(!key_list_.empty());
55 return key_list_.begin()->second;
58 bool Contains(const std::string& session_id) {
59 return Find(session_id) != key_list_.end();
62 private:
63 // Searches the list for an element with |session_id|.
64 KeyList::iterator Find(const std::string& session_id);
66 // Deletes the entry pointed to by |position|.
67 void Erase(KeyList::iterator position);
69 KeyList key_list_;
71 DISALLOW_COPY_AND_ASSIGN(SessionIdDecryptionKeyMap);
74 void AesDecryptor::SessionIdDecryptionKeyMap::Insert(
75 const std::string& session_id,
76 scoped_ptr<DecryptionKey> decryption_key) {
77 KeyList::iterator it = Find(session_id);
78 if (it != key_list_.end())
79 Erase(it);
80 DecryptionKey* raw_ptr = decryption_key.release();
81 key_list_.push_front(std::make_pair(session_id, raw_ptr));
84 void AesDecryptor::SessionIdDecryptionKeyMap::Erase(
85 const std::string& session_id) {
86 KeyList::iterator it = Find(session_id);
87 if (it == key_list_.end())
88 return;
89 Erase(it);
92 AesDecryptor::SessionIdDecryptionKeyMap::KeyList::iterator
93 AesDecryptor::SessionIdDecryptionKeyMap::Find(const std::string& session_id) {
94 for (KeyList::iterator it = key_list_.begin(); it != key_list_.end(); ++it) {
95 if (it->first == session_id)
96 return it;
98 return key_list_.end();
101 void AesDecryptor::SessionIdDecryptionKeyMap::Erase(
102 KeyList::iterator position) {
103 DCHECK(position->second);
104 delete position->second;
105 key_list_.erase(position);
108 uint32_t AesDecryptor::next_session_id_ = 1;
110 enum ClearBytesBufferSel {
111 kSrcContainsClearBytes,
112 kDstContainsClearBytes
115 static void CopySubsamples(const std::vector<SubsampleEntry>& subsamples,
116 const ClearBytesBufferSel sel,
117 const uint8_t* src,
118 uint8_t* dst) {
119 for (size_t i = 0; i < subsamples.size(); i++) {
120 const SubsampleEntry& subsample = subsamples[i];
121 if (sel == kSrcContainsClearBytes) {
122 src += subsample.clear_bytes;
123 } else {
124 dst += subsample.clear_bytes;
126 memcpy(dst, src, subsample.cypher_bytes);
127 src += subsample.cypher_bytes;
128 dst += subsample.cypher_bytes;
132 // Decrypts |input| using |key|. Returns a DecoderBuffer with the decrypted
133 // data if decryption succeeded or NULL if decryption failed.
134 static scoped_refptr<DecoderBuffer> DecryptData(const DecoderBuffer& input,
135 crypto::SymmetricKey* key) {
136 CHECK(input.data_size());
137 CHECK(input.decrypt_config());
138 CHECK(key);
140 crypto::Encryptor encryptor;
141 if (!encryptor.Init(key, crypto::Encryptor::CTR, "")) {
142 DVLOG(1) << "Could not initialize decryptor.";
143 return NULL;
146 DCHECK_EQ(input.decrypt_config()->iv().size(),
147 static_cast<size_t>(DecryptConfig::kDecryptionKeySize));
148 if (!encryptor.SetCounter(input.decrypt_config()->iv())) {
149 DVLOG(1) << "Could not set counter block.";
150 return NULL;
153 const char* sample = reinterpret_cast<const char*>(input.data());
154 size_t sample_size = static_cast<size_t>(input.data_size());
156 DCHECK_GT(sample_size, 0U) << "No sample data to be decrypted.";
157 if (sample_size == 0)
158 return NULL;
160 if (input.decrypt_config()->subsamples().empty()) {
161 std::string decrypted_text;
162 base::StringPiece encrypted_text(sample, sample_size);
163 if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) {
164 DVLOG(1) << "Could not decrypt data.";
165 return NULL;
168 // TODO(xhwang): Find a way to avoid this data copy.
169 return DecoderBuffer::CopyFrom(
170 reinterpret_cast<const uint8_t*>(decrypted_text.data()),
171 decrypted_text.size());
174 const std::vector<SubsampleEntry>& subsamples =
175 input.decrypt_config()->subsamples();
177 size_t total_clear_size = 0;
178 size_t total_encrypted_size = 0;
179 for (size_t i = 0; i < subsamples.size(); i++) {
180 total_clear_size += subsamples[i].clear_bytes;
181 total_encrypted_size += subsamples[i].cypher_bytes;
182 // Check for overflow. This check is valid because *_size is unsigned.
183 DCHECK(total_clear_size >= subsamples[i].clear_bytes);
184 if (total_encrypted_size < subsamples[i].cypher_bytes)
185 return NULL;
187 size_t total_size = total_clear_size + total_encrypted_size;
188 if (total_size < total_clear_size || total_size != sample_size) {
189 DVLOG(1) << "Subsample sizes do not equal input size";
190 return NULL;
193 // No need to decrypt if there is no encrypted data.
194 if (total_encrypted_size <= 0) {
195 return DecoderBuffer::CopyFrom(reinterpret_cast<const uint8_t*>(sample),
196 sample_size);
199 // The encrypted portions of all subsamples must form a contiguous block,
200 // such that an encrypted subsample that ends away from a block boundary is
201 // immediately followed by the start of the next encrypted subsample. We
202 // copy all encrypted subsamples to a contiguous buffer, decrypt them, then
203 // copy the decrypted bytes over the encrypted bytes in the output.
204 // TODO(strobe): attempt to reduce number of memory copies
205 scoped_ptr<uint8_t[]> encrypted_bytes(new uint8_t[total_encrypted_size]);
206 CopySubsamples(subsamples, kSrcContainsClearBytes,
207 reinterpret_cast<const uint8_t*>(sample),
208 encrypted_bytes.get());
210 base::StringPiece encrypted_text(
211 reinterpret_cast<const char*>(encrypted_bytes.get()),
212 total_encrypted_size);
213 std::string decrypted_text;
214 if (!encryptor.Decrypt(encrypted_text, &decrypted_text)) {
215 DVLOG(1) << "Could not decrypt data.";
216 return NULL;
218 DCHECK_EQ(decrypted_text.size(), encrypted_text.size());
220 scoped_refptr<DecoderBuffer> output = DecoderBuffer::CopyFrom(
221 reinterpret_cast<const uint8_t*>(sample), sample_size);
222 CopySubsamples(subsamples, kDstContainsClearBytes,
223 reinterpret_cast<const uint8_t*>(decrypted_text.data()),
224 output->writable_data());
225 return output;
228 AesDecryptor::AesDecryptor(const GURL& /* security_origin */,
229 const SessionMessageCB& session_message_cb,
230 const SessionClosedCB& session_closed_cb,
231 const SessionKeysChangeCB& session_keys_change_cb)
232 : session_message_cb_(session_message_cb),
233 session_closed_cb_(session_closed_cb),
234 session_keys_change_cb_(session_keys_change_cb) {
235 // AesDecryptor doesn't keep any persistent data, so no need to do anything
236 // with |security_origin|.
237 DCHECK(!session_message_cb_.is_null());
238 DCHECK(!session_closed_cb_.is_null());
239 DCHECK(!session_keys_change_cb_.is_null());
242 AesDecryptor::~AesDecryptor() {
243 key_map_.clear();
246 void AesDecryptor::SetServerCertificate(const std::vector<uint8_t>& certificate,
247 scoped_ptr<SimpleCdmPromise> promise) {
248 promise->reject(
249 NOT_SUPPORTED_ERROR, 0, "SetServerCertificate() is not supported.");
252 void AesDecryptor::CreateSessionAndGenerateRequest(
253 SessionType session_type,
254 EmeInitDataType init_data_type,
255 const std::vector<uint8_t>& init_data,
256 scoped_ptr<NewSessionCdmPromise> promise) {
257 std::string session_id(base::UintToString(next_session_id_++));
258 valid_sessions_.insert(session_id);
260 // For now, the AesDecryptor does not care about |session_type|.
261 // TODO(jrummell): Validate |session_type|.
263 std::vector<uint8_t> message;
264 // TODO(jrummell): Since unprefixed will never send NULL, remove this check
265 // when prefixed EME is removed (http://crbug.com/249976).
266 if (!init_data.empty()) {
267 std::vector<std::vector<uint8_t>> keys;
268 switch (init_data_type) {
269 case EmeInitDataType::WEBM:
270 // |init_data| is simply the key needed.
271 keys.push_back(init_data);
272 break;
273 case EmeInitDataType::CENC:
274 // |init_data| is a set of 0 or more concatenated 'pssh' boxes.
275 if (!GetKeyIdsForCommonSystemId(init_data, &keys)) {
276 promise->reject(NOT_SUPPORTED_ERROR, 0,
277 "No supported PSSH box found.");
278 return;
280 break;
281 case EmeInitDataType::KEYIDS: {
282 std::string init_data_string(init_data.begin(), init_data.end());
283 std::string error_message;
284 if (!ExtractKeyIdsFromKeyIdsInitData(init_data_string, &keys,
285 &error_message)) {
286 promise->reject(NOT_SUPPORTED_ERROR, 0, error_message);
287 return;
289 break;
291 default:
292 NOTREACHED();
293 promise->reject(NOT_SUPPORTED_ERROR, 0,
294 "init_data_type not supported.");
295 return;
297 CreateLicenseRequest(keys, session_type, &message);
300 promise->resolve(session_id);
302 // No URL needed for license requests.
303 session_message_cb_.Run(session_id, LICENSE_REQUEST, message,
304 GURL::EmptyGURL());
307 void AesDecryptor::LoadSession(SessionType session_type,
308 const std::string& session_id,
309 scoped_ptr<NewSessionCdmPromise> promise) {
310 // TODO(xhwang): Change this to NOTREACHED() when blink checks for key systems
311 // that do not support loadSession. See http://crbug.com/342481
312 promise->reject(NOT_SUPPORTED_ERROR, 0, "LoadSession() is not supported.");
315 void AesDecryptor::UpdateSession(const std::string& session_id,
316 const std::vector<uint8_t>& response,
317 scoped_ptr<SimpleCdmPromise> promise) {
318 CHECK(!response.empty());
320 // TODO(jrummell): Convert back to a DCHECK once prefixed EME is removed.
321 if (valid_sessions_.find(session_id) == valid_sessions_.end()) {
322 promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
323 return;
326 std::string key_string(response.begin(), response.end());
328 KeyIdAndKeyPairs keys;
329 SessionType session_type = MediaKeys::TEMPORARY_SESSION;
330 if (!ExtractKeysFromJWKSet(key_string, &keys, &session_type)) {
331 promise->reject(
332 INVALID_ACCESS_ERROR, 0, "Response is not a valid JSON Web Key Set.");
333 return;
336 // Make sure that at least one key was extracted.
337 if (keys.empty()) {
338 promise->reject(
339 INVALID_ACCESS_ERROR, 0, "Response does not contain any keys.");
340 return;
343 bool key_added = false;
344 for (KeyIdAndKeyPairs::iterator it = keys.begin(); it != keys.end(); ++it) {
345 if (it->second.length() !=
346 static_cast<size_t>(DecryptConfig::kDecryptionKeySize)) {
347 DVLOG(1) << "Invalid key length: " << it->second.length();
348 promise->reject(INVALID_ACCESS_ERROR, 0, "Invalid key length.");
349 return;
352 // If this key_id doesn't currently exist in this session,
353 // a new key is added.
354 if (!HasKey(session_id, it->first))
355 key_added = true;
357 if (!AddDecryptionKey(session_id, it->first, it->second)) {
358 promise->reject(INVALID_ACCESS_ERROR, 0, "Unable to add key.");
359 return;
364 base::AutoLock auto_lock(new_key_cb_lock_);
366 if (!new_audio_key_cb_.is_null())
367 new_audio_key_cb_.Run();
369 if (!new_video_key_cb_.is_null())
370 new_video_key_cb_.Run();
373 promise->resolve();
375 // Create the list of all available keys for this session.
376 CdmKeysInfo keys_info;
378 base::AutoLock auto_lock(key_map_lock_);
379 for (const auto& item : key_map_) {
380 if (item.second->Contains(session_id)) {
381 scoped_ptr<CdmKeyInformation> key_info(new CdmKeyInformation);
382 key_info->key_id.assign(item.first.begin(), item.first.end());
383 key_info->status = CdmKeyInformation::USABLE;
384 key_info->system_code = 0;
385 keys_info.push_back(key_info.release());
390 session_keys_change_cb_.Run(session_id, key_added, keys_info.Pass());
393 void AesDecryptor::CloseSession(const std::string& session_id,
394 scoped_ptr<SimpleCdmPromise> promise) {
395 // Validate that this is a reference to an active session and then forget it.
396 std::set<std::string>::iterator it = valid_sessions_.find(session_id);
397 DCHECK(it != valid_sessions_.end());
399 valid_sessions_.erase(it);
401 // Close the session.
402 DeleteKeysForSession(session_id);
403 promise->resolve();
404 session_closed_cb_.Run(session_id);
407 void AesDecryptor::RemoveSession(const std::string& session_id,
408 scoped_ptr<SimpleCdmPromise> promise) {
409 // AesDecryptor doesn't keep any persistent data, so this should be
410 // NOT_REACHED().
411 // TODO(jrummell): Make sure persistent session types are rejected.
412 // http://crbug.com/384152.
414 // However, v0.1b calls to CancelKeyRequest() will call this, so close the
415 // session, if it exists.
416 // TODO(jrummell): Remove the close() call when prefixed EME is removed.
417 // http://crbug.com/249976.
418 if (valid_sessions_.find(session_id) != valid_sessions_.end()) {
419 CloseSession(session_id, promise.Pass());
420 return;
423 promise->reject(INVALID_ACCESS_ERROR, 0, "Session does not exist.");
426 CdmContext* AesDecryptor::GetCdmContext() {
427 return this;
430 Decryptor* AesDecryptor::GetDecryptor() {
431 return this;
434 int AesDecryptor::GetCdmId() const {
435 return kInvalidCdmId;
438 void AesDecryptor::RegisterNewKeyCB(StreamType stream_type,
439 const NewKeyCB& new_key_cb) {
440 base::AutoLock auto_lock(new_key_cb_lock_);
442 switch (stream_type) {
443 case kAudio:
444 new_audio_key_cb_ = new_key_cb;
445 break;
446 case kVideo:
447 new_video_key_cb_ = new_key_cb;
448 break;
449 default:
450 NOTREACHED();
454 void AesDecryptor::Decrypt(StreamType stream_type,
455 const scoped_refptr<DecoderBuffer>& encrypted,
456 const DecryptCB& decrypt_cb) {
457 CHECK(encrypted->decrypt_config());
459 scoped_refptr<DecoderBuffer> decrypted;
460 // An empty iv string signals that the frame is unencrypted.
461 if (encrypted->decrypt_config()->iv().empty()) {
462 decrypted = DecoderBuffer::CopyFrom(encrypted->data(),
463 encrypted->data_size());
464 } else {
465 const std::string& key_id = encrypted->decrypt_config()->key_id();
466 DecryptionKey* key = GetKey(key_id);
467 if (!key) {
468 DVLOG(1) << "Could not find a matching key for the given key ID.";
469 decrypt_cb.Run(kNoKey, NULL);
470 return;
473 crypto::SymmetricKey* decryption_key = key->decryption_key();
474 decrypted = DecryptData(*encrypted.get(), decryption_key);
475 if (!decrypted.get()) {
476 DVLOG(1) << "Decryption failed.";
477 decrypt_cb.Run(kError, NULL);
478 return;
482 decrypted->set_timestamp(encrypted->timestamp());
483 decrypted->set_duration(encrypted->duration());
484 decrypt_cb.Run(kSuccess, decrypted);
487 void AesDecryptor::CancelDecrypt(StreamType stream_type) {
488 // Decrypt() calls the DecryptCB synchronously so there's nothing to cancel.
491 void AesDecryptor::InitializeAudioDecoder(const AudioDecoderConfig& config,
492 const DecoderInitCB& init_cb) {
493 // AesDecryptor does not support audio decoding.
494 init_cb.Run(false);
497 void AesDecryptor::InitializeVideoDecoder(const VideoDecoderConfig& config,
498 const DecoderInitCB& init_cb) {
499 // AesDecryptor does not support video decoding.
500 init_cb.Run(false);
503 void AesDecryptor::DecryptAndDecodeAudio(
504 const scoped_refptr<DecoderBuffer>& encrypted,
505 const AudioDecodeCB& audio_decode_cb) {
506 NOTREACHED() << "AesDecryptor does not support audio decoding";
509 void AesDecryptor::DecryptAndDecodeVideo(
510 const scoped_refptr<DecoderBuffer>& encrypted,
511 const VideoDecodeCB& video_decode_cb) {
512 NOTREACHED() << "AesDecryptor does not support video decoding";
515 void AesDecryptor::ResetDecoder(StreamType stream_type) {
516 NOTREACHED() << "AesDecryptor does not support audio/video decoding";
519 void AesDecryptor::DeinitializeDecoder(StreamType stream_type) {
520 NOTREACHED() << "AesDecryptor does not support audio/video decoding";
523 bool AesDecryptor::AddDecryptionKey(const std::string& session_id,
524 const std::string& key_id,
525 const std::string& key_string) {
526 scoped_ptr<DecryptionKey> decryption_key(new DecryptionKey(key_string));
527 if (!decryption_key->Init()) {
528 DVLOG(1) << "Could not initialize decryption key.";
529 return false;
532 base::AutoLock auto_lock(key_map_lock_);
533 KeyIdToSessionKeysMap::iterator key_id_entry = key_map_.find(key_id);
534 if (key_id_entry != key_map_.end()) {
535 key_id_entry->second->Insert(session_id, decryption_key.Pass());
536 return true;
539 // |key_id| not found, so need to create new entry.
540 scoped_ptr<SessionIdDecryptionKeyMap> inner_map(
541 new SessionIdDecryptionKeyMap());
542 inner_map->Insert(session_id, decryption_key.Pass());
543 key_map_.add(key_id, inner_map.Pass());
544 return true;
547 AesDecryptor::DecryptionKey* AesDecryptor::GetKey(
548 const std::string& key_id) const {
549 base::AutoLock auto_lock(key_map_lock_);
550 KeyIdToSessionKeysMap::const_iterator key_id_found = key_map_.find(key_id);
551 if (key_id_found == key_map_.end())
552 return NULL;
554 // Return the key from the "latest" session_id entry.
555 return key_id_found->second->LatestDecryptionKey();
558 bool AesDecryptor::HasKey(const std::string& session_id,
559 const std::string& key_id) {
560 base::AutoLock auto_lock(key_map_lock_);
561 KeyIdToSessionKeysMap::const_iterator key_id_found = key_map_.find(key_id);
562 if (key_id_found == key_map_.end())
563 return false;
565 return key_id_found->second->Contains(session_id);
568 void AesDecryptor::DeleteKeysForSession(const std::string& session_id) {
569 base::AutoLock auto_lock(key_map_lock_);
571 // Remove all keys associated with |session_id|. Since the data is
572 // optimized for access in GetKey(), we need to look at each entry in
573 // |key_map_|.
574 KeyIdToSessionKeysMap::iterator it = key_map_.begin();
575 while (it != key_map_.end()) {
576 it->second->Erase(session_id);
577 if (it->second->Empty()) {
578 // Need to get rid of the entry for this key_id. This will mess up the
579 // iterator, so we need to increment it first.
580 KeyIdToSessionKeysMap::iterator current = it;
581 ++it;
582 key_map_.erase(current);
583 } else {
584 ++it;
589 AesDecryptor::DecryptionKey::DecryptionKey(const std::string& secret)
590 : secret_(secret) {
593 AesDecryptor::DecryptionKey::~DecryptionKey() {}
595 bool AesDecryptor::DecryptionKey::Init() {
596 CHECK(!secret_.empty());
597 decryption_key_.reset(crypto::SymmetricKey::Import(
598 crypto::SymmetricKey::AES, secret_));
599 if (!decryption_key_)
600 return false;
601 return true;
604 } // namespace media