Add Property to Access System ID
Adds a new property to the CDM's QueryStatus called QUERY_KEY_SYSTEM_ID that contains the System ID. (as read from OEMCrypto_GetKeyData) Adds a new property to the DrmPlugin (cleverly named "systemId") that allows the app to query for this. Also adds unit tests. Also changes the Device ID getter in crypto_engine.cpp to return a failure instead of an empty ID. Bug: 8621632 Merge of https://widevine-internal-review.googlesource.com/#/c/5010/ from widevine cdm repository to android repository. Change-Id: I8f309af18487c499e8ce25e829059e45623ea4dc
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#ifndef CDM_BASE_CRYPTO_ENGINE_H_
|
#ifndef CDM_BASE_CRYPTO_ENGINE_H_
|
||||||
#define CDM_BASE_CRYPTO_ENGINE_H_
|
#define CDM_BASE_CRYPTO_ENGINE_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "crypto_session.h"
|
#include "crypto_session.h"
|
||||||
@@ -48,7 +49,8 @@ class CryptoEngine {
|
|||||||
} SecurityLevel;
|
} SecurityLevel;
|
||||||
|
|
||||||
SecurityLevel GetSecurityLevel();
|
SecurityLevel GetSecurityLevel();
|
||||||
std::string GetDeviceUniqueId();
|
bool GetDeviceUniqueId(std::string* deviceId);
|
||||||
|
bool GetSystemId(uint32_t* systemId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ static const std::string QUERY_KEY_SECURITY_LEVEL = "SecurityLevel";
|
|||||||
// "L1", "L3"
|
// "L1", "L3"
|
||||||
static const std::string QUERY_KEY_DEVICE_ID = "DeviceID";
|
static const std::string QUERY_KEY_DEVICE_ID = "DeviceID";
|
||||||
// device unique id
|
// device unique id
|
||||||
|
static const std::string QUERY_KEY_SYSTEM_ID = "SystemID";
|
||||||
|
// system id
|
||||||
|
|
||||||
static const std::string QUERY_VALUE_TRUE = "True";
|
static const std::string QUERY_VALUE_TRUE = "True";
|
||||||
static const std::string QUERY_VALUE_FALSE = "False";
|
static const std::string QUERY_VALUE_FALSE = "False";
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "cdm_engine.h"
|
#include "cdm_engine.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "buffer_reader.h"
|
#include "buffer_reader.h"
|
||||||
#include "cdm_session.h"
|
#include "cdm_session.h"
|
||||||
@@ -315,7 +316,19 @@ CdmResponseType CdmEngine::QueryStatus(CdmQueryMap* key_info) {
|
|||||||
return KEY_ERROR;
|
return KEY_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
(*key_info)[QUERY_KEY_DEVICE_ID] = crypto_engine->GetDeviceUniqueId();
|
std::string deviceId;
|
||||||
|
bool success = crypto_engine->GetDeviceUniqueId(&deviceId);
|
||||||
|
if (success) {
|
||||||
|
(*key_info)[QUERY_KEY_DEVICE_ID] = deviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t system_id;
|
||||||
|
success = crypto_engine->GetSystemId(&system_id);
|
||||||
|
if (success) {
|
||||||
|
std::ostringstream system_id_stream;
|
||||||
|
system_id_stream << system_id;
|
||||||
|
(*key_info)[QUERY_KEY_SYSTEM_ID] = system_id_stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "crypto_engine.h"
|
#include "crypto_engine.h"
|
||||||
|
|
||||||
|
#include <arpa/inet.h> // TODO(fredgc): Add ntoh to wv_cdm_utilities.h
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -195,7 +196,7 @@ CryptoEngine::SecurityLevel CryptoEngine::GetSecurityLevel() {
|
|||||||
return kSecurityLevelUnknown;
|
return kSecurityLevelUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CryptoEngine::GetDeviceUniqueId() {
|
bool CryptoEngine::GetDeviceUniqueId(std::string* deviceId) {
|
||||||
std::vector<uint8_t> id;
|
std::vector<uint8_t> id;
|
||||||
size_t idLength = 32;
|
size_t idLength = 32;
|
||||||
|
|
||||||
@@ -204,10 +205,29 @@ std::string CryptoEngine::GetDeviceUniqueId() {
|
|||||||
OEMCryptoResult sts = OEMCrypto_GetDeviceID(&id[0], &idLength);
|
OEMCryptoResult sts = OEMCrypto_GetDeviceID(&id[0], &idLength);
|
||||||
|
|
||||||
if (OEMCrypto_SUCCESS != sts) {
|
if (OEMCrypto_SUCCESS != sts) {
|
||||||
return std::string();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::string(reinterpret_cast<const char*>(&id[0]));
|
*deviceId = reinterpret_cast<const char*>(&id[0]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CryptoEngine::GetSystemId(uint32_t* systemId) {
|
||||||
|
uint8_t buf[72];
|
||||||
|
size_t buflen = 72;
|
||||||
|
|
||||||
|
OEMCryptoResult sts = OEMCrypto_GetKeyData(buf, &buflen);
|
||||||
|
|
||||||
|
if (OEMCrypto_SUCCESS != sts) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode 32-bit int encoded as network-byte-order byte array starting at
|
||||||
|
// index 4.
|
||||||
|
uint32_t* id = reinterpret_cast<uint32_t*>(&buf[4]);
|
||||||
|
|
||||||
|
*systemId = ntohl(*id);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}; // namespace wvcdm
|
}; // namespace wvcdm
|
||||||
|
|||||||
@@ -154,8 +154,11 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
|||||||
client_info->set_value(value);
|
client_info->set_value(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
client_info->set_name(kDeviceIdKey);
|
if (CryptoEngine::GetInstance()->GetDeviceUniqueId(&value)) {
|
||||||
client_info->set_value(CryptoEngine::GetInstance()->GetDeviceUniqueId());
|
client_info = client_id->add_client_info();
|
||||||
|
client_info->set_name(kDeviceIdKey);
|
||||||
|
client_info->set_value(value);
|
||||||
|
}
|
||||||
|
|
||||||
// Content Identification may be a cenc_id, a webm_id or a license_id
|
// Content Identification may be a cenc_id, a webm_id or a license_id
|
||||||
LicenseRequest_ContentIdentification* content_id =
|
LicenseRequest_ContentIdentification* content_id =
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "config_test_env.h"
|
#include "config_test_env.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
@@ -217,6 +218,13 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatus) {
|
|||||||
ASSERT_TRUE(itr != query_info.end());
|
ASSERT_TRUE(itr != query_info.end());
|
||||||
EXPECT_GT((int)itr->second.size(), 0);
|
EXPECT_GT((int)itr->second.size(), 0);
|
||||||
|
|
||||||
|
itr = query_info.find(wvcdm::QUERY_KEY_SYSTEM_ID);
|
||||||
|
ASSERT_TRUE(itr != query_info.end());
|
||||||
|
std::istringstream ss(itr->second);
|
||||||
|
uint32_t system_id;
|
||||||
|
EXPECT_TRUE(ss >> system_id);
|
||||||
|
EXPECT_TRUE(ss.eof());
|
||||||
|
|
||||||
decryptor_.CloseSession(session_id_);
|
decryptor_.CloseSession(session_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -285,9 +285,7 @@ status_t WVDrmPlugin::getPropertyString(const String8& name,
|
|||||||
value = "AES/CBC/NoPadding,HmacSHA256";
|
value = "AES/CBC/NoPadding,HmacSHA256";
|
||||||
} else if (name == "securityLevel") {
|
} else if (name == "securityLevel") {
|
||||||
CdmQueryMap status;
|
CdmQueryMap status;
|
||||||
|
|
||||||
CdmResponseType res = mCDM->QueryStatus(&status);
|
CdmResponseType res = mCDM->QueryStatus(&status);
|
||||||
|
|
||||||
if (!isCdmResponseTypeSuccess(res)) {
|
if (!isCdmResponseTypeSuccess(res)) {
|
||||||
ALOGE("Error querying CDM status: %u", res);
|
ALOGE("Error querying CDM status: %u", res);
|
||||||
return mapCdmResponseType(res);
|
return mapCdmResponseType(res);
|
||||||
@@ -295,11 +293,18 @@ status_t WVDrmPlugin::getPropertyString(const String8& name,
|
|||||||
ALOGE("CDM did not report a security level");
|
ALOGE("CDM did not report a security level");
|
||||||
return kErrorCDMGeneric;
|
return kErrorCDMGeneric;
|
||||||
}
|
}
|
||||||
|
value = status[QUERY_KEY_SECURITY_LEVEL].c_str();
|
||||||
const string& securityLevel = status[QUERY_KEY_SECURITY_LEVEL];
|
} else if (name == "systemId") {
|
||||||
|
CdmQueryMap status;
|
||||||
value.clear();
|
CdmResponseType res = mCDM->QueryStatus(&status);
|
||||||
value.append(securityLevel.data(), securityLevel.size());
|
if (res != wvcdm::NO_ERROR) {
|
||||||
|
ALOGE("Error querying CDM status: %u", res);
|
||||||
|
return mapCdmResponseType(res);
|
||||||
|
} else if (!status.count(QUERY_KEY_SYSTEM_ID)) {
|
||||||
|
ALOGE("CDM did not report a system ID");
|
||||||
|
return kErrorCDMGeneric;
|
||||||
|
}
|
||||||
|
value = status[QUERY_KEY_SYSTEM_ID].c_str();
|
||||||
} else {
|
} else {
|
||||||
ALOGE("App requested unknown property %s", name.string());
|
ALOGE("App requested unknown property %s", name.string());
|
||||||
return android::ERROR_DRM_CANNOT_HANDLE;
|
return android::ERROR_DRM_CANNOT_HANDLE;
|
||||||
|
|||||||
@@ -422,48 +422,57 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
|||||||
l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3;
|
l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3;
|
||||||
|
|
||||||
static const string uniqueId = "The Universe";
|
static const string uniqueId = "The Universe";
|
||||||
CdmQueryMap idMap;
|
CdmQueryMap deviceIDMap;
|
||||||
idMap[QUERY_KEY_DEVICE_ID] = uniqueId;
|
deviceIDMap[QUERY_KEY_DEVICE_ID] = uniqueId;
|
||||||
|
|
||||||
|
static const string systemId = "42";
|
||||||
|
CdmQueryMap systemIDMap;
|
||||||
|
systemIDMap[QUERY_KEY_SYSTEM_ID] = systemId;
|
||||||
|
|
||||||
EXPECT_CALL(cdm, QueryStatus(_))
|
EXPECT_CALL(cdm, QueryStatus(_))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(l1Map),
|
.WillOnce(DoAll(SetArgPointee<0>(l1Map),
|
||||||
Return(wvcdm::NO_ERROR)))
|
Return(wvcdm::NO_ERROR)))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(l3Map),
|
.WillOnce(DoAll(SetArgPointee<0>(l3Map),
|
||||||
Return(wvcdm::NO_ERROR)))
|
Return(wvcdm::NO_ERROR)))
|
||||||
.WillOnce(DoAll(SetArgPointee<0>(idMap),
|
.WillOnce(DoAll(SetArgPointee<0>(deviceIDMap),
|
||||||
|
Return(wvcdm::NO_ERROR)))
|
||||||
|
.WillOnce(DoAll(SetArgPointee<0>(systemIDMap),
|
||||||
Return(wvcdm::NO_ERROR)));
|
Return(wvcdm::NO_ERROR)));
|
||||||
|
|
||||||
String8 stringResult;
|
String8 stringResult;
|
||||||
|
Vector<uint8_t> vectorResult;
|
||||||
|
|
||||||
status_t res = plugin.getPropertyString(String8("vendor"), stringResult);
|
status_t res = plugin.getPropertyString(String8("vendor"), stringResult);
|
||||||
ASSERT_EQ(OK, res);
|
ASSERT_EQ(OK, res);
|
||||||
EXPECT_EQ(String8("Google"), stringResult);
|
EXPECT_STREQ("Google", stringResult.string());
|
||||||
|
|
||||||
res = plugin.getPropertyString(String8("version"), stringResult);
|
res = plugin.getPropertyString(String8("version"), stringResult);
|
||||||
ASSERT_EQ(OK, res);
|
ASSERT_EQ(OK, res);
|
||||||
EXPECT_EQ(String8("1.0"), stringResult);
|
EXPECT_STREQ("1.0", stringResult.string());
|
||||||
|
|
||||||
res = plugin.getPropertyString(String8("description"), stringResult);
|
res = plugin.getPropertyString(String8("description"), stringResult);
|
||||||
ASSERT_EQ(OK, res);
|
ASSERT_EQ(OK, res);
|
||||||
EXPECT_EQ(String8("Widevine CDM"), stringResult);
|
EXPECT_STREQ("Widevine CDM", stringResult.string());
|
||||||
|
|
||||||
res = plugin.getPropertyString(String8("algorithms"), stringResult);
|
res = plugin.getPropertyString(String8("algorithms"), stringResult);
|
||||||
ASSERT_EQ(OK, res);
|
ASSERT_EQ(OK, res);
|
||||||
EXPECT_EQ(String8("AES/CBC/NoPadding,HmacSHA256"), stringResult);
|
EXPECT_STREQ("AES/CBC/NoPadding,HmacSHA256", stringResult.string());
|
||||||
|
|
||||||
res = plugin.getPropertyString(String8("securityLevel"), stringResult);
|
res = plugin.getPropertyString(String8("securityLevel"), stringResult);
|
||||||
ASSERT_EQ(OK, res);
|
ASSERT_EQ(OK, res);
|
||||||
EXPECT_EQ(String8("L1"), stringResult);
|
EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L1.c_str(), stringResult.string());
|
||||||
|
|
||||||
res = plugin.getPropertyString(String8("securityLevel"), stringResult);
|
res = plugin.getPropertyString(String8("securityLevel"), stringResult);
|
||||||
ASSERT_EQ(OK, res);
|
ASSERT_EQ(OK, res);
|
||||||
EXPECT_EQ(String8("L3"), stringResult);
|
EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L3.c_str(), stringResult.string());
|
||||||
|
|
||||||
Vector<uint8_t> vectorResult;
|
|
||||||
|
|
||||||
res = plugin.getPropertyByteArray(String8("deviceUniqueId"), vectorResult);
|
res = plugin.getPropertyByteArray(String8("deviceUniqueId"), vectorResult);
|
||||||
ASSERT_EQ(OK, res);
|
ASSERT_EQ(OK, res);
|
||||||
EXPECT_THAT(vectorResult, ElementsAreArray(uniqueId.data(), uniqueId.size()));
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WVDrmPluginTest, DoesNotGetUnknownProperties) {
|
TEST_F(WVDrmPluginTest, DoesNotGetUnknownProperties) {
|
||||||
|
|||||||
Reference in New Issue
Block a user