Files
ce_cdm/core/test/crypto_session_unittest.cpp
2024-03-28 19:15:22 -07:00

155 lines
5.7 KiB
C++

// Copyright 2018 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include "crypto_session.h"
#include "google/protobuf/text_format.h"
#include "key_session.h"
#include "license_protocol.pb.h"
#include "log.h"
#include "metrics_collections.h"
#include "platform.h"
#include "test_base.h"
#include "test_printers.h"
#include "wv_cdm_types.h"
#include "wv_metrics.pb.h"
using ::testing::AllOf;
using ::testing::Ge;
using ::testing::Le;
namespace wvcdm {
class CryptoSessionForTest : public TestCryptoSession, public WvCdmTestBase {
public:
CryptoSessionForTest() : TestCryptoSession(metrics_.GetCryptoMetrics()) {}
void SetUp() override {}
KeySession* key_session() { return key_session_.get(); }
private:
static metrics::SessionMetrics metrics_;
};
metrics::SessionMetrics CryptoSessionForTest::metrics_;
class CryptoSessionMetricsTest : public WvCdmTestBase {
protected:
uint32_t FindKeyboxSystemID() {
if (CryptoSession::needs_keybox_provisioning()) {
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 NULL_SYSTEM_ID;
const uint32_t* data = reinterpret_cast<uint32_t*>(key_data);
return htonl(data[1]);
}
};
TEST_F(CryptoSessionMetricsTest, OpenSessionValidMetrics) {
metrics::CryptoMetrics crypto_metrics;
std::unique_ptr<CryptoSession> session(
CryptoSession::MakeCryptoSession(&crypto_metrics));
session->Open(wvcdm::kLevelDefault);
// Exercise a method that will touch a metric.
bool supports_usage_table;
ASSERT_TRUE(session->HasUsageTableSupport(&supports_usage_table));
drm_metrics::WvCdmMetrics::CryptoMetrics metrics_proto;
crypto_metrics.Serialize(&metrics_proto);
// TODO(blueeyes): If we an convert to use full proto rather than proto
// lite, convert these tests to use Message-based convenience functions.
// Validate common metrics regardless of provisioning type.
ASSERT_EQ(1, metrics_proto.oemcrypto_initialize_time_us().size());
EXPECT_TRUE(metrics_proto.oemcrypto_initialize_time_us(0)
.attributes()
.has_oem_crypto_result());
EXPECT_EQ(1u,
metrics_proto.oemcrypto_initialize_time_us(0).operation_count());
EXPECT_TRUE(metrics_proto.oemcrypto_initialize_time_us(0).has_mean());
const CdmUsageSupportType usage_type =
supports_usage_table ? kUsageEntrySupport : kNonSecureUsageSupport;
EXPECT_EQ(usage_type,
metrics_proto.oemcrypto_usage_table_support().int_value());
// Validate metrics that differ based on provisioning type.
CdmClientTokenType token_type = session->GetPreProvisionTokenType();
if (token_type == kClientTokenKeybox) {
EXPECT_EQ(OEMCrypto_Keybox,
metrics_proto.oemcrypto_provisioning_method().int_value());
} else if (token_type == kClientTokenOemCert) {
EXPECT_EQ(OEMCrypto_OEMCertificate,
metrics_proto.oemcrypto_provisioning_method().int_value());
} else if (token_type == kClientTokenDrmCert) {
// TODO(blueeyes): Add support for getting the system id from a
// pre-installed DRM certificate..
} else if (token_type == kClientTokenBootCertChain) {
EXPECT_EQ(OEMCrypto_BootCertificateChain,
metrics_proto.oemcrypto_provisioning_method().int_value());
} else if (token_type == kClientTokenDrmCertificateReprovisioning) {
EXPECT_EQ(OEMCrypto_DrmReprovisioning,
metrics_proto.oemcrypto_provisioning_method().int_value());
} else {
FAIL() << "Unexpected token type: " << token_type;
}
}
TEST_F(CryptoSessionMetricsTest, GetProvisioningTokenValidMetrics) {
metrics::CryptoMetrics crypto_metrics;
std::unique_ptr<CryptoSession> session(
CryptoSession::MakeCryptoSession(&crypto_metrics));
ASSERT_EQ(NO_ERROR, session->Open(wvcdm::kLevelDefault));
CdmClientTokenType token_type = session->GetPreProvisionTokenType();
LOGI("token_type: %d", token_type);
// DRM Certificate provisioning method does not support a provisioning
// token. Otherwise, we should be able to fetch the token.
std::string token;
std::string additional_token;
if (token_type != kClientTokenDrmCert) {
ASSERT_EQ(NO_ERROR,
session->GetProvisioningToken(&token, &additional_token));
}
drm_metrics::WvCdmMetrics::CryptoMetrics metrics_proto;
crypto_metrics.Serialize(&metrics_proto);
if (token_type == kClientTokenKeybox) {
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) {
EXPECT_EQ(OEMCrypto_OEMCertificate,
metrics_proto.oemcrypto_provisioning_method().int_value());
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)));
} else if (token_type == kClientTokenBootCertChain) {
EXPECT_EQ(OEMCrypto_BootCertificateChain,
metrics_proto.oemcrypto_provisioning_method().int_value());
} else if (token_type == kClientTokenDrmCertificateReprovisioning) {
EXPECT_EQ(OEMCrypto_DrmReprovisioning,
metrics_proto.oemcrypto_provisioning_method().int_value());
} else {
ASSERT_EQ(0, metrics_proto.crypto_session_get_token().size());
}
}
} // namespace wvcdm