From 3d599197be4e11ff5cf1bdc5404c0fa28b370f69 Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Sat, 15 Apr 2017 02:06:02 -0700 Subject: [PATCH 1/2] Correct CryptoException error returned before keys have been loaded [ Merge of http://go/wvgerrit/25983 ] Earlier versions of android returned CryptoException with error code ERROR_NO_KEY, when a decrypt call was received before keys were loaded. Changes to O resulted in ERROR_SESSION_NOT_OPENED being returned instead. This CL reverts the behaviour. Also a change to correct CDM error code numbering in comments. Test: Verified by unit and integration tests b/37219830 Change-Id: I43758cd29cf9d1945f878ac352a5f26538b48cdb --- .../cdm/core/include/wv_cdm_types.h | 56 ++++++++++--------- .../cdm/core/test/test_printers.cpp | 6 ++ .../cdm/src/wv_content_decryption_module.cpp | 5 +- libwvdrmengine/include/mapErrors-inl.h | 2 + .../mediacrypto/src/WVCryptoPlugin.cpp | 1 + .../mediacrypto/src_hidl/WVCryptoPlugin.cpp | 1 + 6 files changed, 40 insertions(+), 31 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 6b4d6e50..f69cb20f 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -229,72 +229,74 @@ enum CdmResponseType { INVALID_PARAMETERS_ENG_8, INVALID_PARAMETERS_ENG_9, INVALID_PARAMETERS_ENG_10, - INVALID_PARAMETERS_ENG_11, /* 190 */ - INVALID_PARAMETERS_ENG_12, + INVALID_PARAMETERS_ENG_11, + INVALID_PARAMETERS_ENG_12, /* 190 */ SESSION_NOT_FOUND_13, SESSION_NOT_FOUND_14, SESSION_NOT_FOUND_15, - SESSION_NOT_FOUND_16, /* 195 */ - KEY_NOT_FOUND_3, + SESSION_NOT_FOUND_16, + KEY_NOT_FOUND_3, /* 195 */ KEY_NOT_FOUND_4, KEY_NOT_FOUND_5, KEY_NOT_FOUND_6, - INVALID_SESSION_1, /* 200 */ - NO_DEVICE_KEY_1, + INVALID_SESSION_1, + NO_DEVICE_KEY_1, /* 200 */ NO_CONTENT_KEY_2, INSUFFICIENT_CRYPTO_RESOURCES_2, INVALID_PARAMETERS_ENG_13, - INVALID_PARAMETERS_ENG_14, /* 205 */ - INVALID_PARAMETERS_ENG_15, + INVALID_PARAMETERS_ENG_14, + INVALID_PARAMETERS_ENG_15, /* 205 */ INVALID_PARAMETERS_ENG_16, DEVICE_CERTIFICATE_ERROR_5, CERT_PROVISIONING_CLIENT_TOKEN_ERROR_1, - CERT_PROVISIONING_CLIENT_TOKEN_ERROR_2, /* 210 */ - LICENSING_CLIENT_TOKEN_ERROR_1, + CERT_PROVISIONING_CLIENT_TOKEN_ERROR_2, + LICENSING_CLIENT_TOKEN_ERROR_1, /* 210 */ ANALOG_OUTPUT_ERROR, UNKNOWN_SELECT_KEY_ERROR_1, UNKNOWN_SELECT_KEY_ERROR_2, - CREATE_USAGE_TABLE_ERROR, /* 215 */ - LOAD_USAGE_HEADER_GENERATION_SKEW, + CREATE_USAGE_TABLE_ERROR, + LOAD_USAGE_HEADER_GENERATION_SKEW, /* 215 */ LOAD_USAGE_HEADER_SIGNATURE_FAILURE, LOAD_USAGE_HEADER_BAD_MAGIC, LOAD_USAGE_HEADER_UNKNOWN_ERROR, - INVALID_PARAMETERS_ENG_17, /* 220 */ - INVALID_PARAMETERS_ENG_18, + INVALID_PARAMETERS_ENG_17, + INVALID_PARAMETERS_ENG_18, /* 220 */ INSUFFICIENT_CRYPTO_RESOURCES_3, CREATE_USAGE_ENTRY_UNKNOWN_ERROR, LOAD_USAGE_ENTRY_GENERATION_SKEW, - LOAD_USAGE_ENTRY_SIGNATURE_FAILURE, /* 225 */ - LOAD_USAGE_ENTRY_UNKNOWN_ERROR, + LOAD_USAGE_ENTRY_SIGNATURE_FAILURE, + LOAD_USAGE_ENTRY_UNKNOWN_ERROR, /* 225 */ INVALID_PARAMETERS_ENG_19, INVALID_PARAMETERS_ENG_20, UPDATE_USAGE_ENTRY_UNKNOWN_ERROR, - INVALID_PARAMETERS_ENG_21, /* 230 */ - SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR, + INVALID_PARAMETERS_ENG_21, + SHRINK_USAGE_TABLER_HEADER_UNKNOWN_ERROR, /* 230 */ MOVE_USAGE_ENTRY_UNKNOWN_ERROR, COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR, INVALID_PARAMETERS_ENG_22, - STORE_LICENSE_ERROR_4, /* 235 */ - LIST_LICENSES_ERROR, + STORE_LICENSE_ERROR_4, + LIST_LICENSES_ERROR, /* 235 */ INVALID_PARAMETERS_ENG_23, USAGE_INFORMATION_SUPPORT_FAILED, USAGE_SUPPORT_GET_API_FAILED, - UNEXPECTED_EMPTY_USAGE_ENTRY, /* 240 */ - INVALID_USAGE_ENTRY_NUMBER_MODIFICATION, + UNEXPECTED_EMPTY_USAGE_ENTRY, + INVALID_USAGE_ENTRY_NUMBER_MODIFICATION, /* 240 */ USAGE_INVALID_NEW_ENTRY, USAGE_INVALID_PARAMETERS_1, USAGE_RETRIEVE_LICENSE_FAILED, - USAGE_RETRIEVE_USAGE_INFO_FAILED, /* 245 */ - USAGE_RETRIEVE_INVALID_STORAGE_TYPE, + USAGE_RETRIEVE_USAGE_INFO_FAILED, + USAGE_RETRIEVE_INVALID_STORAGE_TYPE, /* 245 */ USAGE_ENTRY_NUMBER_MISMATCH, USAGE_STORE_LICENSE_FAILED, USAGE_STORE_USAGE_INFO_FAILED, - USAGE_INVALID_LOAD_ENTRY, /* 250 */ - RELEASE_ALL_USAGE_INFO_ERROR_4, + USAGE_INVALID_LOAD_ENTRY, + RELEASE_ALL_USAGE_INFO_ERROR_4, /* 250 */ RELEASE_ALL_USAGE_INFO_ERROR_5, RELEASE_USAGE_INFO_FAILED, INCORRECT_USAGE_SUPPORT_TYPE_1, - INCORRECT_USAGE_SUPPORT_TYPE_2, /* 255 */ + INCORRECT_USAGE_SUPPORT_TYPE_2, + KEY_PROHIBITED_FOR_SECURITY_LEVEL, /* 255 */ + KEY_NOT_FOUND_IN_SESSION, }; enum CdmKeyStatus { diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index b33389d9..3a511785 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -568,6 +568,12 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) { case INCORRECT_USAGE_SUPPORT_TYPE_2: *os << "INCORRECT_USAGE_SUPPORT_TYPE_2"; break; + case KEY_PROHIBITED_FOR_SECURITY_LEVEL: + *os << "KEY_PROHIBITED_FOR_SECURITY_LEVEL"; + break; + case KEY_NOT_FOUND_IN_SESSION: + *os << "KEY_NOT_FOUND_IN_SESSION"; + break; default: *os << "Unknown CdmResponseType"; diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 36bf23db..dbf32132 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -379,10 +379,7 @@ CdmResponseType WvContentDecryptionModule::Decrypt( cdm_engine->GetMetrics(), cdm_engine_find_session_for_key_, status); - if (!status) { - LOGE("WvContentDecryptionModule::Decrypt: unable to find session"); - return SESSION_NOT_FOUND_FOR_DECRYPT; - } + if (!status) return KEY_NOT_FOUND_IN_SESSION; } CdmResponseType sts; M_TIME( diff --git a/libwvdrmengine/include/mapErrors-inl.h b/libwvdrmengine/include/mapErrors-inl.h index a0143967..f235819e 100644 --- a/libwvdrmengine/include/mapErrors-inl.h +++ b/libwvdrmengine/include/mapErrors-inl.h @@ -23,6 +23,7 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return android::OK; case wvcdm::NEED_KEY: case wvcdm::DECRYPT_NOT_READY: + case wvcdm::KEY_NOT_FOUND_IN_SESSION: return android::ERROR_DRM_NO_LICENSE; case wvcdm::NEED_PROVISIONING: return android::ERROR_DRM_NOT_PROVISIONED; @@ -368,6 +369,7 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) { return android::ERROR_DRM_CANNOT_HANDLE; case wvcdm::INSUFFICIENT_OUTPUT_PROTECTION: case wvcdm::ANALOG_OUTPUT_ERROR: + case wvcdm::KEY_PROHIBITED_FOR_SECURITY_LEVEL: return android::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION; case wvcdm::SESSION_NOT_FOUND_12: return kSessionNotFound12; diff --git a/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp b/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp index f813c9d4..cbe68546 100644 --- a/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp +++ b/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp @@ -306,6 +306,7 @@ status_t WVCryptoPlugin::attemptDecrypt(const CdmDecryptionParameters& params, "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; diff --git a/libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp b/libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp index 570e54a7..e755405d 100644 --- a/libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp +++ b/libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp @@ -338,6 +338,7 @@ status_t WVCryptoPlugin::attemptDecrypt(const CdmDecryptionParameters& params, "Error decrypting data: insufficient crypto resources"); break; case wvcdm::NEED_KEY: + case wvcdm::KEY_NOT_FOUND_IN_SESSION: errorDetailMsg->assign( "Error decrypting data: requested key has not been loaded"); break; From 0f374af4abb6015c83e8bf747945b3d5dec5e59b Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Mon, 17 Apr 2017 15:53:14 -0700 Subject: [PATCH 2/2] Allow decryption of unencrypted data before key has been retrieved [ Merge of http://go/wvgerrit/25987 ] Test: Added Cdm/WvCdmSessionSharingNoKeyTest to request_license_test. Verified by wv unit and integration tests. b/28182987 Change-Id: I9039bc1fca83e2c1044c3af2f47f31dc4fb5c910 --- .../cdm/src/wv_content_decryption_module.cpp | 2 +- .../cdm/test/request_license_test.cpp | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index dbf32132..6668fc60 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -379,7 +379,7 @@ CdmResponseType WvContentDecryptionModule::Decrypt( cdm_engine->GetMetrics(), cdm_engine_find_session_for_key_, status); - if (!status) return KEY_NOT_FOUND_IN_SESSION; + if (!status && parameters.is_encrypted) return KEY_NOT_FOUND_IN_SESSION; } CdmResponseType sts; M_TIME( diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index e564fc86..7a9f74f5 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -3552,6 +3552,59 @@ INSTANTIATE_TEST_CASE_P(Cdm, WvCdmDecryptionTest, &switch_key_encrypted_sub_samples[0], &partial_encrypted_sub_samples[0])); +class WvCdmSessionSharingNoKeyTest + : public WvCdmRequestLicenseTest, + public ::testing::WithParamInterface {}; + +TEST_P(WvCdmSessionSharingNoKeyTest, DecryptionTest) { + SubSampleInfo* data = GetParam(); + + TestWvCdmClientPropertySet property_set; + property_set.set_session_sharing_mode(true); + + decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier, + NULL, &session_id_); + CdmSessionId gp_session_id_1 = session_id_; + GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); + + // TODO(rfrias): Move content information to ConfigTestEnv + std::string gp_client_auth2 = + "?source=YOUTUBE&video_id=z3S_NhwueaM&oauth=ya.gtsqawidevine"; + std::string gp_key_id2 = wvcdm::a2bs_hex( + "000000347073736800000000" // blob size and pssh + "edef8ba979d64acea3c827dcd51d21ed00000014" // Widevine system id + "08011210bdf1cb4fffc6506b8b7945b0bd2917fb"); // pssh data + + decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier, + NULL, &session_id_); + CdmSessionId gp_session_id_2 = session_id_; + GenerateKeyRequest(gp_key_id2, kLicenseTypeStreaming); + + std::vector decrypt_buffer(data->encrypt_data.size()); + CdmDecryptionParameters decryption_parameters( + &data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(), + &data->iv, data->block_offset, &decrypt_buffer[0]); + decryption_parameters.is_encrypted = data->is_encrypted; + decryption_parameters.is_secure = data->is_secure; + decryption_parameters.subsample_flags = data->subsample_flags; + + EXPECT_EQ(data->is_encrypted ? KEY_NOT_FOUND_IN_SESSION : NO_ERROR, + decryptor_.Decrypt(gp_session_id_2, data->validate_key_id, + decryption_parameters)); + if (!data->is_encrypted) { + EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(), + decrypt_buffer.begin())); + } + + decryptor_.CloseSession(gp_session_id_1); + decryptor_.CloseSession(gp_session_id_2); +} + +INSTANTIATE_TEST_CASE_P(Cdm, WvCdmSessionSharingNoKeyTest, + ::testing::Values(&clear_sub_sample, + &clear_sub_sample_no_key, + &single_encrypted_sub_sample)); + TEST(VersionNumberTest, VersionNumberChangeCanary) { char release_number[PROPERTY_VALUE_MAX]; ASSERT_GT(property_get("ro.build.version.release", release_number, "Unknown"),