From ce6bd416275d5a91aded9b2330b5547d4f5ae0b3 Mon Sep 17 00:00:00 2001 From: "John W. Bruce" Date: Tue, 11 Apr 2017 11:58:33 -0700 Subject: [PATCH] Define Provisioning-Unique ID for New Device IDs (This is a merge of wvgerrit/25583) Devices that use Provisioning 3.0 did not have a Provisioning-Unique ID defined. Attempting to retrieve it would result in an error. Devices that use SPOIDs with keyboxes would expose the keybox's real Provisioning-Unique ID when asked. This is a security flaw. To solve both cases, an alternative Provisioning-Unique ID is used, consisting of the Device-Unique ID bitwise-inverted. Bug: 36065223 Test: run_all_unit_tests.sh Change-Id: I32512a3e11403e679939187e156904a57a9e24ef --- .../cdm/core/src/crypto_session.cpp | 47 ++++++++++++------- .../mediadrm/include_hidl/WVDrmPlugin.h | 1 + .../mediadrm/src_hidl/WVDrmPlugin.cpp | 24 +++++++++- 3 files changed, 55 insertions(+), 17 deletions(-) diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 4962d870..f62cd347 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -374,23 +374,38 @@ bool CryptoSession::GetProvisioningId(std::string* provisioning_id) { if (!initialized_) { return false; } - OEMCryptoResult sts; - M_TIME( - sts = OEMCrypto_GetKeyData( - buf, - &buf_size, - requested_security_level_), - metrics_, - oemcrypto_get_key_data_, - sts, - metrics::Pow2Bucket(buf_size), - requested_security_level_); - if (OEMCrypto_SUCCESS != sts) { - return false; - } - provisioning_id->assign(reinterpret_cast(&buf[8]), 16); - return true; + if (pre_provision_token_type_ == kClientTokenOemCert) { + // OEM Cert devices have no provisioning-unique ID embedded in them, so we + // synthesize one by using the External Device-Unique ID and inverting all + // the bits. + if (!GetExternalDeviceUniqueId(provisioning_id)) return false; + + for (size_t i = 0; i < provisioning_id->size(); ++i) { + char value = (*provisioning_id)[i]; + (*provisioning_id)[i] = ~value; + } + + return true; + } else { + OEMCryptoResult sts; + M_TIME( + sts = OEMCrypto_GetKeyData( + buf, + &buf_size, + requested_security_level_), + metrics_, + oemcrypto_get_key_data_, + sts, + metrics::Pow2Bucket(buf_size), + requested_security_level_); + if (OEMCrypto_SUCCESS != sts) { + return false; + } + + provisioning_id->assign(reinterpret_cast(&buf[8]), 16); + return true; + } } uint8_t CryptoSession::GetSecurityPatchLevel() { diff --git a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h index 4e283b2c..1aa89a46 100644 --- a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h @@ -323,6 +323,7 @@ struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener, // On SPOID devices, calling this will seal the CDM Identifier Builder, thus // making it an error to change the origin. status_t getDeviceUniqueId(std::string* id); + status_t getProvisioningUniqueId(std::string* id); const std::string& origin() const { return mCdmIdentifier.origin; } bool set_origin(const std::string& id); diff --git a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp index ab668fa4..bcbe9903 100644 --- a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp @@ -678,7 +678,11 @@ Return WVDrmPlugin::getPropertyByteArray( value = StrToVector(id); } } else if (name == "provisioningUniqueId") { - status = queryProperty(wvcdm::QUERY_KEY_PROVISIONING_ID, value); + std::string id; + status = mCdmIdentifierBuilder.getProvisioningUniqueId(&id); + if (status == android::OK) { + value = StrToVector(id); + } } else if (name == "serviceCertificate") { value = StrToVector(mPropertySet.service_certificate()); } else { @@ -1343,6 +1347,24 @@ status_t WVDrmPlugin::CdmIdentifierBuilder::getDeviceUniqueId(std::string* id) { } } +status_t WVDrmPlugin::CdmIdentifierBuilder::getProvisioningUniqueId(std::string* id) { + if (mUseSpoid) { + // To fake a provisioning-unique ID on SPOID devices where we can't expose + // the real provisioning-unique ID, we just use the SPOID and invert all the + // bits. + status_t res = getDeviceUniqueId(id); + if (res != android::OK) return res; + + for (char& c : *id) { + c = ~c; + } + + return android::OK; + } else { + return mParent.queryProperty(wvcdm::QUERY_KEY_PROVISIONING_ID, *id); + } +} + bool WVDrmPlugin::CdmIdentifierBuilder::set_origin(const std::string& id) { if (mIsIdentifierSealed) return false; mCdmIdentifier.origin = id;