// Copyright 2012 Google Inc. All Rights Reserved. // Author: jfore@google.com (Jeff Fore), rkuroiwa@google.com (Rintaro Kuroiwa) #include "cdm_session.h" #include #include #include "clock.h" #include "crypto_engine.h" #include "log.h" #include "properties.h" #include "string_conversions.h" #include "wv_cdm_constants.h" namespace wvcdm { typedef std::set::iterator CdmEventListenerIter; CdmResponseType CdmSession::Init() { CryptoEngine* crypto_engine = CryptoEngine::GetInstance(); if (!crypto_engine) { LOGE("CdmSession::Init failed to get CryptoEngine instance."); return UNKNOWN_ERROR; } crypto_session_ = crypto_engine->CreateSession(session_id_); if (!crypto_session_) { return UNKNOWN_ERROR; } std::string token; if (Properties::use_certificates_as_identification()) { if (!LoadDeviceCertificate(&token, &wrapped_key_)) return NEED_PROVISIONING; } else { if (!crypto_engine->GetToken(&token)) return UNKNOWN_ERROR; } if (license_parser_.Init(token, crypto_session_, &policy_engine_)) return NO_ERROR; else return UNKNOWN_ERROR; } bool CdmSession::DestroySession() { if (crypto_session_) { delete crypto_session_; crypto_session_ = NULL; } return true; } bool CdmSession::VerifySession(const CdmKeySystem& key_system, const CdmInitData& init_data) { // TODO(gmorgan): Compare key_system and init_data with value received // during session startup - they should be the same. return true; } CdmResponseType CdmSession::GenerateKeyRequest( const CdmInitData& pssh_data, const CdmLicenseType license_type, CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request) { if (!crypto_session_) { LOGW("CdmSession::GenerateKeyRequest: Invalid crypto session"); return UNKNOWN_ERROR; } if (!crypto_session_->IsOpen()) { LOGW("CdmSession::GenerateKeyRequest: Crypto session not open"); return UNKNOWN_ERROR; } if (license_received_) { return Properties::require_explicit_renew_request() ? UNKNOWN_ERROR : GenerateRenewalRequest(key_request); } else { if (Properties::use_certificates_as_identification()) { if (!crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) return NEED_PROVISIONING; } if (!license_parser_.PrepareKeyRequest(pssh_data, license_type, app_parameters, key_request)) { return KEY_ERROR; } else { return KEY_MESSAGE; } } } // AddKey() - Accept license response and extract key info. CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) { if (!crypto_session_) { LOGW("CdmSession::AddKey: Invalid crypto session"); return UNKNOWN_ERROR; } if (!crypto_session_->IsOpen()) { LOGW("CdmSession::AddKey: Crypto session not open"); return UNKNOWN_ERROR; } if (license_received_) { return Properties::require_explicit_renew_request() ? UNKNOWN_ERROR : RenewKey(key_response); } else { CdmResponseType sts = license_parser_.HandleKeyResponse(key_response); if (sts == KEY_ADDED) license_received_ = true; return sts; } } CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* key_info) { return policy_engine_.Query(key_info); } CdmResponseType CdmSession::QueryKeyControlInfo(CdmQueryMap* key_info) { if ((!crypto_session_) || (!crypto_session_->IsOpen())) return UNKNOWN_ERROR; std::stringstream ss; ss << crypto_session_->oec_session_id(); (*key_info)[QUERY_KEY_OEMCRYPTO_SESSION_ID] = ss.str(); return NO_ERROR; } // CancelKeyRequest() - Cancel session. CdmResponseType CdmSession::CancelKeyRequest() { // TODO(gmorgan): cancel and clean up session crypto_session_->Close(); return NO_ERROR; } // Decrypt() - Accept encrypted buffer and return decrypted data. CdmResponseType CdmSession::Decrypt(bool is_encrypted, const KeyId& key_id, const uint8_t* encrypt_buffer, size_t encrypt_length, const std::vector& iv, size_t block_offset, void* decrypt_buffer, bool is_video) { if (!crypto_session_ || !crypto_session_->IsOpen()) return UNKNOWN_ERROR; // Check if key needs to be selected if (is_encrypted) { if (key_id_.compare(key_id) != 0) { if (crypto_session_->SelectKey(key_id)) { key_id_ = key_id; } else { return NEED_KEY; } } } return crypto_session_->Decrypt(is_encrypted, encrypt_buffer, encrypt_length, iv, block_offset, decrypt_buffer, is_video); } // License renewal // GenerateRenewalRequest() - Construct valid renewal request for the current // session keys. CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request) { if (!license_parser_.PrepareKeyRenewalRequest(key_request)) { return KEY_ERROR; } else { return KEY_MESSAGE; } } // RenewKey() - Accept renewal response and update key info. CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) { return license_parser_.HandleKeyRenewalResponse(key_response); } bool CdmSession::IsKeyValid(const KeyId& key_id) { // TODO(gmorgan): lookup key and determine if valid. // return (session_keys_.find(key_id) != session_keys_.end()); return true; } CdmSessionId CdmSession::GenerateSessionId() { static const std::string kSessionPrefix("Session"); static int session_num = 1; // TODO(rkuroiwa): Want this to be unique. Probably doing Hash(time+init_data) // to get something that is reasonably unique. return kSessionPrefix + IntToString(++session_num); } bool CdmSession::LoadDeviceCertificate(std::string* certificate, std::string* wrapped_key) { // TODO(edwingwong,rfrias): Need to read in the private key return false; } bool CdmSession::AttachEventListener(WvCdmEventListener* listener) { std::pair result = listeners_.insert(listener); return result.second; } bool CdmSession::DetachEventListener(WvCdmEventListener* listener) { return (listeners_.erase(listener) == 1); } void CdmSession::OnTimerEvent() { bool event_occurred = false; CdmEventType event; policy_engine_.OnTimerEvent(event_occurred, event); if (event_occurred) { for (CdmEventListenerIter iter = listeners_.begin(); iter != listeners_.end(); ++iter) { (*iter)->onEvent(session_id(), event); } } } } // namespace wvcdm