diff --git a/libwvdrmengine/Android.bp b/libwvdrmengine/Android.bp index cb75396d..c3b7b718 100644 --- a/libwvdrmengine/Android.bp +++ b/libwvdrmengine/Android.bp @@ -96,7 +96,7 @@ cc_defaults { relative_install_path: "hw", include_dirs: [ "vendor/widevine/libwvdrmengine/include_hidl", - "vendor/widevine/libwvdrmengine/mediadrm/include", + "vendor/widevine/libwvdrmengine/mediadrm/include_hidl", "vendor/widevine/libwvdrmengine/oemcrypto/include", ], header_libs: ["libstagefright_foundation_headers"], @@ -274,68 +274,6 @@ cc_library_static { } -// ---------------------------------------------------------------------------- -// Builds libwvdrmengine.so -// -cc_library_shared { - name: "libwvdrmengine", - - srcs: [ - "src/WVCDMSingleton.cpp", - "src/WVCreatePluginFactories.cpp", - "src/WVCryptoFactory.cpp", - "src/WVDrmFactory.cpp", - "src/WVUUID.cpp", - ], - - include_dirs: [ - "frameworks/av/include", - "frameworks/native/include", - "vendor/widevine/libwvdrmengine/cdm/core/include", - "vendor/widevine/libwvdrmengine/cdm/metrics/include", - "vendor/widevine/libwvdrmengine/cdm/util/include", - "vendor/widevine/libwvdrmengine/cdm/include", - "vendor/widevine/libwvdrmengine/include", - "vendor/widevine/libwvdrmengine/mediacrypto/include", - "vendor/widevine/libwvdrmengine/mediadrm/include", - "vendor/widevine/libwvdrmengine/oemcrypto/include", - ], - - static_libs: [ - "libcdm", - "libcdm_protos", - "libcdm_utils", - "libjsmn", - "libwvdrmcryptoplugin", - "libwvdrmdrmplugin", - "libwvlevel3", - "libwv_odk", - ], - - shared_libs: [ - "libbase", - "libcrypto", - "libdl", - "libhidlbase", - "liblog", - "libprotobuf-cpp-lite", - "libstagefright_foundation", - "libutils", - ], - - header_libs: [ - "libutils_headers", - "libstagefright_headers", - ], - - relative_install_path: "mediadrm", - - owner: "widevine", - - proprietary: true, - -} - // ---------------------------------------------------------------------------- // Builds libwvhidl.so // @@ -361,9 +299,7 @@ cc_library_shared { "vendor/widevine/libwvdrmengine/include_hidl", "vendor/widevine/libwvdrmengine/include", "vendor/widevine/libwvdrmengine/mediacrypto/include_hidl", - "vendor/widevine/libwvdrmengine/mediacrypto/include", "vendor/widevine/libwvdrmengine/mediadrm/include_hidl", - "vendor/widevine/libwvdrmengine/mediadrm/include", "vendor/widevine/libwvdrmengine/oemcrypto/include", ], diff --git a/libwvdrmengine/build_all_unit_tests.sh b/libwvdrmengine/build_all_unit_tests.sh index 0ff0a34e..b09aa39b 100755 --- a/libwvdrmengine/build_all_unit_tests.sh +++ b/libwvdrmengine/build_all_unit_tests.sh @@ -50,11 +50,8 @@ WV_TEST_TARGETS="base64_test \ initialization_data_unittest \ keybox_ota_test \ libwvdrmdrmplugin_hidl_test \ - libwvdrmdrmplugin_test \ libwvdrmengine_hidl_test \ - libwvdrmengine_test \ libwvdrmmediacrypto_hidl_test \ - libwvdrmmediacrypto_test \ license_keys_unittest \ license_unittest \ metrics_collections_unittest \ diff --git a/libwvdrmengine/include/WVCreatePluginFactories.h b/libwvdrmengine/include/WVCreatePluginFactories.h deleted file mode 100644 index ba3b4ed8..00000000 --- a/libwvdrmengine/include/WVCreatePluginFactories.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_CREATE_PLUGIN_FACTORIES_H_ -#define WV_CREATE_PLUGIN_FACTORIES_H_ - -#include "media/drm/DrmAPI.h" -#include "media/hardware/CryptoAPI.h" - -extern "C" { - android::DrmFactory* createDrmFactory(); - android::CryptoFactory* createCryptoFactory(); -} - -#endif // WV_CREATE_PLUGIN_FACTORIES_H_ diff --git a/libwvdrmengine/include/WVCryptoFactory.h b/libwvdrmengine/include/WVCryptoFactory.h deleted file mode 100644 index 54c7402a..00000000 --- a/libwvdrmengine/include/WVCryptoFactory.h +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_CRYPTO_FACTORY_H_ -#define WV_CRYPTO_FACTORY_H_ - -#include "media/hardware/CryptoAPI.h" -#include "media/stagefright/foundation/ABase.h" -#include "utils/Errors.h" - -namespace wvdrm { - -class WVCryptoFactory : public android::CryptoFactory { - public: - WVCryptoFactory() {} - virtual ~WVCryptoFactory() {} - - virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const; - - virtual android::status_t createPlugin(const uint8_t uuid[16], - const void* data, size_t size, - android::CryptoPlugin** plugin); - - private: - DISALLOW_EVIL_CONSTRUCTORS(WVCryptoFactory); -}; - -} // namespace wvdrm - -#endif // WV_CRYPTO_FACTORY_H_ diff --git a/libwvdrmengine/include/WVDrmFactory.h b/libwvdrmengine/include/WVDrmFactory.h deleted file mode 100644 index 1c6d0cf0..00000000 --- a/libwvdrmengine/include/WVDrmFactory.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_DRM_FACTORY_H_ -#define WV_DRM_FACTORY_H_ - -#include "media/drm/DrmAPI.h" -#include "media/stagefright/foundation/ABase.h" -#include "utils/Errors.h" -#include "WVGenericCryptoInterface.h" - -namespace wvdrm { - -class WVDrmFactory : public android::DrmFactory { - public: - WVDrmFactory() {} - virtual ~WVDrmFactory() {} - - virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]); - - virtual bool isContentTypeSupported(const android::String8 &initDataType); - - virtual android::status_t createDrmPlugin(const uint8_t uuid[16], - android::DrmPlugin** plugin); - - private: - DISALLOW_EVIL_CONSTRUCTORS(WVDrmFactory); - - static WVGenericCryptoInterface sOemCryptoInterface; -}; - -} // namespace wvdrm - -#endif // WV_DRM_FACTORY_H_ diff --git a/libwvdrmengine/include/mapErrors-inl.h b/libwvdrmengine/include/mapErrors-inl.h deleted file mode 100644 index f9ea0b98..00000000 --- a/libwvdrmengine/include/mapErrors-inl.h +++ /dev/null @@ -1,630 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_MAP_ERRORS_H_ -#define WV_MAP_ERRORS_H_ - -#include "media/stagefright/MediaErrors.h" -#include "utils/Errors.h" -#include "wv_cdm_types.h" -#include "WVErrors.h" - -namespace wvdrm { - -static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { - switch (res) { - // Android return codes. - // This first group is for "android::OK". - case wvcdm::NO_ERROR: - case wvcdm::KEY_ADDED: - case wvcdm::KEY_MESSAGE: - case wvcdm::KEY_CANCELED: - // KEY_ADDED, KEY_MESSAGE, and KEY_CANCELLED are all alternative - // success messages for certain CDM methods instead of NO_ERROR. - return android::OK; - // The remaining android::* are alphabetically ordered based on the first - // case condition in the group. - case wvcdm::ANALOG_OUTPUT_ERROR: - case wvcdm::INSUFFICIENT_OUTPUT_PROTECTION: - case wvcdm::KEY_PROHIBITED_FOR_SECURITY_LEVEL: - return android::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION; - case wvcdm::DECRYPT_ERROR: - case wvcdm::SECURE_BUFFER_REQUIRED: - return android::ERROR_DRM_CANNOT_HANDLE; - case wvcdm::DECRYPT_NOT_READY: - case wvcdm::KEY_NOT_FOUND_IN_SESSION: - case wvcdm::NEED_KEY: - case wvcdm::NO_MATCHING_ENTITLEMENT_KEY: - case wvcdm::NO_CONTENT_KEY_3: - return android::ERROR_DRM_NO_LICENSE; - case wvcdm::DEVICE_REVOKED: - return android::ERROR_DRM_DEVICE_REVOKED; - case wvcdm::INSUFFICIENT_CRYPTO_RESOURCES: - return android::ERROR_DRM_RESOURCE_BUSY; - case wvcdm::NEED_PROVISIONING: - return android::ERROR_DRM_NOT_PROVISIONED; - case wvcdm::RELEASE_USAGE_INFO_FAILED: - case wvcdm::RELEASE_USAGE_INFO_ERROR: - return android::ERROR_DRM_TAMPER_DETECTED; - case wvcdm::SESSION_NOT_FOUND_1: - case wvcdm::SESSION_NOT_FOUND_2: - case wvcdm::SESSION_NOT_FOUND_3: - case wvcdm::SESSION_NOT_FOUND_4: - case wvcdm::SESSION_NOT_FOUND_5: - case wvcdm::SESSION_NOT_FOUND_6: - case wvcdm::SESSION_NOT_FOUND_7: - case wvcdm::SESSION_NOT_FOUND_8: - case wvcdm::SESSION_NOT_FOUND_9: - case wvcdm::SESSION_NOT_FOUND_10: - case wvcdm::SESSION_NOT_FOUND_18: - case wvcdm::SESSION_NOT_FOUND_19: - case wvcdm::SESSION_NOT_FOUND_20: - case wvcdm::SESSION_NOT_FOUND_21: - case wvcdm::SESSION_NOT_FOUND_22: - case wvcdm::SESSION_NOT_FOUND_23: - case wvcdm::SESSION_NOT_FOUND_FOR_DECRYPT: - return android::ERROR_DRM_SESSION_NOT_OPENED; - case wvcdm::UNKNOWN_ERROR: - return android::ERROR_DRM_UNKNOWN; - // WV return codes. - // Alphabetically ordered based on the case condition. - case wvcdm::ADD_KEY_ERROR: - return kAddKeyError; - case wvcdm::CANNOT_DECRYPT_ZERO_SAMPLES: - return kCannotDecryptZeroSamples; - case wvcdm::CANNOT_DECRYPT_ZERO_SUBSAMPLES: - return kCannotDecryptZeroSubsamples; - case wvcdm::CENC_INIT_DATA_UNAVAILABLE: - return kCencInitDataUnavailable; - case wvcdm::CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE: - return kCertProvisioningEmptyServiceCertificate; - case wvcdm::CERT_PROVISIONING_GET_KEYBOX_ERROR_1: - return kCertProvisioningGetKeyboxError1; - case wvcdm::CERT_PROVISIONING_INVALID_CERT_TYPE: - return kCertProvisioningInvalidCertType; - case wvcdm::CERT_PROVISIONING_NONCE_GENERATION_ERROR: - return kCertProvisioningRequestNonceGenerationError; - case wvcdm::CERT_PROVISIONING_REQUEST_ERROR_1: - return kCertProvisioningRequestError1; - case wvcdm::CERT_PROVISIONING_REQUEST_ERROR_4: - return kCertProvisioningRequestError4; - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_1: - return kCertProvisioningResponseError1; - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_2: - return kCertProvisioningResponseError2; - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_3: - return kCertProvisioningResponseError3; - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_4: - return kCertProvisioningResponseError4; - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_7: - return kCertProvisioningResponseError7; - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_8: - return kCertProvisioningResponseError8; - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_9: - return kCertProvisioningResponseError9; - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_10: - return kCertProvisioningResponseError10; - case wvcdm::CLIENT_IDENTIFICATION_TOKEN_ERROR_1: - return kClientIdentificationTokenError1; - case wvcdm::CLIENT_ID_AES_ENCRYPT_ERROR: - return kClientIdAesEncryptError; - case wvcdm::CLIENT_ID_AES_INIT_ERROR: - return kClientIdAesInitError; - case wvcdm::CLIENT_ID_GENERATE_RANDOM_ERROR: - return kClientIdGenerateRandomError; - case wvcdm::CLIENT_ID_RSA_ENCRYPT_ERROR: - return kClientIdRsaEncryptError; - case wvcdm::CLIENT_ID_RSA_INIT_ERROR: - return kClientIdRsaInitError; - case wvcdm::CLIENT_TOKEN_NOT_SET: - return kClientTokenNotSet; - case wvcdm::COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR: - return kCopyOldUsageEntryUnknownError; - case wvcdm::CORE_MESSAGE_NOT_FOUND: - return kCoreMessageNotFound; - case wvcdm::CREATE_USAGE_ENTRY_UNKNOWN_ERROR: - return kCreateUsageEntryUnknownError; - case wvcdm::CREATE_USAGE_TABLE_ERROR: - return kCreateUsageTableError; - case wvcdm::DELETE_USAGE_ERROR_1: - return kDeleteUsageError1; - case wvcdm::DELETE_USAGE_ERROR_2: - return kDeleteUsageError2; - case wvcdm::DELETE_USAGE_ERROR_3: - return kDeleteUsageError3; - case wvcdm::DEVICE_CANNOT_REPROVISION: - return kDeviceCannotReprovision; - case wvcdm::DEVICE_CERTIFICATE_ERROR_1: - return kDeviceCertificateError1; - case wvcdm::DEVICE_CERTIFICATE_ERROR_2: - return kDeviceCertificateError2; - case wvcdm::DEVICE_CERTIFICATE_ERROR_3: - return kDeviceCertificateError3; - case wvcdm::DEVICE_CERTIFICATE_ERROR_4: - return kDeviceCertificateError4; - case wvcdm::DUPLICATE_SESSION_ID_SPECIFIED: - return kDuplicateSessionIdSpecified; - case wvcdm::EMPTY_KEYSET_ID: - return kEmptyKeySetId; - case wvcdm::EMPTY_KEYSET_ID_ENG_1: - return kEmptyKeySetIdEng1; - case wvcdm::EMPTY_KEYSET_ID_ENG_2: - return kEmptyKeySetIdEng2; - case wvcdm::EMPTY_KEYSET_ID_ENG_3: - return kEmptyKeySetIdEng3; - case wvcdm::EMPTY_KEYSET_ID_ENG_4: - return kEmptyKeySetIdEng4; - case wvcdm::EMPTY_KEYSET_ID_ENG_5: - return kEmptyKeySetIdEng5; - case wvcdm::EMPTY_KEY_DATA_1: - return kEmptyKeyData1; - case wvcdm::EMPTY_KEY_DATA_2: - return kEmptyKeyData2; - case wvcdm::EMPTY_LICENSE_RENEWAL: - return kEmptyLicenseRenewal; - case wvcdm::EMPTY_LICENSE_REQUEST: - return kEmptyLicenseRequest; - case wvcdm::EMPTY_LICENSE_REQUEST_2: - return kEmptyLicenseRequest2; - case wvcdm::EMPTY_LICENSE_REQUEST_3: - return kEmptyLicenseRequest3; - case wvcdm::EMPTY_LICENSE_RESPONSE_1: - return kEmptyLicenseResponse1; - case wvcdm::EMPTY_LICENSE_RESPONSE_2: - return kEmptyLicenseResponse2; - case wvcdm::EMPTY_LICENSE_RESPONSE_3: - return kEmptyLicenseResponse3; - case wvcdm::EMPTY_LICENSE_RESPONSE_4: - return kEmptyLicenseResponse4; - case wvcdm::EMPTY_PROVISIONING_CERTIFICATE_1: - return kEmptyProvisioningCertificate1; - case wvcdm::EMPTY_PROVISIONING_CERTIFICATE_2: - return kEmptyProvisioningCertificate2; - case wvcdm::EMPTY_PROVISIONING_RESPONSE: - return kEmptyProvisioningResponse; - case wvcdm::EMPTY_RESPONSE_ERROR_1: - return kEmptyResponseError1; - case wvcdm::EMPTY_SESSION_ID: - return kEmptySessionId; - case wvcdm::GENERATE_DERIVED_KEYS_ERROR: - return kGenerateDerivedKeysError; - case wvcdm::GENERATE_USAGE_REPORT_ERROR: - return kGenerateUsageReportError; - case wvcdm::GET_DECRYPT_HASH_ERROR: - return kGetDecryptHashError; - case wvcdm::GET_LICENSE_ERROR: - case wvcdm::KEYSET_ID_NOT_FOUND_4: - // There is a sub-error code that distinguishes the two. - return kGetLicenseError; - case wvcdm::GET_PROVISIONING_METHOD_ERROR: - return kGetProvisioningError; - case wvcdm::GET_RELEASED_LICENSE_ERROR: - return kGetReleasedLicenseError; - case wvcdm::GET_USAGE_INFO_ERROR_1: - return kGetUsageInfoError1; - case wvcdm::GET_USAGE_INFO_ERROR_2: - return kGetUsageInfoError2; - case wvcdm::GET_USAGE_INFO_ERROR_3: - return kGetUsageInfoError3; - case wvcdm::GET_USAGE_INFO_ERROR_4: - return kGetUsageInfoError4; - case wvcdm::INCORRECT_CRYPTO_MODE: - return kIncorrectCryptoMode; - case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_1: - return kIncorrectUsageSupportType1; - case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_2: - return kIncorrectUsageSupportType2; - case wvcdm::INIT_DATA_NOT_FOUND: - return kInitDataNotFound; - case wvcdm::INVALID_DECRYPT_HASH_FORMAT: - return kInvalidDecryptHashFormat; - case wvcdm::INVALID_DECRYPT_PARAMETERS_ENG_1: - return kInvalidDecryptParametersEng1; - case wvcdm::INVALID_DECRYPT_PARAMETERS_ENG_2: - return kInvalidDecryptParametersEng2; - case wvcdm::INVALID_DECRYPT_PARAMETERS_ENG_3: - return kInvalidDecryptParametersEng3; - case wvcdm::INVALID_DECRYPT_PARAMETERS_ENG_4: - return kInvalidDecryptParametersEng4; - case wvcdm::INVALID_DEVICE_CERTIFICATE_TYPE: - return kInvalidDeviceCertificateType; - case wvcdm::INVALID_IV_SIZE: - return kInvalidIvSize; - case wvcdm::INVALID_KEY_SYSTEM: - return kInvalidKeySystem; - case wvcdm::INVALID_LICENSE_REQUEST_TYPE_1: - return kInvalidLicenseRequestType1; - case wvcdm::INVALID_LICENSE_REQUEST_TYPE_2: - return kInvalidLicenseRequestType2; - case wvcdm::INVALID_LICENSE_RESPONSE: - return kInvalidLicenseResponse; - case wvcdm::INVALID_LICENSE_TYPE: - return kInvalidLicenseType; - case wvcdm::INVALID_LICENSE_TYPE_2: - return kInvalidLicenseType2; - case wvcdm::INVALID_PARAMETERS_ENG_5: - return kInvalidParametersEng5; - case wvcdm::INVALID_PARAMETERS_ENG_13: - return kInvalidParametersEng13; - case wvcdm::INVALID_PARAMETERS_ENG_14: - return kInvalidParametersEng14; - case wvcdm::INVALID_PARAMETERS_ENG_15: - return kInvalidParametersEng15; - case wvcdm::INVALID_PARAMETERS_ENG_16: - return kInvalidParametersEng16; - case wvcdm::INVALID_PARAMETERS_ENG_22: - return kInvalidParametersEng22; - case wvcdm::INVALID_PARAMETERS_ENG_23: - return kInvalidParametersEng23; - case wvcdm::INVALID_PARAMETERS_ENG_24: - return kInvalidParametersEng24; - case wvcdm::INVALID_PARAMETERS_LIC_1: - return kInvalidParametersLic1; - case wvcdm::INVALID_PARAMETERS_LIC_2: - return kInvalidParametersLic2; - case wvcdm::INVALID_PARAMETERS_LIC_3: - return kInvalidParametersLic3; - case wvcdm::INVALID_PARAMETERS_LIC_4: - return kInvalidParametersLic4; - case wvcdm::INVALID_PARAMETERS_LIC_6: - return kInvalidParametersLic6; - case wvcdm::INVALID_PARAMETERS_LIC_7: - return kInvalidParametersLic7; - case wvcdm::INVALID_PROVISIONING_PARAMETERS_1: - return kInvalidProvisioningParam1; - case wvcdm::INVALID_PROVISIONING_PARAMETERS_2: - return kInvalidProvisioningParam2; - case wvcdm::INVALID_PROVISIONING_REQUEST_PARAM_1: - return kInvalidProvisioningReqParam1; - case wvcdm::INVALID_PROVISIONING_REQUEST_PARAM_2: - return kInvalidProvisioningReqParam2; - case wvcdm::INVALID_QUERY_KEY: - return kInvalidQueryKey; - case wvcdm::INVALID_SESSION_1: - return kInvalidSession1; - case wvcdm::INVALID_SESSION_2: - return kInvalidSession2; - case wvcdm::INVALID_SESSION_ID: - return kInvalidSessionId; - case wvcdm::INVALID_USAGE_ENTRY_NUMBER_MODIFICATION: - return kInvalidUsageEntryNumberModification; - case wvcdm::KEYSET_ID_NOT_FOUND_1: - return kKeySetIdNotFound1; - case wvcdm::KEYSET_ID_NOT_FOUND_2: - return kKeySetIdNotFound2; - case wvcdm::KEYSET_ID_NOT_FOUND_3: - return kKeySetIdNotFound3; - case wvcdm::KEY_CONFLICT_1: - return kKeyConflict1; - case wvcdm::KEY_ERROR: - // KEY_ERROR is used by the CDM to mean just about any kind of error, not - // just license errors, so it is mapped to the generic response. - return kErrorCDMGeneric; - case wvcdm::KEY_NOT_FOUND_1: - return kKeyNotFound1; - case wvcdm::KEY_NOT_FOUND_2: - return kKeyNotFound2; - case wvcdm::KEY_NOT_FOUND_3: - return kKeyNotFound3; - case wvcdm::KEY_NOT_FOUND_4: - return kKeyNotFound4; - case wvcdm::KEY_NOT_FOUND_5: - return kKeyNotFound5; - case wvcdm::KEY_NOT_FOUND_6: - return kKeyNotFound6; - case wvcdm::KEY_REQUEST_ERROR_1: - return kKeyRequestError1; - case wvcdm::KEY_SIZE_ERROR_1: - return kKeySizeError1; - case wvcdm::KEY_SIZE_ERROR_2: - return kKeySizeError2; - case wvcdm::LICENSE_ID_NOT_FOUND: - return kLicenseIdNotFound; - case wvcdm::LICENSE_PARSER_INIT_ERROR: - return kLicenseParserInitError; - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_1: - return kLicenseParserNotInitialized1; - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_2: - return kLicenseParserNotInitialized2; - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_3: - return kLicenseParserNotInitialized3; - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_4: - return kLicenseParserNotInitialized4; - case wvcdm::LICENSE_RENEWAL_NONCE_GENERATION_ERROR: - return kLicenseRenewalNonceGenerationError; - case wvcdm::LICENSE_RENEWAL_PROHIBITED: - return kLicenseRenewalProhibited; - case wvcdm::LICENSE_REQUEST_NONCE_GENERATION_ERROR: - return kLicenseRequestNonceGenerationError; - case wvcdm::LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR: - return kLicenseRequestServiceCertificateGenerationError; - case wvcdm::LICENSE_RESPONSE_NOT_SIGNED: - return kLicenseResponseNotSigned; - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_1: - return kLicenseResponseParseError1; - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_2: - return kLicenseResponseParseError2; - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_3: - return kLicenseResponseParseError3; - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_4: - return kLicenseResponseParseError4; - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_5: - return kLicenseResponseParseError5; - case wvcdm::LICENSE_USAGE_ENTRY_MISSING: - return kLicenseUsageEntryMissing; - case wvcdm::LIST_LICENSE_ERROR_1: - return kListLicenseError1; - case wvcdm::LIST_LICENSE_ERROR_2: - return kListLicenseError2; - case wvcdm::LIST_USAGE_ERROR_1: - return kListUsageError1; - case wvcdm::LIST_USAGE_ERROR_2: - return kListUsageError2; - case wvcdm::LOAD_ENTITLED_CONTENT_KEYS_ERROR: - return kLoadEntitledContentKeysError; - case wvcdm::LOAD_KEY_ERROR: - return kLoadKeyError; - case wvcdm::LOAD_LICENSE_ERROR: - return kLoadLicenseError; - case wvcdm::LOAD_PROVISIONING_ERROR: - return kLoadProvisioningError; - case wvcdm::LOAD_RENEWAL_ERROR: - return kLoadRenewalError; - case wvcdm::LOAD_SYSTEM_ID_ERROR: - return kLoadSystemIdError; - case wvcdm::LOAD_USAGE_ENTRY_GENERATION_SKEW: - return kLoadUsageEntryGenerationSkew; - case wvcdm::LOAD_USAGE_ENTRY_INVALID_SESSION: - return kLoadUsageEntryInvalidSession; - case wvcdm::LOAD_USAGE_ENTRY_SIGNATURE_FAILURE: - return kLoadUsageEntrySignatureFailure; - case wvcdm::LOAD_USAGE_ENTRY_UNKNOWN_ERROR: - return kLoadUsageEntryUnknownError; - case wvcdm::LOAD_USAGE_HEADER_BAD_MAGIC: - return kLoadUsageHeaderBadMagic; - case wvcdm::LOAD_USAGE_HEADER_GENERATION_SKEW: - return kLoadUsageHeaderGenerationSkew; - case wvcdm::LOAD_USAGE_HEADER_SIGNATURE_FAILURE: - return kLoadUsageHeaderSignatureFailure; - case wvcdm::LOAD_USAGE_HEADER_UNKNOWN_ERROR: - return kLoadUsageHeaderUnknownError; - case wvcdm::LOAD_USAGE_INFO_FILE_ERROR: - return kLoadUsageInfoFileError; - case wvcdm::LOAD_USAGE_INFO_MISSING: - return kLoadUsageInfoMissing; - case wvcdm::MOVE_USAGE_ENTRY_DESTINATION_IN_USE: - return kMoveUsageEntryDestinationInUse; - case wvcdm::MOVE_USAGE_ENTRY_UNKNOWN_ERROR: - return kMoveUsageEntryUnknownError; - case wvcdm::NOT_AN_ENTITLEMENT_SESSION: - return kNotAnEntitlementSession; - case wvcdm::NOT_INITIALIZED_ERROR: - return kNotInitializedError; - case wvcdm::NO_CONTENT_KEY: - return kNoContentKey; - case wvcdm::NO_CONTENT_KEY_2: - return kNoContentKey2; - case wvcdm::NO_DEVICE_KEY_1: - return kNoDeviceKey1; - case wvcdm::NO_SRM_VERSION: - return kNoSrmVersion; - case wvcdm::NO_USAGE_ENTRIES: - return kNoUsageEntries; - case wvcdm::OFFLINE_LICENSE_PROHIBITED: - return kOfflineLicenseProhibited; - case wvcdm::OKP_ALREADY_PROVISIONED: - return kOkpAlreadyProvisioned; - case wvcdm::PARAMETER_NULL: - return kParameterNull; - case wvcdm::PARSE_OKP_RESPONSE_ERROR: - return kParseOkpResponseError; - case wvcdm::PARSE_REQUEST_ERROR_1: - return kParseRequestError1; - case wvcdm::PARSE_REQUEST_ERROR_2: - return kParseRequestError2; - case wvcdm::PARSE_RESPONSE_ERROR_1: - return kParseResponseError1; - case wvcdm::PARSE_RESPONSE_ERROR_2: - return kParseResponseError2; - case wvcdm::PARSE_RESPONSE_ERROR_3: - return kParseResponseError3; - case wvcdm::PARSE_RESPONSE_ERROR_4: - return kParseResponseError4; - case wvcdm::PARSE_SERVICE_CERTIFICATE_ERROR: - return kParseServiceCertificateError; - case wvcdm::PREPARE_CENC_CONTENT_ID_FAILED: - return kPrepareCencContentIdFailed; - case wvcdm::PREPARE_WEBM_CONTENT_ID_FAILED: - return kPrepareWebmContentIdFailed; - case wvcdm::PRIVACY_MODE_ERROR_1: - return kPrivacyModeError1; - case wvcdm::PRIVACY_MODE_ERROR_2: - 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: - return kReinitError; - case wvcdm::RELEASE_KEY_ERROR: - return kReleaseKeyError; - case wvcdm::RELEASE_KEY_REQUEST_ERROR: - return kReleaseKeyRequestError; - case wvcdm::RELEASE_LICENSE_ERROR_1: - return kReleaseLicenseError1; - case wvcdm::RELEASE_LICENSE_ERROR_2: - return kReleaseLicenseError2; - case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_1: - return kRemoveAllUsageInfoError1; - case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_2: - return kRemoveAllUsageInfoError2; - case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_5: - return kRemoveAllUsageInfoError5; - case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_6: - return kRemoveAllUsageInfoError6; - case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_7: - return kRemoveAllUsageInfoError7; - case wvcdm::REMOVE_USAGE_INFO_ERROR_1: - return kRemoveUsageInfoError1; - case wvcdm::REMOVE_USAGE_INFO_ERROR_2: - return kRemoveUsageInfoError2; - case wvcdm::REMOVE_USAGE_INFO_ERROR_3: - return kRemoveUsageInfoError3; - case wvcdm::RENEW_KEY_ERROR_1: - return kRenewKeyError1; - case wvcdm::RENEW_KEY_ERROR_2: - return kRenewKeyError2; - case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_2: - return kRestoreOfflineLicenseError2; - case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_3: - return kRestoreOfflineLicenseError3; - case wvcdm::SAMPLE_AND_SUBSAMPLE_SIZE_MISMATCH: - return kSampleAndSubsampleSizeMismatch; - case wvcdm::SESSION_FILE_HANDLE_INIT_ERROR: - return kSessionFileHandleInitError; - case wvcdm::SESSION_KEYS_NOT_FOUND: - return kSessionKeysNotFound; - case wvcdm::SESSION_KEYS_NOT_FOUND_2: - return kSessionKeysNotFound2; - case wvcdm::SESSION_NOT_FOUND_11: - return kSessionNotFound11; - case wvcdm::SESSION_NOT_FOUND_12: - return kSessionNotFound12; - case wvcdm::SESSION_NOT_FOUND_13: - return kSessionNotFound13; - case wvcdm::SESSION_NOT_FOUND_14: - return kSessionNotFound14; - case wvcdm::SESSION_NOT_FOUND_15: - return kSessionNotFound15; - case wvcdm::SESSION_NOT_FOUND_16: - return kSessionNotFound16; - case wvcdm::SET_DECRYPT_HASH_ERROR: - return kSetDecryptHashError; - case wvcdm::SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE: - return kShrinkUsageTableHeaderEntryInUse; - case wvcdm::SHRINK_USAGE_TABLE_HEADER_UNKNOWN_ERROR: - return kShrinkUsageTableHeaderUnknownError; - case wvcdm::SIGNATURE_NOT_FOUND: - return kSignatureNotFound; - case wvcdm::SIGNATURE_NOT_FOUND_2: - return kSignatureNotFound2; - case wvcdm::STORAGE_PROHIBITED: - return kStorageProhibited; - case wvcdm::STORE_LICENSE_ERROR_1: - return kStoreLicenseError1; - case wvcdm::STORE_LICENSE_ERROR_2: - return kStoreLicenseError2; - case wvcdm::STORE_USAGE_INFO_ERROR: - return kStoreUsageInfoError; - case wvcdm::UNEXPECTED_EMPTY_USAGE_ENTRY: - return kUnexpectedEmptyUsageEntry; - case wvcdm::UNKNOWN_SELECT_KEY_ERROR_1: - return kUnknownSelectKeyError1; - case wvcdm::UNKNOWN_SELECT_KEY_ERROR_2: - return kUnknownSelectKeyError2; - case wvcdm::UNPROVISION_ERROR_1: - return kUnprovisioningError1; - case wvcdm::UNPROVISION_ERROR_2: - return kUnprovisioningError2; - case wvcdm::UNPROVISION_ERROR_3: - return kUnprovisioningError3; - case wvcdm::UNPROVISION_ERROR_4: - return kUnprovisioningError4; - case wvcdm::UNSUPPORTED_INIT_DATA: - return kUnsupportedInitData; - case wvcdm::UNSUPPORTED_INIT_DATA_FORMAT: - return kUnsupportedInitDataFormat; - case wvcdm::UPDATE_USAGE_ENTRY_UNKNOWN_ERROR: - return kUpdateUsageEntryUnknownError; - case wvcdm::USAGE_ENTRY_NUMBER_MISMATCH: - return kUsageEntryNumberMismatch; - case wvcdm::USAGE_ENTRY_ALREADY_LOADED: - return kUsageEntryAlreadyLoaded; - case wvcdm::USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE: - return kUsageGetEntryRetrieveInvalidStorageType; - case wvcdm::USAGE_GET_ENTRY_RETRIEVE_LICENSE_FAILED: - return kUsageGetEntryRetrieveLicenseFailed; - case wvcdm::USAGE_GET_ENTRY_RETRIEVE_USAGE_INFO_FAILED: - return kUsageGetEntryRetrieveUsageInfoFailed; - case wvcdm::USAGE_INFORMATION_SUPPORT_FAILED: - return kUsageInformationSupportFailed; - case wvcdm::USAGE_INFO_NOT_FOUND: - return kUsageInfoNotFound; - case wvcdm::USAGE_INVALID_LOAD_ENTRY: - return kUsageInvalidLoadEntry; - case wvcdm::USAGE_INVALID_NEW_ENTRY: - return kUsageInvalidNewEntry; - case wvcdm::USAGE_INVALID_PARAMETERS_1: - return kUsageInvalidParameters1; - case wvcdm::USAGE_INVALID_PARAMETERS_2: - return kUsageInvalidParameters2; - case wvcdm::USAGE_STORE_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE: - return kUsageStoreEntryRetrieveInvalidStorageType; - case wvcdm::USAGE_STORE_ENTRY_RETRIEVE_LICENSE_FAILED: - return kUsageStoreEntryRetrieveLicenseFailed; - case wvcdm::USAGE_STORE_ENTRY_RETRIEVE_USAGE_INFO_FAILED: - return kUsageStoreEntryRetrieveUsageInfoFailed; - case wvcdm::USAGE_STORE_LICENSE_FAILED: - return kUsageStoreLicenseFailed; - case wvcdm::USAGE_STORE_USAGE_INFO_FAILED: - return kUsageStoreUsageInfoFailed; - case wvcdm::USAGE_SUPPORT_GET_API_FAILED: - return kUsageSupportGetApiFailed; - case wvcdm::WEBM_INIT_DATA_UNAVAILABLE: - return kWebmInitDataUnavailable; - - // This error is only returned in API 29 by the hidl service. - // It should never be used in the legacy plugin. - // It is mapped here to clear the compiler warning. - case wvcdm::GET_OFFLINE_LICENSE_STATE_ERROR_1: - case wvcdm::GET_OFFLINE_LICENSE_STATE_ERROR_2: - case wvcdm::REMOVE_OFFLINE_LICENSE_ERROR_1: - case wvcdm::REMOVE_OFFLINE_LICENSE_ERROR_2: - case wvcdm::OUTPUT_TOO_LARGE_ERROR: - case wvcdm::SESSION_LOST_STATE_ERROR: - case wvcdm::GENERATE_DERIVED_KEYS_ERROR_2: - case wvcdm::LOAD_DEVICE_RSA_KEY_ERROR: - case wvcdm::NONCE_GENERATION_ERROR: - case wvcdm::GENERATE_SIGNATURE_ERROR: - case wvcdm::UNKNOWN_CLIENT_TOKEN_TYPE: - case wvcdm::DEACTIVATE_USAGE_ENTRY_ERROR: - case wvcdm::SYSTEM_INVALIDATED_ERROR: - case wvcdm::OPEN_CRYPTO_SESSION_ERROR: - case wvcdm::LOAD_SRM_ERROR: - case wvcdm::RANDOM_GENERATION_ERROR: - case wvcdm::CRYPTO_SESSION_NOT_INITIALIZED: - case wvcdm::GET_DEVICE_ID_ERROR: - case wvcdm::GET_TOKEN_FROM_OEM_CERT_ERROR: - case wvcdm::CRYPTO_SESSION_NOT_OPEN: - case wvcdm::GET_TOKEN_FROM_KEYBOX_ERROR: - case wvcdm::KEYBOX_TOKEN_TOO_SHORT: - case wvcdm::EXTRACT_SYSTEM_ID_FROM_OEM_CERT_ERROR: - case wvcdm::RSA_SIGNATURE_GENERATION_ERROR: - case wvcdm::GET_HDCP_CAPABILITY_FAILED: - case wvcdm::GET_NUMBER_OF_OPEN_SESSIONS_ERROR: - case wvcdm::GET_MAX_NUMBER_OF_OPEN_SESSIONS_ERROR: - case wvcdm::NOT_IMPLEMENTED_ERROR: - case wvcdm::GET_SRM_VERSION_ERROR: - case wvcdm::REWRAP_DEVICE_RSA_KEY_ERROR: - case wvcdm::SERVICE_CERTIFICATE_PROVIDER_ID_EMPTY: - case wvcdm::INVALID_SRM_LIST: - return android::ERROR_DRM_UNKNOWN; - } - - // Return here instead of as a default case so that the compiler will warn - // us if we forget to include an enum member in the switch statement. - return android::UNKNOWN_ERROR; -} - -static inline bool isCdmResponseTypeSuccess(wvcdm::CdmResponseType res) { - return mapCdmResponseType(res) == android::OK; -} - -} // namespace wvdrm - -#endif // WV_MAP_ERRORS_H_ diff --git a/libwvdrmengine/mediacrypto/Android.bp b/libwvdrmengine/mediacrypto/Android.bp index 02821504..d5744495 100644 --- a/libwvdrmengine/mediacrypto/Android.bp +++ b/libwvdrmengine/mediacrypto/Android.bp @@ -11,56 +11,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - -// ---------------------------------------------------------------------------- -// Builds libwvdrmcryptoplugin -// -// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE -// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE -// DEPENDING ON IT IN YOUR PROJECT. *** -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "vendor_widevine_license" - // to get the below license kinds: - // legacy_by_exception_only (by exception only) - default_applicable_licenses: ["vendor_widevine_license"], -} - -cc_library_static { - name: "libwvdrmcryptoplugin", - - srcs: ["src/WVCryptoPlugin.cpp"], - - include_dirs: [ - "frameworks/av/include", - "frameworks/native/include", - "vendor/widevine/libwvdrmengine/cdm/core/include", - "vendor/widevine/libwvdrmengine/cdm/include", - "vendor/widevine/libwvdrmengine/cdm/metrics/include", - "vendor/widevine/libwvdrmengine/cdm/util/include", - "vendor/widevine/libwvdrmengine/include", - "vendor/widevine/libwvdrmengine/mediacrypto/include", - "vendor/widevine/libwvdrmengine/oemcrypto/include", - ], - - header_libs: [ - "libstagefright_headers", - "libstagefright_foundation_headers", - "libutils_headers", - ], - - static_libs: ["libcdm_protos"], - - shared_libs: [ - "libcrypto", - "liblog", - ], - - proprietary: true, - -} - // ----------------------------------------------------------------------------- // Builds libwvdrmcryptoplugin_hidl // @@ -76,10 +26,9 @@ cc_library_static { "vendor/widevine/libwvdrmengine/cdm/include", "vendor/widevine/libwvdrmengine/cdm/metrics/include", "vendor/widevine/libwvdrmengine/cdm/util/include", - "vendor/widevine/libwvdrmengine/include_hidl", + "vendor/widevine/libwvdrmengine/include_hidl", "vendor/widevine/libwvdrmengine/include", "vendor/widevine/libwvdrmengine/mediacrypto/include_hidl", - "vendor/widevine/libwvdrmengine/mediacrypto/include", "vendor/widevine/libwvdrmengine/oemcrypto/include", ], diff --git a/libwvdrmengine/mediacrypto/include/WVCryptoPlugin.h b/libwvdrmengine/mediacrypto/include/WVCryptoPlugin.h deleted file mode 100644 index faf4cd5a..00000000 --- a/libwvdrmengine/mediacrypto/include/WVCryptoPlugin.h +++ /dev/null @@ -1,57 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_CRYPTO_PLUGIN_H_ -#define WV_CRYPTO_PLUGIN_H_ - -#include - -#include "utils/StrongPointer.h" -#include "utils/Vector.h" - -#include "media/hardware/CryptoAPI.h" -#include "media/stagefright/foundation/ABase.h" -#include "media/stagefright/foundation/AString.h" -#include "wv_content_decryption_module.h" - -namespace wvdrm { - -class WVCryptoPlugin : public android::CryptoPlugin { - public: - WVCryptoPlugin(const void* data, size_t size, - const android::sp& cdm); - virtual ~WVCryptoPlugin() {} - - virtual bool requiresSecureDecoderComponent(const char* mime) const; - - virtual void notifyResolution(uint32_t width, uint32_t height); - - virtual android::status_t setMediaDrmSession( - const android::Vector& sessionId); - - virtual ssize_t decrypt(bool secure, const uint8_t key[16], - const uint8_t iv[16], Mode mode, const Pattern &pattern, - const void* srcPtr, - const SubSample* subSamples, size_t numSubSamples, - void* dstPtr, android::AString* errorDetailMsg); - - private: - DISALLOW_EVIL_CONSTRUCTORS(WVCryptoPlugin); - - android::sp const mCDM; - - bool mTestMode; - wvcdm::CdmSessionId mSessionId; - - wvcdm::CdmSessionId configureTestMode(const void* data, size_t size); - android::status_t attemptDecrypt( - const wvcdm::CdmDecryptionParametersV16& params, - bool haveEncryptedSubsamples, android::AString* errorDetailMsg); -}; - -} // namespace wvdrm - -#endif // WV_CRYPTO_PLUGIN_H_ diff --git a/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp b/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp deleted file mode 100644 index add3e5be..00000000 --- a/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp +++ /dev/null @@ -1,261 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -//#define LOG_NDEBUG 0 -#define LOG_TAG "WVCdm" -#include - -#include "WVCryptoPlugin.h" - -#include -#include -#include -#include -#include -#include - -#include "mapErrors-inl.h" -#include "media/stagefright/MediaErrors.h" -#include "OEMCryptoCENC.h" -#include "openssl/sha.h" -#include "utils/Errors.h" -#include "utils/String8.h" -#include "wv_cdm_constants.h" -#include "WVErrors.h" - -namespace wvdrm { - -using namespace android; -using namespace std; -using namespace wvcdm; - -WVCryptoPlugin::WVCryptoPlugin(const void* data, size_t size, - const sp& cdm) - : mCDM(cdm), - mTestMode(false), - mSessionId(configureTestMode(data, size)) {} - -CdmSessionId WVCryptoPlugin::configureTestMode(const void* data, size_t size) { - CdmSessionId sessionId; - if (data != NULL) { - sessionId.assign(static_cast(data), size); - size_t index = sessionId.find("test_mode"); - if (index != string::npos) { - sessionId = sessionId.substr(0, index); - mTestMode = true; - } - } - if (!mCDM->IsOpenSession(sessionId)) { - sessionId.clear(); - } - return sessionId; -} - -bool WVCryptoPlugin::requiresSecureDecoderComponent(const char* mime) const { - if (!strncasecmp(mime, "video/", 6)) { - // Type is video, so query CDM to see if we require a secure decoder. - CdmQueryMap status; - - CdmResponseType res = mCDM->QuerySessionStatus(mSessionId, &status); - - if (!isCdmResponseTypeSuccess(res)) { - ALOGE("Error querying CDM status: %u", res); - return false; - } - - return status[QUERY_KEY_SECURITY_LEVEL] == QUERY_VALUE_SECURITY_LEVEL_L1; - } else { - // Type is not video, so never require a secure decoder. - return false; - } -} - -void WVCryptoPlugin::notifyResolution(uint32_t width, uint32_t height) { - mCDM->NotifyResolution(mSessionId, width, height); -} - -status_t WVCryptoPlugin::setMediaDrmSession(const Vector& sessionId) { - CdmSessionId cdmSessionId(reinterpret_cast(sessionId.array()), - sessionId.size()); - if (sessionId.size() == 0) { - return android::BAD_VALUE; - } - if (!mCDM->IsOpenSession(cdmSessionId)) { - return android::ERROR_DRM_SESSION_NOT_OPENED; - } else { - mSessionId = cdmSessionId; - return android::NO_ERROR; - } -} - -// Returns negative values for error code and positive values for the size of -// decrypted data. In theory, the output size can be larger than the input -// size, but in practice this should never happen for AES-CTR. -ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE], - const uint8_t iv[KEY_IV_SIZE], Mode mode, - const Pattern& pattern, const void* srcPtr, - const SubSample* subSamples, - size_t numSubSamples, void* dstPtr, - AString* errorDetailMsg) { - if (mode != kMode_Unencrypted && - mode != kMode_AES_CTR && - mode != kMode_AES_CBC) { - errorDetailMsg->setTo( - "The requested encryption mode is not supported by Widevine CDM."); - return kErrorUnsupportedCrypto; - } else if (mode == kMode_AES_CTR && - (pattern.mEncryptBlocks != 0 || pattern.mSkipBlocks != 0)) { - errorDetailMsg->setTo( - "The 'cens' schema is not supported by Widevine CDM."); - return kErrorUnsupportedCrypto; - } - - // Convert parameters to the form the CDM wishes to consume them in. - const KeyId keyId(reinterpret_cast(key), KEY_ID_SIZE); - vector ivVector(iv, iv + KEY_IV_SIZE); - const uint8_t* const source = static_cast(srcPtr); - uint8_t* const dest = static_cast(dstPtr); - - // Set up the decrypt params - CdmDecryptionParametersV16 params; - params.key_id = keyId; - params.is_secure = secure; - if (mode == kMode_AES_CTR) { - params.cipher_mode = kCipherModeCtr; - } else if (mode == kMode_AES_CBC) { - params.cipher_mode = kCipherModeCbc; - } - params.pattern.encrypt_blocks = pattern.mEncryptBlocks; - params.pattern.skip_blocks = pattern.mSkipBlocks; - - // Set up the sample - // Android's API only supports one at a time - params.samples.emplace_back(); - CdmDecryptionSample& sample = params.samples.back(); - sample.encrypt_buffer = source; - sample.decrypt_buffer = dest; - sample.decrypt_buffer_offset = 0; - sample.iv = ivVector; - - // Set up the subsamples - // We abuse std::transform() here to also do some side-effects: Tallying the - // total size of the sample and checking if any of the data is protected. - size_t totalSize = 0; - bool hasProtectedData = false; - sample.subsamples.reserve(numSubSamples); - std::transform(subSamples, subSamples + numSubSamples, - std::back_inserter(sample.subsamples), - [&](const SubSample& subSample) -> CdmDecryptionSubsample { - totalSize += - subSample.mNumBytesOfClearData + subSample.mNumBytesOfEncryptedData; - hasProtectedData |= subSample.mNumBytesOfEncryptedData > 0; - return CdmDecryptionSubsample(subSample.mNumBytesOfClearData, - subSample.mNumBytesOfEncryptedData); - }); - - sample.encrypt_buffer_length = totalSize; - sample.decrypt_buffer_size = totalSize; - - if (mode == kMode_Unencrypted && hasProtectedData) { - errorDetailMsg->setTo("Protected ranges found in allegedly clear data."); - return kErrorExpectedUnencrypted; - } - - // Decrypt - status_t res = attemptDecrypt(params, hasProtectedData, errorDetailMsg); - if (res != android::OK) { - return res; - } - - // In test mode, we return an error that causes a detailed error - // message string containing a SHA256 hash of the decrypted data - // to get passed to the java app via CryptoException. The test app - // can then use the hash to verify that decryption was successful. - - if (mTestMode) { - if (secure) { - // can't access data in secure mode - errorDetailMsg->setTo("secure"); - } else { - SHA256_CTX ctx; - uint8_t digest[SHA256_DIGEST_LENGTH]; - SHA256_Init(&ctx); - SHA256_Update(&ctx, dstPtr, totalSize); - SHA256_Final(digest, &ctx); - String8 buf; - for (size_t i = 0; i < sizeof(digest); i++) { - buf.appendFormat("%02x", digest[i]); - } - errorDetailMsg->setTo(buf.string()); - } - - return kErrorTestMode; - } - - return static_cast(totalSize); -} - -status_t WVCryptoPlugin::attemptDecrypt( - const CdmDecryptionParametersV16& params, bool hasProtectedData, - AString* errorDetailMsg) { - CdmResponseType res = mCDM->DecryptV16(mSessionId, hasProtectedData, - params); - - if (isCdmResponseTypeSuccess(res)) { - return android::OK; - } else { - ALOGE("Decrypt error in session %s during a sample %s protected data: %d", - mSessionId.c_str(), - hasProtectedData ? "with" : "without", - res); - bool actionableError = true; - switch (res) { - case wvcdm::INSUFFICIENT_CRYPTO_RESOURCES: - errorDetailMsg->setTo( - "Error decrypting data: insufficient crypto resources"); - break; - case wvcdm::NEED_KEY: - case wvcdm::KEY_NOT_FOUND_IN_SESSION: - errorDetailMsg->setTo( - "Error decrypting data: requested key has not been loaded"); - break; - case wvcdm::DECRYPT_NOT_READY: - errorDetailMsg->setTo( - "Error decrypting data: license validity period is in the future"); - break; - case wvcdm::SESSION_NOT_FOUND_FOR_DECRYPT: - errorDetailMsg->setTo( - "Error decrypting data: session not found, possibly reclaimed"); - break; - case wvcdm::DECRYPT_ERROR: - errorDetailMsg->setTo( - "Error decrypting data: unspecified error"); - break; - case wvcdm::INSUFFICIENT_OUTPUT_PROTECTION: - case wvcdm::ANALOG_OUTPUT_ERROR: - errorDetailMsg->setTo( - "Error decrypting data: insufficient output protection"); - break; - case wvcdm::KEY_PROHIBITED_FOR_SECURITY_LEVEL: - errorDetailMsg->setTo( - "Error decrypting data: key prohibited for security level"); - break; - default: - actionableError = false; - break; - } - - if (actionableError) { - // This error is actionable by the app and should be passed up. - return mapCdmResponseType(res); - } else { - // Swallow the specifics of other errors to obscure decrypt internals. - return kErrorCDMGeneric; - } - } -} - -} // namespace wvdrm diff --git a/libwvdrmengine/mediacrypto/test/Android.mk b/libwvdrmengine/mediacrypto/test/Android.mk index 91169e8a..979fe75b 100644 --- a/libwvdrmengine/mediacrypto/test/Android.mk +++ b/libwvdrmengine/mediacrypto/test/Android.mk @@ -1,67 +1,4 @@ LOCAL_PATH := $(call my-dir) - -# ----------------------------------------------------------------------------- -# Builds libwvdrmmediacrypto_test -# -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - legacy_src/WVCryptoPlugin_test.cpp \ - -LOCAL_C_INCLUDES := \ - frameworks/av/include \ - frameworks/native/include \ - vendor/widevine/libwvdrmengine/cdm/core/include \ - vendor/widevine/libwvdrmengine/cdm/include \ - vendor/widevine/libwvdrmengine/cdm/metrics/include \ - vendor/widevine/libwvdrmengine/cdm/util/include \ - vendor/widevine/libwvdrmengine/mediacrypto/include \ - vendor/widevine/libwvdrmengine/oemcrypto/include \ - -LOCAL_STATIC_LIBRARIES := \ - libcdm \ - libcdm_protos \ - libcdm_utils \ - libjsmn \ - libgmock \ - libgmock_main \ - libgtest \ - libwvlevel3 \ - libwvdrmcryptoplugin \ - libwv_odk \ - -LOCAL_SHARED_LIBRARIES := \ - libbase \ - libcrypto \ - libcutils \ - libdl \ - libhidlbase \ - liblog \ - libprotobuf-cpp-lite \ - libstagefright_foundation \ - libutils \ - -LOCAL_C_INCLUDES += \ - external/protobuf/src \ - -LOCAL_MODULE := libwvdrmmediacrypto_test -LOCAL_LICENSE_KINDS := legacy_by_exception_only -LOCAL_LICENSE_CONDITIONS := by_exception_only - -LOCAL_MODULE_TAGS := tests - -LOCAL_MODULE_OWNER := widevine -LOCAL_PROPRIETARY_MODULE := true - -# When built, explicitly put it in the DATA/nativetest directory. -LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest - -ifneq ($(TARGET_ENABLE_MEDIADRM_64), true) -LOCAL_MODULE_TARGET_ARCH := arm x86 mips -endif - -include $(BUILD_EXECUTABLE) - # ----------------------------------------------------------------------------- # Builds libwvdrmmediacrypto_hidl_test # @@ -79,7 +16,6 @@ LOCAL_C_INCLUDES := \ vendor/widevine/libwvdrmengine/cdm/util/include \ vendor/widevine/libwvdrmengine/include_hidl \ vendor/widevine/libwvdrmengine/mediacrypto/include_hidl \ - vendor/widevine/libwvdrmengine/mediacrypto/include \ vendor/widevine/libwvdrmengine/oemcrypto/include \ LOCAL_STATIC_LIBRARIES := \ diff --git a/libwvdrmengine/mediacrypto/test/legacy_src/WVCryptoPlugin_test.cpp b/libwvdrmengine/mediacrypto/test/legacy_src/WVCryptoPlugin_test.cpp deleted file mode 100644 index 91ba5034..00000000 --- a/libwvdrmengine/mediacrypto/test/legacy_src/WVCryptoPlugin_test.cpp +++ /dev/null @@ -1,430 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "media/stagefright/foundation/ABase.h" -#include "media/stagefright/foundation/AString.h" -#include "media/stagefright/MediaErrors.h" - -#include "OEMCryptoCENC.h" -#include "wv_cdm_constants.h" -#include "wv_cdm_types.h" -#include "wv_content_decryption_module.h" -#include "WVCryptoPlugin.h" - -using namespace android; -using namespace std; -using namespace testing; -using namespace wvcdm; -using namespace wvdrm; - -namespace { -constexpr ssize_t kErrorUnsupportedCrypto = ERROR_DRM_VENDOR_MIN + 2; -} - -class MockCDM : public WvContentDecryptionModule { - public: - MOCK_METHOD1(IsOpenSession, bool(const CdmSessionId&)); - - MOCK_METHOD3(DecryptV16, CdmResponseType(const CdmSessionId&, bool, - const CdmDecryptionParametersV16&)); - - MOCK_METHOD2(QuerySessionStatus, CdmResponseType(const CdmSessionId&, - CdmQueryMap*)); -}; - -class WVCryptoPluginTest : public Test { - protected: - static const uint32_t kSessionIdSize = 16; - uint8_t sessionId[kSessionIdSize]; - - virtual void SetUp() { - FILE* fp = fopen("/dev/urandom", "r"); - fread(sessionId, sizeof(uint8_t), kSessionIdSize, fp); - fclose(fp); - - // Set default CdmResponseType value for gMock - DefaultValue::Set(wvcdm::NO_ERROR); - } -}; - -TEST_F(WVCryptoPluginTest, CorrectlyReportsSecureBuffers) { - android::sp> cdm = new StrictMock(); - - CdmQueryMap l1Map; - l1Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1; - CdmQueryMap l3Map; - l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3; - - // Provide the expected behavior for IsOpenSession - EXPECT_CALL(*cdm, IsOpenSession(_)) - .WillRepeatedly(Return(true)); - - // Specify the expected calls to QuerySessionStatus - EXPECT_CALL(*cdm, QuerySessionStatus(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(l1Map), - Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<1>(l3Map), - Return(wvcdm::NO_ERROR))); - - WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get()); - - EXPECT_TRUE(plugin.requiresSecureDecoderComponent("video/mp4")) << - "WVCryptoPlugin incorrectly allows an insecure video decoder on L1"; - EXPECT_FALSE(plugin.requiresSecureDecoderComponent("video/mp4")) << - "WVCryptoPlugin incorrectly expects a secure video decoder on L3"; - EXPECT_FALSE(plugin.requiresSecureDecoderComponent("audio/aac")) << - "WVCryptoPlugin incorrectly expects a secure audio decoder"; -} - -// TODO(b/28295739): -// Add New MediaCrypto Unit Tests for CBC & Pattern Mode in cdmPatternDesc. - -// Predicate that validates that the fields of a passed-in -// CdmDecryptionParametersV16 match the values it was given at construction -// time. -// -// This could be done with a huge pile of gMock matchers, but it is ugly and -// unmaintainable, particularly once you get into validating the subsamples. The -// logic here is complex enough to warrant a custom matcher for this one test. -class CDPMatcher { - public: - CDPMatcher(const uint8_t* keyId, bool isSecure, CryptoPlugin::Mode cipherMode, - const CryptoPlugin::Pattern& pattern, - const uint8_t* input, size_t inputLength, - const uint8_t* output, size_t outputLength, const uint8_t* iv, - const CryptoPlugin::SubSample* subsamples, - size_t subsamplesLength) - : mKeyId(keyId, keyId + KEY_ID_SIZE), mIsSecure(isSecure), - mCipherMode(cipherMode), mPattern(pattern), mInput(input), - mInputLength(inputLength), mOutput(output), mOutputLength(outputLength), - mIv(iv, iv + KEY_IV_SIZE), - mSubsamples(subsamples, subsamples + subsamplesLength) {} - - bool operator()(const CdmDecryptionParametersV16& params) const { - if (mCipherMode == CryptoPlugin::kMode_AES_CTR && - params.cipher_mode != kCipherModeCtr) { - return false; - } else if (mCipherMode == CryptoPlugin::kMode_AES_CBC && - params.cipher_mode != kCipherModeCbc) { - return false; - } - - if (params.key_id != mKeyId || - params.is_secure != mIsSecure || - params.pattern.encrypt_blocks != mPattern.mEncryptBlocks || - params.pattern.skip_blocks != mPattern.mSkipBlocks || - params.samples.size() != 1) { - return false; - } - - const CdmDecryptionSample& sample = params.samples[0]; - if (sample.encrypt_buffer != mInput || - sample.encrypt_buffer_length != mInputLength || - sample.decrypt_buffer != mOutput || - sample.decrypt_buffer_size != mOutputLength || - sample.decrypt_buffer_offset != 0 || - sample.iv != mIv || - sample.subsamples.size() != mSubsamples.size()) { - return false; - } - - for (size_t i = 0; i < mSubsamples.size(); ++i) { - const CryptoPlugin::SubSample& androidSubsample = mSubsamples[i]; - const CdmDecryptionSubsample& cdmSubsample = sample.subsamples[i]; - - if (cdmSubsample.clear_bytes != androidSubsample.mNumBytesOfClearData|| - cdmSubsample.protected_bytes != androidSubsample.mNumBytesOfEncryptedData) { - return false; - } - } - - return true; - } - - private: - const KeyId mKeyId; - const bool mIsSecure; - const CryptoPlugin::Mode mCipherMode; - const CryptoPlugin::Pattern mPattern; - const uint8_t* const mInput; - const size_t mInputLength; - const uint8_t* const mOutput; - const size_t mOutputLength; - const std::vector mIv; - const std::vector mSubsamples; -}; - -TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) { - android::sp> cdm = new StrictMock(); - - constexpr size_t kSubSampleCount = 6; - CryptoPlugin::SubSample subSamples[kSubSampleCount]; - memset(subSamples, 0, sizeof(subSamples)); - subSamples[0].mNumBytesOfEncryptedData = 16; - subSamples[1].mNumBytesOfClearData = 16; - subSamples[1].mNumBytesOfEncryptedData = 16; - subSamples[2].mNumBytesOfEncryptedData = 8; - subSamples[3].mNumBytesOfClearData = 29; - subSamples[3].mNumBytesOfEncryptedData = 24; - subSamples[4].mNumBytesOfEncryptedData = 60; - subSamples[5].mNumBytesOfEncryptedData = 16; - - uint8_t keyId[KEY_ID_SIZE]; - uint8_t iv[KEY_IV_SIZE]; - - constexpr size_t kDataSize = 185; - uint8_t inputData[kDataSize]; - uint8_t outputData[kDataSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(iv, sizeof(uint8_t), KEY_IV_SIZE, fp); - fread(inputData, sizeof(uint8_t), kDataSize, fp); - fclose(fp); - - android::CryptoPlugin::Pattern noPattern = { 0, 0 }; - - // Provide the expected behavior for IsOpenSession - EXPECT_CALL(*cdm, IsOpenSession(_)) - .WillRepeatedly(Return(true)); - - // Specify the expected calls to Decrypt - CDPMatcher paramsMatcher(keyId, false, CryptoPlugin::kMode_AES_CTR, noPattern, - inputData, kDataSize, outputData, kDataSize, iv, - subSamples, kSubSampleCount); - - EXPECT_CALL(*cdm, DecryptV16(ElementsAreArray(sessionId, kSessionIdSize), - true, - Truly(paramsMatcher))) - .Times(1); - - WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get()); - AString errorDetailMessage; - - ssize_t res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR, - noPattern, inputData, subSamples, - kSubSampleCount, outputData, - &errorDetailMessage); - - EXPECT_EQ(static_cast(kDataSize), res) << - "WVCryptoPlugin decrypted the wrong number of bytes"; - EXPECT_EQ(0u, errorDetailMessage.size()) << - "WVCryptoPlugin reported a detailed error message."; -} - -TEST_F(WVCryptoPluginTest, RejectsCens) { - android::sp> cdm = new StrictMock(); - - constexpr size_t kSubSampleCount = 2; - CryptoPlugin::SubSample subSamples[kSubSampleCount]; - memset(subSamples, 0, sizeof(subSamples)); - subSamples[0].mNumBytesOfEncryptedData = 16; - subSamples[1].mNumBytesOfClearData = 16; - subSamples[1].mNumBytesOfEncryptedData = 16; - - uint8_t keyId[KEY_ID_SIZE]; - uint8_t iv[KEY_IV_SIZE]; - - constexpr size_t kDataSize = 48; - uint8_t inputData[kDataSize]; - uint8_t outputData[kDataSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(iv, sizeof(uint8_t), KEY_IV_SIZE, fp); - fread(inputData, sizeof(uint8_t), kDataSize, fp); - fclose(fp); - - android::CryptoPlugin::Pattern recommendedPattern = { 1, 9 }; - - // Provide the expected behavior for IsOpenSession - EXPECT_CALL(*cdm, IsOpenSession(_)) - .WillRepeatedly(Return(true)); - - // Refuse calls to Decrypt - EXPECT_CALL(*cdm, DecryptV16(_, _, _)) - .Times(0); - - WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get()); - AString errorDetailMessage; - - ssize_t res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR, - recommendedPattern, inputData, subSamples, - kSubSampleCount, outputData, - &errorDetailMessage); - - EXPECT_EQ(res, kErrorUnsupportedCrypto) << - "WVCryptoPlugin did not return an error for 'cens'."; - EXPECT_NE(errorDetailMessage.size(), 0u) << - "WVCryptoPlugin did not report a detailed error message for 'cens'."; -} - -TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) { - android::sp> cdm = new StrictMock(); - - uint8_t keyId[KEY_ID_SIZE]; - uint8_t iv[KEY_IV_SIZE]; - - static const size_t kDataSize = 32; - uint8_t in[kDataSize]; - uint8_t out[kDataSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(iv, sizeof(uint8_t), KEY_IV_SIZE, fp); - fread(in, sizeof(uint8_t), kDataSize, fp); - fclose(fp); - - static const uint32_t kSubSampleCount = 1; - CryptoPlugin::SubSample subSamples[kSubSampleCount]; - memset(subSamples, 0, sizeof(subSamples)); - subSamples[0].mNumBytesOfClearData = 16; - subSamples[0].mNumBytesOfEncryptedData = 16; - - // Provide the expected behavior for IsOpenSession - EXPECT_CALL(*cdm, IsOpenSession(_)) - .WillRepeatedly(Return(true)); - - // Specify the expected calls to Decrypt - { - InSequence calls; - - typedef CdmDecryptionParametersV16 CDP; - - EXPECT_CALL(*cdm, DecryptV16(_, _, Field(&CDP::is_secure, false))) - .Times(1); - - EXPECT_CALL(*cdm, DecryptV16(_, _, Field(&CDP::is_secure, true))) - .Times(1); - } - - WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get()); - android::CryptoPlugin::Pattern noPattern = { 0, 0 }; - AString errorDetailMessage; - - ssize_t res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR, - noPattern, in, subSamples, kSubSampleCount, - out, &errorDetailMessage); - ASSERT_GE(res, 0) << - "WVCryptoPlugin returned an error"; - EXPECT_EQ(0u, errorDetailMessage.size()) << - "WVCryptoPlugin reported a detailed error message."; - - res = plugin.decrypt(true, keyId, iv, CryptoPlugin::kMode_AES_CTR, - noPattern, in, subSamples, kSubSampleCount, out, - &errorDetailMessage); - ASSERT_GE(res, 0) << - "WVCryptoPlugin returned an error"; - EXPECT_EQ(0u, errorDetailMessage.size()) << - "WVCryptoPlugin reported a detailed error message."; -} - -TEST_F(WVCryptoPluginTest, AllowsSessionIdChanges) { - android::sp> cdm = new StrictMock(); - - uint8_t keyId[KEY_ID_SIZE]; - uint8_t iv[KEY_IV_SIZE]; - uint8_t sessionId2[kSessionIdSize]; - - static const size_t kDataSize = 32; - uint8_t in[kDataSize]; - uint8_t out[kDataSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(iv, sizeof(uint8_t), KEY_IV_SIZE, fp); - fread(sessionId2, sizeof(uint8_t), kSessionIdSize, fp); - fread(in, sizeof(uint8_t), kDataSize, fp); - fclose(fp); - - static const uint32_t kSubSampleCount = 1; - CryptoPlugin::SubSample subSamples[kSubSampleCount]; - memset(subSamples, 0, sizeof(subSamples)); - subSamples[0].mNumBytesOfClearData = 16; - subSamples[0].mNumBytesOfEncryptedData = 16; - - Vector sessionIdVector; - sessionIdVector.appendArray(sessionId, kSessionIdSize); - Vector sessionId2Vector; - sessionId2Vector.appendArray(sessionId2, kSessionIdSize); - - // Provide the expected behavior for IsOpenSession - EXPECT_CALL(*cdm, IsOpenSession(_)) - .WillRepeatedly(Return(true)); - - // Specify the expected calls to Decrypt - { - InSequence calls; - - EXPECT_CALL(*cdm, - DecryptV16(ElementsAreArray(sessionId, kSessionIdSize), _, _)) - .Times(1); - - EXPECT_CALL(*cdm, - DecryptV16(ElementsAreArray(sessionId2, kSessionIdSize), _, _)) - .Times(1); - } - - uint8_t blank[1]; // Some compilers will not accept 0. - WVCryptoPlugin plugin(blank, 0, cdm.get()); - android::CryptoPlugin::Pattern noPattern = { 0, 0 }; - AString errorDetailMessage; - ssize_t res; - - res = plugin.setMediaDrmSession(sessionIdVector); - EXPECT_EQ(android::NO_ERROR, res); - res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR, - noPattern, in, subSamples, kSubSampleCount, out, - &errorDetailMessage); - EXPECT_GE(res, 0) << - "WVCryptoPlugin returned an error"; - EXPECT_EQ(0u, errorDetailMessage.size()) << - "WVCryptoPlugin reported a detailed error message."; - - res = plugin.setMediaDrmSession(sessionId2Vector); - EXPECT_EQ(android::NO_ERROR, res); - res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR, - noPattern, in, subSamples, kSubSampleCount, out, - &errorDetailMessage); - EXPECT_GE(res, 0) << - "WVCryptoPlugin returned an error"; - EXPECT_EQ(0u, errorDetailMessage.size()) << - "WVCryptoPlugin reported a detailed error message."; -} - -TEST_F(WVCryptoPluginTest, DisallowsUnopenedSessionIdChanges) { - android::sp> cdm = new StrictMock(); - - uint8_t blank[1]; // Some compilers will not accept 0. - Vector sessionIdVector; - sessionIdVector.appendArray(sessionId, kSessionIdSize); - - // Specify the expected calls to IsOpenSession - { - InSequence calls; - - EXPECT_CALL(*cdm, IsOpenSession(ElementsAreArray(blank, 0))) - .WillOnce(Return(false)); - - EXPECT_CALL(*cdm, IsOpenSession(ElementsAreArray(sessionId, kSessionIdSize))) - .WillOnce(Return(false)) - .WillOnce(Return(true)); - } - - WVCryptoPlugin plugin(blank, 0, cdm.get()); - - ssize_t res; - res = plugin.setMediaDrmSession(sessionIdVector); - EXPECT_EQ(android::ERROR_DRM_SESSION_NOT_OPENED, res); - res = plugin.setMediaDrmSession(sessionIdVector); - EXPECT_EQ(android::NO_ERROR, res); -} diff --git a/libwvdrmengine/mediadrm/Android.bp b/libwvdrmengine/mediadrm/Android.bp index 4ad257d1..b45258da 100644 --- a/libwvdrmengine/mediadrm/Android.bp +++ b/libwvdrmengine/mediadrm/Android.bp @@ -12,55 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// ---------------------------------------------------------------------------- -// Builds libwvdrmdrmplugin -// -// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE -// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE -// DEPENDING ON IT IN YOUR PROJECT. *** -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "vendor_widevine_license" - // to get the below license kinds: - // legacy_by_exception_only (by exception only) - default_applicable_licenses: ["vendor_widevine_license"], -} - -cc_library_static { - name: "libwvdrmdrmplugin", - - srcs: [ - "src/WVDrmPlugin.cpp", - "src/WVGenericCryptoInterface.cpp", - ], - - include_dirs: [ - "frameworks/av/include", - "frameworks/native/include", - "vendor/widevine/libwvdrmengine/cdm/core/include", - "vendor/widevine/libwvdrmengine/cdm/include", - "vendor/widevine/libwvdrmengine/cdm/metrics/include", - "vendor/widevine/libwvdrmengine/cdm/util/include", - "vendor/widevine/libwvdrmengine/include", - "vendor/widevine/libwvdrmengine/mediadrm/include", - "vendor/widevine/libwvdrmengine/oemcrypto/include", - ], - - header_libs: [ - "libstagefright_headers", - "libstagefright_foundation_headers", - "libutils_headers", - ], - - shared_libs: ["liblog"], - - static_libs: ["libcdm_protos"], - - proprietary: true, - -} - // ---------------------------------------------------------------------------- // Builds libwvdrmdrmplugin_hidl // @@ -83,7 +34,6 @@ cc_library_static { "vendor/widevine/libwvdrmengine/include_hidl", "vendor/widevine/libwvdrmengine/include", "vendor/widevine/libwvdrmengine/mediadrm/include_hidl", - "vendor/widevine/libwvdrmengine/mediadrm/include", "vendor/widevine/libwvdrmengine/oemcrypto/include", ], diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h deleted file mode 100644 index f61d5e37..00000000 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ /dev/null @@ -1,306 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_DRM_PLUGIN_H_ -#define WV_DRM_PLUGIN_H_ - -#include -#include - -#include "cdm_client_property_set.h" -#include "cdm_identifier.h" -#include "media/drm/DrmAPI.h" -#include "media/stagefright/foundation/ABase.h" -#include "media/stagefright/foundation/AString.h" -#include "OEMCryptoCENC.h" -#include "utils/Errors.h" -#include "utils/KeyedVector.h" -#include "utils/List.h" -#include "utils/String8.h" -#include "utils/StrongPointer.h" -#include "utils/Vector.h" -#include "wv_cdm_event_listener.h" -#include "wv_content_decryption_module.h" -#include "WVGenericCryptoInterface.h" - -namespace wvdrm { - -using android::KeyedVector; -using android::List; -using android::status_t; -using android::String8; -using android::Vector; -using std::map; -using wvcdm::CdmIdentifier; -using wvcdm::CdmKeyStatusMap; -using wvcdm::CdmSessionId; -using wvcdm::CdmResponseType; -using wvcdm::WvContentDecryptionModule; - -const OEMCrypto_Algorithm kInvalidCryptoAlgorithm = - static_cast(-1); - -class WVDrmPlugin : public android::DrmPlugin, - public wvcdm::WvCdmEventListener { - public: - WVDrmPlugin(const android::sp& cdm, - WVGenericCryptoInterface* crypto); - - virtual ~WVDrmPlugin(); - - virtual status_t openSession(Vector& sessionId); - - virtual status_t closeSession(const Vector& sessionId); - - virtual status_t getKeyRequest( - const Vector& scope, - const Vector& initData, - const String8& initDataType, - KeyType keyType, - const KeyedVector& optionalParameters, - Vector& request, - String8& defaultUrl, - KeyRequestType *keyRequestType); - - virtual status_t provideKeyResponse(const Vector& scope, - const Vector& response, - Vector& keySetId); - - virtual status_t removeKeys(const Vector& sessionId); - - virtual status_t restoreKeys(const Vector& sessionId, - const Vector& keySetId); - - virtual status_t queryKeyStatus( - const Vector& sessionId, - KeyedVector& infoMap) const; - - virtual status_t getProvisionRequest(const String8& cert_type, - const String8& cert_authority, - Vector& request, - String8& defaultUrl); - - virtual status_t provideProvisionResponse(const Vector& response, - Vector& certificate, - Vector& wrapped_key); - - virtual status_t unprovisionDevice(); - - virtual status_t getSecureStop(const Vector& ssid, - Vector& secureStop); - - virtual status_t getSecureStops(List >& secureStops); - - virtual status_t releaseAllSecureStops(); - - virtual status_t releaseSecureStops(const Vector& ssRelease); - - virtual status_t getPropertyString(const String8& name, String8& value) const; - - virtual status_t getPropertyByteArray(const String8& name, - Vector& value) const; - - virtual status_t setPropertyString(const String8& name, const String8& value); - - virtual status_t setPropertyByteArray(const String8& name, - const Vector& value); - - virtual status_t setCipherAlgorithm(const Vector& sessionId, - const String8& algorithm); - - virtual status_t setMacAlgorithm(const Vector& sessionId, - const String8& algorithm); - - virtual status_t encrypt(const Vector& sessionId, - const Vector& keyId, - const Vector& input, - const Vector& iv, - Vector& output); - - virtual status_t decrypt(const Vector& sessionId, - const Vector& keyId, - const Vector& input, - const Vector& iv, - Vector& output); - - virtual status_t sign(const Vector& sessionId, - const Vector& keyId, - const Vector& message, - Vector& signature); - - virtual status_t verify(const Vector& sessionId, - const Vector& keyId, - const Vector& message, - const Vector& signature, - bool& match); - - virtual status_t signRSA(const Vector& sessionId, - const String8& algorithm, - const Vector& message, - const Vector& wrappedKey, - Vector& signature); - - virtual void OnSessionRenewalNeeded(const CdmSessionId& cdmSessionId); - - virtual void OnSessionKeysChange(const CdmSessionId& cdmSessionId, - const CdmKeyStatusMap& cdmKeysStatus, - bool hasNewUsableKey); - - virtual void OnExpirationUpdate(const CdmSessionId& cdmSessionId, - int64_t newExpiryTimeSeconds); - - private: - DISALLOW_EVIL_CONSTRUCTORS(WVDrmPlugin); - - struct CryptoSession { - public: - CryptoSession() - : mOecSessionId(-1), - mCipherAlgorithm(kInvalidCryptoAlgorithm), - mMacAlgorithm(kInvalidCryptoAlgorithm) {} - - CryptoSession(OEMCrypto_SESSION sessionId) - : mOecSessionId(sessionId), - mCipherAlgorithm(kInvalidCryptoAlgorithm), - mMacAlgorithm(kInvalidCryptoAlgorithm) {} - - OEMCrypto_SESSION oecSessionId() const { return mOecSessionId; } - - OEMCrypto_Algorithm cipherAlgorithm() const { return mCipherAlgorithm; } - - void setCipherAlgorithm(OEMCrypto_Algorithm newAlgorithm) { - mCipherAlgorithm = newAlgorithm; - } - - OEMCrypto_Algorithm macAlgorithm() const { return mMacAlgorithm; } - - void setMacAlgorithm(OEMCrypto_Algorithm newAlgorithm) { - mMacAlgorithm = newAlgorithm; - } - - private: - OEMCrypto_SESSION mOecSessionId; - OEMCrypto_Algorithm mCipherAlgorithm; - OEMCrypto_Algorithm mMacAlgorithm; - }; - - class WVClientPropertySet : public wvcdm::CdmClientPropertySet { - public: - WVClientPropertySet() - : mUsePrivacyMode(false), mShareKeys(false), mSessionSharingId(0), - mUseAtscMode(false) {} - - virtual ~WVClientPropertySet() {} - - virtual const std::string& security_level() const { - return mSecurityLevel; - } - - void set_security_level(const std::string& securityLevel) { - mSecurityLevel = securityLevel; - } - - virtual bool use_privacy_mode() const { - return mUsePrivacyMode; - } - - void set_use_privacy_mode(bool usePrivacyMode) { - mUsePrivacyMode = usePrivacyMode; - } - - virtual const std::string& service_certificate() const { - return mServiceCertificate; - } - - virtual void set_service_certificate( - const std::string& serviceCertificate) { - mServiceCertificate = serviceCertificate; - } - - virtual bool is_session_sharing_enabled() const { - return mShareKeys; - } - - void set_is_session_sharing_enabled(bool shareKeys) { - mShareKeys = shareKeys; - } - - virtual uint32_t session_sharing_id() const { - return mSessionSharingId; - } - - virtual void set_session_sharing_id(uint32_t id) { - mSessionSharingId = id; - } - - virtual const std::string& app_id() const { - return mAppId; - } - - void set_app_id(const std::string& appId) { - mAppId = appId; - } - - virtual bool use_atsc_mode() const { - return mUseAtscMode; - } - - void set_use_atsc_mode(bool useAtscMode) { - mUseAtscMode = useAtscMode; - } - - private: - DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet); - - std::string mSecurityLevel; - bool mUsePrivacyMode; - std::string mServiceCertificate; - bool mShareKeys; - uint32_t mSessionSharingId; - std::string mAppId; - bool mUseAtscMode; - const std::string mEmptyString; - } mPropertySet; - - android::sp const mCDM; - WVGenericCryptoInterface* mCrypto; - map mCryptoSessions; - - CdmIdentifier mCdmIdentifier; - - std::string mProvisioningServiceCertificate; - - CdmSessionId mDecryptHashSessionId; - - status_t queryProperty(const std::string& property, - std::string& stringValue) const; - - status_t queryProperty(wvcdm::SecurityLevel securityLevel, - const std::string& property, - std::string& stringValue) const; - - status_t queryProperty(const std::string& property, - String8& string8_value) const; - - status_t queryProperty(const std::string& property, - Vector& vector_value) const; - - status_t mapAndNotifyOfCdmResponseType(const Vector& sessionId, - CdmResponseType res); - - status_t mapAndNotifyOfOEMCryptoResult(const Vector& sessionId, - OEMCryptoResult res); - - status_t mapOEMCryptoResult(OEMCryptoResult res); - - bool initDataResemblesPSSH(const Vector& initData); - - status_t unprovision(const CdmIdentifier& identifier); -}; - -} // namespace wvdrm - -#endif // WV_DRM_PLUGIN_H_ diff --git a/libwvdrmengine/mediadrm/include/WVGenericCryptoInterface.h b/libwvdrmengine/mediadrm/include/WVGenericCryptoInterface.h deleted file mode 100644 index 0fc43587..00000000 --- a/libwvdrmengine/mediadrm/include/WVGenericCryptoInterface.h +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_GENERIC_CRYPTO_INTERFACE_H_ -#define WV_GENERIC_CRYPTO_INTERFACE_H_ - -#include - -#include "OEMCryptoCENC.h" -#include "media/stagefright/foundation/ABase.h" -#include "utils/Vector.h" - -namespace wvdrm { - -class WVGenericCryptoInterface { - public: - WVGenericCryptoInterface() {} - virtual ~WVGenericCryptoInterface() {} - - virtual OEMCryptoResult selectKey(const OEMCrypto_SESSION session, - const uint8_t* key_id, - size_t key_id_length) { - return OEMCrypto_SelectKey(session, key_id, key_id_length, - OEMCrypto_CipherMode_CBC); - } - - virtual OEMCryptoResult encrypt(OEMCrypto_SESSION session, - const uint8_t* in_buffer, - size_t buffer_length, const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer) { - return OEMCrypto_Generic_Encrypt(session, in_buffer, buffer_length, iv, - algorithm, out_buffer); - } - - virtual OEMCryptoResult decrypt(OEMCrypto_SESSION session, - const uint8_t* in_buffer, - size_t buffer_length, const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer) { - return OEMCrypto_Generic_Decrypt(session, in_buffer, buffer_length, iv, - algorithm, out_buffer); - } - - virtual OEMCryptoResult sign(OEMCrypto_SESSION session, - const uint8_t* in_buffer, size_t buffer_length, - OEMCrypto_Algorithm algorithm, - uint8_t* signature, size_t* signature_length) { - return OEMCrypto_Generic_Sign(session, in_buffer, buffer_length, algorithm, - signature, signature_length); - } - - virtual OEMCryptoResult verify(OEMCrypto_SESSION session, - const uint8_t* in_buffer, size_t buffer_length, - OEMCrypto_Algorithm algorithm, - const uint8_t* signature, - size_t signature_length) { - return OEMCrypto_Generic_Verify(session, in_buffer, buffer_length, - algorithm, signature, signature_length); - } - - virtual OEMCryptoResult signRSA(const uint8_t* wrapped_rsa_key, - size_t wrapped_rsa_key_length, - const uint8_t* message, - size_t message_length, - android::Vector& signature, - RSA_Padding_Scheme padding_scheme); - - - virtual OEMCryptoResult loadDeviceRSAKey(OEMCrypto_SESSION session, - const uint8_t* wrapped_rsa_key, - size_t wrapped_rsa_key_length) { - return OEMCrypto_LoadDRMPrivateKey(session, OEMCrypto_RSA_Private_Key, - wrapped_rsa_key, wrapped_rsa_key_length); - } - - virtual OEMCryptoResult generateRSASignature( - OEMCrypto_SESSION session, - const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length, - RSA_Padding_Scheme padding_scheme) { - return OEMCrypto_GenerateRSASignature(session, message, message_length, - signature, signature_length, - padding_scheme); -} - - private: - DISALLOW_EVIL_CONSTRUCTORS(WVGenericCryptoInterface); -}; - -} // namespace wvdrm - -#endif // WV_GENERIC_CRYPTO_INTERFACE_H_ diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp deleted file mode 100644 index 76f09a49..00000000 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ /dev/null @@ -1,1154 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -//#define LOG_NDEBUG 0 -#define LOG_TAG "WVCdm" -#include - -#include "WVDrmPlugin.h" - -#include -#include -#include -#include -#include -#include - -#include "mapErrors-inl.h" -#include "media/stagefright/MediaErrors.h" -#include "utils/Errors.h" -#include "wv_cdm_constants.h" - -namespace { - static const char* const kResetSecurityLevel = ""; - static const char* const kEnable = "enable"; - static const char* const kDisable = "disable"; - static const std::string kPsshTag = "pssh"; - static const char* const kSpecialUnprovisionResponse = "unprovision"; -} - -namespace wvdrm { - -using namespace android; -using namespace std; -using namespace wvcdm; - -namespace { - -Vector ToVector(const std::string& str) { - Vector vector; - vector.appendArray(reinterpret_cast(str.data()), str.size()); - return vector; -} - -DrmPlugin::KeyRequestType ConvertFromCdmKeyRequestType( - CdmKeyRequestType keyRequestType) { - switch (keyRequestType) { - case kKeyRequestTypeInitial: - return DrmPlugin::kKeyRequestType_Initial; - case kKeyRequestTypeRenewal: - return DrmPlugin::kKeyRequestType_Renewal; - case kKeyRequestTypeRelease: - return DrmPlugin::kKeyRequestType_Release; - default: - return DrmPlugin::kKeyRequestType_Unknown; - } -} - -DrmPlugin::KeyStatusType ConvertFromCdmKeyStatus(CdmKeyStatus keyStatus) { - switch (keyStatus) { - case kKeyStatusUsable: - return DrmPlugin::kKeyStatusType_Usable; - case kKeyStatusExpired: - return DrmPlugin::kKeyStatusType_Expired; - case kKeyStatusOutputNotAllowed: - return DrmPlugin::kKeyStatusType_OutputNotAllowed; - case kKeyStatusPending: - return DrmPlugin::kKeyStatusType_StatusPending; - case kKeyStatusUsableInFuture: - return DrmPlugin::kKeyStatusType_UsableInFuture; - case kKeyStatusInternalError: - default: - return DrmPlugin::kKeyStatusType_InternalError; - } -} - -} // namespace - -WVDrmPlugin::WVDrmPlugin(const sp& cdm, - WVGenericCryptoInterface* crypto) - : mCDM(cdm), - mCrypto(crypto), - mCryptoSessions(), - mCdmIdentifier(kDefaultCdmIdentifier) {} - -WVDrmPlugin::~WVDrmPlugin() { - typedef map::iterator mapIterator; - for (mapIterator iter = mCryptoSessions.begin(); - iter != mCryptoSessions.end(); - ++iter) { - CdmResponseType res = mCDM->CloseSession(iter->first); - if (!isCdmResponseTypeSuccess(res)) { - ALOGE("Failed to close session while destroying WVDrmPlugin"); - } - } - mCryptoSessions.clear(); -} - -status_t WVDrmPlugin::openSession(Vector& sessionId) { - CdmSessionId cdmSessionId; - CdmResponseType res = - mCDM->OpenSession("com.widevine", &mPropertySet, mCdmIdentifier, this, - &cdmSessionId); - - if (!isCdmResponseTypeSuccess(res)) { - return mapAndNotifyOfCdmResponseType(sessionId, res); - } - - bool success = false; - - // Construct a CryptoSession - CdmQueryMap info; - res = mCDM->QueryOemCryptoSessionId(cdmSessionId, &info); - - if (isCdmResponseTypeSuccess(res) && - info.count(QUERY_KEY_OEMCRYPTO_SESSION_ID)) { - OEMCrypto_SESSION oecSessionId = - std::stoul(info[QUERY_KEY_OEMCRYPTO_SESSION_ID]); - mCryptoSessions[cdmSessionId] = CryptoSession(oecSessionId); - success = true; - } else { - ALOGE("Unable to query key control info."); - } - - if (success) { - // Marshal Session ID - sessionId = ToVector(cdmSessionId); - - return android::OK; - } else { - mCDM->CloseSession(cdmSessionId); - - if (!isCdmResponseTypeSuccess(res)) { - // We got an error code we can return. - return mapAndNotifyOfCdmResponseType(sessionId, res); - } else { - // We got a failure that did not give us an error code, such as a failure - // of AttachEventListener() or the key being missing from the map. - return kErrorCDMGeneric; - } - } -} - -status_t WVDrmPlugin::closeSession(const Vector& sessionId) { - if (!sessionId.size()) { - return android::BAD_VALUE; - } - CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); - CdmResponseType res = mCDM->CloseSession(cdmSessionId); - mCryptoSessions.erase(cdmSessionId); - if (!isCdmResponseTypeSuccess(res)) { - return android::ERROR_DRM_SESSION_NOT_OPENED; - } - return android::OK; -} - -status_t WVDrmPlugin::getKeyRequest( - const Vector& scope, - const Vector& initData, - const String8& initDataType, - KeyType keyType, - const KeyedVector& optionalParameters, - Vector& request, - String8& defaultUrl, - KeyRequestType *keyRequestType) { - CdmLicenseType cdmLicenseType; - CdmSessionId cdmSessionId; - CdmKeySetId cdmKeySetId; - if (!scope.size()) { - return android::BAD_VALUE; - } - if (keyType == kKeyType_Offline) { - cdmLicenseType = kLicenseTypeOffline; - cdmSessionId.assign(scope.begin(), scope.end()); - } else if (keyType == kKeyType_Streaming) { - cdmLicenseType = kLicenseTypeStreaming; - cdmSessionId.assign(scope.begin(), scope.end()); - } else if (keyType == kKeyType_Release) { - cdmLicenseType = kLicenseTypeRelease; - cdmKeySetId.assign(scope.begin(), scope.end()); - } else { - return android::ERROR_DRM_CANNOT_HANDLE; - } - - string cdmInitDataType = initDataType.string(); - // Provide backwards-compatibility for apps that pass non-EME-compatible MIME - // types. - if (!WvContentDecryptionModule::IsSupported(cdmInitDataType)) { - cdmInitDataType = wvcdm::ISO_BMFF_VIDEO_MIME_TYPE; - } - - CdmInitData processedInitData; - if (initData.size() > 0 && - WvContentDecryptionModule::IsCenc(cdmInitDataType) && - !initDataResemblesPSSH(initData)) { - // This data was passed in the old format, pre-unwrapped. We need to wrap - // the init data in a new PSSH header. - static const uint8_t psshPrefix[] = { - 0, 0, 0, 0, // Total size - 'p', 's', 's', 'h', // "PSSH" - 0, 0, 0, 0, // Flags - must be zero - 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, // Widevine UUID - 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED, - 0, 0, 0, 0 // Size of initData - }; - processedInitData.assign(reinterpret_cast(psshPrefix), - sizeof(psshPrefix) / sizeof(uint8_t)); - processedInitData.append(reinterpret_cast(initData.array()), - initData.size()); - const size_t kPsshBoxSizeLocation = 0; - const size_t kInitDataSizeLocation = - sizeof(psshPrefix) - sizeof(uint32_t); - uint32_t psshBoxSize = htonl(processedInitData.size()); - uint32_t initDataSize = htonl(initData.size()); - memcpy(&processedInitData[kPsshBoxSizeLocation], &psshBoxSize, - sizeof(uint32_t)); - memcpy(&processedInitData[kInitDataSizeLocation], &initDataSize, - sizeof(uint32_t)); - } else { - // For other formats, we can pass the init data through unmodified. - processedInitData.assign(reinterpret_cast(initData.array()), - initData.size()); - } - - CdmAppParameterMap cdmParameters; - for (size_t i = 0; i < optionalParameters.size(); ++i) { - const String8& key = optionalParameters.keyAt(i); - const String8& value = optionalParameters.valueAt(i); - - string cdmKey(key.string(), key.size()); - string cdmValue(value.string(), value.size()); - - cdmParameters[cdmKey] = cdmValue; - } - - CdmKeyRequest keyRequest; - CdmResponseType res = mCDM->GenerateKeyRequest( - cdmSessionId, cdmKeySetId, cdmInitDataType, processedInitData, - cdmLicenseType, cdmParameters, &mPropertySet, mCdmIdentifier, - &keyRequest); - - *keyRequestType = ConvertFromCdmKeyRequestType(keyRequest.type); - - if (isCdmResponseTypeSuccess(res)) { - defaultUrl.clear(); - defaultUrl.setTo(keyRequest.url.data(), keyRequest.url.size()); - - request = ToVector(keyRequest.message); - } - - if (keyType == kKeyType_Release) { - // When releasing keys, we do not have a session ID. - return mapCdmResponseType(res); - } else { - // For all other requests, we have a session ID. - return mapAndNotifyOfCdmResponseType(scope, res); - } -} - -status_t WVDrmPlugin::provideKeyResponse( - const Vector& scope, - const Vector& response, - Vector& keySetId) { - if (scope.size() == 0 || response.size() == 0) { - return android::BAD_VALUE; - } - CdmSessionId cdmSessionId; - CdmKeyResponse cdmResponse(response.begin(), response.end()); - CdmKeySetId cdmKeySetId; - - bool isRequest = (memcmp(scope.array(), SESSION_ID_PREFIX, - sizeof(SESSION_ID_PREFIX) - 1) == 0); - bool isRelease = (memcmp(scope.array(), KEY_SET_ID_PREFIX, - sizeof(KEY_SET_ID_PREFIX) - 1) == 0); - - if (isRequest) { - cdmSessionId.assign(scope.begin(), scope.end()); - } else if (isRelease) { - cdmKeySetId.assign(scope.begin(), scope.end()); - } else { - return android::ERROR_DRM_CANNOT_HANDLE; - } - - CdmResponseType res = mCDM->AddKey(cdmSessionId, cdmResponse, &cdmKeySetId); - - if (isRequest && isCdmResponseTypeSuccess(res)) { - keySetId = ToVector(cdmKeySetId); - } - - if (isRelease) { - // When releasing keys, we do not have a session ID. - return mapCdmResponseType(res); - } else { - // For all other requests, we have a session ID. - status_t status = mapAndNotifyOfCdmResponseType(scope, res); - // For "NEED_KEY," we still want to send the notifcation, but then we don't - // return the error. This is because "NEED_KEY" from AddKey() is an - // expected behavior when sending a privacy certificate. - if (res == wvcdm::NEED_KEY && mPropertySet.use_privacy_mode()) { - status = android::OK; - } - return status; - } -} - -status_t WVDrmPlugin::removeKeys(const Vector& sessionId) { - if (!sessionId.size()) { - return android::BAD_VALUE; - } - CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); - - CdmResponseType res = mCDM->RemoveKeys(cdmSessionId); - - return mapAndNotifyOfCdmResponseType(sessionId, res); -} - -status_t WVDrmPlugin::restoreKeys(const Vector& sessionId, - const Vector& keySetId) { - if (sessionId.size() == 0 || keySetId.size() == 0) { - return android::BAD_VALUE; - } - CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); - CdmKeySetId cdmKeySetId(keySetId.begin(), keySetId.end()); - - CdmResponseType res = mCDM->RestoreKey(cdmSessionId, cdmKeySetId); - - return mapAndNotifyOfCdmResponseType(sessionId, res); -} - -status_t WVDrmPlugin::queryKeyStatus( - const Vector& sessionId, - KeyedVector& infoMap) const { - if (sessionId.size() == 0) { - return android::BAD_VALUE; - } - CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); - CdmQueryMap cdmLicenseInfo; - - CdmResponseType res = mCDM->QueryKeyStatus(cdmSessionId, &cdmLicenseInfo); - - if (isCdmResponseTypeSuccess(res)) { - infoMap.clear(); - for (CdmQueryMap::const_iterator iter = cdmLicenseInfo.begin(); - iter != cdmLicenseInfo.end(); - ++iter) { - const string& cdmKey = iter->first; - const string& cdmValue = iter->second; - - String8 key(cdmKey.data(), cdmKey.size()); - String8 value(cdmValue.data(), cdmValue.size()); - - infoMap.add(key, value); - } - } - - return mapCdmResponseType(res); -} - -status_t WVDrmPlugin::getProvisionRequest(const String8& cert_type, - const String8& cert_authority, - Vector& request, - String8& defaultUrl) { - 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; - } - - string cdmCertAuthority = cert_authority.string(); - - wvcdm::SecurityLevel requested_security_level = - mPropertySet.security_level().compare(QUERY_VALUE_SECURITY_LEVEL_L3) == 0 - ? kLevel3 - : kLevelDefault; - - CdmResponseType res = mCDM->GetProvisioningRequest( - cdmCertType, cdmCertAuthority, mCdmIdentifier, - mProvisioningServiceCertificate, requested_security_level, - &cdmProvisionRequest, &cdmDefaultUrl); - - if (isCdmResponseTypeSuccess(res)) { - request = ToVector(cdmProvisionRequest); - defaultUrl.clear(); - defaultUrl.setTo(cdmDefaultUrl.data(), cdmDefaultUrl.size()); - } - - return mapCdmResponseType(res); -} - -status_t WVDrmPlugin::provideProvisionResponse( - const Vector& response, - Vector& certificate, - Vector& wrapped_key) { - if (!response.size()) { - return android::BAD_VALUE; - } - CdmProvisioningResponse cdmResponse(response.begin(), response.end()); - if (cdmResponse == kSpecialUnprovisionResponse) { - if (mCdmIdentifier.IsEquivalentToDefault()) { - return kErrorNoOriginSpecified; - } - return unprovision(mCdmIdentifier); - } else { - string cdmCertificate; - string cdmWrappedKey; - wvcdm::SecurityLevel requested_security_level = - mPropertySet.security_level() - .compare(QUERY_VALUE_SECURITY_LEVEL_L3) == 0 - ? kLevel3 - : kLevelDefault; - CdmResponseType res = - mCDM->HandleProvisioningResponse(mCdmIdentifier, cdmResponse, - requested_security_level, - &cdmCertificate, &cdmWrappedKey); - if (isCdmResponseTypeSuccess(res)) { - certificate = ToVector(cdmCertificate); - wrapped_key = ToVector(cdmWrappedKey); - } - - return mapCdmResponseType(res); - } -} - -status_t WVDrmPlugin::unprovisionDevice() { - return unprovision(kDefaultCdmIdentifier); -} - -status_t WVDrmPlugin::getSecureStop(const Vector& ssid, - Vector& secureStop) { - if (!ssid.size()) { - return android::BAD_VALUE; - } - CdmUsageInfo cdmUsageInfo; - CdmSecureStopId cdmSsid(ssid.begin(), ssid.end()); - CdmResponseType res = mCDM->GetUsageInfo( - mPropertySet.app_id(), cdmSsid, mCdmIdentifier, &cdmUsageInfo); - if (isCdmResponseTypeSuccess(res)) { - secureStop.clear(); - for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin(); - iter != cdmUsageInfo.end(); - ++iter) { - const string& cdmStop = *iter; - - secureStop.appendArray(reinterpret_cast(cdmStop.data()), - cdmStop.size()); - } - } - return mapCdmResponseType(res); -} - -status_t WVDrmPlugin::getSecureStops(List >& secureStops) { - CdmUsageInfo cdmUsageInfo; - CdmResponseType res = - mCDM->GetUsageInfo(mPropertySet.app_id(), mCdmIdentifier, &cdmUsageInfo); - if (isCdmResponseTypeSuccess(res)) { - secureStops.clear(); - for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin(); - iter != cdmUsageInfo.end(); - ++iter) { - const string& cdmStop = *iter; - - secureStops.push_back(ToVector(cdmStop)); - } - } - return mapCdmResponseType(res); -} - -status_t WVDrmPlugin::releaseAllSecureStops() { - CdmResponseType res = mCDM->RemoveAllUsageInfo(mPropertySet.app_id(), - mCdmIdentifier); - return mapCdmResponseType(res); -} - -status_t WVDrmPlugin::releaseSecureStops(const Vector& ssRelease) { - if (!ssRelease.size()) { - return android::BAD_VALUE; - } - CdmUsageInfoReleaseMessage cdmMessage(ssRelease.begin(), ssRelease.end()); - CdmResponseType res = mCDM->ReleaseUsageInfo(cdmMessage, mCdmIdentifier); - return mapCdmResponseType(res); -} - -status_t WVDrmPlugin::getPropertyString(const String8& name, - String8& value) const { - if (name == "vendor") { - value = "Google"; - } else if (name == "version") { - return queryProperty(QUERY_KEY_WVCDM_VERSION, value); - } else if (name == "description") { - value = "Widevine CDM"; - } else if (name == "algorithms") { - value = "AES/CBC/NoPadding,HmacSHA256"; - } else if (name == "securityLevel") { - string requestedLevel = mPropertySet.security_level(); - - if (requestedLevel.length() > 0) { - value = requestedLevel.c_str(); - } else { - return queryProperty(QUERY_KEY_SECURITY_LEVEL, value); - } - } else if (name == "systemId") { - return queryProperty(QUERY_KEY_SYSTEM_ID, value); - } else if (name == "privacyMode") { - if (mPropertySet.use_privacy_mode()) { - value = kEnable; - } else { - value = kDisable; - } - } else if (name == "sessionSharing") { - if (mPropertySet.is_session_sharing_enabled()) { - value = kEnable; - } else { - value = kDisable; - } - } else if (name == "hdcpLevel") { - return queryProperty(QUERY_KEY_CURRENT_HDCP_LEVEL, value); - } else if (name == "maxHdcpLevel") { - return queryProperty(QUERY_KEY_MAX_HDCP_LEVEL, value); - } else if (name == "usageReportingSupport") { - return queryProperty(QUERY_KEY_USAGE_SUPPORT, value); - } else if (name == "numberOfOpenSessions") { - return queryProperty(QUERY_KEY_NUMBER_OF_OPEN_SESSIONS, value); - } else if (name == "maxNumberOfSessions") { - return queryProperty(QUERY_KEY_MAX_NUMBER_OF_SESSIONS, value); - } else if (name == "oemCryptoApiVersion") { - return queryProperty(QUERY_KEY_OEMCRYPTO_API_VERSION, value); - } else if (name == "appId") { - value = mPropertySet.app_id().c_str(); - } else if (name == "origin") { - value = mCdmIdentifier.origin.c_str(); - } else if (name == "CurrentSRMVersion") { - return queryProperty(QUERY_KEY_CURRENT_SRM_VERSION, value); - } else if (name == "SRMUpdateSupport") { - return queryProperty(QUERY_KEY_SRM_UPDATE_SUPPORT, value); - } else if (name == "resourceRatingTier") { - return queryProperty(QUERY_KEY_RESOURCE_RATING_TIER, value); - } else if (name == "oemCryptoBuildInformation") { - return queryProperty(QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION, value); - } else if (name == "decryptHashSupport") { - return queryProperty(QUERY_KEY_DECRYPT_HASH_SUPPORT, value); - } else if (name == "decryptHashError") { - std::string hash_error_string; - CdmResponseType res = - mCDM->GetDecryptHashError(mDecryptHashSessionId, &hash_error_string); - value = hash_error_string.c_str(); - return mapCdmResponseType(res); - } else if (name == "maxUsageEntriesSupported") { - 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 == "analogOutputCapabilities") { - return queryProperty(QUERY_KEY_ANALOG_OUTPUT_CAPABILITIES, value); - } else if (name == "canDisableAnalogOutput") { - return queryProperty(QUERY_KEY_CAN_DISABLE_ANALOG_OUTPUT, 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; - } - - return android::OK; -} - -status_t WVDrmPlugin::getPropertyByteArray(const String8& name, - Vector& value) const { - if (name == "deviceUniqueId") { - return queryProperty(QUERY_KEY_DEVICE_ID, value); - } else if (name == "provisioningUniqueId") { - return queryProperty(QUERY_KEY_PROVISIONING_ID, value); - } else if (name == "serviceCertificate") { - value = ToVector(mPropertySet.service_certificate()); - } else if (name == "provisioningServiceCertificate") { - value = ToVector(mProvisioningServiceCertificate); - } else if (name == "metrics") { - std::string serialized_metrics; - drm_metrics::WvCdmMetrics metrics; - mCDM->GetMetrics(mCdmIdentifier, &metrics); - if (!metrics.SerializeToString(&serialized_metrics)) { - return android::ERROR_DRM_UNKNOWN; - } else { - value = ToVector(serialized_metrics); - } - } else { - ALOGE("App requested unknown byte array property %s", name.string()); - return android::ERROR_DRM_CANNOT_HANDLE; - } - - return android::OK; -} - -status_t WVDrmPlugin::setPropertyString(const String8& name, - const String8& value) { - if (name == "securityLevel") { - if (mCryptoSessions.size() == 0) { - if (value == QUERY_VALUE_SECURITY_LEVEL_L3.c_str()) { - mPropertySet.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3); - } else if (value == QUERY_VALUE_SECURITY_LEVEL_L1.c_str()) { - // We must be sure we CAN set the security level to L1. - std::string current_security_level; - status_t status = - queryProperty(kLevelDefault, QUERY_KEY_SECURITY_LEVEL, - current_security_level); - if (status != android::OK) return status; - - if (current_security_level != QUERY_VALUE_SECURITY_LEVEL_L1) { - ALOGE("App requested L1 security on a non-L1 device."); - return android::BAD_VALUE; - } else { - mPropertySet.set_security_level(kResetSecurityLevel); - } - } else if (value == kResetSecurityLevel) { - mPropertySet.set_security_level(kResetSecurityLevel); - } else { - ALOGE("App requested invalid security level %s", value.string()); - return android::BAD_VALUE; - } - } else { - ALOGE("App tried to change security level while sessions are open."); - return kErrorSessionIsOpen; - } - } else if (name == "privacyMode") { - if (value == kEnable) { - mPropertySet.set_use_privacy_mode(true); - } else if (value == kDisable) { - mPropertySet.set_use_privacy_mode(false); - } else { - ALOGE("App requested unknown privacy mode %s", value.string()); - return android::BAD_VALUE; - } - } else if (name == "sessionSharing") { - if (mCryptoSessions.size() == 0) { - if (value == kEnable) { - mPropertySet.set_is_session_sharing_enabled(true); - } else if (value == kDisable) { - mPropertySet.set_is_session_sharing_enabled(false); - } else { - ALOGE("App requested unknown sharing type %s", value.string()); - return android::BAD_VALUE; - } - } else { - ALOGE("App tried to change key sharing while sessions are open."); - return kErrorSessionIsOpen; - } - } else if (name == "appId") { - if (mCryptoSessions.size() == 0) { - mPropertySet.set_app_id(value.string()); - } else { - ALOGE("App tried to set the application id while sessions are opened."); - return kErrorSessionIsOpen; - } - } else if (name == "origin") { - if (mCryptoSessions.size() != 0) { - ALOGE("App tried to set the origin while sessions are opened."); - return kErrorSessionIsOpen; - } else { - mCdmIdentifier.origin = value.string(); - } - } else if (name == "debugIgnoreKeyboxCount") { - std::istringstream ss(value.string()); - uint32_t count = 0; - ss >> count; - if (ss.fail()) { - ALOGE("Could not parse an integer from '%s'", value.string()); - count = 0; - return android::BAD_VALUE; - } - CdmResponseType res = mCDM->SetDebugIgnoreKeyboxCount(count); - return mapCdmResponseType(res); - } else if (name == "decryptHash") { - CdmSessionId sessionId; - CdmResponseType res = - mCDM->SetDecryptHash(value.string(), &sessionId); - - if (wvcdm::NO_ERROR == res) mDecryptHashSessionId = sessionId; - - return mapCdmResponseType(res); - } else if (name == "decryptHashSessionId") { - mDecryptHashSessionId = value.string(); - } else if (name == "debugOtaKeyboxFallbackDuration") { - bool success = false; - if (value == "default") { - success = mCDM->SetDefaultOtaKeyboxFallbackDurationRules(); - } else if (value == "fast") { - success = mCDM->SetFastOtaKeyboxFallbackDurationRules(); - } else { - ALOGE("Unknown OTA fallback duration value %s", value.string()); - return android::BAD_VALUE; - } - if (!success) { - return android::UNKNOWN_ERROR; - } - } 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; - } - - return android::OK; -} - -status_t WVDrmPlugin::setPropertyByteArray(const String8& name, - const Vector& value) { - if (name == "serviceCertificate") { - std::string cert(value.begin(), value.end()); - if (value.isEmpty() || mCDM->IsValidServiceCertificate(cert)) { - mPropertySet.set_service_certificate(cert); - } else { - return android::BAD_VALUE; - } - } else if (name == "provisioningServiceCertificate") { - std::string cert(value.begin(), value.end()); - if (value.isEmpty() || mCDM->IsValidServiceCertificate(cert)) { - mProvisioningServiceCertificate = cert; - } else { - return android::BAD_VALUE; - } - } else { - ALOGE("App set unknown byte array property %s", name.string()); - return android::ERROR_DRM_CANNOT_HANDLE; - } - - return android::OK; -} - -status_t WVDrmPlugin::setCipherAlgorithm(const Vector& sessionId, - const String8& algorithm) { - if (sessionId.size() == 0 || algorithm.size() == 0) { - return android::BAD_VALUE; - } - CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - return android::ERROR_DRM_SESSION_NOT_OPENED; - } - - CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (algorithm == "AES/CBC/NoPadding") { - cryptoSession.setCipherAlgorithm(OEMCrypto_AES_CBC_128_NO_PADDING); - } else { - return android::ERROR_DRM_CANNOT_HANDLE; - } - - return android::OK; -} - -status_t WVDrmPlugin::setMacAlgorithm(const Vector& sessionId, - const String8& algorithm) { - if (sessionId.size() == 0 || algorithm.size() == 0) { - return android::BAD_VALUE; - } - CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - return android::ERROR_DRM_SESSION_NOT_OPENED; - } - - CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (algorithm == "HmacSHA256") { - cryptoSession.setMacAlgorithm(OEMCrypto_HMAC_SHA256); - } else { - return android::ERROR_DRM_CANNOT_HANDLE; - } - - return android::OK; -} - -status_t WVDrmPlugin::encrypt(const Vector& sessionId, - const Vector& keyId, - const Vector& input, - const Vector& iv, - Vector& output) { - CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - return android::ERROR_DRM_SESSION_NOT_OPENED; - } - - const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (cryptoSession.cipherAlgorithm() == kInvalidCryptoAlgorithm) { - return android::NO_INIT; - } - - OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(), - keyId.array(), keyId.size()); - - if (res != OEMCrypto_SUCCESS) { - ALOGE("OEMCrypto_SelectKey failed with %u", res); - return mapAndNotifyOfOEMCryptoResult(sessionId, res); - } - - output.resize(input.size()); - - res = mCrypto->encrypt(cryptoSession.oecSessionId(), input.array(), - input.size(), iv.array(), - cryptoSession.cipherAlgorithm(), output.editArray()); - - if (res == OEMCrypto_SUCCESS) { - return android::OK; - } else { - ALOGE("OEMCrypto_Generic_Encrypt failed with %u", res); - return mapAndNotifyOfOEMCryptoResult(sessionId, res); - } -} - -status_t WVDrmPlugin::decrypt(const Vector& sessionId, - const Vector& keyId, - const Vector& input, - const Vector& iv, - Vector& output) { - CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - return android::ERROR_DRM_SESSION_NOT_OPENED; - } - - const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (cryptoSession.cipherAlgorithm() == kInvalidCryptoAlgorithm) { - return android::NO_INIT; - } - - OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(), - keyId.array(), keyId.size()); - - if (res != OEMCrypto_SUCCESS) { - ALOGE("OEMCrypto_SelectKey failed with %u", res); - return mapAndNotifyOfOEMCryptoResult(sessionId, res); - } - - output.resize(input.size()); - - res = mCrypto->decrypt(cryptoSession.oecSessionId(), input.array(), - input.size(), iv.array(), - cryptoSession.cipherAlgorithm(), output.editArray()); - - if (res == OEMCrypto_SUCCESS) { - return android::OK; - } else { - ALOGE("OEMCrypto_Generic_Decrypt failed with %u", res); - return mapAndNotifyOfOEMCryptoResult(sessionId, res); - } -} - -status_t WVDrmPlugin::sign(const Vector& sessionId, - const Vector& keyId, - const Vector& message, - Vector& signature) { - CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - return android::ERROR_DRM_SESSION_NOT_OPENED; - } - - const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (cryptoSession.macAlgorithm() == kInvalidCryptoAlgorithm) { - return android::NO_INIT; - } - - OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(), - keyId.array(), keyId.size()); - - if (res != OEMCrypto_SUCCESS) { - ALOGE("OEMCrypto_SelectKey failed with %u", res); - return mapAndNotifyOfOEMCryptoResult(sessionId, res); - } - - size_t signatureSize = 0; - - res = mCrypto->sign(cryptoSession.oecSessionId(), message.array(), - message.size(), cryptoSession.macAlgorithm(), - NULL, &signatureSize); - - if (res != OEMCrypto_ERROR_SHORT_BUFFER) { - ALOGE("OEMCrypto_Generic_Sign failed with %u when requesting signature " - "size", res); - if (res != OEMCrypto_SUCCESS) { - return mapAndNotifyOfOEMCryptoResult(sessionId, res); - } else { - return android::ERROR_DRM_UNKNOWN; - } - } - - signature.resize(signatureSize); - - res = mCrypto->sign(cryptoSession.oecSessionId(), message.array(), - message.size(), cryptoSession.macAlgorithm(), - signature.editArray(), &signatureSize); - - if (res == OEMCrypto_SUCCESS) { - return android::OK; - } else { - ALOGE("OEMCrypto_Generic_Sign failed with %u", res); - return mapAndNotifyOfOEMCryptoResult(sessionId, res); - } -} - -status_t WVDrmPlugin::verify(const Vector& sessionId, - const Vector& keyId, - const Vector& message, - const Vector& signature, - bool& match) { - CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - return android::ERROR_DRM_SESSION_NOT_OPENED; - } - - const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (cryptoSession.macAlgorithm() == kInvalidCryptoAlgorithm) { - return android::NO_INIT; - } - - OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(), - keyId.array(), keyId.size()); - - if (res != OEMCrypto_SUCCESS) { - ALOGE("OEMCrypto_SelectKey failed with %u", res); - return mapAndNotifyOfOEMCryptoResult(sessionId, res); - } - - res = mCrypto->verify(cryptoSession.oecSessionId(), message.array(), - message.size(), cryptoSession.macAlgorithm(), - signature.array(), signature.size()); - - if (res == OEMCrypto_SUCCESS) { - match = true; - return android::OK; - } else if (res == OEMCrypto_ERROR_SIGNATURE_FAILURE) { - match = false; - return android::OK; - } else { - ALOGE("OEMCrypto_Generic_Verify failed with %u", res); - return mapAndNotifyOfOEMCryptoResult(sessionId, res); - } -} - -status_t WVDrmPlugin::signRSA(const Vector& sessionId, - const String8& algorithm, - const Vector& message, - const Vector& wrappedKey, - Vector& signature) { - if (sessionId.size() == 0 || algorithm.size() == 0 || - message.size() == 0 || wrappedKey.size() == 0) { - return android::BAD_VALUE; - } - RSA_Padding_Scheme padding_scheme; - if (algorithm == "RSASSA-PSS-SHA1") { - padding_scheme = kSign_RSASSA_PSS; - } else if (algorithm == "PKCS1-BlockType1") { - padding_scheme = kSign_PKCS1_Block1; - } else { - ALOGE("Unknown RSA Algorithm %s", algorithm.string()); - return android::ERROR_DRM_CANNOT_HANDLE; - } - OEMCryptoResult res = mCrypto->signRSA(wrappedKey.array(), - wrappedKey.size(), - message.array(), message.size(), - signature, - padding_scheme); - - if (res != OEMCrypto_SUCCESS) { - ALOGE("OEMCrypto_GenerateRSASignature failed with %u", res); - return mapOEMCryptoResult(res); - } - - return android::OK; -} - -void WVDrmPlugin::OnSessionRenewalNeeded(const CdmSessionId& cdmSessionId) { - Vector sessionId = ToVector(cdmSessionId); - sendEvent(kDrmPluginEventKeyNeeded, 0, &sessionId, NULL); -} - -void WVDrmPlugin::OnSessionKeysChange(const CdmSessionId& cdmSessionId, - const CdmKeyStatusMap& cdmKeysStatus, - bool hasNewUsableKey) { - bool expired = false; - Vector keyStatusList; - for (CdmKeyStatusMap::const_iterator it = cdmKeysStatus.begin(); - it != cdmKeysStatus.end(); ++it) { - const KeyId& keyId = it->first; - const CdmKeyStatus cdmKeyStatus = it->second; - if (cdmKeyStatus == kKeyStatusExpired) expired = true; - - keyStatusList.push( - {ToVector(keyId), ConvertFromCdmKeyStatus(cdmKeyStatus)}); - } - - Vector sessionId = ToVector(cdmSessionId); - sendKeysChange(&sessionId, &keyStatusList, hasNewUsableKey); - // For backward compatibility. - if (expired) sendEvent(kDrmPluginEventKeyExpired, 0, &sessionId, NULL); -} - -void WVDrmPlugin::OnExpirationUpdate(const CdmSessionId& cdmSessionId, - int64_t newExpiryTimeSeconds) { - Vector sessionId = ToVector(cdmSessionId); - int64_t newExpiryTimeMilliseconds = newExpiryTimeSeconds == NEVER_EXPIRES - ? newExpiryTimeSeconds - : newExpiryTimeSeconds * 1000; - sendExpirationUpdate(&sessionId, newExpiryTimeMilliseconds); -} - -status_t WVDrmPlugin::queryProperty(const std::string& property, - std::string& stringValue) const { - wvcdm::SecurityLevel securityLevel = - mPropertySet.security_level().compare(QUERY_VALUE_SECURITY_LEVEL_L3) == 0 - ? kLevel3 - : kLevelDefault; - return queryProperty(securityLevel, property, stringValue); -} - -status_t WVDrmPlugin::queryProperty(wvcdm::SecurityLevel securityLevel, - const std::string& property, - std::string& stringValue) const { - CdmResponseType res = - mCDM->QueryStatus(securityLevel, property, &stringValue); - - if (res != wvcdm::NO_ERROR) { - ALOGE("Error querying CDM status: %u", res); - } - return mapCdmResponseType(res); -} - -status_t WVDrmPlugin::queryProperty(const std::string& property, - String8& string8_value) const { - std::string string_value; - status_t status = queryProperty(property, string_value); - if (status != android::OK) return status; - string8_value = string_value.c_str(); - return android::OK; -} - -status_t WVDrmPlugin::queryProperty(const std::string& property, - Vector& vector_value) const { - std::string string_value; - status_t status = queryProperty(property, string_value); - if (status != android::OK) return status; - vector_value = ToVector(string_value); - return android::OK; -} - -status_t WVDrmPlugin::mapAndNotifyOfCdmResponseType( - const Vector& sessionId, - CdmResponseType res) { - if (res == wvcdm::NEED_PROVISIONING) { - sendEvent(kDrmPluginEventProvisionRequired, 0, &sessionId, NULL); - } else if (res == wvcdm::NEED_KEY) { - sendEvent(kDrmPluginEventKeyNeeded, 0, &sessionId, NULL); - } - - return mapCdmResponseType(res); -} - -status_t WVDrmPlugin::mapAndNotifyOfOEMCryptoResult( - const Vector& sessionId, - OEMCryptoResult res) { - if (res == OEMCrypto_ERROR_NO_DEVICE_KEY) { - sendEvent(kDrmPluginEventProvisionRequired, 0, &sessionId, NULL); - } - return mapOEMCryptoResult(res); -} - -status_t WVDrmPlugin::mapOEMCryptoResult(OEMCryptoResult res) { - switch (res) { - case OEMCrypto_SUCCESS: - return android::OK; - case OEMCrypto_ERROR_SIGNATURE_FAILURE: - return android::ERROR_DRM_TAMPER_DETECTED; - case OEMCrypto_ERROR_SHORT_BUFFER: - return kErrorIncorrectBufferSize; - case OEMCrypto_ERROR_NO_DEVICE_KEY: - return android::ERROR_DRM_NOT_PROVISIONED; - case OEMCrypto_ERROR_INVALID_SESSION: - return android::ERROR_DRM_SESSION_NOT_OPENED; - case OEMCrypto_ERROR_TOO_MANY_SESSIONS: - return android::ERROR_DRM_RESOURCE_BUSY; - case OEMCrypto_ERROR_INVALID_RSA_KEY: - return kErrorInvalidKey; - case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES: - return android::ERROR_DRM_RESOURCE_BUSY; - case OEMCrypto_ERROR_NOT_IMPLEMENTED: - return android::ERROR_DRM_CANNOT_HANDLE; - case OEMCrypto_ERROR_UNKNOWN_FAILURE: - case OEMCrypto_ERROR_OPEN_SESSION_FAILED: - return android::ERROR_DRM_UNKNOWN; - default: - return android::UNKNOWN_ERROR; - } -} - -bool WVDrmPlugin::initDataResemblesPSSH(const Vector& initData) { - const uint8_t* const initDataArray = initData.array(); - - if (sizeof(uint32_t) + kPsshTag.size() > initData.size()) { - // The init data is so small that it couldn't contain a size and PSSH tag. - return false; - } - - // Extract the size field - const uint8_t* const sizeField = &initDataArray[0]; - uint32_t nboSize; - memcpy(&nboSize, sizeField, sizeof(nboSize)); - uint32_t size = ntohl(nboSize); - - if (size > initData.size()) { - return false; - } - - // Extract the ID field - const char* const idField = - reinterpret_cast(&initDataArray[sizeof(nboSize)]); - string id(idField, kPsshTag.size()); - return id == kPsshTag; -} - -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)) - { - return mapCdmResponseType(res1); - } - else - { - return mapCdmResponseType(res3); - } -} - -} // namespace wvdrm diff --git a/libwvdrmengine/mediadrm/src/WVGenericCryptoInterface.cpp b/libwvdrmengine/mediadrm/src/WVGenericCryptoInterface.cpp deleted file mode 100644 index f32d51fb..00000000 --- a/libwvdrmengine/mediadrm/src/WVGenericCryptoInterface.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -//#define LOG_NDEBUG 0 -#define LOG_TAG "WVCdm" -#include - -#include "WVGenericCryptoInterface.h" - -#include "wv_cdm_constants.h" - -namespace wvdrm { - -using namespace android; -using namespace std; -using namespace wvcdm; - -OEMCryptoResult WVGenericCryptoInterface::signRSA(const uint8_t* wrapped_rsa_key, - size_t wrapped_rsa_key_length, - const uint8_t* message, - size_t message_length, - Vector& signature, - RSA_Padding_Scheme padding_scheme) { - OEMCrypto_SESSION session; - OEMCryptoResult sts = OEMCrypto_OpenSession(&session); - if (sts != OEMCrypto_SUCCESS) return sts; - sts = OEMCrypto_LoadDRMPrivateKey(session, OEMCrypto_RSA_Private_Key, - wrapped_rsa_key, wrapped_rsa_key_length); - if (sts == OEMCrypto_SUCCESS) { - size_t signatureSize = 0; - sts = OEMCrypto_GenerateRSASignature(session, message, message_length, - NULL, &signatureSize, - padding_scheme); - if (sts == OEMCrypto_SUCCESS) { - // Should be short buffer. - sts = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } else if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { - signature.resize(signatureSize); - sts = OEMCrypto_GenerateRSASignature(session, message, message_length, - signature.editArray(), &signatureSize, - padding_scheme); - } - } - OEMCrypto_CloseSession(session); - return sts; -} - -} // namespace wvdrm diff --git a/libwvdrmengine/mediadrm/test/Android.mk b/libwvdrmengine/mediadrm/test/Android.mk index b6792a33..146fa7fe 100644 --- a/libwvdrmengine/mediadrm/test/Android.mk +++ b/libwvdrmengine/mediadrm/test/Android.mk @@ -1,70 +1,5 @@ LOCAL_PATH := $(call my-dir) -# ----------------------------------------------------------------------------- -# Builds libwvdrmdrmplugin_test -# -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - legacy_src/WVDrmPlugin_test.cpp \ - -LOCAL_C_INCLUDES := \ - frameworks/av/include \ - frameworks/native/include \ - vendor/widevine/libwvdrmengine/cdm/core/include \ - vendor/widevine/libwvdrmengine/cdm/include \ - vendor/widevine/libwvdrmengine/cdm/metrics/include \ - vendor/widevine/libwvdrmengine/cdm/util/include \ - vendor/widevine/libwvdrmengine/include \ - vendor/widevine/libwvdrmengine/mediadrm/include \ - vendor/widevine/libwvdrmengine/oemcrypto/include \ - -LOCAL_STATIC_LIBRARIES := \ - libcdm \ - libcdm_protos \ - libcdm_utils \ - libjsmn \ - libgmock \ - libgmock_main \ - libgtest \ - libwvlevel3 \ - libwvdrmdrmplugin \ - libwv_odk \ - -LOCAL_SHARED_LIBRARIES := \ - libbase \ - libcrypto \ - libdl \ - libhidlbase \ - liblog \ - libprotobuf-cpp-lite \ - libutils \ - -LOCAL_HEADER_LIBRARIES := \ - libstagefright_headers \ - libstagefright_foundation_headers \ - -LOCAL_C_INCLUDES += \ - external/protobuf/src \ - -LOCAL_MODULE := libwvdrmdrmplugin_test -LOCAL_LICENSE_KINDS := legacy_by_exception_only -LOCAL_LICENSE_CONDITIONS := by_exception_only - -LOCAL_MODULE_TAGS := tests - -LOCAL_MODULE_OWNER := widevine -LOCAL_PROPRIETARY_MODULE := true - -# When built, explicitly put it in the DATA/nativetest directory. -LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest - -ifneq ($(TARGET_ENABLE_MEDIADRM_64), true) -LOCAL_MODULE_TARGET_ARCH := arm x86 mips -endif - -include $(BUILD_EXECUTABLE) - # ----------------------------------------------------------------------------- # Builds libwvdrmdrmplugin_hidl_test # @@ -83,7 +18,6 @@ LOCAL_C_INCLUDES := \ vendor/widevine/libwvdrmengine/include_hidl \ vendor/widevine/libwvdrmengine/include \ vendor/widevine/libwvdrmengine/mediadrm/include_hidl \ - vendor/widevine/libwvdrmengine/mediadrm/include \ vendor/widevine/libwvdrmengine/oemcrypto/include \ LOCAL_STATIC_LIBRARIES := \ @@ -156,7 +90,6 @@ LOCAL_C_INCLUDES := \ vendor/widevine/libwvdrmengine/include_hidl \ vendor/widevine/libwvdrmengine/include \ vendor/widevine/libwvdrmengine/mediadrm/include_hidl \ - vendor/widevine/libwvdrmengine/mediadrm/include \ vendor/widevine/libwvdrmengine/oemcrypto/include \ LOCAL_STATIC_LIBRARIES := \ diff --git a/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp deleted file mode 100644 index 7a8e8d14..00000000 --- a/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp +++ /dev/null @@ -1,1930 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#include -#include -#include -#include - -#include "WVDrmPlugin.h" -#include "WVErrors.h" -#include "cdm_client_property_set.h" -#include "media/stagefright/MediaErrors.h" -#include "media/stagefright/foundation/ABase.h" -#include "media/stagefright/foundation/AString.h" -#include "string_conversions.h" -#include "wv_cdm_constants.h" -#include "wv_cdm_types.h" -#include "wv_content_decryption_module.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -using namespace android; -using namespace std; -using namespace testing; -using namespace wvcdm; -using namespace wvdrm; - -namespace { -const String8 kEmptyString; -const String8 kOrigin("widevine.com"); -const String8 kAppId("com.unittest.mock.app.id"); -const uint8_t* const kUnprovisionResponse = - reinterpret_cast("unprovision"); -const size_t kUnprovisionResponseSize = 11; - -// This is a serialized WvCdmMetrics message containing a small amount of -// sample data. This ensures we're able to extract it via a property. -const char kSerializedMetricsHex[] = - "0a580a001a0210072202100d2a02100832182216636f6d2e676f6f676c652e616e64726f69" - "642e676d734208220631342e302e304a06080112020800520610d5f3fad5056a0b1d00fd4c" - "47280132020804a2010608011202080012cb010a0622047369643412b5010a021001520919" - "1d5a643bdfff50405a0b1d00d01945280132021001620d1d00f8e84528013204080020006a" - "0310b739820102100d8a01060801120248009a010310ff01da0106080112024800e2010e1d" - "005243472801320528800248009a020d1d00b016452801320428404800a202060801120248" - "19aa0206080212024800b2020b1d8098f047280132024800ba02021001ca020b1d00101945" - "280132024800e202021004fa02021002a203021000b2030210021a09196891ed7c3f355040"; - -} // anonymous namespace - -class MockCDM : public WvContentDecryptionModule { - public: - MOCK_METHOD5(OpenSession, CdmResponseType(const CdmKeySystem&, - CdmClientPropertySet*, - const CdmIdentifier&, - WvCdmEventListener*, - CdmSessionId*)); - - MOCK_METHOD1(CloseSession, CdmResponseType(const CdmSessionId&)); - - MOCK_METHOD9(GenerateKeyRequest, - CdmResponseType(const CdmSessionId&, const CdmKeySetId&, - const std::string&, const CdmInitData&, - const CdmLicenseType, CdmAppParameterMap&, - CdmClientPropertySet*, const CdmIdentifier&, - CdmKeyRequest*)); - - MOCK_METHOD3(AddKey, CdmResponseType(const CdmSessionId&, - const CdmKeyResponse&, - CdmKeySetId*)); - - MOCK_METHOD1(RemoveKeys, CdmResponseType(const CdmSessionId&)); - - MOCK_METHOD2(RestoreKey, CdmResponseType(const CdmSessionId&, - const CdmKeySetId&)); - - MOCK_METHOD3(QueryStatus, CdmResponseType(SecurityLevel, const std::string&, - std::string*)); - - MOCK_METHOD2(QueryKeyStatus, CdmResponseType(const CdmSessionId&, - CdmQueryMap*)); - - MOCK_METHOD2(QueryOemCryptoSessionId, CdmResponseType(const CdmSessionId&, - CdmQueryMap*)); - - MOCK_METHOD7(GetProvisioningRequest, CdmResponseType(CdmCertificateType, - const std::string&, - const CdmIdentifier&, - const std::string&, - SecurityLevel, - CdmProvisioningRequest*, - std::string*)); - - MOCK_METHOD5(HandleProvisioningResponse, - CdmResponseType(const CdmIdentifier&, CdmProvisioningResponse&, - SecurityLevel, std::string*, std::string*)); - - MOCK_METHOD2(Unprovision, CdmResponseType(CdmSecurityLevel, - const CdmIdentifier&)); - - MOCK_METHOD3(GetUsageInfo, CdmResponseType(const std::string&, - const CdmIdentifier&, - CdmUsageInfo*)); - - MOCK_METHOD4(GetUsageInfo, CdmResponseType(const std::string&, - const CdmSecureStopId&, - const CdmIdentifier&, - CdmUsageInfo*)); - - MOCK_METHOD2(RemoveAllUsageInfo, CdmResponseType(const std::string&, - const CdmIdentifier&)); - - MOCK_METHOD2(ReleaseUsageInfo, - CdmResponseType(const CdmUsageInfoReleaseMessage&, const CdmIdentifier&)); - - MOCK_METHOD1(IsValidServiceCertificate, bool(const std::string&)); - - MOCK_METHOD2(GetMetrics, CdmResponseType(const CdmIdentifier&, - drm_metrics::WvCdmMetrics*)); -}; - -class MockCrypto : public WVGenericCryptoInterface { - public: - MOCK_METHOD3(selectKey, OEMCryptoResult(const OEMCrypto_SESSION, - const uint8_t*, size_t)); - - MOCK_METHOD6(encrypt, OEMCryptoResult(OEMCrypto_SESSION, const uint8_t*, - size_t, const uint8_t*, - OEMCrypto_Algorithm, uint8_t*)); - - MOCK_METHOD6(decrypt, OEMCryptoResult(OEMCrypto_SESSION, const uint8_t*, - size_t, const uint8_t*, - OEMCrypto_Algorithm, uint8_t*)); - - MOCK_METHOD6(sign, OEMCryptoResult(OEMCrypto_SESSION, const uint8_t*, size_t, - OEMCrypto_Algorithm, uint8_t*, size_t*)); - - MOCK_METHOD6(verify, OEMCryptoResult(OEMCrypto_SESSION, const uint8_t*, - size_t, OEMCrypto_Algorithm, - const uint8_t*, size_t)); - - MOCK_METHOD3(loadDeviceRSAKey, OEMCryptoResult(OEMCrypto_SESSION, - const uint8_t*, size_t)); - - MOCK_METHOD6(generateRSASignature, OEMCryptoResult(OEMCrypto_SESSION, - const uint8_t*, size_t, - uint8_t*, size_t*, - RSA_Padding_Scheme)); -}; - -class MockDrmPluginListener : public DrmPluginListener { - public: - MOCK_METHOD4(sendEvent, void(DrmPlugin::EventType, int, - const Vector*, const Vector*)); - MOCK_METHOD2(sendExpirationUpdate, void(const Vector*, int64_t)); - MOCK_METHOD3(sendKeysChange, void(const Vector*, - const Vector*, bool)); -}; - -template -CdmResponseType setSessionIdOnMap(Unused, CdmQueryMap* map) { - static const char oecId[] = {DIGIT + '0', '\0'}; - (*map)[QUERY_KEY_OEMCRYPTO_SESSION_ID] = oecId; - return wvcdm::NO_ERROR; -} - -MATCHER_P(HasOrigin, origin, "") { - return arg.origin == origin; -} - -class WVDrmPluginTest : public Test { - protected: - static const uint32_t kSessionIdSize = 16; - uint8_t sessionIdRaw[kSessionIdSize]; - Vector sessionId; - CdmSessionId cdmSessionId; - - virtual void SetUp() { - // Fill the session ID - FILE* fp = fopen("/dev/urandom", "r"); - fread(sessionIdRaw, sizeof(uint8_t), kSessionIdSize, fp); - fclose(fp); - - memcpy(sessionIdRaw, SESSION_ID_PREFIX, sizeof(SESSION_ID_PREFIX) - 1); - sessionId.appendArray(sessionIdRaw, kSessionIdSize); - cdmSessionId.assign(sessionId.begin(), sessionId.end()); - - // Set default return values for gMock - DefaultValue::Set(wvcdm::NO_ERROR); - DefaultValue::Set(OEMCrypto_SUCCESS); - DefaultValue::Set(true); - } -}; - -struct OriginTestVariant { - // For a test that does not expect any follow-up queries - OriginTestVariant(const std::string& nameValue, const String8& originValue, - const std::string& expectedOriginValue) - : name(nameValue), origin(originValue), - expectedOrigin(expectedOriginValue) {} - - const std::string name; - const String8 origin; - const std::string expectedOrigin; -}; - -void PrintTo(const OriginTestVariant& param, ::std::ostream* os) { - *os << param.name << " Variant"; - -} - -class WVDrmPluginOriginTest : public WVDrmPluginTest, - public WithParamInterface {}; - -TEST_F(WVDrmPluginTest, OpensSessions) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - EXPECT_CALL(*cdm, - OpenSession(StrEq("com.widevine"), _, HasOrigin(EMPTY_ORIGIN), _, _)) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), - Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)) - .Times(AtLeast(0)); - - status_t res = plugin.openSession(sessionId); - - ASSERT_EQ(OK, res); - EXPECT_THAT(sessionId, ElementsAreArray(sessionIdRaw, kSessionIdSize)); -} - -TEST_F(WVDrmPluginTest, ClosesSessions) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - EXPECT_CALL(*cdm, CloseSession(cdmSessionId)) - .Times(1); - - status_t res = plugin.closeSession(sessionId); - - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, ClosesSessionWithError) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - EXPECT_CALL(*cdm, CloseSession(cdmSessionId)) - .WillOnce(Return(SESSION_NOT_FOUND_1)); - - status_t res = plugin.closeSession(sessionId); - - ASSERT_EQ(ERROR_DRM_SESSION_NOT_OPENED, res); -} - -TEST_F(WVDrmPluginTest, GeneratesKeyRequests) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - static const size_t kInitDataSize = 128; - uint8_t initDataRaw[kInitDataSize]; - static const size_t kRequestSize = 256; - uint8_t requestRaw[kRequestSize]; - static const uint32_t kKeySetIdSize = 32; - uint8_t keySetIdRaw[kKeySetIdSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(initDataRaw, sizeof(uint8_t), kInitDataSize, fp); - fread(requestRaw, sizeof(uint8_t), kRequestSize, fp); - fread(keySetIdRaw, sizeof(uint8_t), kKeySetIdSize, fp); - fclose(fp); - - memcpy(keySetIdRaw, KEY_SET_ID_PREFIX, sizeof(KEY_SET_ID_PREFIX) - 1); - CdmKeySetId cdmKeySetId(reinterpret_cast(keySetIdRaw), kKeySetIdSize); - Vector keySetId; - keySetId.appendArray(keySetIdRaw, kKeySetIdSize); - - CdmInitData cdmInitData(reinterpret_cast(initDataRaw), kInitDataSize); - Vector initData; - initData.appendArray(initDataRaw, kInitDataSize); - - static const uint8_t psshPrefix[] = { - 0, 0, 0, 32 + kInitDataSize, // Total size - 'p', 's', 's', 'h', // "PSSH" - 0, 0, 0, 0, // Flags - must be zero - 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, // Widevine UUID - 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED, - 0, 0, 0, kInitDataSize // Size of initData - }; - static const size_t kPsshPrefixSize = sizeof(psshPrefix); - static const size_t kPsshBoxSize = kPsshPrefixSize + kInitDataSize; - uint8_t psshBoxRaw[kPsshBoxSize]; - memcpy(psshBoxRaw, psshPrefix, kPsshPrefixSize); - memcpy(psshBoxRaw + kPsshPrefixSize, initDataRaw, kInitDataSize); - CdmInitData cdmPsshBox(reinterpret_cast(psshBoxRaw), kPsshBoxSize); - Vector psshBox; - psshBox.appendArray(psshBoxRaw, kPsshBoxSize); - - CdmKeyMessage cdmRequest(requestRaw, requestRaw + kRequestSize); - - KeyedVector parameters; - CdmAppParameterMap cdmParameters; - parameters.add(String8("paddingScheme"), String8("BUBBLE WRAP")); - cdmParameters["paddingScheme"] = "BUBBLE WRAP"; - parameters.add(String8("favorite-particle"), String8("tetraquark")); - cdmParameters["favorite-particle"] = "tetraquark"; - parameters.add(String8("answer"), String8("6 * 9")); - cdmParameters["answer"] = "6 * 9"; - - static const char* kDefaultUrl = "http://google.com/"; - static const char* kIsoBmffMimeType = "cenc"; - static const char* kWebmMimeType = "webm"; - - struct TestSet { - const char* mimeType; - const Vector& initDataIn; - const CdmInitData& initDataOut; - }; - - // We run the same set of operations on several sets of data, simulating - // different valid calling patterns. - TestSet testSets[] = { - {kIsoBmffMimeType, psshBox, cdmPsshBox}, // ISO-BMFF, EME passing style - {kIsoBmffMimeType, initData, cdmPsshBox}, // ISO-BMFF, old passing style - {kWebmMimeType, initData, cdmInitData} // WebM - }; - size_t testSetCount = sizeof(testSets) / sizeof(TestSet); - - // Set up the expected calls. Per gMock rules, this must be done for all test - // sets prior to testing any of them. - { - InSequence calls; - - for (size_t i = 0; i < testSetCount; ++i) - { - const char* mimeType = testSets[i].mimeType; - const CdmInitData& initData = testSets[i].initDataOut; - - CdmKeyRequest initialRequest = { - cdmRequest, - kKeyRequestTypeInitial, - kDefaultUrl - }; - - CdmKeyRequest renewalRequest = { - cdmRequest, - kKeyRequestTypeRenewal, - kDefaultUrl - }; - - CdmKeyRequest releaseRequest = { - cdmRequest, - kKeyRequestTypeRelease, - kDefaultUrl - }; - - EXPECT_CALL(*cdm, GenerateKeyRequest(cdmSessionId, "", mimeType, initData, - kLicenseTypeOffline, cdmParameters, - NotNull(), HasOrigin(EMPTY_ORIGIN), - _)) - .WillOnce(DoAll(SetArgPointee<8>(initialRequest), - Return(wvcdm::KEY_MESSAGE))); - - EXPECT_CALL(*cdm, GenerateKeyRequest(cdmSessionId, "", mimeType, initData, - kLicenseTypeStreaming, cdmParameters, - NotNull(), HasOrigin(EMPTY_ORIGIN), - _)) - .WillOnce(DoAll(SetArgPointee<8>(renewalRequest), - Return(wvcdm::KEY_MESSAGE))); - - EXPECT_CALL(*cdm, GenerateKeyRequest("", cdmKeySetId, mimeType, initData, - kLicenseTypeRelease, cdmParameters, - NotNull(), HasOrigin(EMPTY_ORIGIN), - _)) - - .WillOnce(DoAll(SetArgPointee<8>(releaseRequest), - Return(wvcdm::KEY_MESSAGE))); - } - } - - // Performs the actual tests - for (size_t i = 0; i < testSetCount; ++i) - { - const String8 mimeType(testSets[i].mimeType); - const Vector& initData = testSets[i].initDataIn; - - Vector request; - String8 defaultUrl; - DrmPlugin::KeyRequestType keyRequestType; - - status_t res = plugin.getKeyRequest(sessionId, initData, mimeType, - DrmPlugin::kKeyType_Offline, - parameters, request, defaultUrl, - &keyRequestType); - ASSERT_EQ(OK, res); - EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize)); - EXPECT_EQ(DrmPlugin::kKeyRequestType_Initial, keyRequestType); - EXPECT_STREQ(kDefaultUrl, defaultUrl.string()); - - res = plugin.getKeyRequest(sessionId, initData, mimeType, - DrmPlugin::kKeyType_Streaming, parameters, - request, defaultUrl, &keyRequestType); - ASSERT_EQ(OK, res); - EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize)); - EXPECT_EQ(DrmPlugin::kKeyRequestType_Renewal, keyRequestType); - EXPECT_STREQ(kDefaultUrl, defaultUrl.string()); - - res = plugin.getKeyRequest(keySetId, initData, mimeType, - DrmPlugin::kKeyType_Release, parameters, - request, defaultUrl, &keyRequestType); - ASSERT_EQ(OK, res); - EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize)); - EXPECT_EQ(DrmPlugin::kKeyRequestType_Release, keyRequestType); - EXPECT_STREQ(kDefaultUrl, defaultUrl.string()); - } -} - -TEST_F(WVDrmPluginTest, AddsKeys) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - static const uint32_t kResponseSize = 256; - uint8_t responseRaw[kResponseSize]; - static const uint32_t kKeySetIdSize = 32; - uint8_t keySetIdRaw[kKeySetIdSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(responseRaw, sizeof(uint8_t), kResponseSize, fp); - fread(keySetIdRaw, sizeof(uint8_t), kKeySetIdSize, fp); - fclose(fp); - - Vector response; - response.appendArray(responseRaw, kResponseSize); - - memcpy(keySetIdRaw, KEY_SET_ID_PREFIX, sizeof(KEY_SET_ID_PREFIX) - 1); - CdmKeySetId cdmKeySetId(reinterpret_cast(keySetIdRaw), kKeySetIdSize); - Vector keySetId; - - Vector emptyKeySetId; - - EXPECT_CALL(*cdm, AddKey(cdmSessionId, - ElementsAreArray(responseRaw, kResponseSize), _)) - .WillOnce(DoAll(SetArgPointee<2>(cdmKeySetId), - Return(wvcdm::KEY_ADDED))); - - EXPECT_CALL(*cdm, AddKey("", ElementsAreArray(responseRaw, kResponseSize), - Pointee(cdmKeySetId))) - .Times(1); - - status_t res = plugin.provideKeyResponse(sessionId, response, keySetId); - ASSERT_EQ(OK, res); - ASSERT_THAT(keySetId, ElementsAreArray(keySetIdRaw, kKeySetIdSize)); - - res = plugin.provideKeyResponse(keySetId, response, emptyKeySetId); - ASSERT_EQ(OK, res); - EXPECT_EQ(0u, emptyKeySetId.size()); -} - -TEST_F(WVDrmPluginTest, HandlesPrivacyCertCaseOfAddKey) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - sp > listener = - new StrictMock(); - - const CdmClientPropertySet* propertySet = NULL; - - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - 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)); - - static const uint32_t kResponseSize = 256; - uint8_t responseRaw[kResponseSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(responseRaw, sizeof(uint8_t), kResponseSize, fp); - fclose(fp); - - Vector response; - response.appendArray(responseRaw, kResponseSize); - Vector keySetId; - - EXPECT_CALL(*listener, sendEvent(DrmPlugin::kDrmPluginEventKeyNeeded, 0, - Pointee(ElementsAreArray(sessionIdRaw, - kSessionIdSize)), - NULL)) - .Times(1); - - EXPECT_CALL(*cdm, AddKey(_, _, _)) - .WillRepeatedly(Return(wvcdm::NEED_KEY)); - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - - status_t res = plugin.setListener(listener); - ASSERT_EQ(OK, res); - - res = plugin.setPropertyString(String8("privacyMode"), String8("enable")); - ASSERT_EQ(OK, res); - EXPECT_TRUE(propertySet->use_privacy_mode()); - - res = plugin.provideKeyResponse(sessionId, response, keySetId); - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, RemovesKeys) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - EXPECT_CALL(*cdm, RemoveKeys(cdmSessionId)) - .Times(1); - - status_t res = plugin.removeKeys(sessionId); - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, RestoresKeys) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - static const size_t kKeySetIdSize = 32; - uint8_t keySetIdRaw[kKeySetIdSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(keySetIdRaw, sizeof(uint8_t), kKeySetIdSize, fp); - fclose(fp); - - Vector keySetId; - keySetId.appendArray(keySetIdRaw, kKeySetIdSize); - - EXPECT_CALL(*cdm, RestoreKey(cdmSessionId, - ElementsAreArray(keySetIdRaw, kKeySetIdSize))) - .Times(1); - - status_t res = plugin.restoreKeys(sessionId, keySetId); - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, QueriesKeyStatus) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - KeyedVector expectedLicenseStatus; - CdmQueryMap cdmLicenseStatus; - - expectedLicenseStatus.add(String8("areTheKeysAllRight"), String8("yes")); - cdmLicenseStatus["areTheKeysAllRight"] = "yes"; - expectedLicenseStatus.add(String8("isGMockAwesome"), String8("ohhhhhhYeah")); - cdmLicenseStatus["isGMockAwesome"] = "ohhhhhhYeah"; - expectedLicenseStatus.add(String8("answer"), String8("42")); - cdmLicenseStatus["answer"] = "42"; - - EXPECT_CALL(*cdm, QueryKeyStatus(cdmSessionId, _)) - .WillOnce(DoAll(SetArgPointee<1>(cdmLicenseStatus), - Return(wvcdm::NO_ERROR))); - - KeyedVector licenseStatus; - - status_t res = plugin.queryKeyStatus(sessionId, licenseStatus); - - ASSERT_EQ(OK, res); - - ASSERT_EQ(expectedLicenseStatus.size(), licenseStatus.size()); - for (size_t i = 0; i < expectedLicenseStatus.size(); ++i) { - const String8& key = expectedLicenseStatus.keyAt(i); - EXPECT_NE(android::NAME_NOT_FOUND, licenseStatus.indexOfKey(key)); - EXPECT_EQ(expectedLicenseStatus.valueFor(key), licenseStatus.valueFor(key)); - } -} - -TEST_F(WVDrmPluginTest, GetsProvisioningRequests) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - static const uint32_t kRequestSize = 256; - uint8_t requestRaw[kRequestSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(requestRaw, sizeof(uint8_t), kRequestSize, fp); - fclose(fp); - - CdmProvisioningRequest cdmRequest(requestRaw, requestRaw + kRequestSize); - - static const char* kDefaultUrl = "http://google.com/"; - - EXPECT_CALL(*cdm, GetProvisioningRequest(kCertificateWidevine, IsEmpty(), - HasOrigin(EMPTY_ORIGIN), IsEmpty(), - wvcdm::kLevelDefault, _, _)) - .WillOnce(DoAll(SetArgPointee<5>(cdmRequest), - SetArgPointee<6>(kDefaultUrl), - Return(wvcdm::NO_ERROR))); - - Vector request; - String8 defaultUrl; - - status_t res = plugin.getProvisionRequest(String8(""), String8(""), request, - defaultUrl); - - ASSERT_EQ(OK, res); - EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize)); - EXPECT_STREQ(kDefaultUrl, defaultUrl.string()); -} - -TEST_F(WVDrmPluginTest, HandlesProvisioningResponses) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - static const uint32_t kResponseSize = 512; - uint8_t responseRaw[kResponseSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(responseRaw, sizeof(uint8_t), kResponseSize, fp); - fclose(fp); - - Vector response; - response.appendArray(responseRaw, kResponseSize); - - EXPECT_CALL(*cdm, HandleProvisioningResponse(HasOrigin(EMPTY_ORIGIN), - ElementsAreArray(responseRaw, - kResponseSize), - wvcdm::kLevelDefault, _, _)) - .Times(1); - - Vector cert; - Vector key; - - status_t res = plugin.provideProvisionResponse(response, cert, key); - - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, UnprovisionsDevice) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL1, HasOrigin(EMPTY_ORIGIN))) - .Times(1); - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL3, HasOrigin(EMPTY_ORIGIN))) - .Times(1); - - status_t res = plugin.unprovisionDevice(); - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, MuxesUnprovisioningErrors) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - // Tests that both Unprovisions are called even if one fails. Also tests that - // no matter which fails, the function always propagates the error. - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL1, HasOrigin(EMPTY_ORIGIN))) - .WillOnce(Return(wvcdm::UNKNOWN_ERROR)) - .WillOnce(Return(wvcdm::NO_ERROR)) - .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL3, HasOrigin(EMPTY_ORIGIN))) - .WillOnce(Return(wvcdm::NO_ERROR)) - .WillOnce(Return(wvcdm::UNKNOWN_ERROR)) - .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); - - status_t res = plugin.unprovisionDevice(); - ASSERT_NE(OK, res); - res = plugin.unprovisionDevice(); - ASSERT_NE(OK, res); - res = plugin.unprovisionDevice(); - ASSERT_NE(OK, res); -} - -TEST_F(WVDrmPluginTest, UnprovisionsOrigin) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - Vector cert; - Vector key; - Vector specialResponse; - specialResponse.appendArray(kUnprovisionResponse, kUnprovisionResponseSize); - - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL1, HasOrigin(kOrigin.string()))) - .Times(1); - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL3, HasOrigin(kOrigin.string()))) - .Times(1); - - status_t res = plugin.setPropertyString(String8("origin"), kOrigin); - ASSERT_EQ(OK, res); - res = plugin.provideProvisionResponse(specialResponse, cert, key); - EXPECT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, WillNotUnprovisionWithoutOrigin) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - Vector cert; - Vector key; - Vector specialResponse; - specialResponse.appendArray(kUnprovisionResponse, kUnprovisionResponseSize); - - EXPECT_CALL(*cdm, Unprovision(_, _)) - .Times(0); - - status_t res = plugin.provideProvisionResponse(specialResponse, cert, key); - EXPECT_NE(OK, res); -} - -TEST_F(WVDrmPluginTest, MuxesOriginUnprovisioningErrors) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - Vector cert; - Vector key; - Vector specialResponse; - specialResponse.appendArray(kUnprovisionResponse, kUnprovisionResponseSize); - - // Tests that both Unprovisions are called even if one fails. Also tests that - // no matter which fails, the function always propagates the error. - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL1, HasOrigin(kOrigin.string()))) - .WillOnce(Return(wvcdm::UNKNOWN_ERROR)) - .WillOnce(Return(wvcdm::NO_ERROR)) - .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL3, HasOrigin(kOrigin.string()))) - .WillOnce(Return(wvcdm::NO_ERROR)) - .WillOnce(Return(wvcdm::UNKNOWN_ERROR)) - .WillOnce(Return(wvcdm::UNKNOWN_ERROR)); - - status_t res = plugin.setPropertyString(String8("origin"), kOrigin); - ASSERT_EQ(OK, res); - res = plugin.provideProvisionResponse(specialResponse, cert, key); - EXPECT_NE(OK, res); - res = plugin.provideProvisionResponse(specialResponse, cert, key); - EXPECT_NE(OK, res); - res = plugin.provideProvisionResponse(specialResponse, cert, key); - EXPECT_NE(OK, res); -} - -TEST_F(WVDrmPluginTest, GetsSecureStops) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - const char* app_id = "my_app_id"; - plugin.setPropertyString(String8("appId"), String8(app_id)); - - static const uint32_t kStopSize = 53; - static const uint32_t kStopCount = 7; - uint8_t stopsRaw[kStopCount][kStopSize]; - FILE* fp = fopen("/dev/urandom", "r"); - for (uint32_t i = 0; i < kStopCount; ++i) { - fread(stopsRaw[i], sizeof(uint8_t), kStopSize, fp); - } - fclose(fp); - - CdmUsageInfo cdmStops; - for (uint32_t i = 0; i < kStopCount; ++i) { - cdmStops.push_back(string(stopsRaw[i], stopsRaw[i] + kStopSize)); - } - - EXPECT_CALL(*cdm, GetUsageInfo(StrEq(app_id), _, _)) - .WillOnce(DoAll(SetArgPointee<2>(cdmStops), - Return(wvcdm::NO_ERROR))); - - List > stops; - - status_t res = plugin.getSecureStops(stops); - - ASSERT_EQ(OK, res); - - List >::iterator iter = stops.begin(); - uint32_t rawIter = 0; - while (rawIter < kStopCount && iter != stops.end()) { - EXPECT_THAT(*iter, ElementsAreArray(stopsRaw[rawIter], kStopSize)); - - ++iter; - ++rawIter; - } - // Assert that both lists are the same length - EXPECT_EQ(kStopCount, rawIter); - EXPECT_EQ(stops.end(), iter); -} - -TEST_F(WVDrmPluginTest, ReleasesAllSecureStops) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - status_t res = plugin.setPropertyString(String8("appId"), String8("")); - ASSERT_EQ(OK, res); - - EXPECT_CALL(*cdm, RemoveAllUsageInfo(StrEq(""), _)) - .Times(1); - - res = plugin.releaseAllSecureStops(); - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, ReleasesSecureStops) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - static const uint32_t kMessageSize = 128; - uint8_t messageRaw[kMessageSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(messageRaw, sizeof(uint8_t), kMessageSize, fp); - fclose(fp); - - Vector message; - message.appendArray(messageRaw, kMessageSize); - - EXPECT_CALL(*cdm, ReleaseUsageInfo(ElementsAreArray(messageRaw, - kMessageSize), - _)) - .Times(1); - - status_t res = plugin.releaseSecureStops(message); - - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - CdmQueryMap l1Map; - l1Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1; - - CdmQueryMap l3Map; - l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3; - - static const string uniqueId = "The Universe"; - static const string systemId = "42"; - static const string provisioningId("Life\0&Everything", 16); - static const string openSessions = "15"; - static const string maxSessions = "18"; - static const string oemCryptoApiVersion = "10"; - static const string currentSRMVersion = "1"; - static const string cdmVersion = "Infinity Minus 1"; - - drm_metrics::WvCdmMetrics expected_metrics; - std::string serialized_metrics = wvcdm::a2bs_hex(kSerializedMetricsHex); - ASSERT_TRUE(expected_metrics.ParseFromString(serialized_metrics)); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), - Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L3), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DEVICE_ID, _)) - .WillOnce(DoAll(SetArgPointee<2>(uniqueId), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SYSTEM_ID, _)) - .WillOnce(DoAll(SetArgPointee<2>(systemId), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_PROVISIONING_ID, _)) - .WillOnce(DoAll(SetArgPointee<2>(provisioningId), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_NUMBER_OF_OPEN_SESSIONS, _)) - .WillOnce(DoAll(SetArgPointee<2>(openSessions), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_MAX_NUMBER_OF_SESSIONS, _)) - .WillOnce(DoAll(SetArgPointee<2>(maxSessions), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_OEMCRYPTO_API_VERSION, _)) - .WillOnce(DoAll(SetArgPointee<2>(oemCryptoApiVersion), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SRM_UPDATE_SUPPORT, _)) - .WillOnce(DoAll(SetArgPointee<2>("True"), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_CURRENT_SRM_VERSION, _)) - .WillOnce(DoAll(SetArgPointee<2>(currentSRMVersion), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_WVCDM_VERSION, _)) - .WillOnce(DoAll(SetArgPointee<2>(cdmVersion), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, GetMetrics(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(expected_metrics), - testing::Return(wvcdm::NO_ERROR))); - - String8 stringResult; - Vector vectorResult; - - status_t res = plugin.getPropertyString(String8("vendor"), stringResult); - ASSERT_EQ(OK, res); - EXPECT_STREQ("Google", stringResult.string()); - - res = plugin.getPropertyString(String8("version"), stringResult); - ASSERT_EQ(OK, res); - EXPECT_STREQ(cdmVersion.c_str(), stringResult.string()); - - res = plugin.getPropertyString(String8("description"), stringResult); - ASSERT_EQ(OK, res); - EXPECT_STREQ("Widevine CDM", stringResult.string()); - - res = plugin.getPropertyString(String8("algorithms"), stringResult); - ASSERT_EQ(OK, res); - EXPECT_STREQ("AES/CBC/NoPadding,HmacSHA256", stringResult.string()); - - res = plugin.getPropertyString(String8("securityLevel"), stringResult); - ASSERT_EQ(OK, res); - EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L1.c_str(), stringResult.string()); - - res = plugin.getPropertyString(String8("securityLevel"), stringResult); - ASSERT_EQ(OK, res); - EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L3.c_str(), stringResult.string()); - - res = plugin.getPropertyByteArray(String8("deviceUniqueId"), vectorResult); - ASSERT_EQ(OK, res); - EXPECT_THAT(vectorResult, ElementsAreArray(uniqueId.data(), uniqueId.size())); - - res = plugin.getPropertyString(String8("systemId"), stringResult); - ASSERT_EQ(OK, res); - EXPECT_STREQ(systemId.c_str(), stringResult.string()); - - res = plugin.getPropertyByteArray(String8("provisioningUniqueId"), vectorResult); - ASSERT_EQ(OK, res); - EXPECT_THAT(vectorResult, ElementsAreArray(provisioningId.data(), - provisioningId.size())); - - res = plugin.getPropertyString(String8("numberOfOpenSessions"), stringResult); - ASSERT_EQ(OK, res); - EXPECT_EQ(openSessions, stringResult.string()); - - res = plugin.getPropertyString(String8("maxNumberOfSessions"), stringResult); - ASSERT_EQ(OK, res); - EXPECT_EQ(maxSessions, stringResult.string()); - - res = plugin.getPropertyString(String8("oemCryptoApiVersion"), stringResult); - ASSERT_EQ(OK, res); - - EXPECT_STREQ(oemCryptoApiVersion.c_str(), stringResult.string()); - - res = plugin.getPropertyString(String8("SRMUpdateSupport"), stringResult); - ASSERT_EQ(OK, res); - EXPECT_STREQ("True", stringResult.string()); - - res = plugin.getPropertyString(String8("CurrentSRMVersion"), stringResult); - ASSERT_EQ(OK, res); - EXPECT_STREQ(currentSRMVersion.c_str(), stringResult.string()); - - vectorResult.clear(); - res = plugin.getPropertyByteArray(String8("metrics"), vectorResult); - ASSERT_EQ(OK, res); - EXPECT_THAT(vectorResult, ElementsAreArray(serialized_metrics.data(), - serialized_metrics.size())); -} - -TEST_F(WVDrmPluginTest, DoesNotGetUnknownProperties) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - String8 stringResult; - Vector vectorResult; - - status_t res = plugin.getPropertyString(String8("unknownProperty"), - stringResult); - ASSERT_NE(OK, res); - EXPECT_TRUE(stringResult.isEmpty()); - - res = plugin.getPropertyByteArray(String8("unknownProperty"), - vectorResult); - ASSERT_NE(OK, res); - EXPECT_TRUE(vectorResult.isEmpty()); -} - -TEST_F(WVDrmPluginTest, DoesNotSetUnknownProperties) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - static const uint32_t kValueSize = 32; - uint8_t valueRaw[kValueSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(valueRaw, sizeof(uint8_t), kValueSize, fp); - fclose(fp); - - Vector value; - value.appendArray(valueRaw, kValueSize); - - status_t res = plugin.setPropertyString(String8("unknownProperty"), - String8("ignored")); - ASSERT_NE(OK, res); - - res = plugin.setPropertyByteArray(String8("unknownProperty"), value); - ASSERT_NE(OK, res); -} - -TEST_F(WVDrmPluginTest, FailsGenericMethodsWithoutAnAlgorithmSet) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - Vector keyId; - Vector input; - Vector iv; - Vector output; - bool match; - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)) - .Times(AtLeast(0)); - - status_t res = plugin.openSession(sessionId); - ASSERT_EQ(OK, res); - - // Note that we do not set the algorithms. This should cause these methods - // to fail. - - res = plugin.encrypt(sessionId, keyId, input, iv, output); - EXPECT_EQ(NO_INIT, res); - - res = plugin.decrypt(sessionId, keyId, input, iv, output); - EXPECT_EQ(NO_INIT, res); - - res = plugin.sign(sessionId, keyId, input, output); - EXPECT_EQ(NO_INIT, res); - - res = plugin.verify(sessionId, keyId, input, output, match); - EXPECT_EQ(NO_INIT, res); -} - -MATCHER_P(IsIV, iv, "") { - for (size_t i = 0; i < KEY_IV_SIZE; ++i) { - if (iv[i] != arg[i]) { - return false; - } - } - - return true; -} - -TEST_F(WVDrmPluginTest, CallsGenericEncrypt) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - static const size_t kDataSize = 256; - uint8_t keyIdRaw[KEY_ID_SIZE]; - uint8_t inputRaw[kDataSize]; - uint8_t ivRaw[KEY_IV_SIZE]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyIdRaw, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(inputRaw, sizeof(uint8_t), kDataSize, fp); - fread(ivRaw, sizeof(uint8_t), KEY_IV_SIZE, fp); - fclose(fp); - - Vector keyId; - keyId.appendArray(keyIdRaw, KEY_ID_SIZE); - Vector input; - input.appendArray(inputRaw, kDataSize); - Vector iv; - iv.appendArray(ivRaw, KEY_IV_SIZE); - Vector output; - - { - InSequence calls; - - EXPECT_CALL(crypto, selectKey(4, _, KEY_ID_SIZE)) - .With(Args<1, 2>(ElementsAreArray(keyIdRaw, KEY_ID_SIZE))) - .Times(1); - - EXPECT_CALL(crypto, encrypt(4, _, kDataSize, IsIV(ivRaw), - OEMCrypto_AES_CBC_128_NO_PADDING, _)) - .With(Args<1, 2>(ElementsAreArray(inputRaw, kDataSize))) - .Times(1); - } - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)) - .Times(AtLeast(0)); - - status_t res = plugin.openSession(sessionId); - ASSERT_EQ(OK, res); - - res = plugin.setCipherAlgorithm(sessionId, String8("AES/CBC/NoPadding")); - ASSERT_EQ(OK, res); - - res = plugin.encrypt(sessionId, keyId, input, iv, output); - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, CallsGenericDecrypt) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - static const size_t kDataSize = 256; - uint8_t keyIdRaw[KEY_ID_SIZE]; - uint8_t inputRaw[kDataSize]; - uint8_t ivRaw[KEY_IV_SIZE]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyIdRaw, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(inputRaw, sizeof(uint8_t), kDataSize, fp); - fread(ivRaw, sizeof(uint8_t), KEY_IV_SIZE, fp); - fclose(fp); - - Vector keyId; - keyId.appendArray(keyIdRaw, KEY_ID_SIZE); - Vector input; - input.appendArray(inputRaw, kDataSize); - Vector iv; - iv.appendArray(ivRaw, KEY_IV_SIZE); - Vector output; - - { - InSequence calls; - - EXPECT_CALL(crypto, selectKey(4, _, KEY_ID_SIZE)) - .With(Args<1, 2>(ElementsAreArray(keyIdRaw, KEY_ID_SIZE))) - .Times(1); - - EXPECT_CALL(crypto, decrypt(4, _, kDataSize, IsIV(ivRaw), - OEMCrypto_AES_CBC_128_NO_PADDING, _)) - .With(Args<1, 2>(ElementsAreArray(inputRaw, kDataSize))) - .Times(1); - } - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)) - .Times(AtLeast(0)); - - status_t res = plugin.openSession(sessionId); - ASSERT_EQ(OK, res); - - res = plugin.setCipherAlgorithm(sessionId, String8("AES/CBC/NoPadding")); - ASSERT_EQ(OK, res); - - res = plugin.decrypt(sessionId, keyId, input, iv, output); - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, CallsGenericSign) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - static const size_t kDataSize = 256; - uint8_t keyIdRaw[KEY_ID_SIZE]; - uint8_t messageRaw[kDataSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyIdRaw, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(messageRaw, sizeof(uint8_t), kDataSize, fp); - fclose(fp); - - Vector keyId; - keyId.appendArray(keyIdRaw, KEY_ID_SIZE); - Vector message; - message.appendArray(messageRaw, kDataSize); - Vector signature; - - { - InSequence calls; - - EXPECT_CALL(crypto, selectKey(4, _, KEY_ID_SIZE)) - .With(Args<1, 2>(ElementsAreArray(keyIdRaw, KEY_ID_SIZE))) - .Times(1); - - EXPECT_CALL(crypto, sign(4, _, kDataSize, OEMCrypto_HMAC_SHA256, _, - Pointee(0))) - .With(Args<1, 2>(ElementsAreArray(messageRaw, kDataSize))) - .WillOnce(DoAll(SetArgPointee<5>(64), - Return(OEMCrypto_ERROR_SHORT_BUFFER))); - - EXPECT_CALL(crypto, sign(4, _, kDataSize, OEMCrypto_HMAC_SHA256, _, - Pointee(64))) - .With(Args<1, 2>(ElementsAreArray(messageRaw, kDataSize))) - .Times(1); - } - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)) - .Times(AtLeast(0)); - - status_t res = plugin.openSession(sessionId); - ASSERT_EQ(OK, res); - - res = plugin.setMacAlgorithm(sessionId, String8("HmacSHA256")); - ASSERT_EQ(OK, res); - - res = plugin.sign(sessionId, keyId, message, signature); - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, CallsGenericVerify) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - static const size_t kDataSize = 256; - static const size_t kSignatureSize = 16; - uint8_t keyIdRaw[KEY_ID_SIZE]; - uint8_t messageRaw[kDataSize]; - uint8_t signatureRaw[kSignatureSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyIdRaw, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(messageRaw, sizeof(uint8_t), kDataSize, fp); - fread(signatureRaw, sizeof(uint8_t), kSignatureSize, fp); - fclose(fp); - - Vector keyId; - keyId.appendArray(keyIdRaw, KEY_ID_SIZE); - Vector message; - message.appendArray(messageRaw, kDataSize); - Vector signature; - signature.appendArray(signatureRaw, kSignatureSize); - bool match; - - { - InSequence calls; - - EXPECT_CALL(crypto, selectKey(4, _, KEY_ID_SIZE)) - .With(Args<1, 2>(ElementsAreArray(keyIdRaw, KEY_ID_SIZE))) - .Times(1); - - EXPECT_CALL(crypto, verify(4, _, kDataSize, OEMCrypto_HMAC_SHA256, _, - kSignatureSize)) - .With(AllOf(Args<1, 2>(ElementsAreArray(messageRaw, kDataSize)), - Args<4, 5>(ElementsAreArray(signatureRaw, kSignatureSize)))) - .WillOnce(Return(OEMCrypto_SUCCESS)); - - EXPECT_CALL(crypto, selectKey(4, _, KEY_ID_SIZE)) - .With(Args<1, 2>(ElementsAreArray(keyIdRaw, KEY_ID_SIZE))) - .Times(1); - - EXPECT_CALL(crypto, verify(4, _, kDataSize, OEMCrypto_HMAC_SHA256, _, - kSignatureSize)) - .With(AllOf(Args<1, 2>(ElementsAreArray(messageRaw, kDataSize)), - Args<4, 5>(ElementsAreArray(signatureRaw, kSignatureSize)))) - .WillOnce(Return(OEMCrypto_ERROR_SIGNATURE_FAILURE)); - } - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)) - .Times(AtLeast(0)); - - status_t res = plugin.openSession(sessionId); - ASSERT_EQ(OK, res); - - res = plugin.setMacAlgorithm(sessionId, String8("HmacSHA256")); - ASSERT_EQ(OK, res); - - res = plugin.verify(sessionId, keyId, message, signature, match); - ASSERT_EQ(OK, res); - EXPECT_TRUE(match); - - res = plugin.verify(sessionId, keyId, message, signature, match); - ASSERT_EQ(OK, res); - EXPECT_FALSE(match); -} - -TEST_F(WVDrmPluginTest, RegistersForEvents) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, &plugin, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)) - .Times(AtLeast(0)); - - status_t res = plugin.openSession(sessionId); - ASSERT_EQ(OK, res); -} - -TEST_F(WVDrmPluginTest, UnregistersForAllEventsOnDestruction) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - - { - WVDrmPlugin plugin(cdm.get(), &crypto); - - uint8_t sessionIdRaw1[kSessionIdSize]; - uint8_t sessionIdRaw2[kSessionIdSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(sessionIdRaw1, sizeof(uint8_t), kSessionIdSize, fp); - fread(sessionIdRaw2, sizeof(uint8_t), kSessionIdSize, fp); - fclose(fp); - - CdmSessionId cdmSessionId1(sessionIdRaw1, sessionIdRaw1 + kSessionIdSize); - CdmSessionId cdmSessionId2(sessionIdRaw2, sessionIdRaw2 + kSessionIdSize); - - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId1), - Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId2), - Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId1, _)) - .WillOnce(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId2, _)) - .WillOnce(Invoke(setSessionIdOnMap<5>)); - - EXPECT_CALL(*cdm, CloseSession(_)) - .Times(AtLeast(0)); - - status_t res = plugin.openSession(sessionId); - ASSERT_EQ(OK, res); - - res = plugin.openSession(sessionId); - ASSERT_EQ(OK, res); - } -} - -TEST_F(WVDrmPluginTest, MarshalsEvents) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - sp > listener = - new StrictMock(); - - const int64_t kExpiryTimeInSeconds = 123456789012LL; - const char kKeyId1[] = "Testing Key1 Id "; - const char kKeyId2[] = "Testing Key2 Id "; - const char kKeyId3[] = "Testing Key3 Id "; - const char kKeyId4[] = "Testing Key4 Id "; - const char kKeyId5[] = "Testing Key5 Id "; - - { - InSequence calls; - - EXPECT_CALL(*listener, - sendKeysChange( - Pointee(ElementsAreArray(sessionIdRaw, kSessionIdSize)), - Pointee(UnorderedElementsAre(AllOf( - Field(&DrmPlugin::KeyStatus::mKeyId, - ElementsAreArray(kKeyId1, sizeof(kKeyId1) - 1)), - Field(&DrmPlugin::KeyStatus::mType, - DrmPlugin::kKeyStatusType_Expired)))), - false)); - EXPECT_CALL( - *listener, - sendEvent(DrmPlugin::kDrmPluginEventKeyExpired, 0, - Pointee(ElementsAreArray(sessionIdRaw, kSessionIdSize)), - NULL)); - EXPECT_CALL( - *listener, - sendEvent(DrmPlugin::kDrmPluginEventKeyNeeded, 0, - Pointee(ElementsAreArray(sessionIdRaw, kSessionIdSize)), - NULL)); - // Expiry Time in Java API is in milliseconds. - EXPECT_CALL(*listener, - sendExpirationUpdate( - Pointee(ElementsAreArray(sessionIdRaw, kSessionIdSize)), - NEVER_EXPIRES)); - EXPECT_CALL(*listener, - sendExpirationUpdate( - Pointee(ElementsAreArray(sessionIdRaw, kSessionIdSize)), - kExpiryTimeInSeconds * 1000)); - EXPECT_CALL( - *listener, - sendKeysChange( - Pointee(ElementsAreArray(sessionIdRaw, kSessionIdSize)), - Pointee(UnorderedElementsAre( - AllOf(Field(&DrmPlugin::KeyStatus::mKeyId, - ElementsAreArray(kKeyId1, sizeof(kKeyId1) - 1)), - Field(&DrmPlugin::KeyStatus::mType, - DrmPlugin::kKeyStatusType_Usable)), - AllOf(Field(&DrmPlugin::KeyStatus::mKeyId, - ElementsAreArray(kKeyId2, sizeof(kKeyId2) - 1)), - Field(&DrmPlugin::KeyStatus::mType, - DrmPlugin::kKeyStatusType_OutputNotAllowed)), - AllOf(Field(&DrmPlugin::KeyStatus::mKeyId, - ElementsAreArray(kKeyId3, sizeof(kKeyId3) - 1)), - Field(&DrmPlugin::KeyStatus::mType, - DrmPlugin::kKeyStatusType_InternalError)), - AllOf(Field(&DrmPlugin::KeyStatus::mKeyId, - ElementsAreArray(kKeyId4, sizeof(kKeyId4) - 1)), - Field(&DrmPlugin::KeyStatus::mType, - DrmPlugin::kKeyStatusType_StatusPending)), - AllOf(Field(&DrmPlugin::KeyStatus::mKeyId, - ElementsAreArray(kKeyId5, sizeof(kKeyId5) - 1)), - Field(&DrmPlugin::KeyStatus::mType, - DrmPlugin::kKeyStatusType_UsableInFuture)))), - true)); - } - - status_t res = plugin.setListener(listener); - ASSERT_EQ(OK, res); - - CdmKeyStatusMap cdmKeysStatus; - cdmKeysStatus[kKeyId1] = kKeyStatusExpired; - plugin.OnSessionKeysChange(cdmSessionId, cdmKeysStatus, false); - - plugin.OnSessionRenewalNeeded(cdmSessionId); - plugin.OnExpirationUpdate(cdmSessionId, NEVER_EXPIRES); - plugin.OnExpirationUpdate(cdmSessionId, kExpiryTimeInSeconds); - - cdmKeysStatus[kKeyId1] = kKeyStatusUsable; - cdmKeysStatus[kKeyId2] = kKeyStatusOutputNotAllowed; - cdmKeysStatus[kKeyId3] = kKeyStatusInternalError; - cdmKeysStatus[kKeyId4] = kKeyStatusPending; - cdmKeysStatus[kKeyId5] = kKeyStatusUsableInFuture; - plugin.OnSessionKeysChange(cdmSessionId, cdmKeysStatus, true); -} - -TEST_F(WVDrmPluginTest, GeneratesProvisioningNeededEvent) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - sp > listener = - new StrictMock(); - - EXPECT_CALL(*listener, sendEvent(DrmPlugin::kDrmPluginEventProvisionRequired, 0, - Pointee(ElementsAreArray(sessionIdRaw, - kSessionIdSize)), - NULL)) - .Times(1); - - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - Return(wvcdm::NEED_PROVISIONING))); - - EXPECT_CALL(*cdm, CloseSession(_)) - .Times(AtLeast(0)); - - status_t res = plugin.setListener(listener); - ASSERT_EQ(OK, res); - - res = plugin.openSession(sessionId); - ASSERT_EQ(ERROR_DRM_NOT_PROVISIONED, res); -} - -TEST_F(WVDrmPluginTest, ProvidesExpectedDefaultPropertiesToCdm) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - const CdmClientPropertySet* propertySet = NULL; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - 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)); - } - - plugin.openSession(sessionId); - - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("", propertySet->security_level().c_str()); - EXPECT_FALSE(propertySet->use_privacy_mode()); - EXPECT_EQ(0u, propertySet->service_certificate().size()); - EXPECT_FALSE(propertySet->is_session_sharing_enabled()); - EXPECT_EQ(0u, propertySet->session_sharing_id()); - EXPECT_STREQ("", propertySet->app_id().c_str()); -} - -TEST_F(WVDrmPluginTest, CanSetAppId) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - const CdmClientPropertySet* propertySet = NULL; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin queries for the security level - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) - .WillRepeatedly(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L3), - 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)); - } - - status_t res; - - // Test setting an empty string - res = plugin.setPropertyString(String8("appId"), String8("")); - ASSERT_EQ(OK, res); - - // Test setting an application id before a session is opened. - res = plugin.setPropertyString(String8("appId"), kAppId); - ASSERT_EQ(OK, res); - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - - // Verify application id is set correctly. - EXPECT_STREQ(kAppId, propertySet->app_id().c_str()); - - // Test setting application id while session is opened, this should fail. - res = plugin.setPropertyString(String8("appId"), kAppId); - ASSERT_EQ(kErrorSessionIsOpen, res); -} - -TEST_P(WVDrmPluginOriginTest, CanSetOrigin) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - OriginTestVariant params = GetParam(); - - // Provide expected mock behavior - { - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - // Provide expected behavior when plugin closes a session - EXPECT_CALL(*cdm, CloseSession(_)) - .Times(AtLeast(0)); - } - - // Note which mock calls we expect - EXPECT_CALL(*cdm, OpenSession(_, _, HasOrigin(params.expectedOrigin), _, _)) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), - Return(wvcdm::NO_ERROR))); - - // Set the properties & run the test - if (!params.origin.isEmpty()) { - ASSERT_EQ(OK, plugin.setPropertyString(String8("origin"), params.origin)); - } - EXPECT_EQ(OK, plugin.openSession(sessionId)); - // Test setting an origin while sessions are opened. This should fail. - EXPECT_NE(OK, plugin.setPropertyString(String8("origin"), kOrigin)); - EXPECT_EQ(OK, plugin.closeSession(sessionId)); -} - -INSTANTIATE_TEST_CASE_P(OriginTests, WVDrmPluginOriginTest, Values( - OriginTestVariant("No Origin", kEmptyString, EMPTY_ORIGIN), - OriginTestVariant("With an Origin", kOrigin, kOrigin.string()))); - -TEST_F(WVDrmPluginTest, CanSetSecurityLevel) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - const CdmClientPropertySet* propertySet = NULL; - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L3), - Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), - Return(wvcdm::NO_ERROR))); - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - 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)); - } - - status_t res; - - // Test forcing L3 - res = plugin.setPropertyString(String8("securityLevel"), String8("L3")); - ASSERT_EQ(OK, res); - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("L3", propertySet->security_level().c_str()); - plugin.closeSession(sessionId); - - // Test returning to L1 on an L3 device (Should Fail) - res = plugin.setPropertyString(String8("securityLevel"), String8("L1")); - ASSERT_NE(OK, res); - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("L3", propertySet->security_level().c_str()); - plugin.closeSession(sessionId); - - // Test returning to L1 on an L1 device - res = plugin.setPropertyString(String8("securityLevel"), String8("L1")); - ASSERT_EQ(OK, res); - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("", propertySet->security_level().c_str()); - plugin.closeSession(sessionId); - - // Test un-forcing a level (first forcing to L3 so we have something to reset) - res = plugin.setPropertyString(String8("securityLevel"), String8("L3")); - ASSERT_EQ(OK, res); - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("L3", propertySet->security_level().c_str()); - plugin.closeSession(sessionId); - - res = plugin.setPropertyString(String8("securityLevel"), String8("")); - ASSERT_EQ(OK, res); - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("", propertySet->security_level().c_str()); - plugin.closeSession(sessionId); - - // Test nonsense (Should Fail) - res = plugin.setPropertyString(String8("securityLevel"), String8("nonsense")); - ASSERT_NE(OK, res); - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("", propertySet->security_level().c_str()); - plugin.closeSession(sessionId); - - // Test attempting to force a level with a session open (Should Fail) - plugin.openSession(sessionId); - res = plugin.setPropertyString(String8("securityLevel"), String8("L3")); - ASSERT_NE(OK, res); -} - -TEST_F(WVDrmPluginTest, CanSetPrivacyMode) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - const CdmClientPropertySet* propertySet = NULL; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - 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)); - } - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - - status_t res; - - // Test turning on privacy mode - res = plugin.setPropertyString(String8("privacyMode"), String8("enable")); - ASSERT_EQ(OK, res); - EXPECT_TRUE(propertySet->use_privacy_mode()); - - // Test turning off privacy mode - res = plugin.setPropertyString(String8("privacyMode"), String8("disable")); - ASSERT_EQ(OK, res); - EXPECT_FALSE(propertySet->use_privacy_mode()); - - // Test nonsense (Should Fail) - res = plugin.setPropertyString(String8("privacyMode"), String8("nonsense")); - ASSERT_NE(OK, res); -} - -TEST_F(WVDrmPluginTest, CanSetServiceCertificate) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - const CdmClientPropertySet* propertySet = NULL; - - static const size_t kPrivacyCertSize = 256; - uint8_t privacyCertRaw[kPrivacyCertSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(privacyCertRaw, sizeof(uint8_t), kPrivacyCertSize, fp); - fclose(fp); - - Vector privacyCert; - privacyCert.appendArray(privacyCertRaw, kPrivacyCertSize); - std::string strPrivacyCert(reinterpret_cast(privacyCertRaw), - kPrivacyCertSize); - Vector emptyVector; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - 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)); - } - - // Validate that the certificate is validated. Accept it once and reject it - // once. Note that there is no expected call for when the certificate is - // cleared. - EXPECT_CALL(*cdm, IsValidServiceCertificate(strPrivacyCert)) - .WillOnce(Return(true)) - .WillOnce(Return(false)); - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - - status_t res; - - // Test setting a certificate - res = plugin.setPropertyByteArray(String8("serviceCertificate"), privacyCert); - ASSERT_EQ(OK, res); - EXPECT_THAT(propertySet->service_certificate(), - ElementsAreArray(privacyCertRaw, kPrivacyCertSize)); - - // Test clearing a certificate - res = plugin.setPropertyByteArray(String8("serviceCertificate"), emptyVector); - ASSERT_EQ(OK, res); - EXPECT_EQ(0u, propertySet->service_certificate().size()); - - // Test setting a certificate and having it fail - res = plugin.setPropertyByteArray(String8("serviceCertificate"), privacyCert); - ASSERT_NE(OK, res); - EXPECT_EQ(0u, propertySet->service_certificate().size()); -} - -TEST_F(WVDrmPluginTest, CanSetSessionSharing) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - const CdmClientPropertySet* propertySet = NULL; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - 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)); - } - - status_t res; - - // Test turning on session sharing - res = plugin.setPropertyString(String8("sessionSharing"), String8("enable")); - ASSERT_EQ(OK, res); - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_TRUE(propertySet->is_session_sharing_enabled()); - plugin.closeSession(sessionId); - - // Test turning off session sharing - res = plugin.setPropertyString(String8("sessionSharing"), String8("disable")); - ASSERT_EQ(OK, res); - - plugin.openSession(sessionId); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_FALSE(propertySet->is_session_sharing_enabled()); - plugin.closeSession(sessionId); - - // Test nonsense (Should Fail) - res = plugin.setPropertyString(String8("sessionSharing"), String8("nonsense")); - ASSERT_NE(OK, res); - - // Test changing sharing with a session open (Should Fail) - plugin.openSession(sessionId); - res = plugin.setPropertyString(String8("sessionSharing"), String8("enable")); - ASSERT_NE(OK, res); -} - -TEST_F(WVDrmPluginTest, AllowsStoringOfSessionSharingId) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - WVDrmPlugin plugin(cdm.get(), &crypto); - - CdmClientPropertySet* propertySet = NULL; - - uint32_t sharingId; - FILE* fp = fopen("/dev/urandom", "r"); - fread(&sharingId, sizeof(uint32_t), 1, fp); - fclose(fp); - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - 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)); - } - - plugin.openSession(sessionId); - - ASSERT_THAT(propertySet, NotNull()); - propertySet->set_session_sharing_id(sharingId); - EXPECT_EQ(sharingId, propertySet->session_sharing_id()); -} diff --git a/libwvdrmengine/run_all_unit_tests.sh b/libwvdrmengine/run_all_unit_tests.sh index 3ac58a99..6cb4cd9c 100755 --- a/libwvdrmengine/run_all_unit_tests.sh +++ b/libwvdrmengine/run_all_unit_tests.sh @@ -112,9 +112,7 @@ adb_shell_run hidl_metrics_adapter_unittest adb_shell_run http_socket_test adb_shell_run initialization_data_unittest adb_shell_run libwvdrmdrmplugin_hidl_test -adb_shell_run libwvdrmdrmplugin_test adb_shell_run libwvdrmmediacrypto_hidl_test -adb_shell_run libwvdrmmediacrypto_test adb_shell_run license_keys_unittest adb_shell_run license_unittest adb_shell_run odk_test @@ -130,13 +128,6 @@ adb_shell_run usage_table_header_unittest adb_shell_run value_metric_unittest adb_shell_run wv_cdm_metrics_test -# Run the non-Treble test on non-Treble devices -if adb $SERIAL_NUM shell ls /vendor/lib/mediadrm/libwvdrmengine.so &> /dev/null || - adb $SERIAL_NUM shell ls /vendor/lib64/mediadrm/libwvdrmengine.so &> /dev/null; then - library_path="/vendor/lib/mediadrm/:/vendor/lib64/mediadrm/" - adb_shell_run libwvdrmengine_test LD_LIBRARY_PATH=$library_path -fi - # Run the Treble test on Treble devices if adb $SERIAL_NUM shell ls /vendor/lib/libwvhidl.so &> /dev/null || adb $SERIAL_NUM shell ls /vendor/lib64/libwvhidl.so &> /dev/null; then diff --git a/libwvdrmengine/src/WVCreatePluginFactories.cpp b/libwvdrmengine/src/WVCreatePluginFactories.cpp deleted file mode 100644 index 6c1d2c05..00000000 --- a/libwvdrmengine/src/WVCreatePluginFactories.cpp +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#include "WVCreatePluginFactories.h" - -#include "WVCryptoFactory.h" -#include "WVDrmFactory.h" - -extern "C" { - -android::DrmFactory* createDrmFactory() { - return new wvdrm::WVDrmFactory(); -} - -android::CryptoFactory* createCryptoFactory() { - return new wvdrm::WVCryptoFactory(); -} - -} // extern "C" diff --git a/libwvdrmengine/src/WVCryptoFactory.cpp b/libwvdrmengine/src/WVCryptoFactory.cpp deleted file mode 100644 index c1e3fad4..00000000 --- a/libwvdrmengine/src/WVCryptoFactory.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -//#define LOG_NDEBUG 0 -#define LOG_TAG "WVCdm" -#include - -#include "WVCryptoFactory.h" - -#include - -#include "utils/Errors.h" -#include "WVCDMSingleton.h" -#include "WVCryptoPlugin.h" -#include "WVUUID.h" - -namespace wvdrm { - -using namespace android; - -bool WVCryptoFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) const { - return isWidevineUUID(uuid); -} - -status_t WVCryptoFactory::createPlugin(const uint8_t uuid[16], const void* data, - size_t size, CryptoPlugin** plugin) { - if (!isCryptoSchemeSupported(uuid)) { - *plugin = NULL; - return BAD_VALUE; - } - - *plugin = new WVCryptoPlugin(data, size, getCDM()); - return OK; -} - -} // namespace wvdrm diff --git a/libwvdrmengine/src/WVDrmFactory.cpp b/libwvdrmengine/src/WVDrmFactory.cpp deleted file mode 100644 index 1571f8f4..00000000 --- a/libwvdrmengine/src/WVDrmFactory.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -//#define LOG_NDEBUG 0 -#define LOG_TAG "WVCdm" -#include - -#include "WVDrmFactory.h" - -#include "utils/Errors.h" -#include "wv_cdm_constants.h" -#include "WVCDMSingleton.h" -#include "wv_content_decryption_module.h" -#include "WVDrmPlugin.h" -#include "WVUUID.h" - -namespace wvdrm { - -using namespace android; - -WVGenericCryptoInterface WVDrmFactory::sOemCryptoInterface; - -bool WVDrmFactory::isCryptoSchemeSupported(const uint8_t uuid[16]) { - return isWidevineUUID(uuid); -} - -bool WVDrmFactory::isContentTypeSupported(const String8 &initDataType) { - return wvcdm::WvContentDecryptionModule::IsSupported(initDataType.string()); -} - -status_t WVDrmFactory::createDrmPlugin(const uint8_t uuid[16], - DrmPlugin** plugin) { - if (!isCryptoSchemeSupported(uuid)) { - *plugin = NULL; - return BAD_VALUE; - } - - *plugin = new WVDrmPlugin(getCDM(), &sOemCryptoInterface); - - return OK; -} - -} // namespace wvdrm diff --git a/libwvdrmengine/test/unit/Android.mk b/libwvdrmengine/test/unit/Android.mk index a9cd618e..e7b613a5 100644 --- a/libwvdrmengine/test/unit/Android.mk +++ b/libwvdrmengine/test/unit/Android.mk @@ -1,55 +1,5 @@ LOCAL_PATH:= $(call my-dir) -# ----------------------------------------------------------------------------- -# Builds libwvdrmengine_test -# -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - legacy_src/WVCreatePluginFactories_test.cpp \ - legacy_src/WVCryptoFactory_test.cpp \ - legacy_src/WVDrmFactory_test.cpp \ - -LOCAL_C_INCLUDES := \ - frameworks/av/include \ - frameworks/native/include \ - vendor/widevine/libwvdrmengine/include \ - vendor/widevine/libwvdrmengine/mediadrm/include \ - vendor/widevine/libwvdrmengine/oemcrypto/include \ - -LOCAL_STATIC_LIBRARIES := \ - libgtest \ - libgtest_main \ - -LOCAL_SHARED_LIBRARIES := \ - libcrypto \ - libdl \ - liblog \ - libutils \ - libwvdrmengine \ - -LOCAL_HEADER_LIBRARIES := \ - libstagefright_headers \ - libstagefright_foundation_headers \ - -LOCAL_MODULE := libwvdrmengine_test -LOCAL_LICENSE_KINDS := legacy_by_exception_only -LOCAL_LICENSE_CONDITIONS := by_exception_only - -LOCAL_MODULE_TAGS := tests - -LOCAL_MODULE_OWNER := widevine -LOCAL_PROPRIETARY_MODULE := true - -# When built, explicitly put it in the DATA/nativetest directory. -LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest - -ifneq ($(TARGET_ENABLE_MEDIADRM_64), true) -LOCAL_MODULE_TARGET_ARCH := arm x86 mips -endif - -include $(BUILD_EXECUTABLE) - # ----------------------------------------------------------------------------- # Builds libwvdrmengine_hidl_test # @@ -66,7 +16,6 @@ LOCAL_C_INCLUDES := \ vendor/widevine/libwvdrmengine/include_hidl \ vendor/widevine/libwvdrmengine/include \ vendor/widevine/libwvdrmengine/mediadrm/include_hidl \ - vendor/widevine/libwvdrmengine/mediadrm/include \ vendor/widevine/libwvdrmengine/oemcrypto/include \ LOCAL_STATIC_LIBRARIES := \ diff --git a/libwvdrmengine/test/unit/legacy_src/WVCreatePluginFactories_test.cpp b/libwvdrmengine/test/unit/legacy_src/WVCreatePluginFactories_test.cpp deleted file mode 100644 index 8e3f34e9..00000000 --- a/libwvdrmengine/test/unit/legacy_src/WVCreatePluginFactories_test.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#include "gtest/gtest.h" -#include "WVCreatePluginFactories.h" - -#include - -using namespace android; - -TEST(CreatePluginFactoriesTest, CreatesDrmFactory) { - std::unique_ptr factory(createDrmFactory()); - - EXPECT_NE((DrmFactory*)NULL, factory.get()) << - "createDrmFactory() returned null"; -} - -TEST(CreatePluginFactoriesTest, CreatesCryptoFactory) { - std::unique_ptr factory(createCryptoFactory()); - - EXPECT_NE((CryptoFactory*)NULL, factory.get()) << - "createCryptoFactory() returned null"; -} diff --git a/libwvdrmengine/test/unit/legacy_src/WVCryptoFactory_test.cpp b/libwvdrmengine/test/unit/legacy_src/WVCryptoFactory_test.cpp deleted file mode 100644 index 5dbfa8e8..00000000 --- a/libwvdrmengine/test/unit/legacy_src/WVCryptoFactory_test.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine License - * Agreement. - */ - -#include "gtest/gtest.h" -#include "WVCryptoFactory.h" - -#include - -using namespace wvdrm; - -const uint8_t kWidevineUUID[16] = { - 0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE, - 0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED -}; - -const uint8_t kOldNetflixWidevineUUID[16] = { - 0x29,0x70,0x1F,0xE4,0x3C,0xC7,0x4A,0x34, - 0x8C,0x5B,0xAE,0x90,0xC7,0x43,0x9A,0x47 -}; - -const uint8_t kUnknownUUID[16] = { - 0x6A,0x7F,0xAA,0xB0,0x83,0xC7,0x9E,0x20, - 0x08,0xBC,0xEF,0x32,0x34,0x1A,0x9A,0x26 -}; - -TEST(WVCryptoFactoryTest, SupportsSupportedCryptoSchemes) { - std::unique_ptr factory(new WVCryptoFactory()); - - EXPECT_TRUE(factory->isCryptoSchemeSupported(kWidevineUUID)) << - "WVPluginFactory does not support Widevine's UUID"; - - EXPECT_TRUE(factory->isCryptoSchemeSupported(kOldNetflixWidevineUUID)) << - "WVPluginFactory does not support the old Netflix Widevine UUID"; -} - -TEST(WVCryptoFactoryTest, DoesNotSupportUnsupportedCryptoSchemes) { - std::unique_ptr factory(new WVCryptoFactory()); - - EXPECT_FALSE(factory->isCryptoSchemeSupported(kUnknownUUID)) << - "WVPluginFactory incorrectly claims to support an unknown UUID"; -} diff --git a/libwvdrmengine/test/unit/legacy_src/WVDrmFactory_test.cpp b/libwvdrmengine/test/unit/legacy_src/WVDrmFactory_test.cpp deleted file mode 100644 index 841d0493..00000000 --- a/libwvdrmengine/test/unit/legacy_src/WVDrmFactory_test.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine License - * Agreement. - */ - -#include "gtest/gtest.h" -#include "WVDrmFactory.h" - -using namespace wvdrm; -using namespace android; - -const uint8_t kWidevineUUID[16] = { - 0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE, - 0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED -}; - -const uint8_t kOldNetflixWidevineUUID[16] = { - 0x29,0x70,0x1F,0xE4,0x3C,0xC7,0x4A,0x34, - 0x8C,0x5B,0xAE,0x90,0xC7,0x43,0x9A,0x47 -}; - -const uint8_t kUnknownUUID[16] = { - 0x6A,0x7F,0xAA,0xB0,0x83,0xC7,0x9E,0x20, - 0x08,0xBC,0xEF,0x32,0x34,0x1A,0x9A,0x26 -}; - -TEST(WVDrmFactoryTest, SupportsSupportedCryptoSchemes) { - WVDrmFactory factory; - - EXPECT_TRUE(factory.isCryptoSchemeSupported(kWidevineUUID)) << - "WVPluginFactory does not support Widevine's UUID"; - - EXPECT_TRUE(factory.isCryptoSchemeSupported(kOldNetflixWidevineUUID)) << - "WVPluginFactory does not support the old Netflix Widevine UUID"; -} - -TEST(WVDrmFactoryTest, DoesNotSupportUnsupportedCryptoSchemes) { - WVDrmFactory factory; - - EXPECT_FALSE(factory.isCryptoSchemeSupported(kUnknownUUID)) << - "WVPluginFactory incorrectly claims to support an unknown UUID"; -} - -TEST(WVDrmFactoryTest, SupportsSupportedContainerFormats) { - WVDrmFactory factory; - - EXPECT_TRUE(factory.isContentTypeSupported(String8("video/mp4"))) << - "WVPluginFactory does not support ISO-BMFF video"; - - EXPECT_TRUE(factory.isContentTypeSupported(String8("audio/mp4"))) << - "WVPluginFactory does not support ISO-BMFF audio"; - - EXPECT_TRUE(factory.isContentTypeSupported(String8("video/webm"))) << - "WVPluginFactory does not support WebM video"; - - EXPECT_TRUE(factory.isContentTypeSupported(String8("audio/webm"))) << - "WVPluginFactory does not support WebM audio"; -} - -TEST(WVDrmFactoryTest, DoesNotSupportUnsupportedContainerFormats) { - WVDrmFactory factory; - - // Taken from Encoding.com's list of the most common internet video MIME-types - EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-matroska"))) << - "WVPluginFactory incorrectly claims to support Matroska"; - - EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-flv"))) << - "WVPluginFactory incorrectly claims to support Flash Video"; - - EXPECT_FALSE(factory.isContentTypeSupported(String8("application/x-mpegURL"))) << - "WVPluginFactory incorrectly claims to support m3u8 Indexes"; - - EXPECT_FALSE(factory.isContentTypeSupported(String8("video/MP2T"))) << - "WVPluginFactory incorrectly claims to support MPEG-2 TS"; - - EXPECT_FALSE(factory.isContentTypeSupported(String8("video/3gpp"))) << - "WVPluginFactory incorrectly claims to support 3GP Mobile"; - - EXPECT_FALSE(factory.isContentTypeSupported(String8("video/quicktime"))) << - "WVPluginFactory incorrectly claims to support Quicktime"; - - EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-msvideo"))) << - "WVPluginFactory incorrectly claims to support AVI"; - - EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-ms-wmv"))) << - "WVPluginFactory incorrectly claims to support WMV"; -} diff --git a/tests/Android.mk b/tests/Android.mk index 0bc2668a..0bec3f8d 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -27,11 +27,8 @@ WIDEVINE_TEST_MAKE_TARGETS += \ http_socket_test \ initialization_data_unittest \ libwvdrmdrmplugin_hidl_test \ - libwvdrmdrmplugin_test \ libwvdrmengine_hidl_test \ - libwvdrmengine_test \ libwvdrmmediacrypto_hidl_test \ - libwvdrmmediacrypto_test \ license_keys_unittest \ license_unittest \ odk_test \