From bbe9f6afc4b5ebbb68d3500f6004fb6cb3f1a876 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Mon, 16 Mar 2020 18:18:46 -0700 Subject: [PATCH 1/2] Add ATSC support - part 1 [ Merge of http://go/wvgerrit/100864 and http://go/ag/10704773 ] ATSC 3.0 allows for licenses to be downloaded OTA and are tied to a DRM certificate that may be shared across apps. The provisioning process for ATSC may happen at the factory or during an OS update. This contrasts from the regular OTT model, which requires that provisioning and license download have an uplink as well as a downlink connection. This adds support for the ATSC mode property. ATSC mode can only be set (or unset) before sessions are opened. Once the CDM identifier is set/sealed, requests to modify the ATSC mode will be rejected. If one needs to open sessions with both ATSC mode and regular (non-ATSC) mode, separate MediaDrm objects will need to be created. The default mode is to not use ATSC. Enable ATSC mode by calling mediaDrm.setPropertyString("atscMode", "enable") Disable ATSC mode by calling mediaDrm.setPropertyString("atscMode", "disable") Provisioning and unprovisioning requests for ATSC will be rejected as certificates will be retrieved by the ATSC service. Bug: 139730600 Test: WV unit/integration test, GtsMediaTestCases Change-Id: I142f286c711fe007ff42125c3c8cdc6450b6ea36 --- .../core/include/cdm_client_property_set.h | 1 + .../cdm/core/include/wv_cdm_constants.h | 1 + .../cdm/core/include/wv_cdm_types.h | 4 +- libwvdrmengine/cdm/core/src/cdm_engine.cpp | 1 + .../cdm_engine_metrics_decorator_unittest.cpp | 2 + .../cdm/core/test/license_request.h | 4 +- .../test/service_certificate_unittest.cpp | 1 + .../cdm/core/test/test_printers.cpp | 3 + .../cdm/test/cdm_extended_duration_test.cpp | 8 +- .../cdm/test/request_license_test.cpp | 6 +- libwvdrmengine/include/WVErrors.h | 7 +- libwvdrmengine/include/mapErrors-inl.h | 2 + libwvdrmengine/include_hidl/mapErrors-inl.h | 1 + libwvdrmengine/mediadrm/include/WVDrmPlugin.h | 12 +- .../mediadrm/include_hidl/WVDrmPlugin.h | 15 +- libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp | 23 +++ .../mediadrm/src_hidl/WVDrmPlugin.cpp | 42 +++++- .../mediadrm/test/WVDrmPlugin_test.cpp | 133 ++++++++++++++++++ 18 files changed, 256 insertions(+), 10 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/cdm_client_property_set.h b/libwvdrmengine/cdm/core/include/cdm_client_property_set.h index 38398ebe..e6c7ba4c 100644 --- a/libwvdrmengine/cdm/core/include/cdm_client_property_set.h +++ b/libwvdrmengine/cdm/core/include/cdm_client_property_set.h @@ -24,6 +24,7 @@ class CdmClientPropertySet { virtual uint32_t session_sharing_id() const = 0; virtual void set_session_sharing_id(uint32_t id) = 0; virtual const std::string& app_id() const = 0; + virtual bool use_atsc_mode() const = 0; }; } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h index 5d427e20..0c152b07 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h @@ -45,6 +45,7 @@ static const uint32_t OEM_CRYPTO_API_VERSION_SUPPORTS_RESOURCE_RATING_TIER = 15; static const char SESSION_ID_PREFIX[] = "sid"; static const char KEY_SET_ID_PREFIX[] = "ksid"; static const char KEY_SYSTEM[] = "com.widevine"; +static const char ATSC_APP_PACKAGE_NAME[] = "org.atsc"; // define query keys, values here static const std::string QUERY_KEY_LICENSE_TYPE = diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 7d87adfe..c06ed7e5 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -408,10 +408,12 @@ enum CdmResponseType { CANNOT_DECRYPT_ZERO_SUBSAMPLES = 354, SAMPLE_AND_SUBSAMPLE_SIZE_MISMATCH = 355, INVALID_IV_SIZE = 356, - LOAD_USAGE_ENTRY_INVALID_SESSION = 357, + PROVISIONING_NOT_ALLOWED_FOR_ATSC = 357, + // 357 was |LOAD_USAGE_ENTRY_INVALID_SESSION| in early R builds MOVE_USAGE_ENTRY_DESTINATION_IN_USE = 358, SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE = 359, LICENSE_USAGE_ENTRY_MISSING = 360, + LOAD_USAGE_ENTRY_INVALID_SESSION = 361, // Don't forget to add new values to // * core/test/test_printers.cpp. // * android/include/mapErrors-inl.h diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index 66309966..c18dc339 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -62,6 +62,7 @@ class UsagePropertySet : public CdmClientPropertySet { void set_session_sharing_id(uint32_t /* id */) override {} const std::string& app_id() const override { return app_id_; } void set_app_id(const std::string& appId) { app_id_ = appId; } + bool use_atsc_mode() const override { return false; } private: std::string app_id_; diff --git a/libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp b/libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp index 6d09be08..4b9d2d4b 100644 --- a/libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_engine_metrics_decorator_unittest.cpp @@ -38,6 +38,8 @@ class MockCdmClientPropertySet : public CdmClientPropertySet { MOCK_CONST_METHOD0(is_session_sharing_enabled, bool()); MOCK_CONST_METHOD0(session_sharing_id, uint32_t()); MOCK_METHOD1(set_session_sharing_id, void(uint32_t)); + MOCK_CONST_METHOD0(use_atsc_mode, bool()); + MOCK_METHOD1(set_use_atsc_mode, void(bool)); MOCK_CONST_METHOD0(app_id, const std::string&()); }; diff --git a/libwvdrmengine/cdm/core/test/license_request.h b/libwvdrmengine/cdm/core/test/license_request.h index 93254c1e..6188d8e4 100644 --- a/libwvdrmengine/cdm/core/test/license_request.h +++ b/libwvdrmengine/cdm/core/test/license_request.h @@ -15,8 +15,8 @@ namespace wvcdm { // Google license servers. class LicenseRequest { public: - LicenseRequest() {}; - ~LicenseRequest() {}; + LicenseRequest() {} + ~LicenseRequest() {} void GetDrmMessage(const std::string& response, std::string& drm_msg); diff --git a/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp b/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp index aecbc92a..6958d307 100644 --- a/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/service_certificate_unittest.cpp @@ -79,6 +79,7 @@ class StubCdmClientPropertySet : public CdmClientPropertySet { } uint32_t session_sharing_id() const override { return session_sharing_id_; } + virtual bool use_atsc_mode() const { return false; } void set_session_sharing_id(uint32_t id) override { session_sharing_id_ = id; diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index 25bb54b9..6caa8931 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -935,6 +935,9 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { case WEBM_INIT_DATA_UNAVAILABLE: *os << "WEBM_INIT_DATA_UNAVAILABLE"; break; + case PROVISIONING_NOT_ALLOWED_FOR_ATSC: + *os << "PROVISIONING_NOT_ALLOWED_FOR_ATSC"; + break; default: *os << "Unknown CdmResponseType"; break; diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index caf0ae10..d7fd97ba 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -198,7 +198,8 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { TestWvCdmClientPropertySet() : use_privacy_mode_(false), is_session_sharing_enabled_(false), - session_sharing_id_(0) {} + session_sharing_id_(0), + use_atsc_mode_(false) {} virtual ~TestWvCdmClientPropertySet() {} virtual const std::string& app_id() const { return app_id_; } @@ -214,6 +215,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { return is_session_sharing_enabled_; } virtual uint32_t session_sharing_id() const { return session_sharing_id_; } + virtual bool use_atsc_mode() const { return use_atsc_mode_; } void set_app_id(const std::string& app_id) { app_id_ = app_id; } void set_security_level(const std::string& security_level) { @@ -229,6 +231,9 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { is_session_sharing_enabled_ = enable; } void set_session_sharing_id(uint32_t id) { session_sharing_id_ = id; } + void set_use_atsc_mode(bool use_atsc_mode) { + use_atsc_mode_ = use_atsc_mode; + } private: std::string app_id_; @@ -237,6 +242,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { bool use_privacy_mode_; bool is_session_sharing_enabled_; uint32_t session_sharing_id_; + bool use_atsc_mode_; }; class WvCdmExtendedDurationTest : public WvCdmTestBase { diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index f3c562af..a5da0c50 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -1608,7 +1608,8 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { TestWvCdmClientPropertySet() : use_privacy_mode_(false), is_session_sharing_enabled_(false), - session_sharing_id_(0) {} + session_sharing_id_(0), + use_atsc_mode_(false) {} virtual ~TestWvCdmClientPropertySet() {} virtual const std::string& app_id() const { return app_id_; } @@ -1624,6 +1625,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { return is_session_sharing_enabled_; } virtual uint32_t session_sharing_id() const { return session_sharing_id_; } + virtual bool use_atsc_mode() const { return use_atsc_mode_; } void set_app_id(const std::string& app_id) { app_id_ = app_id; } void set_security_level(const std::string& security_level) { @@ -1639,6 +1641,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { is_session_sharing_enabled_ = enable; } void set_session_sharing_id(uint32_t id) { session_sharing_id_ = id; } + void set_use_atsc_mode(bool use_atsc_mode) { use_atsc_mode_ = use_atsc_mode; } private: std::string app_id_; @@ -1647,6 +1650,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet { bool use_privacy_mode_; bool is_session_sharing_enabled_; uint32_t session_sharing_id_; + bool use_atsc_mode_; }; class TestWvCdmEventListener : public WvCdmEventListener { diff --git a/libwvdrmengine/include/WVErrors.h b/libwvdrmengine/include/WVErrors.h index d0bf031c..9cfb2228 100644 --- a/libwvdrmengine/include/WVErrors.h +++ b/libwvdrmengine/include/WVErrors.h @@ -289,14 +289,17 @@ enum { kCannotDecryptZeroSubsamples = ERROR_DRM_VENDOR_MIN + 306, kSampleAndSubsampleSizeMismatch = ERROR_DRM_VENDOR_MIN + 307, kInvalidIvSize = ERROR_DRM_VENDOR_MIN + 308, - kLoadUsageEntryInvalidSession = ERROR_DRM_VENDOR_MIN + 309, + kProvisioningNotAllowedForAtsc = ERROR_DRM_VENDOR_MIN + 309, + // ERROR_DRM_VENDOR_MIN + 309 was |kLoadUsageEntryInvalidSession| + // in early R builds kMoveUsageEntryDestinationInUse = ERROR_DRM_VENDOR_MIN + 310, kShrinkUsageTableHeaderEntryInUse = ERROR_DRM_VENDOR_MIN + 311, kLicenseUsageEntryMissing = ERROR_DRM_VENDOR_MIN + 312, + kLoadUsageEntryInvalidSession = ERROR_DRM_VENDOR_MIN + 313, // This should always follow the last error code. // The offset value should be updated each time a new error code is added. - kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 312, + kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 313, // Used by crypto test mode kErrorTestMode = ERROR_DRM_VENDOR_MAX, diff --git a/libwvdrmengine/include/mapErrors-inl.h b/libwvdrmengine/include/mapErrors-inl.h index c86726ed..e7315d7f 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -442,6 +442,8 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return kPrivacyModeError2; case wvcdm::PRIVACY_MODE_ERROR_3: return kPrivacyModeError3; + case wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC: + return kProvisioningNotAllowedForAtsc; case wvcdm::REFRESH_KEYS_ERROR: return kRefreshKeysError; case wvcdm::REINIT_ERROR: diff --git a/libwvdrmengine/include_hidl/mapErrors-inl.h b/libwvdrmengine/include_hidl/mapErrors-inl.h index dfd4daa4..c6f61778 100644 --- a/libwvdrmengine/include_hidl/mapErrors-inl.h +++ b/libwvdrmengine/include_hidl/mapErrors-inl.h @@ -359,6 +359,7 @@ static Status mapCdmResponseType(wvcdm::CdmResponseType res) { case wvcdm::MOVE_USAGE_ENTRY_DESTINATION_IN_USE: case wvcdm::SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE: case wvcdm::LICENSE_USAGE_ENTRY_MISSING: + case wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC: ALOGW("Returns UNKNOWN error for legacy status: %d", res); return Status::ERROR_DRM_UNKNOWN; diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index 6b9fa6d5..3284a901 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -190,7 +190,8 @@ class WVDrmPlugin : public android::DrmPlugin, class WVClientPropertySet : public wvcdm::CdmClientPropertySet { public: WVClientPropertySet() - : mUsePrivacyMode(false), mShareKeys(false), mSessionSharingId(0) {} + : mUsePrivacyMode(false), mShareKeys(false), mSessionSharingId(0), + mUseAtscMode(false) {} virtual ~WVClientPropertySet() {} @@ -243,6 +244,14 @@ class WVDrmPlugin : public android::DrmPlugin, mAppId = appId; } + virtual bool use_atsc_mode() const { + return mUseAtscMode; + } + + void set_use_atsc_mode(bool useAtscMode) { + mUseAtscMode = useAtscMode; + } + private: DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet); @@ -252,6 +261,7 @@ class WVDrmPlugin : public android::DrmPlugin, bool mShareKeys; uint32_t mSessionSharingId; std::string mAppId; + bool mUseAtscMode; const std::string mEmptyString; } mPropertySet; diff --git a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h index 8f0608a8..06cf4d59 100644 --- a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h @@ -287,7 +287,8 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, class WVClientPropertySet : public wvcdm::CdmClientPropertySet { public: WVClientPropertySet() - : mUsePrivacyMode(false), mShareKeys(false), mSessionSharingId(0) {} + : mUsePrivacyMode(false), mShareKeys(false), mSessionSharingId(0), + mUseAtscMode(false) {} virtual ~WVClientPropertySet() {} @@ -351,6 +352,14 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, mAppId = appId; } + virtual bool use_atsc_mode() const { + return mUseAtscMode; + } + + void set_use_atsc_mode(bool useAtscMode) { + mUseAtscMode = useAtscMode; + } + private: DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet); @@ -360,6 +369,7 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, bool mShareKeys; uint32_t mSessionSharingId; std::string mAppId; + bool mUseAtscMode; const std::string mEmptyString; } mPropertySet; @@ -385,6 +395,9 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, const std::string& origin() const { return mCdmIdentifier.origin; } bool set_origin(const std::string& id); + // This sets the app package name to allow apps to access ATSC licenses + bool set_use_atsc_mode(bool enable); + // Indicates whether the builder can still be modified. This returns false // until a call to getCdmIdentifier. bool is_sealed() { return mIsIdentifierSealed; } diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index ccb01a65..70164ae4 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -364,6 +364,10 @@ status_t WVDrmPlugin::getProvisionRequest(const String8& cert_type, CdmProvisioningRequest cdmProvisionRequest; string cdmDefaultUrl; + if (mPropertySet.use_atsc_mode()) { + return mapCdmResponseType(wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC); + } + CdmCertificateType cdmCertType = kCertificateWidevine; if (cert_type == "X.509") { cdmCertType = kCertificateX509; @@ -551,6 +555,12 @@ status_t WVDrmPlugin::getPropertyString(const String8& name, return queryProperty(QUERY_KEY_MAX_USAGE_TABLE_ENTRIES, value); } else if (name == "oemCryptoApiMinorVersion") { return queryProperty(QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION, value); + } else if (name == "atscMode") { + if (mPropertySet.use_atsc_mode()) { + value = kEnable; + } else { + value = kDisable; + } } else { ALOGE("App requested unknown string property %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; @@ -663,6 +673,15 @@ status_t WVDrmPlugin::setPropertyString(const String8& name, return mapCdmResponseType(res); } else if (name == "decryptHashSessionId") { mDecryptHashSessionId = value.string(); + } else if (name == "atscMode") { + if (value == kEnable) { + mPropertySet.set_use_atsc_mode(true); + } else if (value == kDisable) { + mPropertySet.set_use_atsc_mode(false); + } else { + ALOGE("App requested unknown atsc mode %s", value.string()); + return android::BAD_VALUE; + } } else { ALOGE("App set unknown string property %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; @@ -1087,6 +1106,10 @@ bool WVDrmPlugin::initDataResemblesPSSH(const Vector& initData) { } status_t WVDrmPlugin::unprovision(const CdmIdentifier& identifier) { + if (mPropertySet.use_atsc_mode()) { + return mapCdmResponseType(wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC); + } + CdmResponseType res1 = mCDM->Unprovision(kSecurityLevelL1, identifier); CdmResponseType res3 = mCDM->Unprovision(kSecurityLevelL3, identifier); if (!isCdmResponseTypeSuccess(res1)) diff --git a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp index 205f842e..d14d6ed3 100644 --- a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp @@ -700,6 +700,12 @@ Return WVDrmPlugin::getProvisionRequest_1_2( std::string defaultUrl; std::vector request; + if (mPropertySet.use_atsc_mode()) { + _hidl_cb(mapCdmResponseType_1_2(wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC), + toHidlVec(request), hidl_string(defaultUrl)); + return Void(); + } + CdmIdentifier identifier; status = static_cast(mCdmIdentifierBuilder.getCdmIdentifier(&identifier)); if (status != Status_V1_2::OK) { @@ -1261,6 +1267,12 @@ Return WVDrmPlugin::getPropertyString(const hidl_string& propertyName, status = queryProperty(wvcdm::QUERY_KEY_MAX_USAGE_TABLE_ENTRIES, value); } else if (name == "oemCryptoApiMinorVersion") { status = queryProperty(wvcdm::QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION, value); + } else if (name == "atscMode") { + if (mPropertySet.use_atsc_mode()) { + value = kEnable; + } else { + value = kDisable; + } } else { ALOGE("App requested unknown string property %s", name.c_str()); status = Status::ERROR_DRM_CANNOT_HANDLE; @@ -1413,6 +1425,23 @@ Return WVDrmPlugin::setPropertyString(const hidl_string& propertyName, return mapCdmResponseType(res); } else if (name == "decryptHashSessionId") { mDecryptHashSessionId = _value.c_str(); + } else if (name == "atscMode") { + if (_value == kEnable) { + if (!mCdmIdentifierBuilder.set_use_atsc_mode(true)) { + ALOGE("Cdm identifier builder is sealed. Setting ATSC mode prohibited"); + return Status::BAD_VALUE; + } + mPropertySet.set_use_atsc_mode(true); + } else if (_value == kDisable) { + if (!mCdmIdentifierBuilder.set_use_atsc_mode(false)) { + ALOGE("Cdm identifier builder is sealed. Setting ATSC mode prohibited"); + return Status::BAD_VALUE; + } + mPropertySet.set_use_atsc_mode(false); + } else { + ALOGE("App requested unknown ATSC mode %s", _value.c_str()); + return Status::BAD_VALUE; + } } else { ALOGE("App set unknown string property %s", name.c_str()); return Status::ERROR_DRM_CANNOT_HANDLE; @@ -2077,6 +2106,9 @@ bool WVDrmPlugin::initDataResemblesPSSH(const std::vector& initData) { } Status WVDrmPlugin::unprovision(const CdmIdentifier& identifier) { + if (mPropertySet.use_atsc_mode()) + return mapCdmResponseType(wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC); + CdmResponseType res1 = mCDM->Unprovision(wvcdm::kSecurityLevelL1, identifier); CdmResponseType res3 = mCDM->Unprovision(wvcdm::kSecurityLevelL3, identifier); if (!isCdmResponseTypeSuccess(res1)) @@ -2149,6 +2181,13 @@ bool WVDrmPlugin::CdmIdentifierBuilder::set_origin(const std::string& id) { return true; } +bool WVDrmPlugin::CdmIdentifierBuilder::set_use_atsc_mode(bool enable) { + if (is_sealed()) return false; + mCdmIdentifier.app_package_name = + enable ? wvcdm::ATSC_APP_PACKAGE_NAME : mAppPackageName; + return true; +} + Status WVDrmPlugin::CdmIdentifierBuilder::calculateSpoid() { if (mUseSpoid) { std::string deviceId; @@ -2159,7 +2198,8 @@ Status WVDrmPlugin::CdmIdentifierBuilder::calculateSpoid() { SHA256_CTX ctx; SHA256_Init(&ctx); SHA256_Update(&ctx, deviceId.data(), deviceId.length()); - SHA256_Update(&ctx, mAppPackageName.data(), mAppPackageName.length()); + SHA256_Update(&ctx, mCdmIdentifier.app_package_name.data(), + mCdmIdentifier.app_package_name.length()); SHA256_Update(&ctx, origin().data(), origin().length()); SHA256_Final(hash, &ctx); diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp index 2dbb8669..6d04209f 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp @@ -901,6 +901,23 @@ TEST_F(WVDrmPluginTest, GetsProvisioningRequests) { }); } +TEST_F(WVDrmPluginTest, RejectsAtscProvisioningRequests) { + android::sp> cdm = new StrictMock(); + StrictMock crypto; + std::string appPackageName; + + WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); + + Status status = plugin.setPropertyString(hidl_string("atscMode"), + hidl_string("enable")); + + plugin.getProvisionRequest( + hidl_string(""), hidl_string(""), + [&](Status status, hidl_vec , hidl_string ) { + ASSERT_EQ(Status::ERROR_DRM_UNKNOWN, status); + }); +} + TEST_F(WVDrmPluginTest, HandlesProvisioningResponses) { android::sp> cdm = new StrictMock(); StrictMock crypto; @@ -1129,6 +1146,20 @@ TEST_F(WVDrmPluginTest, MuxesOriginUnprovisioningErrors) { }); } +TEST_F(WVDrmPluginTest, RejectsAtscUnprovisionDeviceRequests) { + android::sp> cdm = new StrictMock(); + StrictMock crypto; + std::string appPackageName; + + WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); + + Status status = plugin.setPropertyString(hidl_string("atscMode"), + hidl_string("enable")); + + status = plugin.unprovisionDevice(); + ASSERT_EQ(Status::ERROR_DRM_UNKNOWN, status); +} + TEST_F(WVDrmPluginTest, GetsSecureStops) { android::sp> cdm = new StrictMock(); StrictMock crypto; @@ -2708,6 +2739,108 @@ TEST_F(WVDrmPluginTest, AllowsStoringOfSessionSharingId) { EXPECT_EQ(sharingId, propertySet->session_sharing_id()); } +TEST_F(WVDrmPluginTest, CanSetAtscMode) { + android::sp> cdm = new StrictMock(); + StrictMock crypto; + std::string appPackageName = "com.test.package"; + + const CdmClientPropertySet* propertySet = nullptr; + CdmIdentifier cdmIdAtscModeNotSet; + CdmIdentifier cdmIdAtscModeSet; + CdmIdentifier cdmIdAtscModeReset; + + // Provide expected mock behavior + { + // Provide expected behavior in response to OpenSession and store the + // property set + EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) + .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), + SaveArg<1>(&propertySet), + SaveArg<2>(&cdmIdAtscModeNotSet), + testing::Return(wvcdm::NO_ERROR))) + .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), + SaveArg<1>(&propertySet), + SaveArg<2>(&cdmIdAtscModeSet), + testing::Return(wvcdm::NO_ERROR))) + .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), + SaveArg<1>(&propertySet), + SaveArg<2>(&cdmIdAtscModeReset), + testing::Return(wvcdm::NO_ERROR))); + + // Provide expected behavior when plugin requests session control info + EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) + .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); + + EXPECT_CALL(*cdm, CloseSession(_)) + .Times(AtLeast(0)); + } + + WVDrmPlugin plugin1(cdm.get(), appPackageName, &crypto, false); + + // Verify that ATSC mode is disabled by default + plugin1.openSession([&](Status status, hidl_vec hSessionId) { + ASSERT_EQ(Status::OK, status); + sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); + }); + ASSERT_THAT(propertySet, NotNull()); + EXPECT_FALSE(propertySet->use_atsc_mode()); + EXPECT_EQ(cdmIdAtscModeNotSet.app_package_name, appPackageName); + Status status = plugin1.closeSession(toHidlVec(sessionId)); + ASSERT_EQ(Status::OK, status); + + // Verify that ATSC mode can be enabled + WVDrmPlugin plugin2(cdm.get(), appPackageName, &crypto, false); + + // Test turning on ATSC mode + status = plugin2.setPropertyString(hidl_string("atscMode"), + hidl_string("enable")); + ASSERT_EQ(Status::OK, status); + + plugin2.openSession([&](Status status, hidl_vec hSessionId) { + ASSERT_EQ(Status::OK, status); + sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); + }); + ASSERT_THAT(propertySet, NotNull()); + EXPECT_TRUE(propertySet->use_atsc_mode()); + EXPECT_EQ(cdmIdAtscModeSet.app_package_name, wvcdm::ATSC_APP_PACKAGE_NAME); + status = plugin2.closeSession(toHidlVec(sessionId)); + ASSERT_EQ(Status::OK, status); + + + // Verify that ATSC mode can be enabled and disabled + WVDrmPlugin plugin3(cdm.get(), appPackageName, &crypto, false); + + // Test turning on ATSC mode + status = plugin3.setPropertyString(hidl_string("atscMode"), + hidl_string("enable")); + ASSERT_EQ(Status::OK, status); + + // Test turning off ATSC mode + status = plugin3.setPropertyString(hidl_string("atscMode"), + hidl_string("disable")); + ASSERT_EQ(Status::OK, status); + + plugin3.openSession([&](Status status, hidl_vec hSessionId) { + ASSERT_EQ(Status::OK, status); + sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); + }); + ASSERT_THAT(propertySet, NotNull()); + EXPECT_FALSE(propertySet->use_atsc_mode()); + EXPECT_EQ(cdmIdAtscModeReset.app_package_name, appPackageName); + status = plugin3.closeSession(toHidlVec(sessionId)); + ASSERT_EQ(Status::OK, status); + + // Test turning on and off ATSC mode. They should be rejected since the SPOID + // has been calculated + status = plugin3.setPropertyString(hidl_string("atscMode"), + hidl_string("enable")); + ASSERT_NE(Status::OK, status); + + status = plugin3.setPropertyString(hidl_string("atscMode"), + hidl_string("disable")); + ASSERT_NE(Status::OK, status); +} + TEST_F(WVDrmPluginTest, CanSetDecryptHashProperties) { android::sp> cdm = new StrictMock(); StrictMock crypto; From 8da11450122c3debee0c5028dd03a4f7ab402f26 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Tue, 17 Mar 2020 01:35:01 -0700 Subject: [PATCH 2/2] Add ATSC support - part 2 [ Merge of http://go/wvgerrit/100905 and http://go/ag/10708438 ] Add support for ATSC certificate and licenses handling. ATSC files are distinguished from the apps DRM certificate and licenses by file naming conventions. Bug: 139730600 Test: WV unit/integration test, GtsMediaTestCases Change-Id: I295f66f92fe01d7716978deac9dc360d74addedd --- libwvdrmengine/cdm/core/include/cdm_session.h | 2 +- .../cdm/core/include/device_files.h | 13 +- .../cdm/core/include/wv_cdm_constants.h | 1 + libwvdrmengine/cdm/core/src/cdm_session.cpp | 18 +- libwvdrmengine/cdm/core/src/device_files.cpp | 23 ++- .../cdm/core/test/cdm_session_unittest.cpp | 22 +-- .../cdm/core/test/device_files_unittest.cpp | 166 ++++++++++-------- .../cdm/test/request_license_test.cpp | 8 +- 8 files changed, 143 insertions(+), 110 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index 65f96955..6325e49e 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -219,7 +219,7 @@ class CdmSession { private: friend class CdmSessionTest; - bool GenerateKeySetId(CdmKeySetId* key_set_id); + bool GenerateKeySetId(bool atsc_mode_enabled, CdmKeySetId* key_set_id); CdmResponseType StoreLicense(); diff --git a/libwvdrmengine/cdm/core/include/device_files.h b/libwvdrmengine/cdm/core/include/device_files.h index 5de50572..70f55e36 100644 --- a/libwvdrmengine/cdm/core/include/device_files.h +++ b/libwvdrmengine/cdm/core/include/device_files.h @@ -95,13 +95,16 @@ class DeviceFiles { return Init(security_level); } + // ATSC certificates are installed by the ATSC service. They can be read + // and used but not written or removed. virtual bool StoreCertificate(const std::string& certificate, const std::string& wrapped_private_key); - virtual bool RetrieveCertificate(std::string* certificate, + virtual bool RetrieveCertificate(bool atsc_mode_enabled, + std::string* certificate, std::string* wrapped_private_key, std::string* serial_number, uint32_t* system_id); - virtual bool HasCertificate(); + virtual bool HasCertificate(bool atsc_mode_enabled); virtual bool RemoveCertificate(); virtual bool StoreLicense(const CdmLicenseData& license_data, @@ -256,7 +259,7 @@ class DeviceFiles { bool RemoveFile(const std::string& name); ssize_t GetFileSize(const std::string& name); - static std::string GetCertificateFileName(); + static std::string GetCertificateFileName(bool atsc_mode_enabled); static std::string GetHlsAttributesFileNameExtension(); static std::string GetLicenseFileNameExtension(); static std::string GetUsageTableFileName(); @@ -264,8 +267,8 @@ class DeviceFiles { #if defined(UNIT_TEST) FRIEND_TEST(DeviceFilesSecurityLevelTest, SecurityLevel); - FRIEND_TEST(DeviceCertificateStoreTest, StoreCertificate); - FRIEND_TEST(DeviceCertificateTest, DISABLED_ReadCertificate); + FRIEND_TEST(DeviceCertificateTest, StoreCertificate); + FRIEND_TEST(DeviceCertificateTest, ReadCertificate); FRIEND_TEST(DeviceCertificateTest, HasCertificate); FRIEND_TEST(DeviceFilesStoreTest, StoreLicense); FRIEND_TEST(DeviceFilesHlsAttributesTest, Delete); diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h index 0c152b07..3db2a051 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h @@ -43,6 +43,7 @@ static const uint32_t RESOURCE_RATING_TIER_MAX = RESOURCE_RATING_TIER_VERY_HIGH; static const uint32_t OEM_CRYPTO_API_VERSION_SUPPORTS_RESOURCE_RATING_TIER = 15; static const char SESSION_ID_PREFIX[] = "sid"; +static const char ATSC_KEY_SET_ID_PREFIX[] = "atscksid"; static const char KEY_SET_ID_PREFIX[] = "ksid"; static const char KEY_SYSTEM[] = "com.widevine"; static const char ATSC_APP_PACKAGE_NAME[] = "org.atsc"; diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 6955ed52..9dd23530 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -159,8 +159,12 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set, // License server client ID token is a stored certificate. Stage it or // indicate that provisioning is needed. Get token from stored certificate std::string wrapped_key; - if (!file_handle_->RetrieveCertificate(&client_token, &wrapped_key, - &serial_number, nullptr)) { + bool atsc_mode_enabled = false; + if (cdm_client_property_set != nullptr) + atsc_mode_enabled = cdm_client_property_set->use_atsc_mode(); + if (!file_handle_->RetrieveCertificate(atsc_mode_enabled, &client_token, + &wrapped_key, &serial_number, + nullptr)) { return NEED_PROVISIONING; } CdmResponseType load_cert_sts; @@ -186,7 +190,7 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set, if (forced_session_id) { key_set_id_ = *forced_session_id; } else { - bool ok = GenerateKeySetId(&key_set_id_); + bool ok = GenerateKeySetId(atsc_mode_enabled, &key_set_id_); (void)ok; // ok is now used when assertions are turned off. assert(ok); } @@ -849,7 +853,8 @@ CdmSessionId CdmSession::GenerateSessionId() { return SESSION_ID_PREFIX + IntToString(++session_num); } -bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) { +bool CdmSession::GenerateKeySetId(bool atsc_mode_enabled, + CdmKeySetId* key_set_id) { RETURN_FALSE_IF_NULL(key_set_id); std::vector random_data( @@ -861,7 +866,10 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) { return false; } - *key_set_id = KEY_SET_ID_PREFIX + b2a_hex(random_data); + if (atsc_mode_enabled) + *key_set_id = ATSC_KEY_SET_ID_PREFIX + b2a_hex(random_data); + else + *key_set_id = KEY_SET_ID_PREFIX + b2a_hex(random_data); // key set collision if (file_handle_->LicenseExists(*key_set_id)) { diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index c49c34db..0401e8f8 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -70,6 +70,7 @@ using video_widevine_client::sdk:: namespace { +const char kAtscCertificateFileName[] = "atsccert.bin"; const char kCertificateFileName[] = "cert.bin"; const char kHlsAttributesFileNameExt[] = ".hal"; const char kUsageInfoFileNamePrefix[] = "usage"; @@ -126,19 +127,21 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate, std::string serialized_file; file.SerializeToString(&serialized_file); - return StoreFileWithHash(GetCertificateFileName(), serialized_file) == + return StoreFileWithHash(GetCertificateFileName(false), serialized_file) == kNoError; } -bool DeviceFiles::RetrieveCertificate(std::string* certificate, +bool DeviceFiles::RetrieveCertificate(bool atsc_mode_enabled, + std::string* certificate, std::string* wrapped_private_key, std::string* serial_number, uint32_t* system_id) { RETURN_FALSE_IF_UNINITIALIZED(); video_widevine_client::sdk::File file; - if (RetrieveHashedFile(GetCertificateFileName(), &file) != kNoError) { - LOGE("Unable to retrieve certificate file"); + if (RetrieveHashedFile(GetCertificateFileName(atsc_mode_enabled), &file) != + kNoError) { + LOGW("Unable to retrieve certificate file"); return false; } @@ -166,14 +169,16 @@ bool DeviceFiles::RetrieveCertificate(std::string* certificate, device_certificate.certificate(), serial_number, system_id); } -bool DeviceFiles::HasCertificate() { +bool DeviceFiles::HasCertificate(bool atsc_mode_enabled) { RETURN_FALSE_IF_UNINITIALIZED(); - return FileExists(GetCertificateFileName()); + + return FileExists(GetCertificateFileName(atsc_mode_enabled)); } bool DeviceFiles::RemoveCertificate() { RETURN_FALSE_IF_UNINITIALIZED() - return RemoveFile(GetCertificateFileName()); + + return RemoveFile(GetCertificateFileName(false)); } bool DeviceFiles::StoreLicense(const CdmLicenseData& license_data, @@ -1214,8 +1219,8 @@ ssize_t DeviceFiles::GetFileSize(const std::string& name) { return file_system_->FileSize(path); } -std::string DeviceFiles::GetCertificateFileName() { - return kCertificateFileName; +std::string DeviceFiles::GetCertificateFileName(bool atsc_mode_enabled) { + return atsc_mode_enabled ? kAtscCertificateFileName : kCertificateFileName; } std::string DeviceFiles::GetUsageTableFileName() { return kUsageTableFileName; } diff --git a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp index f0ac0731..674939e8 100644 --- a/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/cdm_session_unittest.cpp @@ -114,8 +114,8 @@ class MockDeviceFiles : public DeviceFiles { MockDeviceFiles() : DeviceFiles(nullptr) {} MOCK_METHOD1(Init, bool(CdmSecurityLevel)); - MOCK_METHOD4(RetrieveCertificate, - bool(std::string*, std::string*, std::string*, uint32_t*)); + MOCK_METHOD5(RetrieveCertificate, + bool(bool, std::string*, std::string*, std::string*, uint32_t*)); }; class MockUsageTableHeader : public UsageTableHeader { @@ -217,8 +217,8 @@ TEST_F(CdmSessionTest, InitWithBuiltInCertificate) { EXPECT_CALL(*crypto_session_, GetPreProvisionTokenType()) .WillOnce(Return(kClientTokenDrmCert)); EXPECT_CALL(*file_handle_, - RetrieveCertificate(NotNull(), NotNull(), NotNull(), _)) - .WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey), + RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _)) + .WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey), Return(true))); EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey))) .InSequence(crypto_session_seq) @@ -245,8 +245,8 @@ TEST_F(CdmSessionTest, InitWithCertificate) { .WillOnce(Return(kClientTokenKeybox)); EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true)); EXPECT_CALL(*file_handle_, - RetrieveCertificate(NotNull(), NotNull(), NotNull(), _)) - .WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey), + RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _)) + .WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey), Return(true))); EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey))) .InSequence(crypto_session_seq) @@ -272,8 +272,8 @@ TEST_F(CdmSessionTest, ReInitFail) { .WillOnce(Return(kClientTokenKeybox)); EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true)); EXPECT_CALL(*file_handle_, - RetrieveCertificate(NotNull(), NotNull(), NotNull(), _)) - .WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey), + RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _)) + .WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey), Return(true))); EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey))) .InSequence(crypto_session_seq) @@ -307,7 +307,7 @@ TEST_F(CdmSessionTest, InitNeedsProvisioning) { .WillOnce(Return(kClientTokenKeybox)); EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true)); EXPECT_CALL(*file_handle_, - RetrieveCertificate(NotNull(), NotNull(), NotNull(), _)) + RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _)) .WillOnce(Return(false)); ASSERT_EQ(NEED_PROVISIONING, cdm_session_->Init(nullptr)); @@ -327,8 +327,8 @@ TEST_F(CdmSessionTest, UpdateUsageEntry) { .WillOnce(Return(kClientTokenKeybox)); EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true)); EXPECT_CALL(*file_handle_, - RetrieveCertificate(NotNull(), NotNull(), NotNull(), _)) - .WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey), + RetrieveCertificate(false, NotNull(), NotNull(), NotNull(), _)) + .WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey), Return(true))); EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey))) .InSequence(crypto_session_seq) diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index 6dc0ec11..94564ea1 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -32,27 +32,26 @@ const std::string kEmptyString; // Structurally valid test certificate. // The data elements in this module are used to test the storage and // retrieval of certificates and licenses -const std::string kTestCertificate = - "124B035F3D256A656F0E505A085E7A6C482B61035E0C4A540F7803137F4C3B45206B7F33" - "347F4D7A005E56400F0955011F4E07072D0D46781817460974326A516E3944385760280E" - "4F166B380F033D045231201E6146041C3A6F01345C59300D32592732192C0F2310586306" - "7B31467B1477010D6F1D1944272509572A26217E1E6F7B666F46153E7749106E48760468" - "19467E164A731773155B3236537D5128682014174D125063380E48356A370B5015416A7F" - "672F132E37364E154B41540F440E47092775531508495F1E55576F363C0C190C3A332179" - "415B343905563E37645E68007053315A1A20286E7C3B4320424A5F7F36635558686C3565" - "762122237D344A411C0F00342135776753461D105C21111E5024434E5E0F275D12061658" - "4435410F210E5228532D214F505D0F0B3C34032C7C597F6159665E664C682C5A6C03212E" - "71333C3A642D796A65642E151827086E2D671C130B172C43192C792D294440630163526D" - "0658537A073E0F32231E7426593230692A4468386D3511542F1A6F71440128466E510445" - "294F4465113D1B1A711D4D67691363093B680854322B041C2F72524A513E5F0E407C6233" - "1728520E6C0C09107C26737B78287231661952283619647A6241391940297D2067036D44" - "3C64766918236C51175A636F000A2E5A4C5B725D5500652B1C39283037723F0255092976" - "6F2D204F0E616F1233206B75661B0F755E1E3807491079663A191C0B2D5E363B3768663A" - "4E222A1D32015D3D783E5148313F05713B140347231C59243648313C23770F554E012715" - "3350597775274A580306202E65265957291F490F642A2E7C6700716400617C7E6A303266" - "523B102906195E003C2D111A7D4740122C6941003726602B59263B5C09473D4E025E3541" - "701B122D340A3D145436137002687E4C470D2F6F4C357A3245384D737B734E2274301179" - "402473486311156E5A0C78644C593273"; +const std::string kTestCertificate = a2bs_hex( + "0A98030802120D73657269616C5F6E756D62657218B4B2CDE00422E8024D49494243674B43" + "415145412B78475A2F77637A39756746705030374E73706F365531376C3059684669467078" + "78553470546B334C69667A3952337A734973754552777461372B66574966784F6F32303865" + "74742F6A68736B69566F645345743351424768345842697079576F704B775A393348486144" + "565A41414C692F32412B785442745764456F37584755756A4B447643322F615A4B756B666A" + "704F6955493841684C41666A6D6C63442F555A31515068306D4873676C524E436D7043776D" + "7753584139564E6D687A2B5069422B446D6C3457576E4B572F56486F32756A54587871372B" + "65664D55344832666E79335365334B594F73465046475A31544E5153596C46755368577248" + "5074694C6D5564506F50364356326D4D4C31746B2B6C3744494971587251684C554B444143" + "654D35726F4D78306B4C6855574238502B30756A31434E6C4E4E344A525A6C433778466671" + "694D62465255395A344E3659774944415141422899203A11746573742E7769646576696E65" + "2E636F6D128202307836353063396632653637303165336665373364333035343930346139" + "61346262646239363733336631633463373433656635373361643661633134633561336266" + "38613437333166366536323736666165613532343733303336373766623864626466323466" + "66373865353363323530353263646361383765656366656538353437366263623861303563" + "62396131656665663763623837646436383232336531313763653830306163343631373731" + "37323534343735376134383762653332663561623866653038373966613861646437386265" + "34363565613866386435616366393737653966316165333664346434373831366561366564" + "343133373262"); // A Wrapped Private Key // The data elements in this module are used to test the storage and @@ -76,42 +75,54 @@ const std::string kTestWrappedPrivateKey = // The test certificate in file storage format. // The data elements in this module are used to test the storage and // retrieval of certificates and licenses -const std::string kTestCertificateFileData = - "0ABD09080110011AB6090ABC05124B035F3D256A656F0E505A085E7A6C482B61035E0C4A" - "540F7803137F4C3B45206B7F33347F4D7A005E56400F0955011F4E07072D0D4678181746" - "0974326A516E3944385760280E4F166B380F033D045231201E6146041C3A6F01345C5930" - "0D32592732192C0F23105863067B31467B1477010D6F1D1944272509572A26217E1E6F7B" - "666F46153E7749106E4876046819467E164A731773155B3236537D5128682014174D1250" - "63380E48356A370B5015416A7F672F132E37364E154B41540F440E47092775531508495F" - "1E55576F363C0C190C3A332179415B343905563E37645E68007053315A1A20286E7C3B43" - "20424A5F7F36635558686C3565762122237D344A411C0F00342135776753461D105C2111" - "1E5024434E5E0F275D120616584435410F210E5228532D214F505D0F0B3C34032C7C597F" - "6159665E664C682C5A6C03212E71333C3A642D796A65642E151827086E2D671C130B172C" - "43192C792D294440630163526D0658537A073E0F32231E7426593230692A4468386D3511" - "542F1A6F71440128466E510445294F4465113D1B1A711D4D67691363093B680854322B04" - "1C2F72524A513E5F0E407C62331728520E6C0C09107C26737B7828723166195228361964" - "7A6241391940297D2067036D443C64766918236C51175A636F000A2E5A4C5B725D550065" - "2B1C39283037723F02550929766F2D204F0E616F1233206B75661B0F755E1E3807491079" - "663A191C0B2D5E363B3768663A4E222A1D32015D3D783E5148313F05713B140347231C59" - "243648313C23770F554E0127153350597775274A580306202E65265957291F490F642A2E" - "7C6700716400617C7E6A303266523B102906195E003C2D111A7D4740122C694100372660" - "2B59263B5C09473D4E025E3541701B122D340A3D145436137002687E4C470D2F6F4C357A" - "3245384D737B734E2274301179402473486311156E5A0C78644C59327312F4034F724B06" - "5326371A2F5F6F51467C2E26555C453B5C7C1B4F2738454B782E3E7B5340435A66374D06" - "12052C521A233D7A67194871751C78575E5177070130264C4F037633320E667B1A491929" - "24491338693D106E6113014A733A241A1A033E28352178146B4F543D38104A5919120325" - "502C31365506096D59585E08774B5B567A7B5D03451E6B11633E52672C226103104B3E4C" - "031A6403050F3A574D2C501711773802741F7F3A0D364757101D02181C7D4D3520716750" - "6A424C094E4A72316F791F162D76657D2B5D3C2D7B273A2869277175613165187E552824" - "30491467086425432347701C3116446D21645C756B2D3D0F797C3220322D622A254D0B7D" - "4F1D5D0C0A36755D1246741A34783C45157247091C78232B7D2E0E1F637A2A3739085D76" - "166747034350613969072F5B5C5B21657E470C7E513B3F091D74455A3A0737057B7E3B53" - "37191D4E7536087C334B6028530F3F5B23380B6A076031294501003D6D1F240F63053D5D" - "0B271B6A0F26185650731308660B0447566041684F584C22216E567D3B7755695F7F3D6B" - "64525E7227165948101540243C19495C4C702F37490F2661335379782562414326304302" - "0E1E6760123D51056F2F1E482F2E3D021B27677D3E7E3C0C11757C3448275E08382E1112" - "63644C6D224714706D760A054A586E17505C3429575A41043F1842091220F8D0A23D4B1B" - "C7B23A38B921BC1EA8938D1FD22FF9A389B58DA856A3E2625F27"; +const std::string kTestCertificateFileData = a2bs_hex( + "0A950D080110011A8E0D0AA0050A98030802120D73657269616C5F6E756D62657218B4B2CD" + "E00422E8024D49494243674B43415145412B78475A2F77637A39756746705030374E73706F" + "365531376C305968466946707878553470546B334C69667A3952337A734973754552777461" + "372B66574966784F6F3230386574742F6A68736B69566F6453457433514247683458426970" + "79576F704B775A393348486144565A41414C692F32412B785442745764456F37584755756A" + "4B447643322F615A4B756B666A704F6955493841684C41666A6D6C63442F555A3151506830" + "6D4873676C524E436D7043776D7753584139564E6D687A2B5069422B446D6C3457576E4B57" + "2F56486F32756A54587871372B65664D55344832666E79335365334B594F73465046475A31" + "544E5153596C467553685772485074694C6D5564506F50364356326D4D4C31746B2B6C3744" + "494971587251684C554B444143654D35726F4D78306B4C6855574238502B30756A31434E6C" + "4E4E344A525A6C433778466671694D62465255395A344E3659774944415141422899203A11" + "746573742E7769646576696E652E636F6D1282023078363530633966326536373031653366" + "65373364333035343930346139613462626462393637333366316334633734336566353733" + "61643661633134633561336266386134373331663665363237366661656135323437333033" + "36373766623864626466323466663738653533633235303532636463613837656563666565" + "38353437366263623861303563623961316566656637636238376464363832323365313137" + "63653830306163343631373731373235343437353761343837626533326635616238666530" + "38373966613861646437386265343635656138663864356163663937376539663161653336" + "6434643437383136656136656434313337326212E807344637323442303635333236333731" + "41324635463646353134363743324532363535354334353342354337433142344632373338" + "34353442373832453345374235333430343335413636333734443036313230353243353231" + "41323333443741363731393438373137353143373835373545353137373037303133303236" + "34433446303337363333333230453636374231413439313932393234343931333338363933" + "44313036453631313330313441373333413234314131413033334532383335323137383134" + "36423446353433443338313034413539313931323033323535303243333133363535303630" + "39364435393538354530383737344235423536374137423544303334353145364231313633" + "33453532363732433232363130333130344233453443303331413634303330353046334135" + "37344432433530313731313737333830323734314637463341304433363437353731303144" + "30323138314337443444333532303731363735303641343234433039344534413732333136" + "46373931463136324437363635374432423544334332443742323733413238363932373731" + "37353631333136353138374535353238323433303439313436373038363432353433323334" + "37373031433331313634343644323136343543373536423244334430463739374333323230" + "33323244363232413235344430423744344631443544304330413336373535443132343637" + "34314133343738334334353135373234373039314337383233324237443245304531463633" + "37413241333733393038354437363136363734373033343335303631333936393037324635" + "42354335423231363537453437304337453531334233463039314437343435354133413037" + "33373035374237453342353333373139314434453735333630383743333334423630323835" + "33304633463542323333383042364130373630333132393435303130303344364431463234" + "30463633303533443544304232373142364130463236313835363530373331333038363630" + "42303434373536363034313638344635383443323232313645353637443342373735353639" + "35463746334436423634353235453732323731363539343831303135343032343343313934" + "39354334433730324633373439304632363631333335333739373832353632343134333236" + "33303433303230453145363736303132334435313035364632463145343832463245334430" + "32314232373637374433453745334330433131373537433334343832373545303833383245" + "31313132363336343443364432323437313437303644373630413035344135383645313735" + "303543333432393537354134313034334631383432303912205C6993E9656F73A41739773A" + "0FCBA8AE232CD8856ACE585FF6BFB2A09C20061E"); struct LicenseInfo { std::string key_set_id; @@ -2075,9 +2086,9 @@ class DeviceFilesTest : public ::testing::Test { class DeviceFilesStoreTest : public DeviceFilesTest, public ::testing::WithParamInterface {}; -class DeviceCertificateStoreTest : public DeviceFilesTest {}; - -class DeviceCertificateTest : public DeviceFilesTest {}; +class DeviceCertificateTest + : public DeviceFilesTest, + public ::testing::WithParamInterface {}; class DeviceFilesSecurityLevelTest : public DeviceFilesTest, @@ -2185,12 +2196,12 @@ MATCHER_P8(Contains, str1, str2, str3, str4, str5, str6, map7, str8, "") { data.find(str8) != std::string::npos); } -TEST_F(DeviceCertificateStoreTest, StoreCertificate) { +TEST_F(DeviceCertificateTest, StoreCertificate) { MockFileSystem file_system; std::string certificate(CdmRandom::RandomData(kCertificateLen)); std::string wrapped_private_key(CdmRandom::RandomData(kWrappedKeyLen)); std::string device_certificate_path = - device_base_path_ + DeviceFiles::GetCertificateFileName(); + device_base_path_ + DeviceFiles::GetCertificateFileName(false); // Call to Open will return a unique_ptr, freeing this object. MockFile* file = new MockFile(); @@ -2207,12 +2218,12 @@ TEST_F(DeviceCertificateStoreTest, StoreCertificate) { EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key)); } -// TODO(tinskip): Fix. kTestCertificateFileData appears to be incorect. -TEST_F(DeviceCertificateTest, DISABLED_ReadCertificate) { +TEST_P(DeviceCertificateTest, ReadCertificate) { MockFileSystem file_system; + const bool atsc_mode = GetParam(); std::string device_certificate_path = - device_base_path_ + DeviceFiles::GetCertificateFileName(); - std::string data = a2bs_hex(kTestCertificateFileData); + device_base_path_ + DeviceFiles::GetCertificateFileName(atsc_mode); + std::string data = kTestCertificateFileData; // Call to Open will return a unique_ptr, freeing this object. MockFile* file = new MockFile(); @@ -2233,16 +2244,18 @@ TEST_F(DeviceCertificateTest, DISABLED_ReadCertificate) { std::string certificate, wrapped_private_key; std::string serial_number; uint32_t system_id = 0; - ASSERT_TRUE(device_files.RetrieveCertificate( - &certificate, &wrapped_private_key, &serial_number, &system_id)); - EXPECT_EQ(kTestCertificate, b2a_hex(certificate)); - EXPECT_EQ(kTestWrappedPrivateKey, b2a_hex(wrapped_private_key)); + ASSERT_TRUE(device_files.RetrieveCertificate(atsc_mode, &certificate, + &wrapped_private_key, + &serial_number, &system_id)); + EXPECT_EQ(kTestCertificate, certificate); + EXPECT_EQ(kTestWrappedPrivateKey, wrapped_private_key); } -TEST_F(DeviceCertificateTest, HasCertificate) { +TEST_P(DeviceCertificateTest, HasCertificate) { MockFileSystem file_system; + bool atsc_mode = GetParam(); std::string device_certificate_path = - device_base_path_ + DeviceFiles::GetCertificateFileName(); + device_base_path_ + DeviceFiles::GetCertificateFileName(atsc_mode); EXPECT_CALL(file_system, Exists(StrEq(device_certificate_path))) .WillOnce(Return(false)) @@ -2253,11 +2266,14 @@ TEST_F(DeviceCertificateTest, HasCertificate) { ASSERT_TRUE(device_files.Init(kSecurityLevelL1)); // MockFile returns false. - EXPECT_FALSE(device_files.HasCertificate()); + EXPECT_FALSE(device_files.HasCertificate(atsc_mode)); // MockFile returns true. - EXPECT_TRUE(device_files.HasCertificate()); + EXPECT_TRUE(device_files.HasCertificate(atsc_mode)); } +INSTANTIATE_TEST_CASE_P(AtscMode, DeviceCertificateTest, + ::testing::Values(false, true)); + TEST_P(DeviceFilesSecurityLevelTest, SecurityLevel) { MockFileSystem file_system; std::string certificate(CdmRandom::RandomData(kCertificateLen)); @@ -2268,7 +2284,7 @@ TEST_P(DeviceFilesSecurityLevelTest, SecurityLevel) { ASSERT_TRUE( Properties::GetDeviceFilesBasePath(security_level, &device_base_path)); std::string device_certificate_path = - device_base_path + DeviceFiles::GetCertificateFileName(); + device_base_path + DeviceFiles::GetCertificateFileName(false); // Call to Open will return a unique_ptr, freeing this object. MockFile* file = new MockFile(); diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index a5da0c50..e7b03eb3 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -2283,13 +2283,13 @@ TEST_F(WvCdmRequestLicenseTest, UnprovisionTest) { std::string wrapped_private_key; std::string serial_number; uint32_t system_id; - EXPECT_TRUE(handle.RetrieveCertificate(&certificate, &wrapped_private_key, - &serial_number, &system_id)); + EXPECT_TRUE(handle.RetrieveCertificate( + false, &certificate, &wrapped_private_key, &serial_number, &system_id)); EXPECT_EQ(NO_ERROR, decryptor_->Unprovision(security_level, kDefaultCdmIdentifier)); - EXPECT_FALSE(handle.RetrieveCertificate(&certificate, &wrapped_private_key, - &serial_number, &system_id)); + EXPECT_FALSE(handle.RetrieveCertificate( + false, &certificate, &wrapped_private_key, &serial_number, &system_id)); } TEST_F(WvCdmRequestLicenseTest, ProvisioningInterposedRetryTest) {