License server SDK between [v16.3.3, v16.4.3] strips 16 bytes from wrapped content keys unconditionally when generating the OEMCrypto core message even when the padding is not present, which happens when license protocol version 2.2 is used. As a result, both key data offset and key data length would be zero in the license response OEMCrypto core message. This CL workaround the problem by assuming deterministic in order serialization of the protobuf fields and deriving the key data offset from the previous field key_data_iv offset. Entitlement keys and generic crypto keys are not handled in this CL intentionally to reduce the implementation complexity. Renewal signing keys do not need to be handled as the paddings are not stripped from the signing keys. The workaround is defined under flag WORKAROUND_STRIP_PADDING_BUG. Also disabled HAS_PROVIDER_KEYS temporarily. Bug: 280521253
211 lines
6.6 KiB
C++
211 lines
6.6 KiB
C++
// Copyright 2020 Google LLC. All Rights Reserved.
|
|
|
|
#ifndef WHITEBOX_API_LICENSE_BUILDER_H_
|
|
#define WHITEBOX_API_LICENSE_BUILDER_H_
|
|
|
|
#include <cstdint>
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "api/test_key_types.h"
|
|
#include "api/test_server.h"
|
|
#include "license_protocol.pb.h"
|
|
|
|
namespace widevine {
|
|
|
|
constexpr size_t kNoProviderKeyId = 0;
|
|
|
|
struct License {
|
|
std::vector<uint8_t> request;
|
|
|
|
std::vector<uint8_t> core_message;
|
|
std::vector<uint8_t> message;
|
|
std::vector<uint8_t> signature;
|
|
|
|
// |session_key_| encrypted using the public key. The white-box expects the
|
|
// session key to be encrypted, so we use the name "session_key_" (even if it
|
|
// is encrypted), we omit the term "encrypted" to match the naming in the API.
|
|
std::vector<uint8_t> session_key;
|
|
};
|
|
|
|
class TestLicenseBuilder {
|
|
public:
|
|
// Signing keys must be 512 bits (64 bytes).
|
|
using SigningKey = std::array<uint8_t, 64>;
|
|
|
|
enum class Padding {
|
|
kNone,
|
|
kPKSC8,
|
|
};
|
|
|
|
enum class RemoteAttestation {
|
|
kUnavailable,
|
|
kVerified,
|
|
kUnverified,
|
|
};
|
|
|
|
enum class VerificationStatus {
|
|
kUnavailable,
|
|
kHardwareVerified,
|
|
kOther,
|
|
};
|
|
|
|
// ODK version of the `core_message`.
|
|
enum class OdkVersion {
|
|
kNone, // No `core_message`
|
|
k16_3, // ODK version 16.3
|
|
k16_5, // ODK version 16.5
|
|
k17_1, // ODK version 17.1
|
|
|
|
k99, // ODK 16.3, but with the version set to 99 (an arbitrary value).
|
|
};
|
|
|
|
enum class KeyControlBlock {
|
|
kNone,
|
|
kClear,
|
|
kEncrypted,
|
|
};
|
|
|
|
struct Settings {
|
|
Padding padding = Padding::kNone;
|
|
bool simulate_strip_padding_bug = false;
|
|
OdkVersion odk_version = OdkVersion::kNone;
|
|
KeyControlBlock key_control_block = KeyControlBlock::kClear;
|
|
RemoteAttestation remote_attestation = RemoteAttestation::kUnavailable;
|
|
VerificationStatus verification_status = VerificationStatus::kUnavailable;
|
|
|
|
// Flags
|
|
//
|
|
// Default to the "correct" structure. We will flip values to test for
|
|
// invalid states (even if they should never happen). These settings are
|
|
// global since a license server would be more likely to be consistency
|
|
// invalid.
|
|
bool include_content_key_id = true;
|
|
bool include_content_key_key = true;
|
|
bool include_content_key_iv = true;
|
|
bool include_content_key_type = true;
|
|
|
|
bool include_signing_key_iv = true;
|
|
bool include_signing_key_key = true;
|
|
bool include_signing_key_type = true;
|
|
|
|
// Whether to insert an error in the KCB header
|
|
bool kcb_header_error = false;
|
|
|
|
// Our content key's key and ivs should always be 16 bytes (see AesKey
|
|
// definition), but we can use these controls to cut them short. If these
|
|
// values are larger than 16, the key/iv with be padded. In order to
|
|
// override the key size, *_override must be set to true. This is to avoid
|
|
// conflicts between padding and key size.
|
|
bool content_key_key_size_override = false;
|
|
size_t content_key_key_size = 16;
|
|
size_t content_key_iv_size = 16;
|
|
|
|
// Our signing key's key should always be 64 (see SigningKey definition) and
|
|
// the iv size should always be 16 bytes (see AesIV definition), but we can
|
|
// use these controls to cut them short. If these values are larger than 64
|
|
// and 16, the key/iv with be padded. In order to override the key size,
|
|
// *_override must be set to true. This is to avoid conflicts between
|
|
// padding and key size.
|
|
bool signing_key_key_size_override = false;
|
|
size_t signing_key_key_size = 64;
|
|
size_t signing_key_iv_size = 16;
|
|
|
|
// If required, use a ProviderKey when encrypting the content keys.
|
|
// By default, no Provider key is used. Note that the list of available
|
|
// provider keys is fixed.
|
|
size_t provider_key_id = kNoProviderKeyId;
|
|
};
|
|
|
|
// Returns a default signing key that can be used with AddSigningKey().
|
|
static SigningKey DefaultSigningKey();
|
|
|
|
TestLicenseBuilder();
|
|
|
|
void AddSigningKey(const SigningKey& key);
|
|
|
|
void AddContentKey(const ContentKeyData& key);
|
|
|
|
void AddEntitlementKey(const EntitlementKeyData& key);
|
|
|
|
void AddGenericKey(const GenericKeyData& key);
|
|
|
|
// The key id will matter as we will need to reference it, but the key won't
|
|
// matter since we are only using it as a means to verify that a non-content
|
|
// key can't be used as a content key.
|
|
void AddOperatorSessionKey(const KeyId& key_id);
|
|
|
|
void SetSettings(const Settings& settings) { settings_ = settings; }
|
|
Settings& GetSettings() { return settings_; }
|
|
const Settings& GetSettings() const { return settings_; }
|
|
|
|
// Gets the serialized license request and response (in components) that would
|
|
// have been used in the license exchange.
|
|
void Build(const TestServer& server, License* license) const;
|
|
|
|
private:
|
|
const std::array<uint8_t, 16> session_key_ = {
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
|
|
|
|
video_widevine::LicenseRequest request_;
|
|
video_widevine::License response_;
|
|
std::string serialized_request_;
|
|
// It is `serialized_request_` for license protocol 2.1, and
|
|
// `sha512(serialized_request_)` for license protocol 2.2.
|
|
std::string request_for_key_derivation_;
|
|
std::string container_key_;
|
|
|
|
Settings settings_;
|
|
|
|
std::vector<ContentKeyData> content_keys_;
|
|
std::vector<EntitlementKeyData> entitlement_keys_;
|
|
std::vector<GenericKeyData> generic_keys_;
|
|
std::vector<SigningKey> signing_keys_;
|
|
std::vector<KeyId> operator_session_keys_;
|
|
};
|
|
|
|
inline std::ostream& operator<<(std::ostream& os,
|
|
TestLicenseBuilder::Padding value) {
|
|
switch (value) {
|
|
case TestLicenseBuilder::Padding::kNone:
|
|
return os << "NoPadding";
|
|
case TestLicenseBuilder::Padding::kPKSC8:
|
|
return os << "PKSC8";
|
|
default:
|
|
return os << "<Unknown Padding>";
|
|
}
|
|
}
|
|
|
|
inline std::ostream& operator<<(std::ostream& os,
|
|
TestLicenseBuilder::RemoteAttestation value) {
|
|
switch (value) {
|
|
case TestLicenseBuilder::RemoteAttestation::kUnavailable:
|
|
return os << "RA Unavailable";
|
|
case TestLicenseBuilder::RemoteAttestation::kVerified:
|
|
return os << "RA Verified";
|
|
case TestLicenseBuilder::RemoteAttestation::kUnverified:
|
|
return os << "RA Unverified";
|
|
default:
|
|
return os << "<Unknown RA>";
|
|
}
|
|
}
|
|
|
|
inline std::ostream& operator<<(std::ostream& os,
|
|
TestLicenseBuilder::VerificationStatus value) {
|
|
switch (value) {
|
|
case TestLicenseBuilder::VerificationStatus::kUnavailable:
|
|
return os << "Unverified";
|
|
case TestLicenseBuilder::VerificationStatus::kHardwareVerified:
|
|
return os << "HardwareVerified";
|
|
default:
|
|
return os << "VerifiedOther";
|
|
}
|
|
}
|
|
|
|
|
|
} // namespace widevine
|
|
|
|
#endif // WHITEBOX_API_LICENSE_BUILDER_H_
|