Fix System ID problem for devices with no keybox am: f6d682b182 am: bf776ef27d
Original change: https://googleplex-android-review.googlesource.com/c/platform/vendor/widevine/+/16408945 Change-Id: I5e1965104ff03a6d973ecf3727121d9f91dc1e26
This commit is contained in:
committed by
Automerger Merge Worker
commit
1373c554a8
@@ -90,6 +90,13 @@ static_assert(ArraySize(kMaxSubsampleRegionSizes) ==
|
||||
|
||||
constexpr size_t kDefaultMaxSubsampleRegionSize = kMaxSubsampleRegionSizes[0];
|
||||
|
||||
// Not a valid system ID. Used as a placeholder for systems without an ID.
|
||||
// Will not be accepted for DRM provisioning requests or license requests.
|
||||
constexpr uint32_t kNullSystemId =
|
||||
static_cast<uint32_t>(std::numeric_limits<int>::max());
|
||||
|
||||
constexpr size_t kMaxExternalDeviceIdLength = 64;
|
||||
|
||||
// This maps a few common OEMCryptoResult to CdmResponseType. Many mappings
|
||||
// are not universal but are OEMCrypto method specific. Those will be
|
||||
// specified in the CryptoSession method rather than here.
|
||||
@@ -477,7 +484,6 @@ bool CryptoSession::SetUpUsageTableHeader(
|
||||
CdmResponseType CryptoSession::GetTokenFromKeybox(std::string* token) {
|
||||
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||
RETURN_IF_NULL(token, PARAMETER_NULL);
|
||||
|
||||
std::string temp_buffer(KEYBOX_KEY_DATA_SIZE, '\0');
|
||||
size_t buf_size = temp_buffer.size();
|
||||
uint8_t* buf = reinterpret_cast<uint8_t*>(&temp_buffer[0]);
|
||||
@@ -613,68 +619,72 @@ CdmResponseType CryptoSession::GetInternalDeviceUniqueId(
|
||||
RETURN_IF_NULL(device_id, PARAMETER_NULL);
|
||||
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||
|
||||
std::vector<uint8_t> id;
|
||||
size_t id_length = 32;
|
||||
id.resize(id_length);
|
||||
size_t device_id_length = 64;
|
||||
device_id->assign(device_id_length, '\0');
|
||||
|
||||
OEMCryptoResult sts;
|
||||
WithOecReadLock("GetInternalDeviceUniqueId Attempt 1", [&] {
|
||||
sts = OEMCrypto_GetDeviceID(&id[0], &id_length, requested_security_level_);
|
||||
});
|
||||
// Increment the count of times this method was called.
|
||||
OEMCryptoResult sts =
|
||||
WithOecReadLock("GetInternalDeviceUniqueId Attempt 1", [&] {
|
||||
return OEMCrypto_GetDeviceID(
|
||||
reinterpret_cast<uint8_t*>(&device_id->front()), &device_id_length,
|
||||
requested_security_level_);
|
||||
});
|
||||
metrics_->oemcrypto_get_device_id_.Increment(sts);
|
||||
|
||||
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
id.resize(id_length);
|
||||
WithOecReadLock("GetInternalDeviceUniqueId Attempt 2", [&] {
|
||||
sts =
|
||||
OEMCrypto_GetDeviceID(&id[0], &id_length, requested_security_level_);
|
||||
device_id->resize(device_id_length, '\0');
|
||||
sts = WithOecReadLock("GetInternalDeviceUniqueId Attempt 2", [&] {
|
||||
return OEMCrypto_GetDeviceID(
|
||||
reinterpret_cast<uint8_t*>(&device_id->front()), &device_id_length,
|
||||
requested_security_level_);
|
||||
});
|
||||
metrics_->oemcrypto_get_device_id_.Increment(sts);
|
||||
}
|
||||
|
||||
// Either the authentication root is a keybox or the device has transitioned
|
||||
// to using OEMCerts.
|
||||
// OEMCryptos, like the Level 3, that transition from Provisioning 2.0 to
|
||||
// 3.0 would have a new device ID, which would affect SPOID calculation.
|
||||
// In order to resolve this, we use OEMCrypto_GetDeviceID if it is
|
||||
// implemented, so the OEMCrypto can continue to report the same device ID.
|
||||
if (sts == OEMCrypto_SUCCESS) {
|
||||
device_id->resize(device_id_length);
|
||||
return NO_ERROR;
|
||||
}
|
||||
device_id->clear();
|
||||
|
||||
if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED &&
|
||||
pre_provision_token_type_ == kClientTokenOemCert) {
|
||||
return GetTokenFromOemCert(device_id);
|
||||
} else {
|
||||
// Either the authentication root is a keybox or the device has transitioned
|
||||
// to using OEMCerts.
|
||||
// OEMCryptos, like the Level 3, that transition from Provisioning 2.0 to
|
||||
// 3.0 would have a new device ID, which would affect SPOID calculation.
|
||||
// In order to resolve this, we use OEMCrypto_GetDeviceID if it is
|
||||
// implemented, so the OEMCrypto can continue to report the same device ID.
|
||||
if (sts == OEMCrypto_SUCCESS) {
|
||||
device_id->assign(reinterpret_cast<char*>(&id[0]), id_length);
|
||||
}
|
||||
|
||||
return MapOEMCryptoResult(sts, GET_DEVICE_ID_ERROR,
|
||||
"GetInternalDeviceUniqueId");
|
||||
}
|
||||
|
||||
const bool use_null_device_id = WithStaticFieldReadLock(
|
||||
"GetInternalDeviceUniqueId() use_null_device_id", [&] {
|
||||
if (requested_security_level_ != kLevelDefault) return false;
|
||||
return sts == OEMCrypto_ERROR_KEYBOX_INVALID &&
|
||||
needs_keybox_provisioning_;
|
||||
});
|
||||
if (use_null_device_id) {
|
||||
LOGD("Using null device ID");
|
||||
constexpr size_t kKeyboxDeviceIdLength = 32;
|
||||
device_id->assign(kKeyboxDeviceIdLength, '\0');
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
return MapOEMCryptoResult(sts, GET_DEVICE_ID_ERROR,
|
||||
"GetInternalDeviceUniqueId");
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GetExternalDeviceUniqueId(
|
||||
std::string* device_id) {
|
||||
RETURN_IF_NULL(device_id, PARAMETER_NULL);
|
||||
|
||||
std::string temp;
|
||||
CdmResponseType status = GetInternalDeviceUniqueId(&temp);
|
||||
|
||||
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||
const CdmResponseType status = GetInternalDeviceUniqueId(device_id);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
size_t id_length = 0;
|
||||
OEMCryptoResult sts;
|
||||
WithOecReadLock("GetExternalDeviceUniqueId", [&] {
|
||||
sts = OEMCrypto_GetDeviceID(nullptr, &id_length, requested_security_level_);
|
||||
});
|
||||
metrics_->oemcrypto_get_device_id_.Increment(sts);
|
||||
|
||||
if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED &&
|
||||
pre_provision_token_type_ == kClientTokenOemCert) {
|
||||
if (device_id->size() > kMaxExternalDeviceIdLength) {
|
||||
// To keep the size of the value passed back to the application down, hash
|
||||
// the large OEM Public Cert to a smaller value.
|
||||
temp = Sha256Hash(temp);
|
||||
*device_id = Sha256Hash(*device_id);
|
||||
}
|
||||
|
||||
*device_id = temp;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -736,11 +746,22 @@ CdmResponseType CryptoSession::GetSystemIdInternal(uint32_t* system_id) {
|
||||
RETURN_IF_NULL(system_id, PARAMETER_NULL);
|
||||
|
||||
if (pre_provision_token_type_ == kClientTokenKeybox) {
|
||||
const bool use_null_system_id = WithStaticFieldReadLock(
|
||||
"GetSystemIdInternal() use_null_system_id", [&] {
|
||||
// Devices with an invalid L1 keybox which support OTA keybox
|
||||
// provisioning require a placeholder system ID while waiting for
|
||||
// keybox.
|
||||
if (requested_security_level_ != kLevelDefault) return false;
|
||||
return needs_keybox_provisioning_;
|
||||
});
|
||||
if (use_null_system_id) {
|
||||
LOGD("Using null system ID");
|
||||
*system_id = kNullSystemId;
|
||||
return NO_ERROR;
|
||||
}
|
||||
std::string token;
|
||||
CdmResponseType status = GetTokenFromKeybox(&token);
|
||||
|
||||
const CdmResponseType status = GetTokenFromKeybox(&token);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
if (token.size() < 2 * sizeof(uint32_t)) {
|
||||
LOGE("Keybox token size too small: token_size = %zu", token.size());
|
||||
return KEYBOX_TOKEN_TOO_SHORT;
|
||||
@@ -748,7 +769,7 @@ CdmResponseType CryptoSession::GetSystemIdInternal(uint32_t* system_id) {
|
||||
|
||||
// Decode 32-bit int encoded as network-byte-order byte array starting at
|
||||
// index 4.
|
||||
uint32_t* id = reinterpret_cast<uint32_t*>(&token[4]);
|
||||
const uint32_t* id = reinterpret_cast<const uint32_t*>(&token[4]);
|
||||
*system_id = ntohl(*id);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user