In this update we have:
- Added the verified platform tests. These tests show how some
platforms, when verified are allowed to by pass the normal policy
restrictions. This is done with ChromeOS, thus the name of the
tests use "chrome_os".
- Removed WB_RESULT_INVALID_PADDING. This error was when we the
non-license APIs exposed a AES function with padding. However,
those functions have been removed from the API and this error is
no longer used by the API.
- Tests have been updated to avoid signed-vs-unsigned comparison
and to use the Chromium path to gTest (which is mocked in this
library).
- Tests have been updated to use a new test base and golden data
system to make them easier to read.
285 lines
12 KiB
C++
285 lines
12 KiB
C++
// Copyright 2020 Google LLC. All Rights Reserved.
|
|
|
|
#include "api/license_whitebox.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "api/golden_data.h"
|
|
#include "api/license_whitebox_test_base.h"
|
|
#include "api/test_data.h"
|
|
#include "api/test_license_builder.h"
|
|
#include "crypto_utils/crypto_util.h"
|
|
#include "crypto_utils/rsa_key.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace widevine {
|
|
|
|
class LicenseWhiteboxProcessLicenseResponseTest
|
|
: public LicenseWhiteboxTestBase {
|
|
protected:
|
|
void UseLicenseWithoutSigningKey() {
|
|
TestLicenseBuilder builder;
|
|
builder.AddStubbedContentKey();
|
|
builder.Build(*public_key_, &license_);
|
|
}
|
|
|
|
void UseLicenseWithSigningKey(const std::vector<uint8_t>& padding) {
|
|
TestLicenseBuilder builder;
|
|
builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey(), padding);
|
|
builder.AddStubbedContentKey();
|
|
builder.Build(*public_key_, &license_);
|
|
}
|
|
|
|
License license_;
|
|
};
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseTest, SuccessWithoutSigningKey) {
|
|
UseLicenseWithoutSigningKey();
|
|
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_OK);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseTest,
|
|
SuccessWithSigningKeyNoPadding) {
|
|
UseLicenseWithSigningKey(TestLicenseBuilder::NoPadding());
|
|
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_OK);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseTest,
|
|
SuccessWithSigningKeyPKSC8Padding) {
|
|
UseLicenseWithSigningKey(TestLicenseBuilder::PKSC8Padding());
|
|
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_OK);
|
|
}
|
|
|
|
class LicenseWhiteboxProcessLicenseResponseErrorTest
|
|
: public LicenseWhiteboxProcessLicenseResponseTest {
|
|
protected:
|
|
void SetUp() override {
|
|
LicenseWhiteboxProcessLicenseResponseTest::SetUp();
|
|
|
|
// For these tests, we don't care what license we use, it just needs to be
|
|
// a valid license.
|
|
UseLicenseWithoutSigningKey();
|
|
}
|
|
};
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidSignatureForModifedMessage) {
|
|
Modify(&license_.message);
|
|
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_INVALID_SIGNATURE);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidSignatureForModifedSignature) {
|
|
Modify(&license_.signature);
|
|
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_INVALID_SIGNATURE);
|
|
}
|
|
|
|
// The license request is used to derive the signing key. If the request was
|
|
// modified, then the wrong signing key should be generated.
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidSignatureForModifedLicenseRequest) {
|
|
Modify(&license_.request);
|
|
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_INVALID_SIGNATURE);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidParameterForNullWhitebox) {
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
nullptr, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidParameterForNullMessage) {
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, nullptr, license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidParameterForZeroMessageSize) {
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), 0,
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidParameterForNullSignature) {
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
nullptr, license_.signature.size(), license_.session_key.data(),
|
|
license_.session_key.size(), license_.request.data(),
|
|
license_.request.size()),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidParameterForInvalidSignatureSize) {
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), 5, license_.session_key.data(),
|
|
license_.session_key.size(), license_.request.data(),
|
|
license_.request.size()),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidParameterForNullSessionKey) {
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(), nullptr,
|
|
license_.session_key.size(), license_.request.data(),
|
|
license_.request.size()),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidParameterForInvalidSessionKeySize) {
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), 5, license_.request.data(),
|
|
license_.request.size()),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
// If the session key is modified, unwrapping it will fail. Therefore, we will
|
|
// know that the parameter is invalid (compared to a modified license request).
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidParameterForModifedSessionKey) {
|
|
Modify(&license_.session_key);
|
|
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidParameterForNullLicenseRequest) {
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
nullptr, license_.request.size()),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_F(LicenseWhiteboxProcessLicenseResponseErrorTest,
|
|
InvalidParameterForZeroLienseRequestSize) {
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), 0),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
class LicenseWhiteboxMultiLicenseTest
|
|
: public LicenseWhiteboxProcessLicenseResponseTest {
|
|
protected:
|
|
void SetUp() override {
|
|
LicenseWhiteboxProcessLicenseResponseTest::SetUp();
|
|
|
|
// For these tests, we don't care what license we use, it just needs to be
|
|
// a valid license.
|
|
UseLicenseWithoutSigningKey();
|
|
}
|
|
};
|
|
|
|
// A whitebox can only process a license once. If it has loaded a license
|
|
// (successfully) it should reject later calls with WB_RESULT_INVALID_STATE.
|
|
TEST_F(LicenseWhiteboxMultiLicenseTest, InvalidState) {
|
|
// Load the first license. This one is expected to succeed as the whitebox has
|
|
// not loaded a license yet.
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_OK);
|
|
|
|
// Attempt to load the same license again. This should fail as it already has
|
|
// a license (even though it is the same license).
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_INVALID_STATE);
|
|
}
|
|
|
|
// Even though a whitebox can only load a license once, if it fails to load a
|
|
// license, it should still be able to try again.
|
|
TEST_F(LicenseWhiteboxMultiLicenseTest, SuccessAfterFailure) {
|
|
// Force this one to fail my changing the request, this will cause an error
|
|
// in key derivation which is a later step of license parsing.
|
|
std::vector<uint8_t> bad_request = license_.request;
|
|
Modify(&bad_request);
|
|
ASSERT_NE(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
bad_request.data(), bad_request.size()),
|
|
WB_RESULT_OK);
|
|
|
|
// Attempt to load the license again, but use the correct (unmodified)
|
|
// request.
|
|
ASSERT_EQ(WB_License_ProcessLicenseResponse(
|
|
whitebox_, license_.message.data(), license_.message.size(),
|
|
license_.signature.data(), license_.signature.size(),
|
|
license_.session_key.data(), license_.session_key.size(),
|
|
license_.request.data(), license_.request.size()),
|
|
WB_RESULT_OK);
|
|
}
|
|
|
|
} // namespace widevine
|