Revise a few metrics and add unit tests.
This is a merge of Widevine cl 39040. A few of the metrics were not implemented, or implemented incorrectly in O MR1. This cleans them up Bug: 64001676 Test: Re-ran unit tests and added some additional tests. GPlay Movies check. Change-Id: I1e8bcc36fecd76e72d853306075bc46d82f45161
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Encode unsigned integer into a big endian formatted string
|
||||
std::string EncodeUint32(unsigned int u) {
|
||||
std::string s;
|
||||
@@ -32,6 +33,7 @@ std::string EncodeUint32(unsigned int u) {
|
||||
s.append(1, (u >> 0) & 0xFF);
|
||||
return s;
|
||||
}
|
||||
|
||||
size_t GetOffset(std::string message, std::string field) {
|
||||
size_t pos = message.find(field);
|
||||
if (pos == std::string::npos) {
|
||||
@@ -40,6 +42,7 @@ size_t GetOffset(std::string message, std::string field) {
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
void GenerateMacContext(const std::string& input_context,
|
||||
std::string* deriv_context) {
|
||||
if (!deriv_context) {
|
||||
@@ -677,6 +680,7 @@ class SubLicenseKeySession : public KeySession {
|
||||
|
||||
CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
|
||||
: metrics_(metrics),
|
||||
system_id_(-1),
|
||||
open_(false),
|
||||
update_usage_table_after_close_session_(false),
|
||||
is_destination_buffer_type_valid_(false),
|
||||
@@ -700,9 +704,11 @@ CryptoSession::~CryptoSession() {
|
||||
}
|
||||
|
||||
bool CryptoSession::GetProvisioningMethod(CdmClientTokenType* token_type) {
|
||||
OEMCrypto_ProvisioningMethod method;
|
||||
OEMCrypto_ProvisioningMethod method =
|
||||
OEMCrypto_GetProvisioningMethod(requested_security_level_);
|
||||
metrics_->oemcrypto_provisioning_method_.Record(method);
|
||||
CdmClientTokenType type;
|
||||
switch (method = OEMCrypto_GetProvisioningMethod(requested_security_level_)) {
|
||||
switch (method) {
|
||||
case OEMCrypto_OEMCertificate:
|
||||
type = kClientTokenOemCert;
|
||||
break;
|
||||
@@ -714,7 +720,8 @@ bool CryptoSession::GetProvisioningMethod(CdmClientTokenType* token_type) {
|
||||
break;
|
||||
case OEMCrypto_ProvisioningError:
|
||||
default:
|
||||
LOGE("OEMCrypto_GetProvisioningMethod failed", method);
|
||||
LOGE("OEMCrypto_GetProvisioningMethod failed. %d", method);
|
||||
metrics_->oemcrypto_provisioning_method_.SetError(method);
|
||||
return false;
|
||||
}
|
||||
*token_type = type;
|
||||
@@ -805,13 +812,14 @@ bool CryptoSession::GetTokenFromOemCert(std::string* token) {
|
||||
size_t buf_size = temp_buffer.size();
|
||||
uint8_t* buf = reinterpret_cast<uint8_t*>(&temp_buffer[0]);
|
||||
status = OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf, &buf_size);
|
||||
metrics_->oemcrypto_get_oem_public_certificate_.Increment(status);
|
||||
if (OEMCrypto_SUCCESS == status) {
|
||||
temp_buffer.resize(buf_size);
|
||||
oem_token_.assign(temp_buffer);
|
||||
token->assign(temp_buffer);
|
||||
return true;
|
||||
}
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER && !retrying) {
|
||||
if (status == OEMCrypto_ERROR_SHORT_BUFFER && !retrying) {
|
||||
temp_buffer.resize(buf_size);
|
||||
retrying = true;
|
||||
continue;
|
||||
@@ -821,42 +829,28 @@ bool CryptoSession::GetTokenFromOemCert(std::string* token) {
|
||||
}
|
||||
}
|
||||
|
||||
bool CryptoSession::GetClientToken(std::string* token) {
|
||||
if (!token) {
|
||||
LOGE("CryptoSession::GetClientToken : No token passed to method.");
|
||||
return false;
|
||||
}
|
||||
LOGV("CryptoSession::GetClientToken: Lock");
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
if (!initialized_) {
|
||||
return false;
|
||||
}
|
||||
// Only keybox is used for client token. All other cases use DRM Cert.
|
||||
if (pre_provision_token_type_ != kClientTokenKeybox) {
|
||||
return false;
|
||||
}
|
||||
return GetTokenFromKeybox(token);
|
||||
}
|
||||
|
||||
bool CryptoSession::GetProvisioningToken(std::string* token) {
|
||||
if (!token) {
|
||||
LOGE("CryptoSession::GetProvisioningToken : No token passed to method.");
|
||||
metrics_->crypto_session_get_token_.Increment(false);
|
||||
return false;
|
||||
}
|
||||
LOGV("CryptoSession::GetProvisioningToken: Lock");
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
|
||||
if (!initialized_) {
|
||||
metrics_->crypto_session_get_token_.Increment(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
if (pre_provision_token_type_ == kClientTokenKeybox) {
|
||||
return GetTokenFromKeybox(token);
|
||||
result = GetTokenFromKeybox(token);
|
||||
} else if (pre_provision_token_type_ == kClientTokenOemCert) {
|
||||
return GetTokenFromOemCert(token);
|
||||
} else {
|
||||
return false;
|
||||
result = GetTokenFromOemCert(token);
|
||||
}
|
||||
metrics_->crypto_session_get_token_.Increment(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
CdmSecurityLevel CryptoSession::GetSecurityLevel() {
|
||||
@@ -977,7 +971,19 @@ bool CryptoSession::GetSystemId(uint32_t* system_id) {
|
||||
|
||||
LOGV("CryptoSession::GetSystemId: Lock");
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
if (!initialized_) {
|
||||
if (!initialized_ || !open_) {
|
||||
return false;
|
||||
}
|
||||
*system_id = system_id_;
|
||||
return true;
|
||||
}
|
||||
|
||||
// This method gets the system id from the keybox key data.
|
||||
// This method assumes that OEMCrypto has been initialized and that
|
||||
// the caller has acquired the crypto_lock_ before making this call.
|
||||
bool CryptoSession::GetSystemIdInternal(uint32_t* system_id) {
|
||||
if (!system_id) {
|
||||
LOGE("CryptoSession::GetSystemIdInternal: No system_id passed to method.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -991,8 +997,8 @@ bool CryptoSession::GetSystemId(uint32_t* system_id) {
|
||||
metrics_, oemcrypto_get_key_data_, sts, metrics::Pow2Bucket(buf_size));
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGE("CryptoSession::GetSystemId: OEMCrypto_GetKeyData failed with %d",
|
||||
sts);
|
||||
LOGE("CryptoSession::GetSystemIdInternal: "
|
||||
"OEMCrypto_GetKeyData failed with %d", sts);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1010,9 +1016,13 @@ bool CryptoSession::GetSystemId(uint32_t* system_id) {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if (pre_provision_token_type_ == kClientTokenDrmCert) {
|
||||
// TODO(blueeyes): Support loading the system id from a pre-provisioned
|
||||
// Drm certificate.
|
||||
return true;
|
||||
} else {
|
||||
LOGE("CryptoSession::GetSystemId: Unsupported pre-provision token type %d",
|
||||
pre_provision_token_type_);
|
||||
LOGE("CryptoSession::GetSystemIdInternal: "
|
||||
"Unsupported pre-provision token type %d", pre_provision_token_type_);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1023,7 +1033,8 @@ bool CryptoSession::ExtractSystemIdFromOemCert(const std::string& oem_cert,
|
||||
const boringssl_ptr<STACK_OF(X509), DeleteX509Stack> x509_stack(
|
||||
sk_X509_new_null());
|
||||
if (x509_stack.get() == NULL) {
|
||||
LOGE("CryptoSession::GetSystemId: Unable to allocate X509 Stack.");
|
||||
LOGE("CryptoSession::ExtractSystemIdFromOemCert: "
|
||||
"Unable to allocate X509 Stack.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1031,7 +1042,8 @@ bool CryptoSession::ExtractSystemIdFromOemCert(const std::string& oem_cert,
|
||||
CBS_init(&pkcs7, reinterpret_cast<const uint8_t*>(oem_cert.data()),
|
||||
oem_cert.size());
|
||||
if (!PKCS7_get_certificates(x509_stack.get(), &pkcs7)) {
|
||||
LOGE("CryptoSession::GetSystemId: Error getting certificate chain.");
|
||||
LOGE("CryptoSession::ExtractSystemIdFromOemCert: "
|
||||
"Error getting certificate chain.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1039,14 +1051,16 @@ bool CryptoSession::ExtractSystemIdFromOemCert(const std::string& oem_cert,
|
||||
|
||||
// Get the Widevine intermediate cert from the stack
|
||||
if (sk_X509_num(certs) != 2) {
|
||||
LOGE("CryptoSession::GetSystemId: Expected 2 certificates in chain, got %d",
|
||||
LOGE("CryptoSession::ExtractSystemIdFromOemCert: "
|
||||
"Expected 2 certificates in chain, got %d",
|
||||
sk_X509_num(certs));
|
||||
return false;
|
||||
}
|
||||
|
||||
X509* const intermediate_cert = sk_X509_value(certs, 1);
|
||||
if (!intermediate_cert) {
|
||||
LOGE("CryptoSession::GetSystemId: Unable to get intermediate cert.");
|
||||
LOGE("CryptoSession::ExtractSystemIdFromOemCert: "
|
||||
"Unable to get intermediate cert.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1055,16 +1069,15 @@ bool CryptoSession::ExtractSystemIdFromOemCert(const std::string& oem_cert,
|
||||
for (int i = 0; i < extension_count; ++i) {
|
||||
X509_EXTENSION* const extension = X509_get_ext(intermediate_cert, i);
|
||||
if (!extension) {
|
||||
LOGE("CryptoSession::GetSystemId: Unable to get cert extension %d", i);
|
||||
LOGE("CryptoSession::ExtractSystemIdFromOemCert: "
|
||||
"Unable to get cert extension %d", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
ASN1_OBJECT* const extension_object = X509_EXTENSION_get_object(extension);
|
||||
if (!extension_object) {
|
||||
LOGE(
|
||||
"CryptoSession::GetSystemId: Unable to get object of cert "
|
||||
"extension %d",
|
||||
i);
|
||||
LOGE("CryptoSession::ExtractSystemIdFromOemCert: "
|
||||
"Unable to get object of cert extension %d", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1078,35 +1091,31 @@ bool CryptoSession::ExtractSystemIdFromOemCert(const std::string& oem_cert,
|
||||
|
||||
ASN1_OCTET_STRING* const octet_str = X509_EXTENSION_get_data(extension);
|
||||
if (!octet_str) {
|
||||
LOGE(
|
||||
"CryptoSession::GetSystemId: Unable to get data of Widevine System "
|
||||
"ID extension.");
|
||||
LOGE("CryptoSession::ExtractSystemIdFromOemCert: "
|
||||
"Unable to get data of Widevine System ID extension.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const unsigned char* data = octet_str->data;
|
||||
if (!data) {
|
||||
LOGE(
|
||||
"CryptoSession::GetSystemId: Null data in Widevine System ID "
|
||||
"extension.");
|
||||
LOGE("CryptoSession::ExtractSystemIdFromOemCert: "
|
||||
"Null data in Widevine System ID extension.");
|
||||
return false;
|
||||
}
|
||||
|
||||
ASN1_INTEGER* const asn1_integer =
|
||||
d2i_ASN1_INTEGER(NULL, &data, octet_str->length);
|
||||
if (!asn1_integer) {
|
||||
LOGE(
|
||||
"CryptoSession::GetSystemId: Unable to decode data in Widevine "
|
||||
"System ID extension.");
|
||||
LOGE("CryptoSession::ExtractSystemIdFromOemCert: "
|
||||
"Unable to decode data in Widevine System ID extension.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const long system_id_long = ASN1_INTEGER_get(asn1_integer);
|
||||
ASN1_INTEGER_free(asn1_integer);
|
||||
if (system_id_long == -1) {
|
||||
LOGE(
|
||||
"CryptoSession::GetSystemId: Unable to decode ASN integer in "
|
||||
"Widevine System ID extension.");
|
||||
LOGE("CryptoSession::ExtractSystemIdFromOemCert: "
|
||||
"Unable to decode ASN integer in Widevine System ID extension.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1114,7 +1123,8 @@ bool CryptoSession::ExtractSystemIdFromOemCert(const std::string& oem_cert,
|
||||
return true;
|
||||
}
|
||||
|
||||
LOGE("CryptoSession::GetSystemId: Widevine System ID extension not found.");
|
||||
LOGE("CryptoSession::ExtractSystemIdFromOemCert: "
|
||||
"Widevine System ID extension not found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1191,13 +1201,25 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||
session_count_, (int)initialized_);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
// Get System ID and save it.
|
||||
if (GetSystemIdInternal(&system_id_)) {
|
||||
metrics_->crypto_session_system_id_.Record(system_id_);
|
||||
} else {
|
||||
LOGE("CryptoSession::Open: Failed to fetch system id.");
|
||||
metrics_->crypto_session_system_id_.SetError(LOAD_SYSTEM_ID_ERROR);
|
||||
return LOAD_SYSTEM_ID_ERROR;
|
||||
}
|
||||
|
||||
OEMCryptoResult random_sts = OEMCrypto_GetRandom(
|
||||
reinterpret_cast<uint8_t*>(&request_id_base_), sizeof(request_id_base_));
|
||||
metrics_->oemcrypto_get_random_.Increment(random_sts);
|
||||
++request_id_index_;
|
||||
|
||||
CdmUsageSupportType usage_support_type;
|
||||
if (GetUsageSupportType(&usage_support_type) == NO_ERROR) {
|
||||
CdmResponseType result = GetUsageSupportType(&usage_support_type);
|
||||
if (result == NO_ERROR) {
|
||||
metrics_->oemcrypto_usage_table_support_.Record(usage_support_type);
|
||||
if (usage_support_type == kUsageEntrySupport) {
|
||||
CdmSecurityLevel security_level = GetSecurityLevel();
|
||||
if (security_level == kSecurityLevelL1 ||
|
||||
@@ -1224,6 +1246,8 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||
usage_table_header_ = *header;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
metrics_->oemcrypto_usage_table_support_.SetError(result);
|
||||
}
|
||||
|
||||
// TODO(gmorgan, jfore): resolve handling of usage records in sublicenses
|
||||
@@ -1361,6 +1385,7 @@ bool CryptoSession::LoadCertificatePrivateKey(std::string& wrapped_key) {
|
||||
uint8_t* buf = reinterpret_cast<uint8_t*>(&temp_buffer[0]);
|
||||
OEMCryptoResult sts =
|
||||
OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf, &buf_size);
|
||||
metrics_->oemcrypto_get_oem_public_certificate_.Increment(sts);
|
||||
|
||||
LOGV("LoadDeviceRSAKey: id=%ld", (uint32_t)oec_session_id_);
|
||||
M_TIME(
|
||||
@@ -2032,10 +2057,15 @@ bool CryptoSession::RewrapDeviceRSAKey30(const std::string& message,
|
||||
// Gets wrapped_rsa_key_length by passing NULL as uint8_t* wrapped_rsa_key
|
||||
// and 0 as wrapped_rsa_key_length.
|
||||
size_t wrapped_private_key_length = 0;
|
||||
OEMCryptoResult status = OEMCrypto_RewrapDeviceRSAKey30(
|
||||
oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(),
|
||||
msg_private_key, private_key.size(), msg_iv, NULL,
|
||||
&wrapped_private_key_length);
|
||||
OEMCryptoResult status;
|
||||
M_TIME(
|
||||
status = OEMCrypto_RewrapDeviceRSAKey30(
|
||||
oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(),
|
||||
msg_private_key, private_key.size(), msg_iv, NULL,
|
||||
&wrapped_private_key_length),
|
||||
metrics_,
|
||||
oemcrypto_rewrap_device_rsa_key_30_,
|
||||
status);
|
||||
|
||||
if (status != OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
LOGE("OEMCrypto_RewrapDeviceRSAKey30 failed getting wrapped key length");
|
||||
@@ -2043,11 +2073,15 @@ bool CryptoSession::RewrapDeviceRSAKey30(const std::string& message,
|
||||
}
|
||||
|
||||
wrapped_private_key->resize(wrapped_private_key_length);
|
||||
status = OEMCrypto_RewrapDeviceRSAKey30(
|
||||
oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(),
|
||||
msg_private_key, private_key.size(), msg_iv,
|
||||
reinterpret_cast<uint8_t*>(&(*wrapped_private_key)[0]),
|
||||
&wrapped_private_key_length);
|
||||
M_TIME(
|
||||
status = OEMCrypto_RewrapDeviceRSAKey30(
|
||||
oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(),
|
||||
msg_private_key, private_key.size(), msg_iv,
|
||||
reinterpret_cast<uint8_t*>(&(*wrapped_private_key)[0]),
|
||||
&wrapped_private_key_length),
|
||||
metrics_,
|
||||
oemcrypto_rewrap_device_rsa_key_30_,
|
||||
status);
|
||||
|
||||
wrapped_private_key->resize(wrapped_private_key_length);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user