tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WMFClearKeySession.cpp (7337B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "WMFClearKeySession.h"
      6 
      7 #include <codecvt>
      8 #include <cmath>
      9 #include <Mferror.h>
     10 #include <winerror.h>
     11 
     12 #include "WMFClearKeyCDM.h"
     13 #include "WMFClearKeyUtils.h"
     14 
     15 namespace mozilla {
     16 
     17 using Microsoft::WRL::ComPtr;
     18 
     19 static cdm::SessionType ToCdmSessionType(MF_MEDIAKEYSESSION_TYPE aSessionType) {
     20  switch (aSessionType) {
     21    case MF_MEDIAKEYSESSION_TYPE_TEMPORARY:
     22      return cdm::SessionType::kTemporary;
     23    default:
     24      MOZ_ASSERT_UNREACHABLE("Only support temporary type for testing");
     25      return cdm::SessionType::kTemporary;
     26  }
     27 }
     28 
     29 static MF_MEDIAKEY_STATUS ToMFKeyStatus(cdm::KeyStatus aStatus) {
     30  switch (aStatus) {
     31    case cdm::KeyStatus::kUsable:
     32      return MF_MEDIAKEY_STATUS_USABLE;
     33    case cdm::KeyStatus::kExpired:
     34      return MF_MEDIAKEY_STATUS_EXPIRED;
     35    case cdm::KeyStatus::kOutputDownscaled:
     36      return MF_MEDIAKEY_STATUS_OUTPUT_DOWNSCALED;
     37    case cdm::KeyStatus::kStatusPending:
     38      return MF_MEDIAKEY_STATUS_STATUS_PENDING;
     39    case cdm::KeyStatus::kInternalError:
     40      return MF_MEDIAKEY_STATUS_INTERNAL_ERROR;
     41    case cdm::KeyStatus::kReleased:
     42      return MF_MEDIAKEY_STATUS_RELEASED;
     43    case cdm::KeyStatus::kOutputRestricted:
     44      return MF_MEDIAKEY_STATUS_OUTPUT_RESTRICTED;
     45  }
     46 }
     47 
     48 HRESULT WMFClearKeySession::RuntimeClassInitialize(
     49    MF_MEDIAKEYSESSION_TYPE aSessionType,
     50    IMFContentDecryptionModuleSessionCallbacks* aCallbacks,
     51    SessionManagerWrapper* aManager) {
     52  ENTRY_LOG();
     53  MOZ_ASSERT(aCallbacks);
     54  MOZ_ASSERT(aManager);
     55  mSessionType = ToCdmSessionType(aSessionType);
     56  mCallbacks = aCallbacks;
     57  mSessionManager = aManager;
     58  return S_OK;
     59 }
     60 
     61 WMFClearKeySession::~WMFClearKeySession() { ENTRY_LOG(); }
     62 
     63 STDMETHODIMP WMFClearKeySession::GenerateRequest(LPCWSTR aInitDataType,
     64                                                 const BYTE* aInitData,
     65                                                 DWORD aInitDataSize) {
     66  if (!mSessionManager) {
     67    return MF_E_SHUTDOWN;
     68  }
     69  ENTRY_LOG_ARGS("init-type=%ls", aInitDataType);
     70  cdm::InitDataType initType;
     71  if (wcscmp(aInitDataType, L"cenc") == 0) {
     72    initType = cdm::InitDataType::kCenc;
     73  } else if (wcscmp(aInitDataType, L"keyids") == 0) {
     74    initType = cdm::InitDataType::kKeyIds;
     75  } else if (wcscmp(aInitDataType, L"webm") == 0) {
     76    initType = cdm::InitDataType::kWebM;
     77  } else {
     78    return MF_NOT_SUPPORTED_ERR;
     79  }
     80  RETURN_IF_FAILED(mSessionManager->GenerateRequest(
     81      initType, aInitData, aInitDataSize, mSessionType, this, mSessionId));
     82  MOZ_ASSERT(!mSessionId.empty());
     83  ENTRY_LOG_ARGS("created session, sid=%s", mSessionId.c_str());
     84  return S_OK;
     85 }
     86 
     87 STDMETHODIMP WMFClearKeySession::Load(LPCWSTR session_id, BOOL* loaded) {
     88  ENTRY_LOG();
     89  // Per step 5, Load can only be called on persistent session, but we only
     90  // support temporary session for MF clearkey due to testing reason.
     91  // https://rawgit.com/w3c/encrypted-media/V1/index.html#dom-mediakeysession-load
     92  return MF_E_NOT_AVAILABLE;
     93 }
     94 
     95 STDMETHODIMP WMFClearKeySession::Update(const BYTE* aResponse,
     96                                        DWORD aResponseSize) {
     97  ENTRY_LOG();
     98  if (!mSessionManager) {
     99    return MF_E_SHUTDOWN;
    100  }
    101  RETURN_IF_FAILED(
    102      mSessionManager->UpdateSession(mSessionId, aResponse, aResponseSize));
    103  return S_OK;
    104 }
    105 
    106 STDMETHODIMP WMFClearKeySession::Close() {
    107  ENTRY_LOG();
    108  // It has been shutdowned and sesssion has been closed.
    109  if (!mSessionManager) {
    110    return S_OK;
    111  }
    112  RETURN_IF_FAILED(mSessionManager->CloseSession(mSessionId));
    113  return S_OK;
    114 }
    115 
    116 STDMETHODIMP WMFClearKeySession::Remove() {
    117  ENTRY_LOG();
    118  // It has been shutdowned and sesssion has been removed.
    119  if (!mSessionManager) {
    120    return S_OK;
    121  }
    122  RETURN_IF_FAILED(mSessionManager->RemoveSession(mSessionId));
    123  return S_OK;
    124 }
    125 
    126 STDMETHODIMP WMFClearKeySession::GetSessionId(LPWSTR* aSessionId) {
    127  ENTRY_LOG();
    128  if (!mSessionManager) {
    129    return S_OK;
    130  }
    131  if (mSessionId.empty()) {
    132    *aSessionId = (LPWSTR)CoTaskMemAlloc(sizeof(wchar_t));
    133    if (*aSessionId != NULL) {
    134      **aSessionId = L'\0';
    135      return S_OK;
    136    } else {
    137      return E_OUTOFMEMORY;
    138    }
    139  }
    140 
    141  std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
    142  std::wstring wideStr = converter.from_bytes(mSessionId);
    143  *aSessionId =
    144      (LPWSTR)CoTaskMemAlloc((wideStr.length() + 1) * sizeof(wchar_t));
    145  if (*aSessionId != NULL) {
    146    wcscpy_s(*aSessionId, wideStr.length() + 1, wideStr.c_str());
    147    return S_OK;
    148  } else {
    149    return E_OUTOFMEMORY;
    150  }
    151 }
    152 
    153 STDMETHODIMP WMFClearKeySession::GetExpiration(double* expiration) {
    154  ENTRY_LOG();
    155  // This is used for testing, never expires.
    156  *expiration = std::nan("1");
    157  return S_OK;
    158 }
    159 
    160 STDMETHODIMP WMFClearKeySession::GetKeyStatuses(MFMediaKeyStatus** aKeyStatuses,
    161                                                UINT* aKeyStatusesCount) {
    162  ENTRY_LOG();
    163  *aKeyStatuses = nullptr;
    164  *aKeyStatusesCount = 0;
    165 
    166  const auto keyStatusCount = mKeyInfo.size();
    167  if (mSessionId.empty() || keyStatusCount == 0) {
    168    ENTRY_LOG_ARGS("No session ID or no key info!");
    169    return S_OK;
    170  }
    171 
    172  MFMediaKeyStatus* keyStatusArray = nullptr;
    173  keyStatusArray = static_cast<MFMediaKeyStatus*>(
    174      CoTaskMemAlloc(keyStatusCount * sizeof(MFMediaKeyStatus)));
    175  if (!keyStatusArray) {
    176    ENTRY_LOG_ARGS("OOM when alloacting keyStatusArray!");
    177    return E_OUTOFMEMORY;
    178  }
    179  ZeroMemory(keyStatusArray, keyStatusCount * sizeof(MFMediaKeyStatus));
    180  for (UINT idx = 0; idx < keyStatusCount; idx++) {
    181    keyStatusArray[idx].cbKeyId = mKeyInfo[idx].mKeyId.size();
    182    keyStatusArray[idx].pbKeyId =
    183        static_cast<BYTE*>(CoTaskMemAlloc(sizeof(mKeyInfo[idx].mKeyId.size())));
    184    if (keyStatusArray[idx].pbKeyId == nullptr) {
    185      ENTRY_LOG_ARGS("OOM when alloacting keyStatusArray's pbKeyId!");
    186      return E_OUTOFMEMORY;
    187    }
    188 
    189    keyStatusArray[idx].eMediaKeyStatus =
    190        ToMFKeyStatus(mKeyInfo[idx].mKeyStatus);
    191    memcpy(keyStatusArray[idx].pbKeyId, mKeyInfo[idx].mKeyId.data(),
    192           mKeyInfo[idx].mKeyId.size());
    193  }
    194 
    195  *aKeyStatuses = keyStatusArray;
    196  *aKeyStatusesCount = keyStatusCount;
    197  ENTRY_LOG_ARGS("return key status!");
    198  return S_OK;
    199 }
    200 
    201 void WMFClearKeySession::OnKeyMessage(
    202    MF_MEDIAKEYSESSION_MESSAGETYPE aMessageType, const BYTE* aMessage,
    203    DWORD aMessageSize) {
    204  ENTRY_LOG_ARGS("aMessageSize=%lu", aMessageSize);
    205  if (!mSessionManager) {
    206    return;
    207  }
    208  mCallbacks->KeyMessage(aMessageType, aMessage, aMessageSize, nullptr);
    209 }
    210 
    211 void WMFClearKeySession::OnKeyStatusChanged(
    212    const cdm::KeyInformation* aKeysInfo, uint32_t aKeysInfoCount) {
    213  ENTRY_LOG_ARGS("aKeysInfoCount=%u", aKeysInfoCount);
    214  if (!mSessionManager) {
    215    return;
    216  }
    217  mKeyInfo.clear();
    218  for (uint32_t idx = 0; idx < aKeysInfoCount; idx++) {
    219    const cdm::KeyInformation& key = aKeysInfo[idx];
    220    mKeyInfo.push_back(KeyInformation{key.key_id, key.key_id_size, key.status});
    221    ENTRY_LOG_ARGS("idx=%u, keySize=%u, status=%u", idx, key.key_id_size,
    222                   key.status);
    223  }
    224  mCallbacks->KeyStatusChanged();
    225 }
    226 
    227 void WMFClearKeySession::Shutdown() {
    228  ENTRY_LOG();
    229  mCallbacks = nullptr;
    230  mSessionManager = nullptr;
    231 }
    232 
    233 }  // namespace mozilla