tor-browser

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

EMEUtils.cpp (9035B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/EMEUtils.h"
      8 
      9 #include "KeySystemConfig.h"
     10 #include "MediaData.h"
     11 #include "jsfriendapi.h"
     12 #include "mozilla/StaticPrefs_media.h"
     13 #include "mozilla/dom/BufferSourceBinding.h"
     14 #include "mozilla/dom/Document.h"
     15 #include "mozilla/dom/KeySystemNames.h"
     16 #include "mozilla/dom/UnionTypes.h"
     17 #include "nsContentUtils.h"
     18 #include "nsIScriptObjectPrincipal.h"
     19 
     20 #ifdef MOZ_WMF_CDM
     21 #  include "mozilla/PMFCDM.h"
     22 #endif
     23 
     24 namespace mozilla {
     25 
     26 LogModule* GetEMELog() {
     27  static LazyLogModule log("EME");
     28  return log;
     29 }
     30 
     31 LogModule* GetEMEVerboseLog() {
     32  static LazyLogModule log("EMEV");
     33  return log;
     34 }
     35 
     36 void CopyArrayBufferViewOrArrayBufferData(
     37    const dom::BufferSource& aBufferOrView, nsTArray<uint8_t>& aOutData) {
     38  aOutData.Clear();
     39  (void)dom::AppendTypedArrayDataTo(aBufferOrView, aOutData);
     40 }
     41 
     42 bool IsClearkeyKeySystem(const nsAString& aKeySystem) {
     43  if (StaticPrefs::media_clearkey_test_key_systems_enabled()) {
     44    return aKeySystem.EqualsLiteral(kClearKeyKeySystemName) ||
     45           aKeySystem.EqualsLiteral(kClearKeyWithProtectionQueryKeySystemName);
     46  }
     47  return aKeySystem.EqualsLiteral(kClearKeyKeySystemName);
     48 }
     49 
     50 bool IsWidevineKeySystem(const nsAString& aKeySystem) {
     51  return aKeySystem.EqualsLiteral(kWidevineKeySystemName);
     52 }
     53 
     54 #ifdef MOZ_WMF_CDM
     55 bool IsMediaFoundationCDMPlaybackEnabled() {
     56  // 1=enabled encrypted and clear, 2=enabled encrypted.
     57  return StaticPrefs::media_wmf_media_engine_enabled() == 1 ||
     58         StaticPrefs::media_wmf_media_engine_enabled() == 2;
     59 }
     60 
     61 bool IsPlayReadyEnabled() {
     62  return StaticPrefs::media_eme_playready_enabled() &&
     63         IsMediaFoundationCDMPlaybackEnabled();
     64 }
     65 
     66 bool IsPlayReadyKeySystemAndSupported(const nsAString& aKeySystem) {
     67  if (!IsPlayReadyEnabled()) {
     68    return false;
     69  }
     70  return aKeySystem.EqualsLiteral(kPlayReadyKeySystemName) ||
     71         aKeySystem.EqualsLiteral(kPlayReadyKeySystemHardware) ||
     72         aKeySystem.EqualsLiteral(kPlayReadyHardwareClearLeadKeySystemName);
     73 }
     74 
     75 bool IsWidevineHardwareDecryptionEnabled() {
     76  return StaticPrefs::media_eme_widevine_experiment_enabled() &&
     77         IsMediaFoundationCDMPlaybackEnabled();
     78 }
     79 
     80 bool IsWidevineExperimentKeySystemAndSupported(const nsAString& aKeySystem) {
     81  if (!IsWidevineHardwareDecryptionEnabled()) {
     82    return false;
     83  }
     84  return aKeySystem.EqualsLiteral(kWidevineExperimentKeySystemName) ||
     85         aKeySystem.EqualsLiteral(kWidevineExperiment2KeySystemName);
     86 }
     87 
     88 bool IsWMFClearKeySystemAndSupported(const nsAString& aKeySystem) {
     89  if (!StaticPrefs::media_eme_wmf_clearkey_enabled()) {
     90    return false;
     91  }
     92  if (!IsMediaFoundationCDMPlaybackEnabled()) {
     93    return false;
     94  }
     95  return aKeySystem.EqualsLiteral(kClearKeyKeySystemName);
     96 }
     97 #endif
     98 
     99 nsString KeySystemToProxyName(const nsAString& aKeySystem) {
    100  if (IsClearkeyKeySystem(aKeySystem)) {
    101 #ifdef MOZ_WMF_CDM
    102    if (StaticPrefs::media_eme_wmf_clearkey_enabled()) {
    103      return u"mfcdm-clearkey"_ns;
    104    }
    105 #endif
    106    return u"gmp-clearkey"_ns;
    107  }
    108  if (IsWidevineKeySystem(aKeySystem)) {
    109    return u"gmp-widevinecdm"_ns;
    110  }
    111 #ifdef MOZ_WMF_CDM
    112  if (IsPlayReadyKeySystemAndSupported(aKeySystem)) {
    113    return u"mfcdm-playready"_ns;
    114  }
    115  if (IsWidevineExperimentKeySystemAndSupported(aKeySystem)) {
    116    return u"mfcdm-widevine"_ns;
    117  }
    118 #endif
    119  MOZ_ASSERT_UNREACHABLE("Not supported key system!");
    120  return u""_ns;
    121 }
    122 
    123 bool IsHardwareDecryptionSupported(
    124    const dom::MediaKeySystemConfiguration& aConfig) {
    125  for (const auto& capabilities : aConfig.mAudioCapabilities) {
    126    if (capabilities.mRobustness.EqualsLiteral("HW_SECURE_ALL")) {
    127      return true;
    128    }
    129  }
    130  for (const auto& capabilities : aConfig.mVideoCapabilities) {
    131    if (capabilities.mRobustness.EqualsLiteral("3000") ||
    132        capabilities.mRobustness.EqualsLiteral("HW_SECURE_ALL") ||
    133        capabilities.mRobustness.EqualsLiteral("HW_SECURE_DECODE")) {
    134      return true;
    135    }
    136  }
    137  return false;
    138 }
    139 
    140 bool IsHardwareDecryptionSupported(const KeySystemConfig& aConfig) {
    141  for (const auto& robustness : aConfig.mAudioRobustness) {
    142    if (robustness.EqualsLiteral("HW_SECURE_ALL")) {
    143      return true;
    144    }
    145  }
    146  for (const auto& robustness : aConfig.mVideoRobustness) {
    147    if (robustness.EqualsLiteral("3000") ||
    148        robustness.EqualsLiteral("HW_SECURE_ALL") ||
    149        robustness.EqualsLiteral("HW_SECURE_DECODE")) {
    150      return true;
    151    }
    152  }
    153  return false;
    154 }
    155 
    156 #ifdef MOZ_WMF_CDM
    157 void MFCDMCapabilitiesIPDLToKeySystemConfig(
    158    const MFCDMCapabilitiesIPDL& aCDMConfig,
    159    KeySystemConfig& aKeySystemConfig) {
    160  aKeySystemConfig.mKeySystem = aCDMConfig.keySystem();
    161 
    162  for (const auto& type : aCDMConfig.initDataTypes()) {
    163    aKeySystemConfig.mInitDataTypes.AppendElement(type);
    164  }
    165 
    166  for (const auto& type : aCDMConfig.sessionTypes()) {
    167    aKeySystemConfig.mSessionTypes.AppendElement(type);
    168  }
    169 
    170  for (const auto& c : aCDMConfig.videoCapabilities()) {
    171    if (!c.robustness().IsEmpty() &&
    172        !aKeySystemConfig.mVideoRobustness.Contains(c.robustness())) {
    173      aKeySystemConfig.mVideoRobustness.AppendElement(c.robustness());
    174    }
    175    CryptoSchemeSet schemes;
    176    for (const auto& scheme : c.encryptionSchemes()) {
    177      schemes += scheme;
    178    }
    179    aKeySystemConfig.mMP4.SetCanDecryptAndDecode(
    180        NS_ConvertUTF16toUTF8(c.contentType()), Some(schemes));
    181  }
    182  for (const auto& c : aCDMConfig.audioCapabilities()) {
    183    if (!c.robustness().IsEmpty() &&
    184        !aKeySystemConfig.mAudioRobustness.Contains(c.robustness())) {
    185      aKeySystemConfig.mAudioRobustness.AppendElement(c.robustness());
    186    }
    187    CryptoSchemeSet schemes;
    188    for (const auto& scheme : c.encryptionSchemes()) {
    189      schemes += scheme;
    190    }
    191    aKeySystemConfig.mMP4.SetCanDecryptAndDecode(
    192        NS_ConvertUTF16toUTF8(c.contentType()), Some(schemes));
    193  }
    194  aKeySystemConfig.mPersistentState = aCDMConfig.persistentState();
    195  aKeySystemConfig.mDistinctiveIdentifier = aCDMConfig.distinctiveID();
    196  EME_LOG("New Capabilities=%s",
    197          NS_ConvertUTF16toUTF8(aKeySystemConfig.GetDebugInfo()).get());
    198 }
    199 #endif
    200 
    201 bool DoesKeySystemSupportClearLead(const nsAString& aKeySystem) {
    202  // I believe that Widevine L3 supports clear-lead, but I couldn't find any
    203  // official documentation to prove that. The only one I can find is that Shaka
    204  // player mentions the clear lead feature. So we expect L3 should have that as
    205  // well. But for HWDRM, Widevine L1 and SL3000 needs to rely on special checks
    206  // to know whether clearlead is supported. That will be implemented by
    207  // querying for special key system names.
    208  // https://shaka-project.github.io/shaka-packager/html/documentation.html
    209 #ifdef MOZ_WMF_CDM
    210  if (aKeySystem.EqualsLiteral(kWidevineExperiment2KeySystemName) ||
    211      aKeySystem.EqualsLiteral(kPlayReadyHardwareClearLeadKeySystemName)) {
    212    return true;
    213  }
    214 #endif
    215  return aKeySystem.EqualsLiteral(kWidevineKeySystemName);
    216 }
    217 
    218 bool CheckIfHarewareDRMConfigExists(
    219    const nsTArray<dom::MediaKeySystemConfiguration>& aConfigs) {
    220  bool foundHWDRMconfig = false;
    221  for (const auto& config : aConfigs) {
    222    if (IsHardwareDecryptionSupported(config)) {
    223      foundHWDRMconfig = true;
    224      break;
    225    }
    226  }
    227  return foundHWDRMconfig;
    228 }
    229 
    230 bool DoesKeySystemSupportHardwareDecryption(const nsAString& aKeySystem) {
    231 #ifdef MOZ_WMF_CDM
    232  if (aKeySystem.EqualsLiteral(kPlayReadyKeySystemHardware) ||
    233      aKeySystem.EqualsLiteral(kPlayReadyHardwareClearLeadKeySystemName) ||
    234      aKeySystem.EqualsLiteral(kWidevineExperimentKeySystemName) ||
    235      aKeySystem.EqualsLiteral(kWidevineExperiment2KeySystemName)) {
    236    return true;
    237  }
    238 #endif
    239  return false;
    240 }
    241 
    242 void DeprecationWarningLog(const dom::Document* aDocument,
    243                           const char* aMsgName) {
    244  if (!aDocument || !aMsgName) {
    245    return;
    246  }
    247  EME_LOG("DeprecationWarning Logging deprecation warning '%s' to WebConsole.",
    248          aMsgName);
    249  nsTHashMap<nsCharPtrHashKey, bool> warnings;
    250  warnings.InsertOrUpdate(aMsgName, true);
    251  AutoTArray<nsString, 1> params;
    252  nsString& uri = *params.AppendElement();
    253  (void)aDocument->GetDocumentURI(uri);
    254  nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "Media"_ns,
    255                                  aDocument, nsContentUtils::eDOM_PROPERTIES,
    256                                  aMsgName, params);
    257 }
    258 
    259 Maybe<nsCString> GetOrigin(const dom::Document* aDocument) {
    260  if (!aDocument) {
    261    return Nothing();
    262  }
    263  nsCOMPtr<nsIScriptObjectPrincipal> sop =
    264      do_QueryInterface(aDocument->GetInnerWindow());
    265  if (!sop) {
    266    return Nothing();
    267  }
    268  auto* principal = sop->GetPrincipal();
    269  nsAutoCString origin;
    270  nsresult rv = principal->GetOrigin(origin);
    271  if (NS_FAILED(rv)) {
    272    return Nothing();
    273  }
    274  return Some(origin);
    275 }
    276 
    277 }  // namespace mozilla