From 30669a7b67546198bbc9831b6de9b20d80aabcc3 Mon Sep 17 00:00:00 2001 From: Cong Lin Date: Wed, 19 Jul 2023 11:17:12 -0700 Subject: [PATCH] Cdm to expose GetDeviceInformation() and GetDeviceSignedCsrPayload() GetDeviceInformation() and GetDeviceSignedCsrPayload() are added to cdm_engine and crypto_session, so that they can be queried by DRM plugin. This is to allow the wv drm HAL to be able to extract BCC and CSR payload to build CSR for prov 4 device registration, such that we don't need a separate RKP HAL to do this job. Changes to the DRM plugin to use the exposed methods will be in the coming CL. Bug: 286556950 Test: request_license_test Merged from https://widevine-internal-review.googlesource.com/178890 Merged from https://widevine-internal-review.googlesource.com/179730 Change-Id: Ibafa3a58c99fbb8f1f25f8951d3749110bd32176 --- libwvdrmengine/cdm/core/include/cdm_engine.h | 5 + .../cdm/core/include/crypto_session.h | 7 ++ .../cdm/core/include/wv_cdm_constants.h | 1 + .../cdm/core/include/wv_cdm_types.h | 2 + libwvdrmengine/cdm/core/src/cdm_engine.cpp | 54 ++++++++++- .../cdm/core/src/crypto_session.cpp | 94 +++++++++++++++++++ libwvdrmengine/cdm/core/src/wv_cdm_types.cpp | 4 + .../cdm/test/request_license_test.cpp | 18 +++- libwvdrmengine/src/WVDrmFactory.cpp | 1 + 9 files changed, 179 insertions(+), 7 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/cdm_engine.h b/libwvdrmengine/cdm/core/include/cdm_engine.h index c8bbe7ad..90a74b8c 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -180,6 +180,11 @@ class CdmEngine { virtual CdmResponseType QueryOemCryptoSessionId( const CdmSessionId& session_id, CdmQueryMap* query_response); + // Query Signed CSR payload for Prov 4 device + virtual CdmResponseType QueryDeviceSignedCsrPayload( + const std::string& challenge, const std::string& device_info, + std::string* query_response); + // Generate and return a valid provisioning request. virtual CdmResponseType GetProvisioningRequest( CdmCertificateType cert_type, const std::string& cert_authority, diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index 3abdebcb..58e7d2ff 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -196,6 +196,13 @@ class CryptoSession { std::string* additional_signature); virtual CdmResponseType GetBootCertificateChain( std::string* bcc, std::string* additional_signature); + virtual CdmResponseType GetDeviceInformation( + RequestedSecurityLevel requested_security_level, + std::string* device_info); + virtual CdmResponseType GetDeviceSignedCsrPayload( + RequestedSecurityLevel requested_security_level, + const std::string& challenge, const std::string& device_info, + std::string* signed_csr_payload); virtual CdmResponseType GenerateCertificateKeyPair( std::string* public_key, std::string* public_key_signature, std::string* wrapped_private_key, CryptoWrappedKey::Type* key_type); diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h index 3c49ff5d..8f473cd3 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h @@ -124,6 +124,7 @@ static const std::string QUERY_KEY_PRODUCTION_READY = "ProductionReady"; // Internal query key. Should not be exposed to Android apps. static const std::string QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN = "DebugBootCertificateChain"; +static const std::string QUERY_KEY_DEVICE_INFORMATION = "DeviceInformation"; static const std::string QUERY_VALUE_TRUE = "True"; static const std::string QUERY_VALUE_FALSE = "False"; diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 55a586b3..f2daa492 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -461,6 +461,8 @@ enum CdmResponseEnum : int32_t { STORE_ATSC_LICENSE_ERROR = 395, SESSION_NOT_FOUND_GENERIC_CRYPTO = 396, SESSION_NOT_FOUND_24 = 397, + GET_DEVICE_INFORMATION_ERROR = 398, + GET_DEVICE_SIGNED_CSR_PAYLOAD_ERROR = 399, // Don't forget to add new values to // * core/src/wv_cdm_types.cpp // * android/include/mapErrors-inl.h diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index ccbe11f7..2eb11cac 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -887,7 +887,7 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level, const CdmResponseType status = crypto_session->GetBootCertificateChain( security_level, &bcc, &signature_unused); if (status == NO_ERROR) { - LOGD("BCC length: %zu", bcc.size()); + LOGV("BCC length: %zu", bcc.size()); *query_response = std::move(bcc); return CdmResponseType(NO_ERROR); } @@ -900,6 +900,24 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level, LOGE("Failed to extract BCC: status = %d", status.ToInt()); return status; } + if (query_token == QUERY_KEY_DEVICE_INFORMATION) { + std::string device_info; + const CdmResponseType status = + crypto_session->GetDeviceInformation(security_level, &device_info); + if (status == NO_ERROR) { + LOGV("device_info length: %zu", device_info.size()); + *query_response = std::move(device_info); + return CdmResponseType(NO_ERROR); + } + if (status == NOT_IMPLEMENTED_ERROR || + status == PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR) { + LOGV("device_info not available: %s", status.ToString().c_str()); + *query_response = QUERY_VALUE_NONE; + return CdmResponseType(NO_ERROR); + } + LOGE("Failed to extract device_info: %s", status.ToString().c_str()); + return status; + } CdmResponseType status; M_TIME(status = crypto_session->Open(security_level), @@ -1038,6 +1056,34 @@ CdmResponseType CdmEngine::QueryOemCryptoSessionId( return session->QueryOemCryptoSessionId(query_response); } +CdmResponseType CdmEngine::QueryDeviceSignedCsrPayload( + const std::string& challenge, const std::string& device_info, + std::string* query_response) { + if (query_response == nullptr) { + LOGE("Output |query_response| is null"); + return CdmResponseType(PARAMETER_NULL); + } + std::unique_ptr crypto_session( + CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics())); + + std::string signed_csr_payload; + const CdmResponseType status = crypto_session->GetDeviceSignedCsrPayload( + kLevelDefault, challenge, device_info, &signed_csr_payload); + if (status == NO_ERROR) { + LOGV("signed_csr_payload length: %zu", signed_csr_payload.size()); + *query_response = std::move(signed_csr_payload); + return CdmResponseType(NO_ERROR); + } + if (status == NOT_IMPLEMENTED_ERROR || + status == PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR) { + LOGD("signed_csr_payload not available: %s", status.ToString().c_str()); + *query_response = QUERY_VALUE_NONE; + return CdmResponseType(NO_ERROR); + } + LOGE("Failed to extract signed_csr_payload: %s", status.ToString().c_str()); + return status; +} + // static bool CdmEngine::IsSecurityLevelSupported(CdmSecurityLevel level) { LOGI("level = %s", CdmSecurityLevelToString(level)); @@ -2358,9 +2404,9 @@ CdmResponseType CdmEngine::SignRsa(const std::string& wrapped_key, { std::unique_lock lock(session_map_lock_); if (!session_map_.FindSession(session_id, &session)) { - LOGE("Session not found: session_id = %s", IdToString(session_id)); - CloseSession(session_id); - return CdmResponseType(SESSION_NOT_FOUND_24); + LOGE("Session not found: session_id = %s", IdToString(session_id)); + CloseSession(session_id); + return CdmResponseType(SESSION_NOT_FOUND_24); } } diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index a46c49d5..24660014 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -1450,6 +1450,100 @@ CdmResponseType CryptoSession::GetBootCertificateChain( return CdmResponseType(NO_ERROR); } +CdmResponseType CryptoSession::GetDeviceInformation( + RequestedSecurityLevel requested_security_level, std::string* device_info) { + RETURN_IF_NULL(device_info, PARAMETER_NULL); + RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED); + if (GetSecurityLevel(requested_security_level) != kSecurityLevelL1) { + LOGE("CDM only supports L1 device_info"); + return CdmResponseType(NOT_IMPLEMENTED_ERROR); + } + CdmClientTokenType token_type = kClientTokenUninitialized; + const CdmResponseType status = + GetProvisioningMethod(requested_security_level, &token_type); + if (status != NO_ERROR) { + LOGE("Failed to get token type"); + return status; + } + if (token_type != kClientTokenBootCertChain) { + return CdmResponseType( + PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR); + } + + size_t device_info_length = 0; + OEMCryptoResult sts = WithOecReadLock("GetDeviceInformation Attempt 1", [&] { + return OEMCrypto_GetDeviceInformation(nullptr, &device_info_length); + }); + if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { + device_info->resize(device_info_length); + sts = WithOecReadLock("GetDeviceInformation Attempt 2", [&] { + return OEMCrypto_GetDeviceInformation( + MutableStringDataPointer(device_info), &device_info_length); + }); + } + if (sts != OEMCrypto_SUCCESS) { + LOGE("OEMCrypto_GetDeviceInformation failed: status = %d", + static_cast(sts)); + device_info->clear(); + return MapOEMCryptoResult(sts, GET_DEVICE_INFORMATION_ERROR, + "GetDeviceInformation"); + } + device_info->resize(device_info_length); + return CdmResponseType(NO_ERROR); +} + +CdmResponseType CryptoSession::GetDeviceSignedCsrPayload( + RequestedSecurityLevel requested_security_level, + const std::string& challenge, const std::string& device_info, + std::string* signed_csr_payload) { + RETURN_IF_NULL(signed_csr_payload, PARAMETER_NULL); + RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED); + if (GetSecurityLevel(requested_security_level) != kSecurityLevelL1) { + LOGE("CDM only supports L1 CSR payload"); + return CdmResponseType(NOT_IMPLEMENTED_ERROR); + } + CdmClientTokenType token_type = kClientTokenUninitialized; + const CdmResponseType status = + GetProvisioningMethod(requested_security_level, &token_type); + if (status != NO_ERROR) { + LOGE("Failed to get token type"); + return status; + } + if (token_type != kClientTokenBootCertChain) { + return CdmResponseType( + PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR); + } + + size_t signed_csr_payload_length = 0; + OEMCryptoResult sts = + WithOecReadLock("GetDeviceSignedCsrPayload Attempt 1", [&] { + return OEMCrypto_GetDeviceSignedCsrPayload( + reinterpret_cast(challenge.data()), + challenge.size(), + reinterpret_cast(device_info.data()), + device_info.size(), nullptr, &signed_csr_payload_length); + }); + if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { + signed_csr_payload->resize(signed_csr_payload_length); + sts = WithOecReadLock("GetDeviceSignedCsrPayload Attempt 2", [&] { + return OEMCrypto_GetDeviceSignedCsrPayload( + reinterpret_cast(challenge.data()), challenge.size(), + reinterpret_cast(device_info.data()), + device_info.size(), MutableStringDataPointer(signed_csr_payload), + &signed_csr_payload_length); + }); + } + if (sts != OEMCrypto_SUCCESS) { + LOGE("OEMCrypto_GetDeviceSignedCsrPayload failed: status = %d", + static_cast(sts)); + signed_csr_payload->clear(); + return MapOEMCryptoResult(sts, GET_DEVICE_SIGNED_CSR_PAYLOAD_ERROR, + "GetDeviceSignedCsrPayload"); + } + signed_csr_payload->resize(signed_csr_payload_length); + return CdmResponseType(NO_ERROR); +} + CdmResponseType CryptoSession::GenerateCertificateKeyPair( std::string* public_key, std::string* public_key_signature, std::string* wrapped_private_key, CryptoWrappedKey::Type* key_type) { diff --git a/libwvdrmengine/cdm/core/src/wv_cdm_types.cpp b/libwvdrmengine/cdm/core/src/wv_cdm_types.cpp index 6015f1f7..e857ab6e 100644 --- a/libwvdrmengine/cdm/core/src/wv_cdm_types.cpp +++ b/libwvdrmengine/cdm/core/src/wv_cdm_types.cpp @@ -819,6 +819,10 @@ const char* CdmResponseEnumToString(CdmResponseEnum cdm_response_enum) { return "PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR"; case GET_BOOT_CERTIFICATE_CHAIN_ERROR: return "GET_BOOT_CERTIFICATE_CHAIN_ERROR"; + case GET_DEVICE_INFORMATION_ERROR: + return "GET_DEVICE_INFORMATION_ERROR"; + case GET_DEVICE_SIGNED_CSR_PAYLOAD_ERROR: + return "GET_DEVICE_SIGNED_CSR_PAYLOAD_ERROR"; case GENERATE_CERTIFICATE_KEY_PAIR_ERROR: return "GENERATE_CERTIFICATE_KEY_PAIR_ERROR"; case GENERATE_CERTIFICATE_KEY_PAIR_UNKNOWN_TYPE_ERROR: diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index 71672ec3..aea3bdd7 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -5348,18 +5348,30 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatus) { value == wvcdm::QUERY_VALUE_OEM_CERTIFICATE || value == wvcdm::QUERY_VALUE_BOOT_CERTIFICATE_CHAIN); - const bool expect_bcc = (value == wvcdm::QUERY_VALUE_BOOT_CERTIFICATE_CHAIN); + const bool is_prov4 = (value == wvcdm::QUERY_VALUE_BOOT_CERTIFICATE_CHAIN); EXPECT_EQ(wvcdm::NO_ERROR, decryptor_->QueryStatus( kLevelDefault, wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN, &value)); - if (expect_bcc) { - // Expect that the BCC is returned; but do not validate the actual value. + if (is_prov4) { + // Expect that the BCC is returned for Prov 4; but do not validate the + // actual value. EXPECT_FALSE(value.empty()) << "BCC is empty"; EXPECT_NE(value, wvcdm::QUERY_VALUE_NONE) << "BCC is none"; } else { EXPECT_EQ(value, wvcdm::QUERY_VALUE_NONE); } + EXPECT_EQ(wvcdm::NO_ERROR, + decryptor_->QueryStatus( + kLevelDefault, wvcdm::QUERY_KEY_DEVICE_INFORMATION, &value)); + if (is_prov4) { + // Expect that the device info is returned for Prov 4; but do not validate + // the actual value. + EXPECT_FALSE(value.empty()) << "Device info is empty"; + EXPECT_NE(value, wvcdm::QUERY_VALUE_NONE) << "Device info is none"; + } else { + EXPECT_EQ(value, wvcdm::QUERY_VALUE_NONE); + } EXPECT_EQ( wvcdm::NO_ERROR, diff --git a/libwvdrmengine/src/WVDrmFactory.cpp b/libwvdrmengine/src/WVDrmFactory.cpp index 12c3bb7a..b33c8442 100644 --- a/libwvdrmengine/src/WVDrmFactory.cpp +++ b/libwvdrmengine/src/WVDrmFactory.cpp @@ -346,6 +346,7 @@ void WVDrmFactory::printCdmProperties(int fd) { // Debug properties. Not exposed to app. {"boot_certificate_chain", wvcdm::QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN}, + {"device_information", wvcdm::QUERY_KEY_DEVICE_INFORMATION}, }; string value;