Move system ID extraction outside of CryptoSession.

[ Merge of http://go/wvgerrit/151391 ]

This CL moves the logic for extracting the system ID from keybox or
OEM certificate (from OEMCrypto or device files) to a dedicated
SystemIdExtractor.

Before Provisioning 4.0, the system ID could only be found from data
returned by OEMCrypto.  However, with provisioning 4.0, the system ID
can now be found in the OEM certificate that is stored on the device
files.

Bug: 232020319
Test: system_id_extractor_unittest
Test: Forest L37800000954493485
Change-Id: Ie1b7987906e2e4fef015cd659a947b6dbb7594b1
This commit is contained in:
Alex Dale
2022-05-09 16:51:39 -07:00
parent 8ac7ca3f46
commit 9d169a00bb
12 changed files with 945 additions and 431 deletions

View File

@@ -73,6 +73,7 @@ WV_UNITTESTS="base64_test \
request_license_test \
rw_lock_test \
service_certificate_unittest \
system_id_extractor_unittest \
timer_unittest \
usage_table_header_unittest \
value_metric_unittest \

View File

@@ -63,6 +63,7 @@ cc_library_static {
CORE_SRC_DIR + "/policy_timers_v16.cpp",
CORE_SRC_DIR + "/privacy_crypto_boringssl.cpp",
CORE_SRC_DIR + "/service_certificate.cpp",
CORE_SRC_DIR + "/system_id_extractor.cpp",
CORE_SRC_DIR + "/usage_table_header.cpp",
CORE_SRC_DIR + "/wv_cdm_types.cpp",
SRC_DIR + "/wv_content_decryption_module.cpp",

View File

@@ -82,12 +82,28 @@ class CryptoSession {
static void DisableDelayedTermination();
virtual CdmResponseType GetProvisioningToken(
RequestedSecurityLevel requested_security_level, std::string* token,
std::string* additional_token);
// Must be called after session is open.
virtual CdmResponseType GetProvisioningToken(std::string* token,
std::string* additional_token);
virtual CdmClientTokenType GetPreProvisionTokenType() {
return pre_provision_token_type_;
}
// Retrieves the key data portion of the OEMCrypto keybox.
// Only valid for keybox-based based devices.
// May return NEED_PROVISIONING if the device is keybox-based, but
// OTA keybox provisioning is required.
virtual CdmResponseType GetTokenFromKeybox(
RequestedSecurityLevel requested_security_level, std::string* key_data);
// Retrieves the public OEM certificate chain from OEMCrypto.
// Only valid for OEM certificate-based based devices.
virtual CdmResponseType GetTokenFromOemCert(
RequestedSecurityLevel requested_security_level, std::string* oem_cert);
// The overloaded methods with |requested_level| may be called
// without a preceding call to Open. The other method must call Open first.
virtual CdmSecurityLevel GetSecurityLevel();
@@ -114,10 +130,15 @@ class CryptoSession {
// - that does not implement |OEMCrypto_GetDeviceID|: the 32 byte hash
// of the OEM public certificate.
virtual CdmResponseType GetExternalDeviceUniqueId(std::string* device_id);
virtual bool GetSystemId(uint32_t* system_id);
virtual CdmResponseType GetProvisioningId(std::string* provisioning_id);
virtual uint8_t GetSecurityPatchLevel();
virtual bool GetCachedSystemId(uint32_t* system_id);
// With provisioning 4.0, the system ID cannot reliably be found within
// OEMCrypto. The system ID can be assigned to the CryptoSession instance
// after the ID has been determined.
virtual void SetSystemId(uint32_t system_id);
virtual CdmResponseType Open() { return Open(kLevelDefault); }
virtual CdmResponseType Open(RequestedSecurityLevel requested_security_level);
virtual void Close();
@@ -179,6 +200,9 @@ class CryptoSession {
std::string* wrapped_private_key);
virtual CdmResponseType LoadCertificatePrivateKey(
const CryptoWrappedKey& private_key);
virtual CdmResponseType GetBootCertificateChain(
RequestedSecurityLevel requested_security_level, std::string* bcc,
std::string* additional_signature);
virtual CdmResponseType GetBootCertificateChain(
std::string* bcc, std::string* additional_signature);
virtual CdmResponseType GenerateCertificateKeyPair(
@@ -377,11 +401,6 @@ class CryptoSession {
// Note: This function will lock the global static field lock in write mode.
bool SetUpUsageTableHeader(RequestedSecurityLevel requested_security_level);
CdmResponseType GetTokenFromKeybox(std::string* token);
CdmResponseType GetTokenFromOemCert(std::string* token);
static bool ExtractSystemIdFromOemCert(const std::string& oem_cert,
uint32_t* system_id);
CdmResponseType GetSystemIdInternal(uint32_t* system_id);
CdmResponseType GenerateRsaSignature(const std::string& message,
std::string* signature);
size_t GetMaxSubsampleRegionSize();

View File

@@ -0,0 +1,68 @@
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#ifndef WVCDM_CORE_SYSTEM_ID_EXTRACTOR_H_
#define WVCDM_CORE_SYSTEM_ID_EXTRACTOR_H_
#include <stdint.h>
#include "wv_cdm_types.h"
namespace wvutil {
class FileSystem;
} // namespace wvutil
namespace wvcdm {
class CryptoSession;
class DeviceFiles;
// System ID extractor will find and extract the system ID of the device.
// Handles the different cases where the system ID may be found in
// different place.
class SystemIdExtractor {
public:
SystemIdExtractor(RequestedSecurityLevel security_level,
CryptoSession* crypto_session, wvutil::FileSystem* fs);
virtual ~SystemIdExtractor() {}
// Disallow copy and move.
SystemIdExtractor(const SystemIdExtractor&) = delete;
SystemIdExtractor(SystemIdExtractor&&) = delete;
SystemIdExtractor& operator=(const SystemIdExtractor&) = delete;
SystemIdExtractor& operator=(SystemIdExtractor&&) = delete;
virtual bool ExtractSystemId(uint32_t* system_id);
// Extracts the system ID from a keybox key data (aka CA token).
static bool ExtractSystemIdFromKeyboxData(const std::string& key_data,
uint32_t* system_id);
// Extracts the system ID from a serialized OEM certificate.
static bool ExtractSystemIdFromOemCert(const std::string& oem_cert,
uint32_t* system_id);
void SetDeviceFilesForTesting(DeviceFiles* device_files) {
test_device_files_ = device_files;
}
private:
// Extracts the system ID from keybox-based OEMCrypto implementations.
// System ID is expected to be found in the keybox data. Devices
// which require OTA keybox provisioning will return a null system ID.
bool ExtractSystemIdProv20(uint32_t* system_id);
// Extracts the system ID from OEM certificate-based OEMCrypto
// implementations. System ID is expected to be in the manufacturers
// intermediate X.509 certificate.
bool ExtractSystemIdProv30(uint32_t* system_id);
// Extracts the system ID from BCC-based OEMCrypto implementations.
// System ID is expected to be found in the stored OEM certificate
// for the provided origin-identifier, after BCC provisioning.
// Clients which have not performed BCC provisioning will return
// a null system ID.
bool ExtractSystemIdProv40(uint32_t* system_id);
RequestedSecurityLevel security_level_ = kLevelDefault;
CryptoSession* crypto_session_ = nullptr;
wvutil::FileSystem* fs_ = nullptr;
DeviceFiles* test_device_files_ = nullptr;
};
} // namespace wvcdm
#endif // WVCDM_CORE_SYSTEM_ID_EXTRACTOR_H_

View File

@@ -5,6 +5,7 @@
#ifndef WVCDM_CORE_WV_CDM_CONSTANTS_H_
#define WVCDM_CORE_WV_CDM_CONSTANTS_H_
#include <limits>
#include <string>
namespace wvcdm {
@@ -28,6 +29,11 @@ static const int64_t NEVER_EXPIRES = 0;
static const int64_t UNLIMITED_DURATION = 0;
static const int64_t INVALID_TIME = -1;
// 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.
static constexpr uint32_t NULL_SYSTEM_ID =
static_cast<uint32_t>(std::numeric_limits<int>::max());
// This is the lower limit. For OEMCrypto v16+ one can query and find how many
// are supported
static constexpr size_t kMinimumUsageTableEntriesSupported = 200;

View File

@@ -25,6 +25,7 @@
#include "ota_keybox_provisioner.h"
#include "properties.h"
#include "string_conversions.h"
#include "system_id_extractor.h"
#include "wv_cdm_constants.h"
#include "wv_cdm_event_listener.h"
@@ -839,6 +840,17 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level,
}
return NO_ERROR;
}
if (query_token == QUERY_KEY_SYSTEM_ID) {
SystemIdExtractor extractor(security_level, crypto_session.get(),
file_system_);
uint32_t system_id;
if (!extractor.ExtractSystemId(&system_id)) {
LOGW("ExtractSystemId failed");
return UNKNOWN_ERROR;
}
*query_response = std::to_string(system_id);
return NO_ERROR;
}
CdmResponseType status;
M_TIME(status = crypto_session->Open(security_level),
@@ -857,16 +869,6 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level,
*query_response = device_id;
return NO_ERROR;
}
if (query_token == QUERY_KEY_SYSTEM_ID) {
uint32_t system_id;
const bool got_id = crypto_session->GetSystemId(&system_id);
if (!got_id) {
LOGW("QUERY_KEY_SYSTEM_ID unknown failure");
return UNKNOWN_ERROR;
}
*query_response = std::to_string(system_id);
return NO_ERROR;
}
if (query_token == QUERY_KEY_PROVISIONING_ID) {
std::string provisioning_id;
status = crypto_session->GetProvisioningId(&provisioning_id);

View File

@@ -72,8 +72,6 @@ constexpr uint32_t kRsaSignatureLength = 256;
constexpr size_t kEstimatedInitialUsageTableHeader = 40;
const size_t kAes128BlockSize = 16;
// Constants and utility objects relating to OEM Certificates
constexpr const char* kWidevineSystemIdExtensionOid = "1.3.6.1.4.1.11129.4.1.1";
constexpr int kMaxTerminateCountDown = 5;
const std::string kStringNotAvailable = "NA";
@@ -100,11 +98,6 @@ static_assert(wvutil::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
@@ -269,7 +262,7 @@ OEMCryptoCipherMode ToOEMCryptoCipherMode(CdmCipherMode cipher_mode) {
CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
: metrics_(metrics),
system_id_(-1),
system_id_(NULL_SYSTEM_ID),
open_(false),
pre_provision_token_type_(kClientTokenUninitialized),
update_usage_table_after_close_session_(false),
@@ -525,76 +518,102 @@ bool CryptoSession::SetUpUsageTableHeader(
return true;
}
CdmResponseType CryptoSession::GetTokenFromKeybox(std::string* token) {
CdmResponseType CryptoSession::GetTokenFromKeybox(
RequestedSecurityLevel requested_security_level, std::string* key_data) {
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]);
RETURN_IF_NULL(key_data, PARAMETER_NULL);
LOGV("requested_security_level = %s",
RequestedSecurityLevelToString(requested_security_level));
// Devices with an invalid L1 keybox which support OTA keybox
// provisioning don't have keybox data.
const bool keybox_provisioning_required = WithStaticFieldReadLock(
"GetTokenFromKeybox - keybox_provisioning_required", [&] {
if (requested_security_level_ != kLevelDefault) return false;
return needs_keybox_provisioning_;
});
if (keybox_provisioning_required) return NEED_PROVISIONING;
size_t key_data_length = KEYBOX_KEY_DATA_SIZE;
key_data->assign(key_data_length, '\0');
OEMCryptoResult status;
WithOecReadLock("GetTokenFromKeybox", [&] {
M_TIME(status =
OEMCrypto_GetKeyData(buf, &buf_size, requested_security_level_),
M_TIME(status = OEMCrypto_GetKeyData(
reinterpret_cast<uint8_t*>(&key_data->front()), &key_data_length,
requested_security_level),
metrics_, oemcrypto_get_key_data_, status,
metrics::Pow2Bucket(buf_size));
metrics::Pow2Bucket(key_data_length));
});
if (OEMCrypto_SUCCESS == status) {
token->swap(temp_buffer);
key_data->resize(key_data_length);
return NO_ERROR;
}
key_data->clear();
return MapOEMCryptoResult(status, GET_TOKEN_FROM_KEYBOX_ERROR,
"GetTokenFromKeybox");
}
CdmResponseType CryptoSession::GetTokenFromOemCert(std::string* token) {
CdmResponseType CryptoSession::GetTokenFromOemCert(
RequestedSecurityLevel requested_security_level, std::string* oem_cert) {
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
RETURN_IF_NULL(token, PARAMETER_NULL);
RETURN_IF_NULL(oem_cert, PARAMETER_NULL);
LOGV("requested_security_level = %s",
RequestedSecurityLevelToString(requested_security_level));
OEMCryptoResult status;
if (!oem_token_.empty()) {
token->assign(oem_token_);
return NO_ERROR;
}
const bool cache_success =
WithOecSessionLock("GetTokenFromOemCert - check cached", [&] {
if (oem_token_.empty()) {
return false;
}
oem_cert->assign(oem_token_);
return true;
});
if (cache_success) return NO_ERROR;
std::string temp_buffer(CERTIFICATE_DATA_SIZE, '\0');
bool retrying = false;
while (true) {
size_t buf_size = temp_buffer.size();
uint8_t* buf = reinterpret_cast<uint8_t*>(&temp_buffer[0]);
WithOecSessionLock("GetTokenFromOemCert", [&] {
status = OEMCrypto_GetOEMPublicCertificate(buf, &buf_size,
requested_security_level_);
size_t oem_cert_length = CERTIFICATE_DATA_SIZE;
oem_cert->assign(oem_cert_length, '\0');
OEMCryptoResult status =
WithOecReadLock("GetTokenFromOemCert - attempt 1", [&] {
return OEMCrypto_GetOEMPublicCertificate(
reinterpret_cast<uint8_t*>(&oem_cert->front()), &oem_cert_length,
requested_security_level);
});
metrics_->oemcrypto_get_oem_public_certificate_.Increment(status);
if (status == OEMCrypto_ERROR_SHORT_BUFFER) {
oem_cert->assign(oem_cert_length, '\0');
status = WithOecReadLock("GetTokenFromOemCert - attempt 2", [&] {
return OEMCrypto_GetOEMPublicCertificate(
reinterpret_cast<uint8_t*>(&oem_cert->front()), &oem_cert_length,
requested_security_level);
});
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 NO_ERROR;
}
if (status == OEMCrypto_ERROR_SHORT_BUFFER && !retrying) {
temp_buffer.resize(buf_size);
retrying = true;
continue;
}
return MapOEMCryptoResult(status, GET_TOKEN_FROM_OEM_CERT_ERROR,
"GetTokenFromOemCert");
}
if (status == OEMCrypto_SUCCESS) {
oem_cert->resize(oem_cert_length);
WithOecSessionLock("GetTokenFromOemCert - set cache",
[&] { oem_token_ = *oem_cert; });
return NO_ERROR;
}
oem_cert->clear();
return MapOEMCryptoResult(status, GET_TOKEN_FROM_OEM_CERT_ERROR,
"GetTokenFromOemCert");
}
CdmResponseType CryptoSession::GetProvisioningToken(
std::string* token, std::string* additional_token) {
RETURN_IF_NOT_OPEN(CRYPTO_SESSION_NOT_OPEN);
return GetProvisioningToken(requested_security_level_, token,
additional_token);
}
CdmResponseType CryptoSession::GetProvisioningToken(
RequestedSecurityLevel requested_security_level, std::string* token,
std::string* additional_token) {
if (token == nullptr || additional_token == nullptr) {
metrics_->crypto_session_get_token_.Increment(PARAMETER_NULL);
RETURN_IF_NULL(token, PARAMETER_NULL);
RETURN_IF_NULL(additional_token, PARAMETER_NULL);
}
if (!IsInitialized()) {
metrics_->crypto_session_get_token_.Increment(
CRYPTO_SESSION_NOT_INITIALIZED);
@@ -603,11 +622,12 @@ CdmResponseType CryptoSession::GetProvisioningToken(
CdmResponseType status = UNKNOWN_CLIENT_TOKEN_TYPE;
if (pre_provision_token_type_ == kClientTokenKeybox) {
status = GetTokenFromKeybox(token);
status = GetTokenFromKeybox(requested_security_level, token);
} else if (pre_provision_token_type_ == kClientTokenOemCert) {
status = GetTokenFromOemCert(token);
status = GetTokenFromOemCert(requested_security_level, token);
} else if (pre_provision_token_type_ == kClientTokenBootCertChain) {
status = GetBootCertificateChain(token, additional_token);
status = GetBootCertificateChain(requested_security_level, token,
additional_token);
}
metrics_->crypto_session_get_token_.Increment(status);
return status;
@@ -689,7 +709,7 @@ CdmResponseType CryptoSession::GetInternalDeviceUniqueId(
if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED &&
pre_provision_token_type_ == kClientTokenOemCert) {
return GetTokenFromOemCert(device_id);
return GetTokenFromOemCert(requested_security_level_, device_id);
}
const bool use_null_device_id = WithStaticFieldReadLock(
@@ -772,84 +792,23 @@ bool CryptoSession::GetApiMinorVersion(RequestedSecurityLevel security_level,
return true;
}
bool CryptoSession::GetSystemId(uint32_t* system_id) {
bool CryptoSession::GetCachedSystemId(uint32_t* system_id) {
RETURN_IF_NULL(system_id, false);
RETURN_IF_UNINITIALIZED(false);
RETURN_IF_NOT_OPEN(false);
if (system_id_ == NULL_SYSTEM_ID) 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 before making this
// call.
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;
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;
}
// Decode 32-bit int encoded as network-byte-order byte array starting at
// index 4.
const uint32_t* id = reinterpret_cast<const uint32_t*>(&token[4]);
*system_id = ntohl(*id);
return NO_ERROR;
}
if (pre_provision_token_type_ == kClientTokenOemCert) {
// Get the OEM Cert
std::string oem_cert;
CdmResponseType status = GetTokenFromOemCert(&oem_cert);
if (status != NO_ERROR) return status;
if (!ExtractSystemIdFromOemCert(oem_cert, system_id))
return EXTRACT_SYSTEM_ID_FROM_OEM_CERT_ERROR;
return NO_ERROR;
}
if (pre_provision_token_type_ == kClientTokenDrmCert) {
// TODO(blueeyes): Support loading the system id from a pre-provisioned
// Drm certificate.
return NO_ERROR;
}
if (pre_provision_token_type_ == kClientTokenBootCertChain) {
// A system id can not be inferred from BCC. If the provisioning process has
// come to the second stage, we may read system id from the stored OEM cert.
return NO_ERROR;
}
LOGE("Unsupported pre-provision token type: %d",
static_cast<int>(pre_provision_token_type_));
return UNKNOWN_CLIENT_TOKEN_TYPE;
}
bool CryptoSession::ExtractSystemIdFromOemCert(const std::string& oem_cert,
uint32_t* system_id) {
return ExtractExtensionValueFromCertificate(
oem_cert, kWidevineSystemIdExtensionOid, /* cert_index */ 1, system_id);
void CryptoSession::SetSystemId(uint32_t system_id) {
if (!IsOpen()) return; // Ignore silently.
system_id_ = system_id;
metrics_->crypto_session_system_id_.Record(system_id_);
}
CdmResponseType CryptoSession::GetProvisioningId(std::string* provisioning_id) {
RETURN_IF_NULL(provisioning_id, PARAMETER_NULL);
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
RETURN_IF_NOT_OPEN(CRYPTO_SESSION_NOT_OPEN);
if (pre_provision_token_type_ == kClientTokenOemCert) {
// OEM Cert devices have no provisioning-unique ID embedded in them, so we
@@ -868,7 +827,8 @@ CdmResponseType CryptoSession::GetProvisioningId(std::string* provisioning_id) {
}
if (pre_provision_token_type_ == kClientTokenKeybox) {
std::string token;
CdmResponseType status = GetTokenFromKeybox(&token);
CdmResponseType status =
GetTokenFromKeybox(requested_security_level_, &token);
if (status != NO_ERROR) return status;
@@ -940,16 +900,6 @@ CdmResponseType CryptoSession::Open(
LOGV("Opened session: id = %u", oec_session_id_);
open_ = true;
// Get System ID and save it.
result = GetSystemIdInternal(&system_id_);
if (result == NO_ERROR) {
metrics_->crypto_session_system_id_.Record(system_id_);
} else {
LOGE("Failed to fetch system ID");
metrics_->crypto_session_system_id_.SetError(result);
return result;
}
// Set up request ID
uint64_t request_id_base;
OEMCryptoResult random_sts;
@@ -989,6 +939,8 @@ void CryptoSession::Close() {
// Clear cached values.
has_usage_info_support_ = kBooleanUnset;
oem_token_.clear();
system_id_ = NULL_SYSTEM_ID;
pre_provision_token_type_ = kClientTokenUninitialized;
if (close_sts != OEMCrypto_SUCCESS) {
LOGW("OEMCrypto_CloseSession failed: status = %d",
@@ -1412,13 +1364,26 @@ CdmResponseType CryptoSession::LoadCertificatePrivateKey(
CdmResponseType CryptoSession::GetBootCertificateChain(
std::string* bcc, std::string* additional_signature) {
RETURN_IF_NOT_OPEN(CRYPTO_SESSION_NOT_OPEN);
return GetBootCertificateChain(requested_security_level_, bcc,
additional_signature);
}
CdmResponseType CryptoSession::GetBootCertificateChain(
RequestedSecurityLevel requested_security_level, std::string* bcc,
std::string* additional_signature) {
RETURN_IF_NULL(bcc, PARAMETER_NULL);
RETURN_IF_NULL(additional_signature, PARAMETER_NULL);
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
LOGV("GetBootCertificateChain");
LOGV("requested_security_level = %s",
RequestedSecurityLevelToString(requested_security_level));
if (pre_provision_token_type_ != kClientTokenBootCertChain) {
return PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR;
}
if (requested_security_level != kLevelDefault) {
LOGE("CDM only supports L1 BCC");
return NOT_IMPLEMENTED_ERROR;
}
size_t bcc_length = 0;
size_t additional_signature_length = 0;
@@ -3346,12 +3311,6 @@ CdmResponseType CryptoSession::LoadOtaProvisioning(
WithOecWriteLock("LoadOtaProvisioning",
[&] { needs_keybox_provisioning_ = false; });
}
CdmResponseType result = GetSystemIdInternal(&system_id_);
if (result == NO_ERROR) {
LOGD("New system id is %d", system_id_);
} else {
LOGE("Failed to fetch system ID");
}
return MapOEMCryptoResult(status, UNKNOWN_ERROR, "LoadOtaProvisioning");
}

View File

@@ -0,0 +1,190 @@
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#include "system_id_extractor.h"
#include <assert.h>
#include "crypto_session.h"
#include "device_files.h"
#include "privacy_crypto.h"
#include "wv_cdm_constants.h"
#include "wv_cdm_types.h"
namespace wvcdm {
namespace {
// Offset within the keybox data where the device ID is stored.
constexpr size_t kKeyboxSystemIdOffset = 4;
// Index of certificate within cerificate chain which contains the
// system ID (0 = leaf/device cert, 1 = intermediate/device family cert).
constexpr size_t kOemCertSystemIdIndex = 1;
// OID of X.509 certificate extension containing the Widevine system ID.
const std::string kWidevineSystemIdExtensionOid = "1.3.6.1.4.1.11129.4.1.1";
constexpr size_t kSystemIdLength = sizeof(uint32_t);
constexpr bool IsSupportedSecurityLevel(CdmSecurityLevel security_level) {
return security_level == kSecurityLevelL1 ||
security_level == kSecurityLevelL2 ||
security_level == kSecurityLevelL3;
}
} // namespace
SystemIdExtractor::SystemIdExtractor(RequestedSecurityLevel security_level,
CryptoSession* crypto_session,
wvutil::FileSystem* fs)
: security_level_(security_level),
crypto_session_(crypto_session),
fs_(fs) {
assert(crypto_session != nullptr);
assert(fs != nullptr);
}
bool SystemIdExtractor::ExtractSystemId(uint32_t* system_id) {
if (system_id == nullptr) {
LOGE("Output |system_id| is null");
return false;
}
if (crypto_session_->GetCachedSystemId(system_id)) {
return true;
}
CdmClientTokenType type = kClientTokenUninitialized;
const CdmResponseType status =
crypto_session_->GetProvisioningMethod(security_level_, &type);
if (status != NO_ERROR) {
LOGE("Failed to get provisioning method: security_level = %s, status = %d",
RequestedSecurityLevelToString(security_level_),
static_cast<int>(status));
return false;
}
bool success = false;
switch (type) {
case kClientTokenDrmCert:
LOGE("Cannot get a system ID from a DRM certificate");
return false;
case kClientTokenKeybox:
success = ExtractSystemIdProv20(system_id);
break;
case kClientTokenOemCert:
success = ExtractSystemIdProv30(system_id);
break;
case kClientTokenBootCertChain:
success = ExtractSystemIdProv40(system_id);
break;
case kClientTokenUninitialized:
default:
LOGE("Unexpected token type: %d", type);
return false;
}
if (success && *system_id != NULL_SYSTEM_ID) {
crypto_session_->SetSystemId(*system_id);
}
return success;
}
// static
bool SystemIdExtractor::ExtractSystemIdFromKeyboxData(
const std::string& key_data, uint32_t* system_id) {
if (system_id == nullptr) return false;
if (key_data.size() < (kKeyboxSystemIdOffset + kSystemIdLength)) {
LOGE("Keybox data does not contain system ID: key_data_size = %zu",
key_data.size());
return false;
}
uint32_t system_id_nbo = 0;
memcpy(&system_id_nbo, &key_data[kKeyboxSystemIdOffset],
sizeof(system_id_nbo));
*system_id = ntohl(system_id_nbo);
return true;
}
// static
bool SystemIdExtractor::ExtractSystemIdFromOemCert(const std::string& oem_cert,
uint32_t* system_id) {
if (system_id == nullptr) return false;
return ExtractExtensionValueFromCertificate(oem_cert,
kWidevineSystemIdExtensionOid,
kOemCertSystemIdIndex, system_id);
}
bool SystemIdExtractor::ExtractSystemIdProv20(uint32_t* system_id) {
std::string key_data;
const CdmResponseType status =
crypto_session_->GetTokenFromKeybox(security_level_, &key_data);
if (status == NEED_PROVISIONING) {
LOGD("Keybox provisioning required, using null system ID");
*system_id = NULL_SYSTEM_ID;
return true;
}
if (status != NO_ERROR) {
LOGE("Failed to get keybox data: security_level = %s, status = %d",
RequestedSecurityLevelToString(security_level_),
static_cast<int>(status));
return false;
}
if (!ExtractSystemIdFromKeyboxData(key_data, system_id)) {
LOGE("Failed to extract system ID from keybox data");
return false;
}
return true;
}
bool SystemIdExtractor::ExtractSystemIdProv30(uint32_t* system_id) {
std::string oem_cert;
const CdmResponseType status =
crypto_session_->GetTokenFromOemCert(security_level_, &oem_cert);
if (status != NO_ERROR) {
LOGE("Failed to get OEM certificate: security_level = %s, status = %d",
RequestedSecurityLevelToString(security_level_),
static_cast<int>(status));
return false;
}
if (!ExtractSystemIdFromOemCert(oem_cert, system_id)) {
LOGE("Failed to extract system ID from OEM certificate");
return false;
}
return true;
}
bool SystemIdExtractor::ExtractSystemIdProv40(uint32_t* system_id) {
const CdmSecurityLevel security_level =
crypto_session_->GetSecurityLevel(security_level_);
if (!IsSupportedSecurityLevel(security_level)) {
LOGE("Unsupported security level: %s",
CdmSecurityLevelToString(security_level));
return false;
}
DeviceFiles real_device_files(fs_);
// Mock DeviceFiles for testing.
DeviceFiles& device_files =
(test_device_files_ ? *test_device_files_ : real_device_files);
if (!device_files.Init(security_level)) {
LOGE("Failed to initialize device files: security_level = %s",
CdmSecurityLevelToString(security_level));
return false;
}
std::string oem_cert;
CryptoWrappedKey wrapped_private_key_unused;
const DeviceFiles::CertificateState cert_state =
device_files.RetrieveOemCertificate(&oem_cert,
&wrapped_private_key_unused);
if (cert_state == DeviceFiles::kCertificateNotFound) {
LOGD("No OEM certificate available, using null system ID");
*system_id = NULL_SYSTEM_ID;
return true;
}
if (cert_state != DeviceFiles::kCertificateValid) {
LOGE(
"Failed to retrieve OEM certificate: "
"security_level = %s, cert_state = %s",
CdmSecurityLevelToString(security_level),
DeviceFiles::CertificateStateToString(cert_state));
return false;
}
if (!ExtractSystemIdFromOemCert(oem_cert, system_id)) {
LOGE("Failed to extract system ID from OEM certificate");
return false;
}
return true;
}
} // namespace wvcdm

View File

@@ -24,233 +24,9 @@ using ::testing::AllOf;
using ::testing::Ge;
using ::testing::Le;
namespace {
const uint8_t kOemCert[] = {
0x30, 0x82, 0x09, 0xf7, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0xe8, 0x30, 0x82, 0x09, 0xe4, 0x02,
0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x09,
0xc8, 0x30, 0x82, 0x04, 0x1a, 0x30, 0x82, 0x03, 0x02, 0xa0, 0x03, 0x02,
0x01, 0x02, 0x02, 0x11, 0x00, 0xf2, 0xa1, 0x08, 0xdf, 0x12, 0x84, 0xb9,
0x73, 0x6c, 0x23, 0x73, 0xe1, 0x1f, 0xf3, 0xac, 0x7a, 0x30, 0x0d, 0x06,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f,
0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08,
0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d,
0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08,
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, 0x2e,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44,
0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65,
0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, 0x1e,
0x17, 0x0d, 0x31, 0x37, 0x30, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, 0x30, 0x38, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6d, 0x31, 0x12, 0x30, 0x10,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x33, 0x34, 0x36, 0x2d,
0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01,
0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x8f, 0x00, 0x30, 0x82, 0x01,
0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xf5, 0x09, 0x64, 0x4a, 0x26, 0xfe,
0xc0, 0x98, 0x55, 0x6a, 0x1d, 0x5d, 0x1c, 0xc7, 0x38, 0xaf, 0xfd, 0x49,
0x9e, 0x85, 0x3f, 0xd6, 0x45, 0x0e, 0x99, 0x09, 0x85, 0x69, 0x84, 0x3c,
0xfe, 0x72, 0xa5, 0x56, 0xfa, 0x11, 0x4f, 0x6b, 0x7d, 0x32, 0x2b, 0x0c,
0xbf, 0x8f, 0xac, 0x47, 0x96, 0x22, 0x82, 0x3d, 0xf5, 0x64, 0x74, 0x7e,
0x62, 0x68, 0x74, 0xcd, 0x0a, 0xec, 0x84, 0xc5, 0x15, 0x06, 0x0e, 0x5a,
0x2f, 0x20, 0xe3, 0xc9, 0x67, 0xcd, 0xdd, 0x01, 0xb8, 0xb3, 0x18, 0x87,
0x8c, 0xa9, 0x58, 0x86, 0x0f, 0xb6, 0xc3, 0x42, 0x7e, 0x87, 0x48, 0x5e,
0x10, 0x49, 0xc7, 0xd7, 0xb7, 0xb8, 0xa6, 0x34, 0x08, 0x0c, 0x94, 0xf4,
0xbb, 0x2a, 0x06, 0xa4, 0x4f, 0xec, 0xbc, 0xc4, 0x37, 0xbe, 0x99, 0x10,
0x23, 0x37, 0x24, 0xb1, 0xdf, 0xcb, 0xe6, 0x3f, 0xc1, 0xf0, 0x0f, 0x04,
0x03, 0xc8, 0xb0, 0x1e, 0xd6, 0xb8, 0xae, 0x77, 0xe1, 0x4d, 0x6d, 0x97,
0x69, 0x6d, 0x8a, 0x73, 0x66, 0x32, 0x57, 0x6f, 0xcf, 0xea, 0x1e, 0x7b,
0x87, 0x03, 0x75, 0xb1, 0xef, 0x83, 0x64, 0x26, 0xf1, 0x3f, 0xbf, 0xe6,
0x28, 0x03, 0x72, 0x57, 0xbf, 0x47, 0x29, 0x99, 0x8f, 0x74, 0x1d, 0x01,
0x16, 0xad, 0xb2, 0xdf, 0x80, 0xa4, 0xd3, 0x8b, 0xeb, 0x61, 0xd1, 0x40,
0x68, 0xb9, 0xa2, 0xa5, 0xef, 0x2b, 0xe5, 0x78, 0xe8, 0x28, 0x88, 0x87,
0xb7, 0x53, 0x49, 0xbb, 0xe4, 0xea, 0x0d, 0x5e, 0x96, 0xa5, 0xdd, 0x1f,
0x0b, 0x25, 0x8b, 0xb5, 0x95, 0x46, 0xe7, 0xba, 0xb8, 0xc4, 0x0a, 0x36,
0xb1, 0x89, 0xeb, 0x27, 0x5d, 0xd9, 0x97, 0x24, 0x59, 0xa3, 0x9b, 0xb0,
0x23, 0x0b, 0xd2, 0xec, 0x65, 0x91, 0xf9, 0xf0, 0xa0, 0x74, 0x5f, 0xb4,
0xce, 0x22, 0x27, 0x18, 0x37, 0xe2, 0x4b, 0xfc, 0x91, 0xf9, 0x09, 0x15,
0xe6, 0xdb, 0x06, 0x9b, 0x4d, 0x82, 0xdc, 0x36, 0x14, 0x48, 0xc6, 0xd5,
0x87, 0xca, 0xec, 0x5a, 0xa2, 0x29, 0x33, 0xef, 0x22, 0x0c, 0x4b, 0xbf,
0xe7, 0x2f, 0x95, 0xe1, 0xd3, 0xa5, 0xd8, 0xaa, 0x44, 0x77, 0x29, 0xa3,
0x20, 0x33, 0xd2, 0x51, 0xa2, 0xf9, 0x4a, 0x6f, 0xf7, 0x3e, 0xf7, 0x0b,
0x8a, 0xec, 0xc1, 0x99, 0x1d, 0x47, 0xf3, 0x74, 0x02, 0x04, 0xab, 0x8e,
0x62, 0x4c, 0x9e, 0x00, 0xc2, 0x84, 0xd7, 0xd0, 0xf8, 0xe4, 0x1c, 0x9d,
0x98, 0x15, 0xa8, 0x8f, 0x08, 0x98, 0x4e, 0x5a, 0xfa, 0xd6, 0x60, 0x87,
0x12, 0xdc, 0x8e, 0xfd, 0xcb, 0xb3, 0x13, 0x97, 0x7a, 0xa8, 0x8c, 0x56,
0x2e, 0x49, 0x26, 0x60, 0xe9, 0x4a, 0xdc, 0xec, 0x3f, 0xf0, 0x94, 0xcd,
0x90, 0x8e, 0x7c, 0x21, 0x3f, 0x80, 0x14, 0x33, 0xdd, 0xb0, 0x00, 0xe2,
0x09, 0x37, 0x06, 0xdd, 0x17, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01,
0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x8e, 0x2d, 0x13, 0x1e, 0x60,
0xaa, 0xda, 0x52, 0x53, 0x55, 0x64, 0x3a, 0xdc, 0xb6, 0x7a, 0xc0, 0xba,
0xfa, 0xeb, 0x20, 0xab, 0xb6, 0x63, 0xcf, 0xcd, 0x9b, 0xdb, 0x71, 0xf3,
0xa0, 0xd6, 0x91, 0xbf, 0x0c, 0xc1, 0xae, 0x8f, 0x02, 0x18, 0x00, 0x54,
0xfb, 0x49, 0x03, 0x34, 0x8d, 0x92, 0x9d, 0x5d, 0x8d, 0xa8, 0x1c, 0x20,
0x0f, 0x85, 0x60, 0xf9, 0xf6, 0x8b, 0xbb, 0x2b, 0x82, 0xce, 0xb3, 0xe2,
0x91, 0xe7, 0xbd, 0x91, 0x61, 0x52, 0x36, 0x40, 0x9f, 0x2f, 0x5e, 0xa6,
0x5d, 0x2f, 0xb3, 0x81, 0xe7, 0xf1, 0x87, 0xbe, 0xc5, 0x9d, 0x67, 0x5a,
0xf7, 0x41, 0x1e, 0x73, 0xb0, 0x1e, 0xdc, 0x4f, 0x8d, 0x53, 0x21, 0x38,
0x1b, 0xfd, 0x92, 0x43, 0x68, 0x83, 0x03, 0xd0, 0x9a, 0xca, 0x92, 0x14,
0x73, 0x04, 0x94, 0x2a, 0x93, 0x22, 0x60, 0x5e, 0xee, 0xb6, 0xec, 0x0f,
0xb0, 0xc8, 0x92, 0x97, 0xfb, 0x5d, 0xed, 0x1f, 0xa0, 0x5f, 0xe4, 0x98,
0x2f, 0xf6, 0x13, 0x78, 0x99, 0xec, 0xb3, 0xf1, 0x0d, 0x27, 0xaa, 0x19,
0x95, 0x39, 0xdb, 0xb0, 0x7b, 0x96, 0x74, 0x03, 0x5e, 0x51, 0xf5, 0x15,
0x27, 0xce, 0xca, 0x0b, 0x2a, 0x0d, 0x43, 0xb3, 0x68, 0x17, 0x1e, 0x11,
0x60, 0xd9, 0x84, 0x9b, 0xc3, 0x53, 0xce, 0xbd, 0xf4, 0x61, 0x51, 0x4b,
0x41, 0x00, 0x7e, 0xe1, 0x5f, 0x69, 0xb3, 0x4a, 0x89, 0x7e, 0x47, 0x67,
0xfd, 0x76, 0xf8, 0x94, 0x2f, 0x72, 0xb6, 0x14, 0x08, 0x2c, 0x16, 0x4e,
0x9d, 0x37, 0x62, 0xbf, 0x11, 0x67, 0xc0, 0x70, 0x71, 0xec, 0x55, 0x51,
0x4e, 0x46, 0x76, 0xb4, 0xc3, 0xeb, 0x52, 0x06, 0x17, 0x06, 0xce, 0x61,
0x43, 0xce, 0x26, 0x80, 0x68, 0xb6, 0x2d, 0x57, 0xba, 0x8c, 0x7d, 0xb7,
0xc5, 0x05, 0x2c, 0xf8, 0xa3, 0x69, 0xf8, 0x96, 0xad, 0xac, 0xd1, 0x30,
0x82, 0x05, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01, 0x02,
0x02, 0x10, 0x73, 0xd1, 0xe1, 0x1d, 0xa9, 0x75, 0xfd, 0x0c, 0xda, 0x7f,
0xfa, 0x43, 0x3c, 0x26, 0xbd, 0x3d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31,
0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57,
0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30,
0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b,
0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04,
0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30,
0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65,
0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04,
0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74,
0x2d, 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30,
0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d,
0x32, 0x37, 0x30, 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31,
0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30,
0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74,
0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30,
0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0x45, 0x13, 0xf2,
0xb2, 0xcb, 0x4b, 0x0f, 0xb4, 0x44, 0x25, 0x9c, 0x8a, 0x68, 0x54, 0xd5,
0x45, 0x1e, 0x15, 0x89, 0x5b, 0xb8, 0xce, 0xda, 0x5a, 0x42, 0xe6, 0x9a,
0x8c, 0xc1, 0xcb, 0xe8, 0xc5, 0xf5, 0x8f, 0x49, 0x0e, 0x02, 0xef, 0x5e,
0x97, 0x1a, 0x91, 0xa4, 0x94, 0xc3, 0x50, 0x13, 0xe5, 0x13, 0xb7, 0x7f,
0x26, 0x53, 0x19, 0xb0, 0x37, 0xa5, 0xef, 0xe6, 0x2a, 0x39, 0xdc, 0x93,
0x37, 0xe2, 0x3d, 0x7f, 0xcb, 0x4b, 0x93, 0xa2, 0xc3, 0x69, 0x78, 0xc9,
0x01, 0xfa, 0x68, 0x3b, 0xe0, 0xe2, 0x22, 0x6c, 0xeb, 0xe4, 0x8a, 0xa8,
0x3e, 0xf5, 0x20, 0x82, 0xa8, 0x62, 0x68, 0x59, 0x78, 0x24, 0xde, 0xef,
0x47, 0x43, 0xb1, 0x6c, 0x38, 0x29, 0xd3, 0x69, 0x3f, 0xae, 0x35, 0x57,
0x75, 0x80, 0xc9, 0x21, 0xe7, 0x01, 0xb9, 0x54, 0x8b, 0x6e, 0x4e, 0x2e,
0x5a, 0x5b, 0x77, 0xa4, 0x22, 0xc2, 0x7b, 0x95, 0xb9, 0x39, 0x2c, 0xbd,
0xc2, 0x1e, 0x02, 0xa6, 0xb2, 0xbc, 0x0f, 0x7a, 0xcb, 0xdc, 0xbc, 0xbc,
0x90, 0x66, 0xe3, 0xca, 0x46, 0x53, 0x3e, 0x98, 0xff, 0x2e, 0x78, 0x9f,
0xd3, 0xa1, 0x12, 0x93, 0x66, 0x7d, 0xcc, 0x94, 0x6b, 0xec, 0x19, 0x0e,
0x20, 0x45, 0x22, 0x57, 0x6d, 0x9e, 0xd0, 0x89, 0xf2, 0xa9, 0x34, 0xdc,
0xab, 0xa5, 0x73, 0x47, 0x38, 0xe3, 0x7f, 0x98, 0x3a, 0x61, 0xae, 0x6c,
0x4d, 0xf2, 0x31, 0x90, 0xcb, 0x83, 0xc1, 0xee, 0xb4, 0xf2, 0x9a, 0x28,
0x5f, 0xbb, 0x7d, 0x89, 0xdf, 0xa2, 0x31, 0xb6, 0x1d, 0x39, 0x2b, 0x70,
0xbf, 0x1e, 0xad, 0xe1, 0x74, 0x94, 0x1d, 0xf8, 0xc5, 0x1a, 0x8d, 0x13,
0x45, 0xf0, 0x6a, 0x80, 0x0c, 0x5d, 0xbb, 0x46, 0x8a, 0x43, 0xd0, 0xff,
0x21, 0x39, 0x57, 0x53, 0x5b, 0x51, 0xf8, 0xa2, 0x8f, 0x7f, 0x27, 0xc7,
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, 0x82, 0x01,
0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06,
0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02,
0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
0xe8, 0xe9, 0xac, 0x16, 0x5c, 0x5e, 0xb2, 0xe8, 0xeb, 0xff, 0x57, 0x27,
0x20, 0x08, 0x72, 0x63, 0x9b, 0xe5, 0xb5, 0x16, 0x30, 0x81, 0xb2, 0x06,
0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7, 0x80, 0x14,
0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, 0xf7, 0x13,
0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81, 0x83, 0xa4,
0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30,
0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65,
0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d,
0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x82, 0x09,
0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30, 0x12, 0x06,
0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04,
0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
0x00, 0x25, 0xce, 0xd2, 0x02, 0x48, 0xbb, 0xbe, 0xfc, 0xb6, 0xa4, 0x87,
0x87, 0xe0, 0x21, 0x7d, 0xfa, 0x23, 0xc3, 0x0d, 0x73, 0x8f, 0x46, 0xe7,
0x09, 0x59, 0xda, 0x2e, 0x55, 0x59, 0xff, 0x3c, 0x1b, 0xf6, 0xf8, 0x9a,
0xc4, 0x1c, 0xf7, 0xac, 0xca, 0xe7, 0x63, 0xf2, 0xc7, 0xd6, 0x0c, 0x2d,
0xa6, 0xad, 0x55, 0xf4, 0x10, 0x0e, 0xa8, 0x82, 0x0f, 0x88, 0xb5, 0x44,
0xe8, 0x8e, 0x84, 0x08, 0xf7, 0xdd, 0xe7, 0x10, 0xce, 0x71, 0x56, 0x57,
0x3f, 0xed, 0x48, 0xee, 0xe2, 0x5d, 0x08, 0x0a, 0x58, 0xe4, 0xfe, 0xbc,
0x8c, 0x27, 0x1a, 0x46, 0x3f, 0xd5, 0x2d, 0xdb, 0x0b, 0x71, 0x73, 0xd1,
0x49, 0xf3, 0x5c, 0x86, 0x4d, 0x0a, 0xe1, 0xeb, 0x53, 0x21, 0x38, 0x4f,
0xec, 0x1e, 0xc2, 0x68, 0x1f, 0x7d, 0xa6, 0x33, 0xe9, 0xa5, 0x37, 0x2a,
0xef, 0xcd, 0x78, 0x56, 0xb3, 0x39, 0x60, 0xf4, 0xa5, 0xf9, 0x2b, 0x85,
0xcf, 0xe6, 0x1c, 0x7c, 0x8a, 0x5d, 0xe8, 0x26, 0x02, 0xcf, 0x7a, 0x56,
0x1f, 0xae, 0x0d, 0x71, 0x20, 0xee, 0xec, 0x3b, 0xae, 0x95, 0x25, 0x15,
0xc8, 0xf6, 0x92, 0x5d, 0xb8, 0x9b, 0xc2, 0xb4, 0x95, 0x33, 0x13, 0x76,
0x45, 0xbe, 0x21, 0xe2, 0x3a, 0x69, 0x66, 0xd7, 0xff, 0x22, 0x00, 0x89,
0xc9, 0x44, 0xb6, 0x54, 0x38, 0x1f, 0x33, 0xe4, 0xda, 0x7b, 0x87, 0xf3,
0x23, 0xed, 0xf5, 0x16, 0x08, 0xbe, 0x4b, 0xea, 0x91, 0x8f, 0x91, 0x8b,
0x4e, 0xd1, 0x02, 0x06, 0xa2, 0x77, 0x15, 0x03, 0x46, 0x11, 0x7d, 0x5b,
0xea, 0x7a, 0xf6, 0x86, 0x7d, 0x96, 0xb7, 0x73, 0x9b, 0x5b, 0x32, 0xc3,
0xf8, 0x92, 0x36, 0xe3, 0xe3, 0x2f, 0xe8, 0xf1, 0x72, 0xec, 0x0d, 0x50,
0xd4, 0x86, 0xc5, 0x62, 0x83, 0xf1, 0x2a, 0x4c, 0xd1, 0xbf, 0x76, 0x62,
0xd4, 0x21, 0x11, 0x68, 0xb2, 0xd6, 0x8d, 0xc4, 0xf8, 0xe4, 0x70, 0x85,
0x19, 0xa7, 0x82, 0x27, 0x2c, 0x24, 0x21, 0x7a, 0x3b, 0xad, 0x8a, 0xd3,
0xae, 0xda, 0x78, 0x3c, 0x6c, 0xab, 0xa2, 0xaa, 0x36, 0xf0, 0x1c, 0x58,
0xd4, 0x72, 0x5e, 0xe8, 0x8b, 0x41, 0x08, 0xf5, 0x85, 0xdd, 0xee, 0x99,
0x12, 0xf4, 0xd6, 0x41, 0x83, 0x69, 0xe7, 0x79, 0x19, 0xa3, 0x74, 0xc4,
0x34, 0x2a, 0x8a, 0x7e, 0x4d, 0xbb, 0x2c, 0x49, 0x19, 0xf7, 0x98, 0x98,
0xfc, 0x81, 0xf7, 0x9b, 0x7f, 0xff, 0xd9, 0x66, 0xf4, 0x51, 0x14, 0x29,
0x2a, 0x14, 0x1d, 0x4f, 0xbd, 0x91, 0xba, 0x6f, 0x32, 0x34, 0x3c, 0x40,
0x28, 0x6c, 0x97, 0xf8, 0x6d, 0x38, 0xcd, 0xa3, 0x7b, 0x18, 0xc8, 0x77,
0x58, 0x4d, 0x53, 0x30, 0x7f, 0x4d, 0x89, 0xca, 0x95, 0x6e, 0xb5, 0xb8,
0x8e, 0xc8, 0x2d, 0x18, 0x2f, 0x52, 0x2a, 0xde, 0xac, 0x56, 0x8d, 0x8c,
0x67, 0x14, 0xf6, 0xb9, 0xf1, 0x65, 0xd3, 0x22, 0x43, 0xa3, 0x98, 0x42,
0x20, 0x43, 0x4c, 0xdf, 0xf2, 0xeb, 0x31, 0x8c, 0x0e, 0x53, 0x5b, 0x99,
0x82, 0xc3, 0x48, 0x04, 0x53, 0xad, 0x96, 0xb6, 0x9f, 0x52, 0xcc, 0x01,
0xc8, 0xb3, 0x87, 0x6b, 0x9e, 0xea, 0xa9, 0xeb, 0xda, 0xac, 0xf9, 0x6f,
0xde, 0xa1, 0x44, 0x32, 0x52, 0x49, 0x47, 0xff, 0x65, 0x79, 0x1e, 0xc5,
0x73, 0x17, 0xb3, 0x36, 0xfc, 0x45, 0xca, 0x90, 0x37, 0x59, 0x1e, 0x16,
0xab, 0x09, 0x69, 0xcf, 0xda, 0x56, 0x51, 0xfd, 0xeb, 0xcf, 0xcb, 0x8f,
0xb1, 0xc3, 0x45, 0x2b, 0x7c, 0x0a, 0xa5, 0x9c, 0x0d, 0x2c, 0xad, 0x1c,
0xd3, 0x33, 0xdd, 0xfe, 0x93, 0x69, 0xa2, 0x4b, 0x4b, 0xcf, 0x1d, 0x20,
0x98, 0x4a, 0x4f, 0x5b, 0xe9, 0x24, 0xca, 0xfa, 0x18, 0x11, 0x81, 0x8b,
0x7a, 0xb4, 0x5a, 0xc8, 0xdf, 0x6f, 0x5f, 0x21, 0x07, 0x31, 0x00};
const uint32_t kOemCertSystemId = 7346;
constexpr uint32_t kNullSystemId =
static_cast<uint32_t>(std::numeric_limits<int>::max());
} // namespace
namespace wvcdm {
class CryptoSessionForTest : public TestCryptoSession, public WvCdmTestBase {
public:
using CryptoSession::ExtractSystemIdFromOemCert;
CryptoSessionForTest() : TestCryptoSession(metrics_.GetCryptoMetrics()) {}
void SetUp() override {}
@@ -263,26 +39,17 @@ class CryptoSessionForTest : public TestCryptoSession, public WvCdmTestBase {
metrics::SessionMetrics CryptoSessionForTest::metrics_;
TEST(CryptoSessionTest, CanExtractSystemIdFromOemCertificate) {
std::string oem_cert(reinterpret_cast<const char*>(kOemCert),
sizeof(kOemCert));
uint32_t system_id;
ASSERT_TRUE(
CryptoSessionForTest::ExtractSystemIdFromOemCert(oem_cert, &system_id));
ASSERT_EQ(kOemCertSystemId, system_id);
}
class CryptoSessionMetricsTest : public WvCdmTestBase {
protected:
uint32_t FindKeyboxSystemID() {
if (CryptoSession::needs_keybox_provisioning()) {
return kNullSystemId;
return NULL_SYSTEM_ID;
}
uint8_t key_data[256];
size_t key_data_len = sizeof(key_data);
const OEMCryptoResult sts =
OEMCrypto_GetKeyData(key_data, &key_data_len, kLevelDefault);
if (sts != OEMCrypto_SUCCESS) return kNullSystemId;
if (sts != OEMCrypto_SUCCESS) return NULL_SYSTEM_ID;
const uint32_t* data = reinterpret_cast<uint32_t*>(key_data);
return htonl(data[1]);
}
@@ -321,30 +88,11 @@ TEST_F(CryptoSessionMetricsTest, OpenSessionValidMetrics) {
CdmClientTokenType token_type = session->GetPreProvisionTokenType();
if (token_type == kClientTokenKeybox) {
const uint32_t expected_system_id = FindKeyboxSystemID();
const uint32_t recorded_system_id = static_cast<uint32_t>(
metrics_proto.crypto_session_system_id().int_value());
EXPECT_EQ(expected_system_id, recorded_system_id);
EXPECT_EQ(OEMCrypto_Keybox,
metrics_proto.oemcrypto_provisioning_method().int_value());
if (recorded_system_id != kNullSystemId) {
// Devices with a null system ID don't actually call into the
// TEE for the keybox.
EXPECT_EQ(1, metrics_proto.oemcrypto_get_key_data_time_us().size());
}
} else if (token_type == kClientTokenOemCert) {
// Recent devices all have a system id between 1k and 6 or 7k. Errors
// we are trying to catch are 0, byte swapped 32 bit numbers, or
// garbage. These errors will most likely be outside the range of 1000
// to 2^16.
EXPECT_LE(1000, metrics_proto.crypto_session_system_id().int_value());
EXPECT_GT(0x10000, metrics_proto.crypto_session_system_id().int_value());
EXPECT_EQ(OEMCrypto_OEMCertificate,
metrics_proto.oemcrypto_provisioning_method().int_value());
ASSERT_EQ(1, metrics_proto.oemcrypto_get_oem_public_certificate().size());
EXPECT_THAT(metrics_proto.oemcrypto_get_oem_public_certificate(0).count(),
AllOf(Ge(1), Le(2)));
} else if (token_type == kClientTokenDrmCert) {
// TODO(blueeyes): Add support for getting the system id from a
// pre-installed DRM certificate..
@@ -376,32 +124,19 @@ TEST_F(CryptoSessionMetricsTest, GetProvisioningTokenValidMetrics) {
crypto_metrics.Serialize(&metrics_proto);
if (token_type == kClientTokenKeybox) {
ASSERT_EQ(1, metrics_proto.crypto_session_get_token().size());
EXPECT_EQ(1, metrics_proto.crypto_session_get_token(0).count());
const uint32_t expected_system_id = FindKeyboxSystemID();
const uint32_t recorded_system_id = static_cast<uint32_t>(
metrics_proto.crypto_session_system_id().int_value());
EXPECT_EQ(expected_system_id, recorded_system_id);
if (recorded_system_id != kNullSystemId) {
EXPECT_EQ(1, metrics_proto.oemcrypto_get_key_data_time_us().size());
}
EXPECT_EQ(OEMCrypto_Keybox,
metrics_proto.oemcrypto_provisioning_method().int_value());
ASSERT_GE(metrics_proto.crypto_session_get_token().size(), 1);
EXPECT_GE(metrics_proto.crypto_session_get_token(0).count(), 1);
} else if (token_type == kClientTokenOemCert) {
// Recent devices all have a system id between 1k and 6 or 7k. Errors
// we are trying to catch are 0, byte swapped 32 bit numbers, or
// garbage. These errors will most likely be outside the range of 1000
// to 2^16.
EXPECT_LE(1000, metrics_proto.crypto_session_system_id().int_value());
EXPECT_GT(0X10000, metrics_proto.crypto_session_system_id().int_value());
EXPECT_EQ(OEMCrypto_OEMCertificate,
metrics_proto.oemcrypto_provisioning_method().int_value());
ASSERT_EQ(1, metrics_proto.oemcrypto_get_oem_public_certificate().size());
ASSERT_GE(metrics_proto.oemcrypto_get_oem_public_certificate().size(), 1);
EXPECT_THAT(metrics_proto.oemcrypto_get_oem_public_certificate(0).count(),
AllOf(Ge(1), Le(2)));
ASSERT_EQ(1, metrics_proto.crypto_session_get_token().size());
EXPECT_EQ(1, metrics_proto.crypto_session_get_token(0).count());
ASSERT_GE(metrics_proto.crypto_session_get_token().size(), 1);
EXPECT_GE(metrics_proto.crypto_session_get_token(0).count(), 1);
} else {
ASSERT_EQ(0, metrics_proto.crypto_session_get_token().size());
}

View File

@@ -0,0 +1,528 @@
// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#include <memory>
#include <string>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "cdm_random.h"
#include "crypto_session.h"
#include "device_files.h"
#include "file_store.h"
#include "system_id_extractor.h"
#include "test_base.h"
#include "wv_cdm_types.h"
namespace wvcdm {
using ::testing::_;
using ::testing::DoAll;
using ::testing::NotNull;
using ::testing::Return;
using ::testing::SetArgPointee;
namespace {
const uint8_t kOemCert[] = {
0x30, 0x82, 0x09, 0xf7, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0xe8, 0x30, 0x82, 0x09, 0xe4, 0x02,
0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x09,
0xc8, 0x30, 0x82, 0x04, 0x1a, 0x30, 0x82, 0x03, 0x02, 0xa0, 0x03, 0x02,
0x01, 0x02, 0x02, 0x11, 0x00, 0xf2, 0xa1, 0x08, 0xdf, 0x12, 0x84, 0xb9,
0x73, 0x6c, 0x23, 0x73, 0xe1, 0x1f, 0xf3, 0xac, 0x7a, 0x30, 0x0d, 0x06,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f,
0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08,
0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d,
0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08,
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, 0x2e,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44,
0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65,
0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, 0x1e,
0x17, 0x0d, 0x31, 0x37, 0x30, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, 0x30, 0x38, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6d, 0x31, 0x12, 0x30, 0x10,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x33, 0x34, 0x36, 0x2d,
0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01,
0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x8f, 0x00, 0x30, 0x82, 0x01,
0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xf5, 0x09, 0x64, 0x4a, 0x26, 0xfe,
0xc0, 0x98, 0x55, 0x6a, 0x1d, 0x5d, 0x1c, 0xc7, 0x38, 0xaf, 0xfd, 0x49,
0x9e, 0x85, 0x3f, 0xd6, 0x45, 0x0e, 0x99, 0x09, 0x85, 0x69, 0x84, 0x3c,
0xfe, 0x72, 0xa5, 0x56, 0xfa, 0x11, 0x4f, 0x6b, 0x7d, 0x32, 0x2b, 0x0c,
0xbf, 0x8f, 0xac, 0x47, 0x96, 0x22, 0x82, 0x3d, 0xf5, 0x64, 0x74, 0x7e,
0x62, 0x68, 0x74, 0xcd, 0x0a, 0xec, 0x84, 0xc5, 0x15, 0x06, 0x0e, 0x5a,
0x2f, 0x20, 0xe3, 0xc9, 0x67, 0xcd, 0xdd, 0x01, 0xb8, 0xb3, 0x18, 0x87,
0x8c, 0xa9, 0x58, 0x86, 0x0f, 0xb6, 0xc3, 0x42, 0x7e, 0x87, 0x48, 0x5e,
0x10, 0x49, 0xc7, 0xd7, 0xb7, 0xb8, 0xa6, 0x34, 0x08, 0x0c, 0x94, 0xf4,
0xbb, 0x2a, 0x06, 0xa4, 0x4f, 0xec, 0xbc, 0xc4, 0x37, 0xbe, 0x99, 0x10,
0x23, 0x37, 0x24, 0xb1, 0xdf, 0xcb, 0xe6, 0x3f, 0xc1, 0xf0, 0x0f, 0x04,
0x03, 0xc8, 0xb0, 0x1e, 0xd6, 0xb8, 0xae, 0x77, 0xe1, 0x4d, 0x6d, 0x97,
0x69, 0x6d, 0x8a, 0x73, 0x66, 0x32, 0x57, 0x6f, 0xcf, 0xea, 0x1e, 0x7b,
0x87, 0x03, 0x75, 0xb1, 0xef, 0x83, 0x64, 0x26, 0xf1, 0x3f, 0xbf, 0xe6,
0x28, 0x03, 0x72, 0x57, 0xbf, 0x47, 0x29, 0x99, 0x8f, 0x74, 0x1d, 0x01,
0x16, 0xad, 0xb2, 0xdf, 0x80, 0xa4, 0xd3, 0x8b, 0xeb, 0x61, 0xd1, 0x40,
0x68, 0xb9, 0xa2, 0xa5, 0xef, 0x2b, 0xe5, 0x78, 0xe8, 0x28, 0x88, 0x87,
0xb7, 0x53, 0x49, 0xbb, 0xe4, 0xea, 0x0d, 0x5e, 0x96, 0xa5, 0xdd, 0x1f,
0x0b, 0x25, 0x8b, 0xb5, 0x95, 0x46, 0xe7, 0xba, 0xb8, 0xc4, 0x0a, 0x36,
0xb1, 0x89, 0xeb, 0x27, 0x5d, 0xd9, 0x97, 0x24, 0x59, 0xa3, 0x9b, 0xb0,
0x23, 0x0b, 0xd2, 0xec, 0x65, 0x91, 0xf9, 0xf0, 0xa0, 0x74, 0x5f, 0xb4,
0xce, 0x22, 0x27, 0x18, 0x37, 0xe2, 0x4b, 0xfc, 0x91, 0xf9, 0x09, 0x15,
0xe6, 0xdb, 0x06, 0x9b, 0x4d, 0x82, 0xdc, 0x36, 0x14, 0x48, 0xc6, 0xd5,
0x87, 0xca, 0xec, 0x5a, 0xa2, 0x29, 0x33, 0xef, 0x22, 0x0c, 0x4b, 0xbf,
0xe7, 0x2f, 0x95, 0xe1, 0xd3, 0xa5, 0xd8, 0xaa, 0x44, 0x77, 0x29, 0xa3,
0x20, 0x33, 0xd2, 0x51, 0xa2, 0xf9, 0x4a, 0x6f, 0xf7, 0x3e, 0xf7, 0x0b,
0x8a, 0xec, 0xc1, 0x99, 0x1d, 0x47, 0xf3, 0x74, 0x02, 0x04, 0xab, 0x8e,
0x62, 0x4c, 0x9e, 0x00, 0xc2, 0x84, 0xd7, 0xd0, 0xf8, 0xe4, 0x1c, 0x9d,
0x98, 0x15, 0xa8, 0x8f, 0x08, 0x98, 0x4e, 0x5a, 0xfa, 0xd6, 0x60, 0x87,
0x12, 0xdc, 0x8e, 0xfd, 0xcb, 0xb3, 0x13, 0x97, 0x7a, 0xa8, 0x8c, 0x56,
0x2e, 0x49, 0x26, 0x60, 0xe9, 0x4a, 0xdc, 0xec, 0x3f, 0xf0, 0x94, 0xcd,
0x90, 0x8e, 0x7c, 0x21, 0x3f, 0x80, 0x14, 0x33, 0xdd, 0xb0, 0x00, 0xe2,
0x09, 0x37, 0x06, 0xdd, 0x17, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01,
0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x8e, 0x2d, 0x13, 0x1e, 0x60,
0xaa, 0xda, 0x52, 0x53, 0x55, 0x64, 0x3a, 0xdc, 0xb6, 0x7a, 0xc0, 0xba,
0xfa, 0xeb, 0x20, 0xab, 0xb6, 0x63, 0xcf, 0xcd, 0x9b, 0xdb, 0x71, 0xf3,
0xa0, 0xd6, 0x91, 0xbf, 0x0c, 0xc1, 0xae, 0x8f, 0x02, 0x18, 0x00, 0x54,
0xfb, 0x49, 0x03, 0x34, 0x8d, 0x92, 0x9d, 0x5d, 0x8d, 0xa8, 0x1c, 0x20,
0x0f, 0x85, 0x60, 0xf9, 0xf6, 0x8b, 0xbb, 0x2b, 0x82, 0xce, 0xb3, 0xe2,
0x91, 0xe7, 0xbd, 0x91, 0x61, 0x52, 0x36, 0x40, 0x9f, 0x2f, 0x5e, 0xa6,
0x5d, 0x2f, 0xb3, 0x81, 0xe7, 0xf1, 0x87, 0xbe, 0xc5, 0x9d, 0x67, 0x5a,
0xf7, 0x41, 0x1e, 0x73, 0xb0, 0x1e, 0xdc, 0x4f, 0x8d, 0x53, 0x21, 0x38,
0x1b, 0xfd, 0x92, 0x43, 0x68, 0x83, 0x03, 0xd0, 0x9a, 0xca, 0x92, 0x14,
0x73, 0x04, 0x94, 0x2a, 0x93, 0x22, 0x60, 0x5e, 0xee, 0xb6, 0xec, 0x0f,
0xb0, 0xc8, 0x92, 0x97, 0xfb, 0x5d, 0xed, 0x1f, 0xa0, 0x5f, 0xe4, 0x98,
0x2f, 0xf6, 0x13, 0x78, 0x99, 0xec, 0xb3, 0xf1, 0x0d, 0x27, 0xaa, 0x19,
0x95, 0x39, 0xdb, 0xb0, 0x7b, 0x96, 0x74, 0x03, 0x5e, 0x51, 0xf5, 0x15,
0x27, 0xce, 0xca, 0x0b, 0x2a, 0x0d, 0x43, 0xb3, 0x68, 0x17, 0x1e, 0x11,
0x60, 0xd9, 0x84, 0x9b, 0xc3, 0x53, 0xce, 0xbd, 0xf4, 0x61, 0x51, 0x4b,
0x41, 0x00, 0x7e, 0xe1, 0x5f, 0x69, 0xb3, 0x4a, 0x89, 0x7e, 0x47, 0x67,
0xfd, 0x76, 0xf8, 0x94, 0x2f, 0x72, 0xb6, 0x14, 0x08, 0x2c, 0x16, 0x4e,
0x9d, 0x37, 0x62, 0xbf, 0x11, 0x67, 0xc0, 0x70, 0x71, 0xec, 0x55, 0x51,
0x4e, 0x46, 0x76, 0xb4, 0xc3, 0xeb, 0x52, 0x06, 0x17, 0x06, 0xce, 0x61,
0x43, 0xce, 0x26, 0x80, 0x68, 0xb6, 0x2d, 0x57, 0xba, 0x8c, 0x7d, 0xb7,
0xc5, 0x05, 0x2c, 0xf8, 0xa3, 0x69, 0xf8, 0x96, 0xad, 0xac, 0xd1, 0x30,
0x82, 0x05, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01, 0x02,
0x02, 0x10, 0x73, 0xd1, 0xe1, 0x1d, 0xa9, 0x75, 0xfd, 0x0c, 0xda, 0x7f,
0xfa, 0x43, 0x3c, 0x26, 0xbd, 0x3d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31,
0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57,
0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30,
0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b,
0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04,
0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30,
0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65,
0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04,
0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74,
0x2d, 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30,
0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d,
0x32, 0x37, 0x30, 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31,
0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30,
0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74,
0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30,
0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0x45, 0x13, 0xf2,
0xb2, 0xcb, 0x4b, 0x0f, 0xb4, 0x44, 0x25, 0x9c, 0x8a, 0x68, 0x54, 0xd5,
0x45, 0x1e, 0x15, 0x89, 0x5b, 0xb8, 0xce, 0xda, 0x5a, 0x42, 0xe6, 0x9a,
0x8c, 0xc1, 0xcb, 0xe8, 0xc5, 0xf5, 0x8f, 0x49, 0x0e, 0x02, 0xef, 0x5e,
0x97, 0x1a, 0x91, 0xa4, 0x94, 0xc3, 0x50, 0x13, 0xe5, 0x13, 0xb7, 0x7f,
0x26, 0x53, 0x19, 0xb0, 0x37, 0xa5, 0xef, 0xe6, 0x2a, 0x39, 0xdc, 0x93,
0x37, 0xe2, 0x3d, 0x7f, 0xcb, 0x4b, 0x93, 0xa2, 0xc3, 0x69, 0x78, 0xc9,
0x01, 0xfa, 0x68, 0x3b, 0xe0, 0xe2, 0x22, 0x6c, 0xeb, 0xe4, 0x8a, 0xa8,
0x3e, 0xf5, 0x20, 0x82, 0xa8, 0x62, 0x68, 0x59, 0x78, 0x24, 0xde, 0xef,
0x47, 0x43, 0xb1, 0x6c, 0x38, 0x29, 0xd3, 0x69, 0x3f, 0xae, 0x35, 0x57,
0x75, 0x80, 0xc9, 0x21, 0xe7, 0x01, 0xb9, 0x54, 0x8b, 0x6e, 0x4e, 0x2e,
0x5a, 0x5b, 0x77, 0xa4, 0x22, 0xc2, 0x7b, 0x95, 0xb9, 0x39, 0x2c, 0xbd,
0xc2, 0x1e, 0x02, 0xa6, 0xb2, 0xbc, 0x0f, 0x7a, 0xcb, 0xdc, 0xbc, 0xbc,
0x90, 0x66, 0xe3, 0xca, 0x46, 0x53, 0x3e, 0x98, 0xff, 0x2e, 0x78, 0x9f,
0xd3, 0xa1, 0x12, 0x93, 0x66, 0x7d, 0xcc, 0x94, 0x6b, 0xec, 0x19, 0x0e,
0x20, 0x45, 0x22, 0x57, 0x6d, 0x9e, 0xd0, 0x89, 0xf2, 0xa9, 0x34, 0xdc,
0xab, 0xa5, 0x73, 0x47, 0x38, 0xe3, 0x7f, 0x98, 0x3a, 0x61, 0xae, 0x6c,
0x4d, 0xf2, 0x31, 0x90, 0xcb, 0x83, 0xc1, 0xee, 0xb4, 0xf2, 0x9a, 0x28,
0x5f, 0xbb, 0x7d, 0x89, 0xdf, 0xa2, 0x31, 0xb6, 0x1d, 0x39, 0x2b, 0x70,
0xbf, 0x1e, 0xad, 0xe1, 0x74, 0x94, 0x1d, 0xf8, 0xc5, 0x1a, 0x8d, 0x13,
0x45, 0xf0, 0x6a, 0x80, 0x0c, 0x5d, 0xbb, 0x46, 0x8a, 0x43, 0xd0, 0xff,
0x21, 0x39, 0x57, 0x53, 0x5b, 0x51, 0xf8, 0xa2, 0x8f, 0x7f, 0x27, 0xc7,
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, 0x82, 0x01,
0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06,
0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02,
0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
0xe8, 0xe9, 0xac, 0x16, 0x5c, 0x5e, 0xb2, 0xe8, 0xeb, 0xff, 0x57, 0x27,
0x20, 0x08, 0x72, 0x63, 0x9b, 0xe5, 0xb5, 0x16, 0x30, 0x81, 0xb2, 0x06,
0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7, 0x80, 0x14,
0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, 0xf7, 0x13,
0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81, 0x83, 0xa4,
0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30,
0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65,
0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d,
0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x82, 0x09,
0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30, 0x12, 0x06,
0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04,
0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
0x00, 0x25, 0xce, 0xd2, 0x02, 0x48, 0xbb, 0xbe, 0xfc, 0xb6, 0xa4, 0x87,
0x87, 0xe0, 0x21, 0x7d, 0xfa, 0x23, 0xc3, 0x0d, 0x73, 0x8f, 0x46, 0xe7,
0x09, 0x59, 0xda, 0x2e, 0x55, 0x59, 0xff, 0x3c, 0x1b, 0xf6, 0xf8, 0x9a,
0xc4, 0x1c, 0xf7, 0xac, 0xca, 0xe7, 0x63, 0xf2, 0xc7, 0xd6, 0x0c, 0x2d,
0xa6, 0xad, 0x55, 0xf4, 0x10, 0x0e, 0xa8, 0x82, 0x0f, 0x88, 0xb5, 0x44,
0xe8, 0x8e, 0x84, 0x08, 0xf7, 0xdd, 0xe7, 0x10, 0xce, 0x71, 0x56, 0x57,
0x3f, 0xed, 0x48, 0xee, 0xe2, 0x5d, 0x08, 0x0a, 0x58, 0xe4, 0xfe, 0xbc,
0x8c, 0x27, 0x1a, 0x46, 0x3f, 0xd5, 0x2d, 0xdb, 0x0b, 0x71, 0x73, 0xd1,
0x49, 0xf3, 0x5c, 0x86, 0x4d, 0x0a, 0xe1, 0xeb, 0x53, 0x21, 0x38, 0x4f,
0xec, 0x1e, 0xc2, 0x68, 0x1f, 0x7d, 0xa6, 0x33, 0xe9, 0xa5, 0x37, 0x2a,
0xef, 0xcd, 0x78, 0x56, 0xb3, 0x39, 0x60, 0xf4, 0xa5, 0xf9, 0x2b, 0x85,
0xcf, 0xe6, 0x1c, 0x7c, 0x8a, 0x5d, 0xe8, 0x26, 0x02, 0xcf, 0x7a, 0x56,
0x1f, 0xae, 0x0d, 0x71, 0x20, 0xee, 0xec, 0x3b, 0xae, 0x95, 0x25, 0x15,
0xc8, 0xf6, 0x92, 0x5d, 0xb8, 0x9b, 0xc2, 0xb4, 0x95, 0x33, 0x13, 0x76,
0x45, 0xbe, 0x21, 0xe2, 0x3a, 0x69, 0x66, 0xd7, 0xff, 0x22, 0x00, 0x89,
0xc9, 0x44, 0xb6, 0x54, 0x38, 0x1f, 0x33, 0xe4, 0xda, 0x7b, 0x87, 0xf3,
0x23, 0xed, 0xf5, 0x16, 0x08, 0xbe, 0x4b, 0xea, 0x91, 0x8f, 0x91, 0x8b,
0x4e, 0xd1, 0x02, 0x06, 0xa2, 0x77, 0x15, 0x03, 0x46, 0x11, 0x7d, 0x5b,
0xea, 0x7a, 0xf6, 0x86, 0x7d, 0x96, 0xb7, 0x73, 0x9b, 0x5b, 0x32, 0xc3,
0xf8, 0x92, 0x36, 0xe3, 0xe3, 0x2f, 0xe8, 0xf1, 0x72, 0xec, 0x0d, 0x50,
0xd4, 0x86, 0xc5, 0x62, 0x83, 0xf1, 0x2a, 0x4c, 0xd1, 0xbf, 0x76, 0x62,
0xd4, 0x21, 0x11, 0x68, 0xb2, 0xd6, 0x8d, 0xc4, 0xf8, 0xe4, 0x70, 0x85,
0x19, 0xa7, 0x82, 0x27, 0x2c, 0x24, 0x21, 0x7a, 0x3b, 0xad, 0x8a, 0xd3,
0xae, 0xda, 0x78, 0x3c, 0x6c, 0xab, 0xa2, 0xaa, 0x36, 0xf0, 0x1c, 0x58,
0xd4, 0x72, 0x5e, 0xe8, 0x8b, 0x41, 0x08, 0xf5, 0x85, 0xdd, 0xee, 0x99,
0x12, 0xf4, 0xd6, 0x41, 0x83, 0x69, 0xe7, 0x79, 0x19, 0xa3, 0x74, 0xc4,
0x34, 0x2a, 0x8a, 0x7e, 0x4d, 0xbb, 0x2c, 0x49, 0x19, 0xf7, 0x98, 0x98,
0xfc, 0x81, 0xf7, 0x9b, 0x7f, 0xff, 0xd9, 0x66, 0xf4, 0x51, 0x14, 0x29,
0x2a, 0x14, 0x1d, 0x4f, 0xbd, 0x91, 0xba, 0x6f, 0x32, 0x34, 0x3c, 0x40,
0x28, 0x6c, 0x97, 0xf8, 0x6d, 0x38, 0xcd, 0xa3, 0x7b, 0x18, 0xc8, 0x77,
0x58, 0x4d, 0x53, 0x30, 0x7f, 0x4d, 0x89, 0xca, 0x95, 0x6e, 0xb5, 0xb8,
0x8e, 0xc8, 0x2d, 0x18, 0x2f, 0x52, 0x2a, 0xde, 0xac, 0x56, 0x8d, 0x8c,
0x67, 0x14, 0xf6, 0xb9, 0xf1, 0x65, 0xd3, 0x22, 0x43, 0xa3, 0x98, 0x42,
0x20, 0x43, 0x4c, 0xdf, 0xf2, 0xeb, 0x31, 0x8c, 0x0e, 0x53, 0x5b, 0x99,
0x82, 0xc3, 0x48, 0x04, 0x53, 0xad, 0x96, 0xb6, 0x9f, 0x52, 0xcc, 0x01,
0xc8, 0xb3, 0x87, 0x6b, 0x9e, 0xea, 0xa9, 0xeb, 0xda, 0xac, 0xf9, 0x6f,
0xde, 0xa1, 0x44, 0x32, 0x52, 0x49, 0x47, 0xff, 0x65, 0x79, 0x1e, 0xc5,
0x73, 0x17, 0xb3, 0x36, 0xfc, 0x45, 0xca, 0x90, 0x37, 0x59, 0x1e, 0x16,
0xab, 0x09, 0x69, 0xcf, 0xda, 0x56, 0x51, 0xfd, 0xeb, 0xcf, 0xcb, 0x8f,
0xb1, 0xc3, 0x45, 0x2b, 0x7c, 0x0a, 0xa5, 0x9c, 0x0d, 0x2c, 0xad, 0x1c,
0xd3, 0x33, 0xdd, 0xfe, 0x93, 0x69, 0xa2, 0x4b, 0x4b, 0xcf, 0x1d, 0x20,
0x98, 0x4a, 0x4f, 0x5b, 0xe9, 0x24, 0xca, 0xfa, 0x18, 0x11, 0x81, 0x8b,
0x7a, 0xb4, 0x5a, 0xc8, 0xdf, 0x6f, 0x5f, 0x21, 0x07, 0x31, 0x00};
const std::string kOemCertStr(kOemCert, kOemCert + sizeof(kOemCert));
const uint32_t kOemCertSystemId = 7346;
// clang-format off
const uint8_t kKeyboxData[72] = {
// Version = 1 - 4 bytes
0x00, 0x00, 0x00, 0x01,
// System ID = 1337 - 4 bytes
0x00, 0x00, 0x05, 0x39,
// Encrypted info = arbitrary - 64 bytes
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
};
// clang-format on
const uint32_t kKeyboxSystemId = 1337;
const std::string kKeyboxDataStr(kKeyboxData,
kKeyboxData + sizeof(kKeyboxData));
class MockCryptoSession : public CryptoSession {
public:
MockCryptoSession(metrics::CryptoMetrics* metrics) : CryptoSession(metrics) {}
// ~MockCryptoSession() override {}
bool IsOpen() override { return true; }
CdmSecurityLevel GetSecurityLevel() override { return kSecurityLevelL1; }
CdmSecurityLevel GetSecurityLevel(
RequestedSecurityLevel security_level) override {
return security_level == kLevelDefault ? kSecurityLevelL1
: kSecurityLevelL3;
}
MOCK_METHOD(bool, GetCachedSystemId, (uint32_t*), (override));
MOCK_METHOD(void, SetSystemId, (uint32_t), (override));
void SetSystemIdBase(uint32_t system_id) {
CryptoSession::SetSystemId(system_id);
}
MOCK_METHOD(CdmResponseType, GetProvisioningMethod,
(RequestedSecurityLevel, CdmClientTokenType*), (override));
MOCK_METHOD(CdmResponseType, GetTokenFromKeybox,
(RequestedSecurityLevel, std::string*), (override));
MOCK_METHOD(CdmResponseType, GetTokenFromOemCert,
(RequestedSecurityLevel, std::string*), (override));
};
class MockDeviceFiles : public DeviceFiles {
public:
MockDeviceFiles(wvutil::FileSystem* fs) : DeviceFiles(fs) {}
// ~MockDeviceFiles() override {}
MOCK_METHOD(bool, Init, (CdmSecurityLevel), (override));
MOCK_METHOD(DeviceFiles::CertificateState, RetrieveOemCertificate,
(std::string*, CryptoWrappedKey*), (override));
};
} // namespace
class SystemIdExtractorTest : public WvCdmTestBase {
protected:
void SetUp() override {
WvCdmTestBase::SetUp();
crypto_session_.reset(new MockCryptoSession(&crypto_metrics_));
ASSERT_TRUE(crypto_session_);
device_files_.reset(new MockDeviceFiles(&fs_));
ASSERT_TRUE(device_files_);
}
void TearDown() override {
device_files_.reset();
crypto_session_.reset();
WvCdmTestBase::TearDown();
}
std::unique_ptr<SystemIdExtractor> CreateExtractor(
RequestedSecurityLevel security_level) {
std::unique_ptr<SystemIdExtractor> extractor(
new SystemIdExtractor(security_level, crypto_session_.get(), &fs_));
extractor->SetDeviceFilesForTesting(device_files_.get());
return extractor;
}
void ExpectProvisioningType(CdmClientTokenType type) {
EXPECT_CALL(*crypto_session_, GetCachedSystemId).WillOnce(Return(false));
EXPECT_CALL(*crypto_session_, GetProvisioningMethod(_, NotNull()))
.WillOnce(DoAll(SetArgPointee<1>(type), Return(NO_ERROR)));
}
void ExpectSet(uint32_t system_id) {
EXPECT_CALL(*crypto_session_, SetSystemId(system_id));
}
std::unique_ptr<MockCryptoSession> crypto_session_ = nullptr;
std::unique_ptr<MockDeviceFiles> device_files_ = nullptr;
wvutil::FileSystem fs_;
metrics::CryptoMetrics crypto_metrics_;
};
TEST_F(SystemIdExtractorTest, ExtractSystemIdFromOemCert) {
uint32_t system_id = 0;
EXPECT_TRUE(
SystemIdExtractor::ExtractSystemIdFromOemCert(kOemCertStr, &system_id));
EXPECT_EQ(system_id, kOemCertSystemId);
}
TEST_F(SystemIdExtractorTest, ExtractSystemIdFromKeyboxData) {
uint32_t system_id = 0;
EXPECT_TRUE(SystemIdExtractor::ExtractSystemIdFromKeyboxData(kKeyboxDataStr,
&system_id));
EXPECT_EQ(system_id, kKeyboxSystemId);
}
TEST_F(SystemIdExtractorTest, CachedSystemId) {
const uint32_t kCachedSystemId = 1234;
EXPECT_CALL(*crypto_session_, GetCachedSystemId(NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kCachedSystemId), Return(true)));
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_TRUE(extractor->ExtractSystemId(&system_id));
EXPECT_EQ(system_id, kCachedSystemId);
}
TEST_F(SystemIdExtractorTest, SetSystemIdMetrics) {
const uint32_t kSystemId = 4321;
crypto_session_->SetSystemIdBase(kSystemId);
drm_metrics::WvCdmMetrics::CryptoMetrics metrics_proto;
crypto_metrics_.Serialize(&metrics_proto);
const uint32_t recorded_system_id = static_cast<uint32_t>(
metrics_proto.crypto_session_system_id().int_value());
EXPECT_EQ(recorded_system_id, kSystemId);
}
TEST_F(SystemIdExtractorTest, GetProvisioningMethod_Failed) {
EXPECT_CALL(*crypto_session_, GetCachedSystemId).WillOnce(Return(false));
EXPECT_CALL(*crypto_session_, GetProvisioningMethod(_, NotNull()))
.WillOnce(Return(UNKNOWN_ERROR));
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
TEST_F(SystemIdExtractorTest, GetProvisioningMethod_Unsupported) {
ExpectProvisioningType(kClientTokenDrmCert);
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
TEST_F(SystemIdExtractorTest, KeyboxDevice_Success) {
ExpectProvisioningType(kClientTokenKeybox);
EXPECT_CALL(*crypto_session_, GetTokenFromKeybox(kLevelDefault, NotNull()))
.WillOnce(DoAll(SetArgPointee<1>(kKeyboxDataStr), Return(NO_ERROR)));
ExpectSet(kKeyboxSystemId);
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_TRUE(extractor->ExtractSystemId(&system_id));
EXPECT_EQ(system_id, kKeyboxSystemId);
}
TEST_F(SystemIdExtractorTest, KeyboxDevice_NeedsOtaKeyboxProvisioning) {
ExpectProvisioningType(kClientTokenKeybox);
EXPECT_CALL(*crypto_session_, GetTokenFromKeybox(kLevelDefault, NotNull()))
.WillOnce(Return(NEED_PROVISIONING));
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_TRUE(extractor->ExtractSystemId(&system_id));
EXPECT_EQ(system_id, NULL_SYSTEM_ID);
}
TEST_F(SystemIdExtractorTest, KeyboxDevice_FailedToGetKeyboxData) {
ExpectProvisioningType(kClientTokenKeybox);
EXPECT_CALL(*crypto_session_, GetTokenFromKeybox(kLevel3, NotNull()))
.WillOnce(Return(UNKNOWN_ERROR));
auto extractor = CreateExtractor(kLevel3);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
TEST_F(SystemIdExtractorTest, KeyboxDevice_FailedToParse) {
const std::string kShortKeyData = "123456";
ExpectProvisioningType(kClientTokenKeybox);
EXPECT_CALL(*crypto_session_, GetTokenFromKeybox(kLevel3, NotNull()))
.WillOnce(DoAll(SetArgPointee<1>(kShortKeyData), Return(NO_ERROR)));
auto extractor = CreateExtractor(kLevel3);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
TEST_F(SystemIdExtractorTest, OemCertDevice_Success) {
ExpectProvisioningType(kClientTokenOemCert);
EXPECT_CALL(*crypto_session_, GetTokenFromOemCert(kLevel3, NotNull()))
.WillOnce(DoAll(SetArgPointee<1>(kOemCertStr), Return(NO_ERROR)));
ExpectSet(kOemCertSystemId);
auto extractor = CreateExtractor(kLevel3);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_TRUE(extractor->ExtractSystemId(&system_id));
EXPECT_EQ(system_id, kOemCertSystemId);
}
TEST_F(SystemIdExtractorTest, OemCertDevice_FailedToGetCert) {
ExpectProvisioningType(kClientTokenOemCert);
EXPECT_CALL(*crypto_session_, GetTokenFromOemCert(kLevelDefault, NotNull()))
.WillOnce(Return(UNKNOWN_ERROR));
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
TEST_F(SystemIdExtractorTest, OemCertDevice_FailedToParse) {
const std::string kNotACertChain =
wvutil::CdmRandom::RandomData(kOemCertStr.size());
ExpectProvisioningType(kClientTokenOemCert);
EXPECT_CALL(*crypto_session_, GetTokenFromOemCert(kLevelDefault, NotNull()))
.WillOnce(DoAll(SetArgPointee<1>(kNotACertChain), Return(NO_ERROR)));
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
TEST_F(SystemIdExtractorTest, BccDevice_Success) {
ExpectProvisioningType(kClientTokenBootCertChain);
EXPECT_CALL(*device_files_, Init(kSecurityLevelL1)).WillOnce(Return(true));
EXPECT_CALL(*device_files_, RetrieveOemCertificate(NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kOemCertStr),
Return(DeviceFiles::kCertificateValid)));
ExpectSet(kOemCertSystemId);
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_TRUE(extractor->ExtractSystemId(&system_id));
EXPECT_EQ(system_id, kOemCertSystemId);
}
TEST_F(SystemIdExtractorTest, BccDevice_NotAvailable) {
ExpectProvisioningType(kClientTokenBootCertChain);
EXPECT_CALL(*device_files_, Init(kSecurityLevelL1)).WillOnce(Return(true));
EXPECT_CALL(*device_files_, RetrieveOemCertificate(NotNull(), NotNull()))
.WillOnce(Return(DeviceFiles::kCertificateNotFound));
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_TRUE(extractor->ExtractSystemId(&system_id));
EXPECT_EQ(system_id, NULL_SYSTEM_ID);
}
TEST_F(SystemIdExtractorTest, BccDevice_FailedToRetrieve) {
ExpectProvisioningType(kClientTokenBootCertChain);
EXPECT_CALL(*device_files_, Init(kSecurityLevelL1)).WillOnce(Return(true));
EXPECT_CALL(*device_files_, RetrieveOemCertificate(NotNull(), NotNull()))
.WillOnce(Return(DeviceFiles::kCertificateInvalid));
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
TEST_F(SystemIdExtractorTest, BccDevice_FailedToParse) {
const std::string kNotACertChain =
wvutil::CdmRandom::RandomData(kOemCertStr.size());
ExpectProvisioningType(kClientTokenBootCertChain);
EXPECT_CALL(*device_files_, Init(kSecurityLevelL1)).WillOnce(Return(true));
EXPECT_CALL(*device_files_, RetrieveOemCertificate(NotNull(), NotNull()))
.WillOnce(DoAll(SetArgPointee<0>(kNotACertChain),
Return(DeviceFiles::kCertificateValid)));
auto extractor = CreateExtractor(kLevelDefault);
ASSERT_TRUE(extractor);
uint32_t system_id;
EXPECT_FALSE(extractor->ExtractSystemId(&system_id));
}
} // namespace wvcdm

View File

@@ -161,6 +161,10 @@ test_name := service_certificate_unittest
test_src_dir := ../core/test
include $(LOCAL_PATH)/unit-test.mk
test_name := system_id_extractor_unittest
test_src_dir := ../core/test
include $(LOCAL_PATH)/integration-test.mk
test_name := timer_unittest
test_src_dir := .
include $(LOCAL_PATH)/unit-test.mk

View File

@@ -123,6 +123,7 @@ adb_shell_run policy_engine_unittest
adb_shell_run policy_integration_test
adb_shell_run rw_lock_test
adb_shell_run service_certificate_unittest
adb_shell_run system_id_extractor_unittest
adb_shell_run timer_unittest
adb_shell_run usage_table_header_unittest
adb_shell_run value_metric_unittest