Merge "Pick widevine oemcrypto-v18 change"
This commit is contained in:
@@ -13,10 +13,12 @@ namespace wvcdm {
|
||||
|
||||
class ContentKeySession : public KeySession {
|
||||
public:
|
||||
ContentKeySession(CryptoSessionId oec_session_id,
|
||||
ContentKeySession(RequestedSecurityLevel security_level,
|
||||
CryptoSessionId oec_session_id,
|
||||
metrics::CryptoMetrics* metrics)
|
||||
: KeySession(metrics),
|
||||
oec_session_id_(oec_session_id),
|
||||
security_level_(security_level),
|
||||
cipher_mode_(kCipherModeCtr) {}
|
||||
~ContentKeySession() override {}
|
||||
|
||||
@@ -52,6 +54,24 @@ class ContentKeySession : public KeySession {
|
||||
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern) override;
|
||||
|
||||
OEMCryptoResult GenericEncrypt(const std::string& in_buffer,
|
||||
const std::string& iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
std::string* out_buffer) override;
|
||||
|
||||
OEMCryptoResult GenericDecrypt(const std::string& in_buffer,
|
||||
const std::string& iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
std::string* out_buffer) override;
|
||||
|
||||
OEMCryptoResult GenericSign(const std::string& message,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
std::string* signature) override;
|
||||
|
||||
OEMCryptoResult GenericVerify(const std::string& message,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
const std::string& signature) override;
|
||||
|
||||
protected:
|
||||
virtual OEMCryptoResult LoadKeysAsLicenseType(
|
||||
const std::string& message, const std::string& signature,
|
||||
@@ -60,11 +80,19 @@ class ContentKeySession : public KeySession {
|
||||
const std::string& provider_session_token,
|
||||
const std::string& srm_requirement, OEMCrypto_LicenseType license_type);
|
||||
|
||||
OEMCryptoResult GetKeyHandle(CryptoSessionId session_id,
|
||||
const std::string& key_id,
|
||||
CdmCipherMode cipher_mode);
|
||||
|
||||
CryptoSessionId oec_session_id_;
|
||||
|
||||
private:
|
||||
RequestedSecurityLevel security_level_;
|
||||
|
||||
KeyId cached_key_id_;
|
||||
CdmCipherMode cipher_mode_;
|
||||
|
||||
std::vector<uint8_t> key_handle_;
|
||||
};
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -153,7 +153,8 @@ class CryptoSession {
|
||||
// License request/responses
|
||||
virtual CdmResponseType PrepareAndSignLicenseRequest(
|
||||
const std::string& message, std::string* core_message,
|
||||
std::string* signature);
|
||||
std::string* signature, bool& should_specify_algorithm,
|
||||
OEMCrypto_SignatureHashAlgorithm& algorithm);
|
||||
virtual CdmResponseType UseSecondaryKey(bool dual_key);
|
||||
// V16 licenses.
|
||||
virtual CdmResponseType LoadLicense(const std::string& signed_message,
|
||||
@@ -164,7 +165,8 @@ class CryptoSession {
|
||||
// Renewal request/responses
|
||||
virtual CdmResponseType PrepareAndSignRenewalRequest(
|
||||
const std::string& message, std::string* core_message,
|
||||
std::string* signature);
|
||||
std::string* signature, bool& should_specify_algorithm,
|
||||
OEMCrypto_SignatureHashAlgorithm& algorithm);
|
||||
// V16 licenses.
|
||||
virtual CdmResponseType LoadRenewal(const std::string& signed_message,
|
||||
const std::string& core_message,
|
||||
@@ -180,7 +182,8 @@ class CryptoSession {
|
||||
const std::string& session_key);
|
||||
virtual CdmResponseType PrepareAndSignProvisioningRequest(
|
||||
const std::string& message, std::string* core_message,
|
||||
std::string* signature);
|
||||
std::string* signature, bool& should_specify_algorithm,
|
||||
OEMCrypto_SignatureHashAlgorithm& algorithm);
|
||||
virtual CdmResponseType LoadProvisioning(const std::string& signed_message,
|
||||
const std::string& core_message,
|
||||
const std::string& signature,
|
||||
@@ -215,7 +218,6 @@ class CryptoSession {
|
||||
uint32_t* tier);
|
||||
|
||||
virtual bool GetSupportedCertificateTypes(SupportedCertificateTypes* support);
|
||||
virtual CdmResponseType GetRandom(size_t data_length, uint8_t* random_data);
|
||||
virtual CdmResponseType GetNumberOfOpenSessions(
|
||||
RequestedSecurityLevel security_level, size_t* count);
|
||||
virtual CdmResponseType GetMaxNumberOfSessions(
|
||||
|
||||
@@ -17,7 +17,8 @@ namespace wvcdm {
|
||||
|
||||
class EntitlementKeySession : public ContentKeySession {
|
||||
public:
|
||||
EntitlementKeySession(CryptoSessionId oec_session_id,
|
||||
EntitlementKeySession(RequestedSecurityLevel security_level,
|
||||
CryptoSessionId oec_session_id,
|
||||
metrics::CryptoMetrics* metrics);
|
||||
~EntitlementKeySession() override;
|
||||
|
||||
@@ -35,9 +36,6 @@ class EntitlementKeySession : public ContentKeySession {
|
||||
const std::vector<CryptoKey>& keys) override;
|
||||
OEMCryptoResult SelectKey(const std::string& key_id,
|
||||
CdmCipherMode cipher_mode) override;
|
||||
OEMCryptoResult Decrypt(
|
||||
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern) override;
|
||||
|
||||
private:
|
||||
// The message is populated with the fields of the provided CryptoKey and the
|
||||
|
||||
@@ -40,6 +40,20 @@ class KeySession {
|
||||
virtual OEMCryptoResult Decrypt(
|
||||
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern) = 0;
|
||||
virtual OEMCryptoResult GenericEncrypt(const std::string& in_buffer,
|
||||
const std::string& iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
std::string* out_buffer) = 0;
|
||||
virtual OEMCryptoResult GenericDecrypt(const std::string& in_buffer,
|
||||
const std::string& iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
std::string* out_buffer) = 0;
|
||||
virtual OEMCryptoResult GenericSign(const std::string& message,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
std::string* signature) = 0;
|
||||
virtual OEMCryptoResult GenericVerify(const std::string& message,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
const std::string& signature) = 0;
|
||||
|
||||
protected:
|
||||
metrics::CryptoMetrics* metrics_;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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_LICENSE_PROTOCOL_CONVERSIONS_H_
|
||||
#define WVCDM_CORE_LICENSE_PROTOCOL_CONVERSIONS_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "license_protocol.pb.h"
|
||||
|
||||
namespace wvcdm {
|
||||
bool OecAlgorithmToProtoAlgorithm(
|
||||
OEMCrypto_SignatureHashAlgorithm oec_algorithm,
|
||||
video_widevine::HashAlgorithmProto& proto_algorithm);
|
||||
} // namespace wvcdm
|
||||
#endif // WVCDM_CORE_LICENSE_PROTOCOL_CONVERSIONS_H_
|
||||
@@ -73,94 +73,32 @@ OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(uint8_t* public_cert,
|
||||
OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(
|
||||
RequestedSecurityLevel level);
|
||||
OEMCryptoResult OEMCrypto_ProductionReady(RequestedSecurityLevel level);
|
||||
|
||||
OEMCryptoResult OEMCrypto_DecryptCENC(
|
||||
RequestedSecurityLevel level, const uint8_t* key_handle,
|
||||
size_t key_handle_length, const OEMCrypto_SampleDescription* samples,
|
||||
size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||
OEMCryptoResult OEMCrypto_Generic_Encrypt(
|
||||
RequestedSecurityLevel level, const uint8_t* key_handle,
|
||||
size_t key_handle_length, const OEMCrypto_SharedMemory* in_buffer,
|
||||
size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm,
|
||||
OEMCrypto_SharedMemory* out_buffer);
|
||||
OEMCryptoResult OEMCrypto_Generic_Decrypt(
|
||||
RequestedSecurityLevel level, const uint8_t* key_handle,
|
||||
size_t key_handle_length, const OEMCrypto_SharedMemory* in_buffer,
|
||||
size_t in_buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm,
|
||||
OEMCrypto_SharedMemory* out_buffer);
|
||||
OEMCryptoResult OEMCrypto_Generic_Sign(
|
||||
RequestedSecurityLevel level, const uint8_t* key_handle,
|
||||
size_t key_handle_length, const OEMCrypto_SharedMemory* buffer,
|
||||
size_t buffer_length, OEMCrypto_Algorithm algorithm,
|
||||
OEMCrypto_SharedMemory* signature, size_t* signature_length);
|
||||
OEMCryptoResult OEMCrypto_Generic_Verify(
|
||||
RequestedSecurityLevel level, const uint8_t* key_handle,
|
||||
size_t key_handle_length, const OEMCrypto_SharedMemory* buffer,
|
||||
size_t buffer_length, OEMCrypto_Algorithm algorithm,
|
||||
const OEMCrypto_SharedMemory* signature, size_t signature_length);
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
/* The following functions are deprecated in OEMCrypto v13. They are defined
|
||||
* here so that core cdm code may be backwards compatible with an OEMCrypto
|
||||
* v12.
|
||||
*/
|
||||
extern "C" {
|
||||
|
||||
typedef struct { // Used for backwards compatibility.
|
||||
const uint8_t* key_id;
|
||||
size_t key_id_length;
|
||||
const uint8_t* key_data_iv;
|
||||
const uint8_t* key_data;
|
||||
size_t key_data_length;
|
||||
const uint8_t* key_control_iv;
|
||||
const uint8_t* key_control;
|
||||
} OEMCrypto_KeyObject_V10;
|
||||
|
||||
typedef struct { // Used for backwards compatibility.
|
||||
const uint8_t* key_id;
|
||||
size_t key_id_length;
|
||||
const uint8_t* key_data_iv;
|
||||
const uint8_t* key_data;
|
||||
size_t key_data_length;
|
||||
const uint8_t* key_control_iv;
|
||||
const uint8_t* key_control;
|
||||
OEMCryptoCipherMode cipher_mode;
|
||||
} OEMCrypto_KeyObject_V13;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t* key_id;
|
||||
size_t key_id_length;
|
||||
const uint8_t* key_data_iv;
|
||||
const uint8_t* key_data;
|
||||
size_t key_data_length;
|
||||
const uint8_t* key_control_iv;
|
||||
const uint8_t* key_control;
|
||||
} OEMCrypto_KeyObject_V14;
|
||||
|
||||
// Backwards compatibility between v14 and v13.
|
||||
OEMCryptoResult OEMCrypto_LoadKeys_Back_Compat(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature, size_t signature_length,
|
||||
OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys,
|
||||
size_t num_keys, const OEMCrypto_KeyObject* key_array,
|
||||
OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data,
|
||||
OEMCrypto_LicenseType license_type, OEMCryptoCipherMode* cipher_modes);
|
||||
|
||||
OEMCryptoResult OEMCrypto_DeactivateUsageEntry_V12(const uint8_t* pst,
|
||||
size_t pst_length);
|
||||
typedef struct {
|
||||
const uint8_t* entitlement_key_id;
|
||||
size_t entitlement_key_id_length;
|
||||
const uint8_t* content_key_id;
|
||||
size_t content_key_id_length;
|
||||
const uint8_t* content_key_data_iv;
|
||||
const uint8_t* content_key_data;
|
||||
size_t content_key_data_length;
|
||||
} OEMCrypto_EntitledContentKeyObject_V14;
|
||||
|
||||
typedef struct {
|
||||
const uint8_t* key_id;
|
||||
size_t key_id_length;
|
||||
const uint8_t* key_control_iv;
|
||||
const uint8_t* key_control;
|
||||
} OEMCrypto_KeyRefreshObject_V14;
|
||||
|
||||
OEMCryptoResult OEMCrypto_LoadKeys_V14(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature, size_t signature_length,
|
||||
const uint8_t* enc_mac_keys_iv, const uint8_t* enc_mac_keys,
|
||||
size_t num_keys, const OEMCrypto_KeyObject_V14* key_array,
|
||||
const uint8_t* pst, size_t pst_length, const uint8_t* srm_requirement,
|
||||
OEMCrypto_LicenseType license_type);
|
||||
|
||||
OEMCryptoResult OEMCrypto_LoadEntitledContentKeys_V14(
|
||||
OEMCrypto_SESSION session, size_t num_keys,
|
||||
const OEMCrypto_EntitledContentKeyObject_V14* key_array);
|
||||
|
||||
OEMCryptoResult OEMCrypto_RefreshKeys_V14(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
const uint8_t* signature, size_t signature_length, size_t num_keys,
|
||||
const OEMCrypto_KeyRefreshObject_V14* key_array);
|
||||
|
||||
OEMCryptoResult OEMCrypto_CopyBuffer_V14(
|
||||
const uint8_t* data_addr, size_t data_length,
|
||||
OEMCrypto_DestBufferDesc* out_buffer_descriptor, uint8_t subsample_flags);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // WVCDM_CORE_OEMCRYPTO_ADAPTER_H_
|
||||
|
||||
@@ -51,6 +51,7 @@ constexpr uint32_t RESOURCE_RATING_TIER_MAX = RESOURCE_RATING_TIER_VERY_HIGH;
|
||||
|
||||
// OEMCrypto features by version
|
||||
constexpr uint32_t OEM_CRYPTO_API_VERSION_SUPPORTS_RESOURCE_RATING_TIER = 15;
|
||||
constexpr uint32_t OEM_CRYPTO_API_VERSION_SUPPORTS_PROV40_CORE_MESSAGE = 18;
|
||||
|
||||
constexpr char SESSION_ID_PREFIX[] = "sid";
|
||||
constexpr char ATSC_KEY_SET_ID_PREFIX[] = "atscksid";
|
||||
|
||||
@@ -444,8 +444,15 @@ enum CdmResponseEnum : int32_t {
|
||||
PROVISIONING_4_FAILED_TO_STORE_OEM_CERTIFICATE = 384,
|
||||
PROVISIONING_4_FAILED_TO_STORE_DRM_CERTIFICATE = 385,
|
||||
PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_3 = 386,
|
||||
GET_SIGNATURE_HASH_ALGORITHM_ERROR_1 = 387,
|
||||
GET_SIGNATURE_HASH_ALGORITHM_ERROR_2 = 388,
|
||||
GET_SIGNATURE_HASH_ALGORITHM_ERROR_3 = 389,
|
||||
UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_1 = 390,
|
||||
UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_2 = 391,
|
||||
UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_3 = 392,
|
||||
UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_4 = 393,
|
||||
// Don't forget to add new values to
|
||||
// * core/test/test_printers.cpp.
|
||||
// * core/src/wv_cdm_types.cpp
|
||||
// * android/include/mapErrors-inl.h
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "cdm_engine.h"
|
||||
#include "cdm_random.h"
|
||||
#include "clock.h"
|
||||
#include "crypto_wrapped_key.h"
|
||||
#include "file_store.h"
|
||||
@@ -306,10 +307,16 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
|
||||
std::string fake_message("empty message");
|
||||
std::string core_message;
|
||||
std::string license_request_signature;
|
||||
bool should_specify_algorithm;
|
||||
OEMCrypto_SignatureHashAlgorithm algorithm = OEMCrypto_SHA1;
|
||||
uint32_t nonce;
|
||||
// Sign a fake message so that OEMCrypto will start the rental clock. The
|
||||
// signature and generated core message are ignored.
|
||||
result = crypto_session_->GenerateNonce(&nonce);
|
||||
if (result != NO_ERROR) return result;
|
||||
result = crypto_session_->PrepareAndSignLicenseRequest(
|
||||
fake_message, &core_message, &license_request_signature);
|
||||
fake_message, &core_message, &license_request_signature,
|
||||
should_specify_algorithm, algorithm);
|
||||
if (result != NO_ERROR) return result;
|
||||
}
|
||||
|
||||
@@ -888,15 +895,14 @@ bool CdmSession::GenerateKeySetId(bool atsc_mode_enabled,
|
||||
CdmKeySetId* key_set_id) {
|
||||
RETURN_FALSE_IF_NULL(key_set_id);
|
||||
|
||||
std::vector<uint8_t> random_data(
|
||||
(kKeySetIdLength - sizeof(KEY_SET_ID_PREFIX)) / 2, 0);
|
||||
|
||||
while (key_set_id->empty()) {
|
||||
if (crypto_session_->GetRandom(random_data.size(), &random_data[0]) !=
|
||||
NO_ERROR) {
|
||||
constexpr size_t random_size =
|
||||
(kKeySetIdLength - sizeof(KEY_SET_ID_PREFIX)) / 2;
|
||||
std::string random_data = wvutil::CdmRandom::RandomData(random_size);
|
||||
if (random_data.size() != random_size) {
|
||||
LOGE("Error generating random id.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (atsc_mode_enabled)
|
||||
*key_set_id = ATSC_KEY_SET_ID_PREFIX + wvutil::b2a_hex(random_data);
|
||||
else
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "device_files.h"
|
||||
#include "file_store.h"
|
||||
#include "license_protocol.pb.h"
|
||||
#include "license_protocol_conversions.h"
|
||||
#include "log.h"
|
||||
#include "properties.h"
|
||||
#include "service_certificate.h"
|
||||
@@ -89,6 +90,7 @@ bool RetrieveOemCertificateAndLoadPrivateKey(CryptoSession& crypto_session,
|
||||
// Protobuf generated classes.
|
||||
using video_widevine::DrmCertificate;
|
||||
using video_widevine::EncryptedClientIdentification;
|
||||
using video_widevine::HashAlgorithmProto;
|
||||
using video_widevine::ProvisioningOptions;
|
||||
using video_widevine::ProvisioningRequest;
|
||||
using video_widevine::ProvisioningResponse;
|
||||
@@ -258,8 +260,11 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
||||
// Derives signing and encryption keys and constructs signature.
|
||||
std::string core_message;
|
||||
std::string request_signature;
|
||||
bool should_specify_algorithm;
|
||||
OEMCrypto_SignatureHashAlgorithm oec_algorithm = OEMCrypto_SHA1;
|
||||
status = crypto_session_->PrepareAndSignProvisioningRequest(
|
||||
serialized_message, &core_message, &request_signature);
|
||||
serialized_message, &core_message, &request_signature,
|
||||
should_specify_algorithm, oec_algorithm);
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to prepare provisioning request: status = %d",
|
||||
@@ -279,6 +284,14 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
||||
signed_provisioning_msg.set_oemcrypto_core_message(core_message);
|
||||
signed_provisioning_msg.set_protocol_version(
|
||||
SignedProvisioningMessage::VERSION_1_1);
|
||||
if (should_specify_algorithm) {
|
||||
HashAlgorithmProto proto_algorithm =
|
||||
HashAlgorithmProto::HASH_ALGORITHM_UNSPECIFIED;
|
||||
if (!OecAlgorithmToProtoAlgorithm(oec_algorithm, proto_algorithm)) {
|
||||
return CdmResponseType(UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_3);
|
||||
}
|
||||
signed_provisioning_msg.set_hash_algorithm(proto_algorithm);
|
||||
}
|
||||
|
||||
std::string serialized_request;
|
||||
signed_provisioning_msg.SerializeToString(&serialized_request);
|
||||
@@ -398,17 +411,56 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
||||
? PublicKeyToCertify::RSA
|
||||
: PublicKeyToCertify::ECC);
|
||||
|
||||
// In provisioning 4, the message is not signed.
|
||||
std::string serialized_message;
|
||||
provisioning_request.SerializeToString(&serialized_message);
|
||||
|
||||
SignedProvisioningMessage signed_provisioning_msg;
|
||||
provisioning_request.SerializeToString(
|
||||
signed_provisioning_msg.mutable_message());
|
||||
signed_provisioning_msg.set_message(serialized_message);
|
||||
signed_provisioning_msg.set_provisioning_type(GetProvisioningType());
|
||||
signed_provisioning_msg.set_protocol_version(
|
||||
SignedProvisioningMessage::VERSION_1_1);
|
||||
|
||||
// Core message and request signature are added to the provisioning request
|
||||
// starting OEMCrypto v18
|
||||
uint32_t api_version = 0;
|
||||
const bool core_message_signature_required =
|
||||
crypto_session_->GetApiVersion(&api_version) &&
|
||||
(api_version >= OEM_CRYPTO_API_VERSION_SUPPORTS_PROV40_CORE_MESSAGE);
|
||||
if (core_message_signature_required) {
|
||||
std::string core_message;
|
||||
std::string request_signature;
|
||||
bool should_specify_algorithm;
|
||||
OEMCrypto_SignatureHashAlgorithm oec_algorithm = OEMCrypto_SHA1;
|
||||
status = crypto_session_->PrepareAndSignProvisioningRequest(
|
||||
serialized_message, &core_message, &request_signature,
|
||||
should_specify_algorithm, oec_algorithm);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to prepare provisioning 4.0 request: status = %d",
|
||||
static_cast<int>(status));
|
||||
return status;
|
||||
}
|
||||
if (core_message.empty()) {
|
||||
LOGE("Core message is empty");
|
||||
return CdmResponseType(CERT_PROVISIONING_REQUEST_ERROR_4);
|
||||
}
|
||||
if (request_signature.empty()) {
|
||||
LOGE("Request signature is empty");
|
||||
return CdmResponseType(CERT_PROVISIONING_REQUEST_ERROR_4);
|
||||
}
|
||||
signed_provisioning_msg.set_oemcrypto_core_message(core_message);
|
||||
signed_provisioning_msg.set_signature(request_signature);
|
||||
if (should_specify_algorithm) {
|
||||
HashAlgorithmProto proto_algorithm =
|
||||
HashAlgorithmProto::HASH_ALGORITHM_UNSPECIFIED;
|
||||
if (!OecAlgorithmToProtoAlgorithm(oec_algorithm, proto_algorithm)) {
|
||||
return CdmResponseType(UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_4);
|
||||
}
|
||||
signed_provisioning_msg.set_hash_algorithm(proto_algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
std::string serialized_request;
|
||||
signed_provisioning_msg.SerializeToString(&serialized_request);
|
||||
|
||||
if (!wvcdm::Properties::provisioning_messages_are_binary()) {
|
||||
// Return request as web-safe base64 string
|
||||
*request = wvutil::Base64SafeEncodeNoPad(serialized_request);
|
||||
|
||||
@@ -80,25 +80,23 @@ OEMCryptoResult ContentKeySession::LoadKeys(
|
||||
OEMCryptoResult ContentKeySession::SelectKey(const std::string& key_id,
|
||||
CdmCipherMode cipher_mode) {
|
||||
// Crypto session lock already locked.
|
||||
if (!cached_key_id_.empty() && cached_key_id_ == key_id &&
|
||||
if (key_id.empty()) {
|
||||
LOGE("Empty key ID argument");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (!key_handle_.empty() && cached_key_id_ == key_id &&
|
||||
cipher_mode_ == cipher_mode) {
|
||||
// Already using the desired key and cipher mode.
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
cached_key_id_ = key_id;
|
||||
cipher_mode_ = cipher_mode;
|
||||
|
||||
const uint8_t* key_id_string =
|
||||
reinterpret_cast<const uint8_t*>(cached_key_id_.data());
|
||||
|
||||
OEMCryptoResult sts;
|
||||
M_TIME(sts = OEMCrypto_SelectKey(oec_session_id_, key_id_string,
|
||||
cached_key_id_.size(),
|
||||
ToOEMCryptoCipherMode(cipher_mode)),
|
||||
metrics_, oemcrypto_select_key_, sts);
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
const OEMCryptoResult sts =
|
||||
GetKeyHandle(oec_session_id_, key_id, cipher_mode);
|
||||
if (sts == OEMCrypto_SUCCESS) {
|
||||
cached_key_id_ = key_id;
|
||||
cipher_mode_ = cipher_mode;
|
||||
} else {
|
||||
key_handle_.clear();
|
||||
cached_key_id_.clear();
|
||||
}
|
||||
return sts;
|
||||
@@ -114,65 +112,192 @@ OEMCryptoResult ContentKeySession::Decrypt(
|
||||
}
|
||||
|
||||
OEMCryptoResult sts;
|
||||
M_TIME(sts = OEMCrypto_DecryptCENC(oec_session_id_, samples, samples_length,
|
||||
&pattern),
|
||||
M_TIME(sts = OEMCrypto_DecryptCENC(security_level_, key_handle_.data(),
|
||||
key_handle_.size(), samples,
|
||||
samples_length, &pattern),
|
||||
metrics_, oemcrypto_decrypt_cenc_, sts,
|
||||
metrics::Pow2Bucket(total_size));
|
||||
return sts;
|
||||
}
|
||||
|
||||
OEMCryptoResult ContentKeySession::GenericEncrypt(const std::string& in_buffer,
|
||||
const std::string& iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
std::string* out_buffer) {
|
||||
OEMCryptoResult sts;
|
||||
M_TIME(
|
||||
sts = OEMCrypto_Generic_Encrypt(
|
||||
security_level_, key_handle_.data(), key_handle_.size(),
|
||||
reinterpret_cast<const uint8_t*>(in_buffer.data()), in_buffer.size(),
|
||||
reinterpret_cast<const uint8_t*>(iv.data()), algorithm,
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(out_buffer->data()))),
|
||||
metrics_, oemcrypto_generic_encrypt_, sts,
|
||||
metrics::Pow2Bucket(in_buffer.size()));
|
||||
if (sts != OEMCrypto_SUCCESS) {
|
||||
LOGE("OEMCrypto_Generic_Encrypt failed: status = %d",
|
||||
static_cast<int>(sts));
|
||||
}
|
||||
return sts;
|
||||
}
|
||||
|
||||
OEMCryptoResult ContentKeySession::GenericDecrypt(const std::string& in_buffer,
|
||||
const std::string& iv,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
std::string* out_buffer) {
|
||||
OEMCryptoResult sts;
|
||||
M_TIME(
|
||||
sts = OEMCrypto_Generic_Decrypt(
|
||||
security_level_, key_handle_.data(), key_handle_.size(),
|
||||
reinterpret_cast<const uint8_t*>(in_buffer.data()), in_buffer.size(),
|
||||
reinterpret_cast<const uint8_t*>(iv.data()), algorithm,
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(out_buffer->data()))),
|
||||
metrics_, oemcrypto_generic_decrypt_, sts,
|
||||
metrics::Pow2Bucket(in_buffer.size()));
|
||||
if (sts != OEMCrypto_SUCCESS) {
|
||||
LOGE("OEMCrypto_Generic_Decrypt failed: status = %d",
|
||||
static_cast<int>(sts));
|
||||
}
|
||||
return sts;
|
||||
}
|
||||
|
||||
OEMCryptoResult ContentKeySession::GenericSign(const std::string& message,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
std::string* signature) {
|
||||
OEMCryptoResult sts;
|
||||
size_t length = signature->size();
|
||||
|
||||
// At most two attempts.
|
||||
// The first attempt may fail due to buffer too short
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
M_TIME(sts = OEMCrypto_Generic_Sign(
|
||||
security_level_, key_handle_.data(), key_handle_.size(),
|
||||
reinterpret_cast<const uint8_t*>(message.data()), message.size(),
|
||||
algorithm,
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length),
|
||||
metrics_, oemcrypto_generic_sign_, sts,
|
||||
metrics::Pow2Bucket(message.size()));
|
||||
|
||||
if (sts != OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
if (sts == OEMCrypto_SUCCESS) {
|
||||
// Trim signature buffer and done
|
||||
signature->resize(length);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Retry with proper-sized return buffer
|
||||
signature->resize(length);
|
||||
}
|
||||
|
||||
if (sts != OEMCrypto_SUCCESS) {
|
||||
LOGE("OEMCrypto_Generic_Sign failed: status = %d", static_cast<int>(sts));
|
||||
}
|
||||
return sts;
|
||||
}
|
||||
|
||||
OEMCryptoResult ContentKeySession::GenericVerify(const std::string& message,
|
||||
OEMCrypto_Algorithm algorithm,
|
||||
const std::string& signature) {
|
||||
OEMCryptoResult sts;
|
||||
M_TIME(sts = OEMCrypto_Generic_Verify(
|
||||
security_level_, key_handle_.data(), key_handle_.size(),
|
||||
reinterpret_cast<const uint8_t*>(message.data()), message.size(),
|
||||
algorithm, reinterpret_cast<const uint8_t*>(signature.data()),
|
||||
signature.size()),
|
||||
metrics_, oemcrypto_generic_verify_, sts,
|
||||
metrics::Pow2Bucket(signature.size()));
|
||||
if (sts != OEMCrypto_SUCCESS) {
|
||||
LOGE("OEMCrypto_Generic_Verify failed: status = %d", static_cast<int>(sts));
|
||||
}
|
||||
return sts;
|
||||
}
|
||||
|
||||
OEMCryptoResult ContentKeySession::LoadKeysAsLicenseType(
|
||||
const std::string& message, const std::string& signature,
|
||||
const std::string& mac_key_iv, const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& keys,
|
||||
const std::string& provider_session_token,
|
||||
const std::string& srm_requirement, OEMCrypto_LicenseType license_type) {
|
||||
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
|
||||
cached_key_id_.clear();
|
||||
bool valid_mac_keys =
|
||||
mac_key.length() >= MAC_KEY_SIZE && mac_key_iv.length() >= KEY_IV_SIZE;
|
||||
OEMCrypto_Substring enc_mac_key =
|
||||
GetSubstring(message, mac_key, !valid_mac_keys);
|
||||
OEMCrypto_Substring enc_mac_key_iv =
|
||||
GetSubstring(message, mac_key_iv, !valid_mac_keys);
|
||||
if (!valid_mac_keys) LOGV("|enc_mac_key| is not set");
|
||||
std::vector<OEMCrypto_KeyObject> load_keys(keys.size());
|
||||
std::vector<OEMCryptoCipherMode> cipher_modes(keys.size());
|
||||
for (size_t i = 0; i < keys.size(); ++i) {
|
||||
const CryptoKey* ki = &keys[i];
|
||||
OEMCrypto_KeyObject* ko = &load_keys[i];
|
||||
ko->key_id = GetSubstring(message, ki->key_id());
|
||||
ko->key_data_iv = GetSubstring(message, ki->key_data_iv());
|
||||
ko->key_data = GetSubstring(message, ki->key_data());
|
||||
bool has_key_control = ki->HasKeyControl();
|
||||
ko->key_control_iv =
|
||||
GetSubstring(message, ki->key_control_iv(), !has_key_control);
|
||||
ko->key_control =
|
||||
GetSubstring(message, ki->key_control(), !has_key_control);
|
||||
if (!has_key_control) {
|
||||
LOGE(
|
||||
"Crypto key does not have a control block: "
|
||||
"key_index = %zu, size = %zu",
|
||||
i, ki->key_control().length());
|
||||
}
|
||||
cipher_modes[i] = ToOEMCryptoCipherMode(ki->cipher_mode());
|
||||
// TODO(b/252670759): remove all of this.
|
||||
// const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
|
||||
// cached_key_id_.clear();
|
||||
// bool valid_mac_keys =
|
||||
// mac_key.length() >= MAC_KEY_SIZE && mac_key_iv.length() >= KEY_IV_SIZE;
|
||||
// OEMCrypto_Substring enc_mac_key =
|
||||
// GetSubstring(message, mac_key, !valid_mac_keys);
|
||||
// OEMCrypto_Substring enc_mac_key_iv =
|
||||
// GetSubstring(message, mac_key_iv, !valid_mac_keys);
|
||||
// if (!valid_mac_keys) LOGV("|enc_mac_key| is not set");
|
||||
// std::vector<OEMCrypto_KeyObject> load_keys(keys.size());
|
||||
// std::vector<OEMCryptoCipherMode> cipher_modes(keys.size());
|
||||
// for (size_t i = 0; i < keys.size(); ++i) {
|
||||
// const CryptoKey* ki = &keys[i];
|
||||
// OEMCrypto_KeyObject* ko = &load_keys[i];
|
||||
// ko->key_id = GetSubstring(message, ki->key_id());
|
||||
// ko->key_data_iv = GetSubstring(message, ki->key_data_iv());
|
||||
// ko->key_data = GetSubstring(message, ki->key_data());
|
||||
// bool has_key_control = ki->HasKeyControl();
|
||||
// ko->key_control_iv =
|
||||
// GetSubstring(message, ki->key_control_iv(), !has_key_control);
|
||||
// ko->key_control =
|
||||
// GetSubstring(message, ki->key_control(), !has_key_control);
|
||||
// if (!has_key_control) {
|
||||
// LOGE(
|
||||
// "Crypto key does not have a control block: "
|
||||
// "key_index = %zu, size = %zu",
|
||||
// i, ki->key_control().length());
|
||||
// }
|
||||
// cipher_modes[i] = ToOEMCryptoCipherMode(ki->cipher_mode());
|
||||
// }
|
||||
|
||||
// OEMCrypto_Substring pst = GetSubstring(message, provider_session_token);
|
||||
// OEMCrypto_Substring srm_req = GetSubstring(message, srm_requirement);
|
||||
|
||||
// LOGV("session_id = %u", oec_session_id_);
|
||||
// OEMCryptoResult sts;
|
||||
// OEMCrypto_KeyObject* key_array_ptr = nullptr;
|
||||
// if (keys.size() > 0) key_array_ptr = &load_keys[0];
|
||||
// OEMCryptoCipherMode* cipher_mode_ptr = nullptr;
|
||||
// if (keys.size() > 0) cipher_mode_ptr = &cipher_modes[0];
|
||||
// M_TIME(sts = ::OEMCrypto_LoadKeys_Back_Compat(
|
||||
// oec_session_id_, msg, message.length(),
|
||||
// reinterpret_cast<const uint8_t*>(signature.data()),
|
||||
// signature.length(), enc_mac_key_iv, enc_mac_key, keys.size(),
|
||||
// key_array_ptr, pst, srm_req, license_type, cipher_mode_ptr),
|
||||
// metrics_, oemcrypto_load_keys_, sts);
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
OEMCryptoResult ContentKeySession::GetKeyHandle(CryptoSessionId session_id,
|
||||
const std::string& key_id,
|
||||
CdmCipherMode cipher_mode) {
|
||||
const uint8_t* const key_id_pointer =
|
||||
reinterpret_cast<const uint8_t*>(key_id.data());
|
||||
const OEMCryptoCipherMode oec_cipher_mode =
|
||||
ToOEMCryptoCipherMode(cipher_mode);
|
||||
|
||||
size_t key_handle_length = 0;
|
||||
OEMCryptoResult sts;
|
||||
M_TIME(sts = OEMCrypto_GetKeyHandle(session_id, key_id_pointer, key_id.size(),
|
||||
oec_cipher_mode, nullptr,
|
||||
&key_handle_length),
|
||||
metrics_, oemcrypto_get_key_handle_, sts);
|
||||
|
||||
if (sts == OEMCrypto_SUCCESS) {
|
||||
LOGE(
|
||||
"OEMCrypto_GetKeyHandle returned SUCCESS despite getting no key handle "
|
||||
"buffer");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
} else if (sts != OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
return sts;
|
||||
}
|
||||
|
||||
OEMCrypto_Substring pst = GetSubstring(message, provider_session_token);
|
||||
OEMCrypto_Substring srm_req = GetSubstring(message, srm_requirement);
|
||||
|
||||
LOGV("session_id = %u", oec_session_id_);
|
||||
OEMCryptoResult sts;
|
||||
OEMCrypto_KeyObject* key_array_ptr = nullptr;
|
||||
if (keys.size() > 0) key_array_ptr = &load_keys[0];
|
||||
OEMCryptoCipherMode* cipher_mode_ptr = nullptr;
|
||||
if (keys.size() > 0) cipher_mode_ptr = &cipher_modes[0];
|
||||
M_TIME(sts = ::OEMCrypto_LoadKeys_Back_Compat(
|
||||
oec_session_id_, msg, message.length(),
|
||||
reinterpret_cast<const uint8_t*>(signature.data()),
|
||||
signature.length(), enc_mac_key_iv, enc_mac_key, keys.size(),
|
||||
key_array_ptr, pst, srm_req, license_type, cipher_mode_ptr),
|
||||
metrics_, oemcrypto_load_keys_, sts);
|
||||
key_handle_.resize(key_handle_length);
|
||||
M_TIME(sts = OEMCrypto_GetKeyHandle(session_id, key_id_pointer, key_id.size(),
|
||||
oec_cipher_mode, key_handle_.data(),
|
||||
&key_handle_length),
|
||||
metrics_, oemcrypto_get_key_handle_, sts);
|
||||
return sts;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
#include "advance_iv_ctr.h"
|
||||
#include "arraysize.h"
|
||||
#include "cdm_random.h"
|
||||
#include "content_key_session.h"
|
||||
#include "crypto_key.h"
|
||||
#include "entitlement_key_session.h"
|
||||
#include "log.h"
|
||||
#include "odk_structs.h"
|
||||
#include "okp_fallback_policy.h"
|
||||
#include "platform.h"
|
||||
#include "privacy_crypto.h"
|
||||
@@ -407,6 +409,8 @@ void CryptoSession::ReinitializeForTest() {
|
||||
LOGE("OEMCrypto_Initialize failed: %d", status);
|
||||
return;
|
||||
}
|
||||
OEMCrypto_SetMaxAPIVersion(ODK_MAJOR_VERSION);
|
||||
OEMCrypto_EnterTestMode();
|
||||
initialized_ = true;
|
||||
// For integration and unit tests we will install a test keybox and do not
|
||||
// need to do keybox provisioning.
|
||||
@@ -926,13 +930,8 @@ CdmResponseType CryptoSession::Open(
|
||||
open_ = true;
|
||||
|
||||
// Set up request ID
|
||||
uint64_t request_id_base;
|
||||
OEMCryptoResult random_sts;
|
||||
WithOecReadLock("Open() calling OEMCrypto_GetRandom", [&] {
|
||||
random_sts = OEMCrypto_GetRandom(
|
||||
reinterpret_cast<uint8_t*>(&request_id_base), sizeof(request_id_base));
|
||||
});
|
||||
metrics_->oemcrypto_get_random_.Increment(random_sts);
|
||||
uint64_t request_id_base =
|
||||
wvutil::CdmRandom::RandomInRange(std::numeric_limits<uint64_t>::max());
|
||||
uint64_t request_id_index =
|
||||
request_id_index_source_.fetch_add(1, std::memory_order_relaxed);
|
||||
request_id_ = wvutil::HexEncode(reinterpret_cast<uint8_t*>(&request_id_base),
|
||||
@@ -942,7 +941,8 @@ CdmResponseType CryptoSession::Open(
|
||||
|
||||
// Initialize key session
|
||||
WithOecSessionLock("Open() calling key_session_.reset()", [&] {
|
||||
key_session_.reset(new ContentKeySession(oec_session_id_, metrics_));
|
||||
key_session_.reset(new ContentKeySession(requested_security_level_,
|
||||
oec_session_id_, metrics_));
|
||||
});
|
||||
|
||||
if (!GetApiVersion(&api_version_)) {
|
||||
@@ -987,13 +987,27 @@ void CryptoSession::Close() {
|
||||
|
||||
CdmResponseType CryptoSession::PrepareAndSignLicenseRequest(
|
||||
const std::string& message, std::string* core_message,
|
||||
std::string* signature) {
|
||||
std::string* signature, bool& should_specify_algorithm,
|
||||
OEMCrypto_SignatureHashAlgorithm& algorithm) {
|
||||
LOGV("Preparing and signing license request: id = %u", oec_session_id_);
|
||||
RETURN_IF_NULL(signature, PARAMETER_NULL);
|
||||
RETURN_IF_NULL(core_message, PARAMETER_NULL);
|
||||
RETURN_IF_NOT_OPEN(CRYPTO_SESSION_NOT_OPEN);
|
||||
|
||||
OEMCryptoResult sts;
|
||||
WithOecSessionLock("GetSignatureHashAlgorithm", [&] {
|
||||
sts = OEMCrypto_GetSignatureHashAlgorithm(oec_session_id_, &algorithm);
|
||||
});
|
||||
metrics_->oemcrypto_get_signature_hash_algorithm_.Increment(sts, algorithm);
|
||||
if (sts == OEMCrypto_SUCCESS) {
|
||||
should_specify_algorithm = true;
|
||||
} else if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
should_specify_algorithm = false;
|
||||
} else {
|
||||
return MapOEMCryptoResult(sts, GET_SIGNATURE_HASH_ALGORITHM_ERROR_1,
|
||||
"PrepareAndSignLicenseRequest");
|
||||
}
|
||||
|
||||
size_t signature_length = 0;
|
||||
size_t core_message_length = 0;
|
||||
*core_message = "";
|
||||
@@ -1081,7 +1095,8 @@ CdmResponseType CryptoSession::LoadLicense(const std::string& signed_message,
|
||||
WithOecSessionLock("LoadLicense", [&] {
|
||||
if (key_type == kLicenseKeyTypeEntitlement &&
|
||||
key_session_->Type() != KeySession::kEntitlement) {
|
||||
key_session_.reset(new EntitlementKeySession(oec_session_id_, metrics_));
|
||||
key_session_.reset(new EntitlementKeySession(requested_security_level_,
|
||||
oec_session_id_, metrics_));
|
||||
}
|
||||
|
||||
M_TIME(sts = OEMCrypto_LoadLicense(
|
||||
@@ -1110,7 +1125,8 @@ CdmResponseType CryptoSession::LoadLicense(const std::string& signed_message,
|
||||
|
||||
CdmResponseType CryptoSession::PrepareAndSignRenewalRequest(
|
||||
const std::string& message, std::string* core_message,
|
||||
std::string* signature) {
|
||||
std::string* signature, bool& should_specify_algorithm,
|
||||
OEMCrypto_SignatureHashAlgorithm& algorithm) {
|
||||
LOGV("Preparing and signing renewal request: id = %u", oec_session_id_);
|
||||
if (signature == nullptr) {
|
||||
LOGE("Output parameter |signature| not provided");
|
||||
@@ -1122,6 +1138,19 @@ CdmResponseType CryptoSession::PrepareAndSignRenewalRequest(
|
||||
}
|
||||
|
||||
OEMCryptoResult sts;
|
||||
WithOecSessionLock("GetSignatureHashAlgorithm", [&] {
|
||||
sts = OEMCrypto_GetSignatureHashAlgorithm(oec_session_id_, &algorithm);
|
||||
});
|
||||
metrics_->oemcrypto_get_signature_hash_algorithm_.Increment(sts, algorithm);
|
||||
if (sts == OEMCrypto_SUCCESS) {
|
||||
should_specify_algorithm = true;
|
||||
} else if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
should_specify_algorithm = false;
|
||||
} else {
|
||||
return MapOEMCryptoResult(sts, GET_SIGNATURE_HASH_ALGORITHM_ERROR_2,
|
||||
"PrepareAndSignRenewalRequest");
|
||||
}
|
||||
|
||||
size_t signature_length = 0;
|
||||
size_t core_message_length = 0;
|
||||
*core_message = "";
|
||||
@@ -1197,7 +1226,8 @@ CdmResponseType CryptoSession::LoadRenewal(const std::string& signed_message,
|
||||
|
||||
CdmResponseType CryptoSession::PrepareAndSignProvisioningRequest(
|
||||
const std::string& message, std::string* core_message,
|
||||
std::string* signature) {
|
||||
std::string* signature, bool& should_specify_algorithm,
|
||||
OEMCrypto_SignatureHashAlgorithm& algorithm) {
|
||||
LOGV("Preparing and signing provisioning request: id = %u", oec_session_id_);
|
||||
if (signature == nullptr) {
|
||||
LOGE("Output parameter |signature| not provided");
|
||||
@@ -1208,21 +1238,42 @@ CdmResponseType CryptoSession::PrepareAndSignProvisioningRequest(
|
||||
return CdmResponseType(PARAMETER_NULL);
|
||||
}
|
||||
|
||||
OEMCryptoResult sts;
|
||||
if (pre_provision_token_type_ == kClientTokenKeybox) {
|
||||
should_specify_algorithm = false;
|
||||
const CdmResponseType status = GenerateDerivedKeys(message);
|
||||
if (status != NO_ERROR) return status;
|
||||
} else if (pre_provision_token_type_ == kClientTokenOemCert) {
|
||||
const OEMCryptoResult status = OEMCrypto_LoadOEMPrivateKey(oec_session_id_);
|
||||
if (status != OEMCrypto_SUCCESS) {
|
||||
return MapOEMCryptoResult(status, GET_TOKEN_FROM_OEM_CERT_ERROR,
|
||||
should_specify_algorithm = true;
|
||||
WithOecSessionLock("LoadOEMPrivateKey", [&] {
|
||||
sts = OEMCrypto_LoadOEMPrivateKey(oec_session_id_);
|
||||
});
|
||||
if (sts != OEMCrypto_SUCCESS) {
|
||||
return MapOEMCryptoResult(sts, GET_TOKEN_FROM_OEM_CERT_ERROR,
|
||||
"PrepareAndSignProvisioningRequest");
|
||||
}
|
||||
} else if (pre_provision_token_type_ == kClientTokenBootCertChain) {
|
||||
should_specify_algorithm = true;
|
||||
// Do nothing here. The key to signing the provisioning 4.0 request for each
|
||||
// stage has been loaded already when it was generated by OEMCrypto.
|
||||
} else {
|
||||
LOGE("Unknown method %d", pre_provision_token_type_);
|
||||
return CdmResponseType(UNKNOWN_CLIENT_TOKEN_TYPE);
|
||||
}
|
||||
|
||||
OEMCryptoResult sts;
|
||||
if (should_specify_algorithm) {
|
||||
WithOecSessionLock("GetSignatureHashAlgorithm", [&] {
|
||||
sts = OEMCrypto_GetSignatureHashAlgorithm(oec_session_id_, &algorithm);
|
||||
});
|
||||
metrics_->oemcrypto_get_signature_hash_algorithm_.Increment(sts, algorithm);
|
||||
if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
should_specify_algorithm = false;
|
||||
} else if (sts != OEMCrypto_SUCCESS) {
|
||||
return MapOEMCryptoResult(sts, GET_SIGNATURE_HASH_ALGORITHM_ERROR_3,
|
||||
"PrepareAndSignProvisioningRequest");
|
||||
}
|
||||
}
|
||||
|
||||
size_t signature_length = 0;
|
||||
size_t core_message_length = 0;
|
||||
*core_message = "";
|
||||
@@ -2091,18 +2142,6 @@ bool CryptoSession::GetSupportedCertificateTypes(
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GetRandom(size_t data_length,
|
||||
uint8_t* random_data) {
|
||||
RETURN_IF_NULL(random_data, PARAMETER_NULL);
|
||||
|
||||
OEMCryptoResult sts;
|
||||
WithOecReadLock("GetRandom",
|
||||
[&] { sts = OEMCrypto_GetRandom(random_data, data_length); });
|
||||
metrics_->oemcrypto_get_random_.Increment(sts);
|
||||
|
||||
return MapOEMCryptoResult(sts, RANDOM_GENERATION_ERROR, "GetRandom");
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GetNumberOfOpenSessions(
|
||||
RequestedSecurityLevel security_level, size_t* count) {
|
||||
LOGV("Getting number of open sessions: id = %u, security_level = %s",
|
||||
@@ -2435,14 +2474,8 @@ CdmResponseType CryptoSession::GenericEncrypt(const std::string& in_buffer,
|
||||
OEMCryptoResult sts;
|
||||
|
||||
WithOecSessionLock("GenericEncrypt", [&] {
|
||||
M_TIME(
|
||||
sts = OEMCrypto_Generic_Encrypt(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(in_buffer.data()),
|
||||
in_buffer.size(), reinterpret_cast<const uint8_t*>(iv.data()),
|
||||
oec_algorithm,
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(out_buffer->data()))),
|
||||
metrics_, oemcrypto_generic_encrypt_, sts,
|
||||
metrics::Pow2Bucket(in_buffer.size()));
|
||||
sts =
|
||||
key_session_->GenericEncrypt(in_buffer, iv, oec_algorithm, out_buffer);
|
||||
});
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
@@ -2496,14 +2529,8 @@ CdmResponseType CryptoSession::GenericDecrypt(const std::string& in_buffer,
|
||||
OEMCryptoResult sts;
|
||||
|
||||
WithOecSessionLock("GenericDecrypt", [&] {
|
||||
M_TIME(
|
||||
sts = OEMCrypto_Generic_Decrypt(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(in_buffer.data()),
|
||||
in_buffer.size(), reinterpret_cast<const uint8_t*>(iv.data()),
|
||||
oec_algorithm,
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(out_buffer->data()))),
|
||||
metrics_, oemcrypto_generic_decrypt_, sts,
|
||||
metrics::Pow2Bucket(in_buffer.size()));
|
||||
sts =
|
||||
key_session_->GenericDecrypt(in_buffer, iv, oec_algorithm, out_buffer);
|
||||
});
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
@@ -2542,45 +2569,20 @@ CdmResponseType CryptoSession::GenericSign(const std::string& message,
|
||||
return CdmResponseType(INVALID_PARAMETERS_ENG_15);
|
||||
}
|
||||
|
||||
OEMCryptoResult sts;
|
||||
size_t length = signature->size();
|
||||
|
||||
// TODO(jfore): We need to select a key with a cipher mode and algorithm
|
||||
// doesn't seem to fit. Is it ok to just use a default value here?
|
||||
// Or do we need to pass it in?
|
||||
CdmResponseType result = SelectKey(key_id, kCipherModeCbc);
|
||||
if (result != NO_ERROR) return result;
|
||||
|
||||
// At most two attempts.
|
||||
// The first attempt may fail due to buffer too short
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
WithOecSessionLock("GenericSign", [&] {
|
||||
M_TIME(
|
||||
sts = OEMCrypto_Generic_Sign(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(), oec_algorithm,
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length),
|
||||
metrics_, oemcrypto_generic_sign_, sts,
|
||||
metrics::Pow2Bucket(message.size()));
|
||||
});
|
||||
|
||||
if (OEMCrypto_SUCCESS == sts) {
|
||||
// Trim signature buffer and done
|
||||
signature->resize(length);
|
||||
return CdmResponseType(NO_ERROR);
|
||||
}
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Retry with proper-sized return buffer
|
||||
signature->resize(length);
|
||||
}
|
||||
|
||||
LOGE("OEMCrypto_Generic_Sign failed: status = %d", static_cast<int>(sts));
|
||||
OEMCryptoResult sts;
|
||||
WithOecSessionLock("GenericSign", [&] {
|
||||
sts = key_session_->GenericSign(message, oec_algorithm, signature);
|
||||
});
|
||||
|
||||
switch (sts) {
|
||||
case OEMCrypto_SUCCESS:
|
||||
return CdmResponseType(NO_ERROR);
|
||||
case OEMCrypto_ERROR_KEY_EXPIRED:
|
||||
return CRYPTO_ERROR(NEED_KEY, sts);
|
||||
case OEMCrypto_ERROR_NO_CONTENT_KEY:
|
||||
@@ -2616,14 +2618,7 @@ CdmResponseType CryptoSession::GenericVerify(const std::string& message,
|
||||
|
||||
OEMCryptoResult sts;
|
||||
WithOecSessionLock("GenericVerify", [&] {
|
||||
M_TIME(
|
||||
sts = OEMCrypto_Generic_Verify(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(), oec_algorithm,
|
||||
reinterpret_cast<const uint8_t*>(signature.data()),
|
||||
signature.size()),
|
||||
metrics_, oemcrypto_generic_verify_, sts,
|
||||
metrics::Pow2Bucket(signature.size()));
|
||||
sts = key_session_->GenericVerify(message, oec_algorithm, signature);
|
||||
});
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
@@ -2921,12 +2916,6 @@ bool CryptoSession::GetAnalogOutputCapabilities(bool* can_support_output,
|
||||
return true;
|
||||
}
|
||||
|
||||
// OEMCryptoResult OEMCrypto_DecryptCENC(
|
||||
// OEMCrypto_SESSION session,
|
||||
// const OEMCrypto_SampleDescription* samples, // an array of samples.
|
||||
// size_t samples_length, // the number of samples.
|
||||
// const OEMCrypto_CENCEncryptPatternDesc* pattern);
|
||||
|
||||
OEMCryptoResult CryptoSession::DecryptMultipleSamples(
|
||||
const std::vector<OEMCrypto_SampleDescription>& samples,
|
||||
CdmCipherMode cipher_mode,
|
||||
|
||||
@@ -13,9 +13,10 @@ namespace {
|
||||
constexpr int kInvalidKeySessionId = 0;
|
||||
} // namespace
|
||||
|
||||
EntitlementKeySession::EntitlementKeySession(CryptoSessionId oec_session_id,
|
||||
metrics::CryptoMetrics* metrics)
|
||||
: ContentKeySession(oec_session_id, metrics),
|
||||
EntitlementKeySession::EntitlementKeySession(
|
||||
RequestedSecurityLevel security_level, CryptoSessionId oec_session_id,
|
||||
metrics::CryptoMetrics* metrics)
|
||||
: ContentKeySession(security_level, oec_session_id, metrics),
|
||||
key_session_id_(kInvalidKeySessionId) {}
|
||||
|
||||
EntitlementKeySession::~EntitlementKeySession() {
|
||||
@@ -109,27 +110,7 @@ OEMCryptoResult EntitlementKeySession::SelectKey(const std::string& key_id,
|
||||
key_id;
|
||||
}
|
||||
|
||||
M_TIME(result = OEMCrypto_SelectKey(
|
||||
key_session_id_, reinterpret_cast<const uint8_t*>(key_id.data()),
|
||||
key_id.size(), ToOEMCryptoCipherMode(cipher_mode)),
|
||||
metrics_, oemcrypto_select_key_, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
OEMCryptoResult EntitlementKeySession::Decrypt(
|
||||
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern) {
|
||||
size_t total_size = 0;
|
||||
for (size_t i = 0; i < samples_length; ++i) {
|
||||
total_size += samples[i].buffers.input_data_length;
|
||||
}
|
||||
|
||||
OEMCryptoResult sts;
|
||||
M_TIME(sts = OEMCrypto_DecryptCENC(key_session_id_, samples, samples_length,
|
||||
&pattern),
|
||||
metrics_, oemcrypto_decrypt_cenc_, sts,
|
||||
metrics::Pow2Bucket(total_size));
|
||||
return sts;
|
||||
return GetKeyHandle(key_session_id_, key_id, cipher_mode);
|
||||
}
|
||||
|
||||
OEMCrypto_EntitledContentKeyObject EntitlementKeySession::MakeOecEntitledKey(
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "crypto_key.h"
|
||||
#include "crypto_session.h"
|
||||
#include "device_files.h"
|
||||
#include "license_protocol_conversions.h"
|
||||
#include "log.h"
|
||||
#include "platform.h"
|
||||
#include "policy_engine.h"
|
||||
@@ -38,6 +39,7 @@ constexpr size_t kLicenseMacKeySize = wvcdm::MAC_KEY_SIZE * 2;
|
||||
namespace wvcdm {
|
||||
// Protobuf generated classes.
|
||||
using video_widevine::EncryptedClientIdentification;
|
||||
using video_widevine::HashAlgorithmProto;
|
||||
using video_widevine::License;
|
||||
using video_widevine::License_KeyContainer;
|
||||
using video_widevine::LicenseError;
|
||||
@@ -348,8 +350,11 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
// signature.
|
||||
std::string core_message;
|
||||
std::string license_request_signature;
|
||||
bool should_specify_algorithm;
|
||||
OEMCrypto_SignatureHashAlgorithm oec_algorithm = OEMCrypto_SHA1;
|
||||
status = crypto_session_->PrepareAndSignLicenseRequest(
|
||||
serialized_license_req, &core_message, &license_request_signature);
|
||||
serialized_license_req, &core_message, &license_request_signature,
|
||||
should_specify_algorithm, oec_algorithm);
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
signed_request->clear();
|
||||
@@ -368,6 +373,14 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
signed_message.set_signature(license_request_signature);
|
||||
signed_message.set_msg(serialized_license_req);
|
||||
signed_message.set_oemcrypto_core_message(core_message);
|
||||
if (should_specify_algorithm) {
|
||||
HashAlgorithmProto proto_algorithm =
|
||||
HashAlgorithmProto::HASH_ALGORITHM_UNSPECIFIED;
|
||||
if (!OecAlgorithmToProtoAlgorithm(oec_algorithm, proto_algorithm)) {
|
||||
return CdmResponseType(UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_1);
|
||||
}
|
||||
signed_message.set_hash_algorithm(proto_algorithm);
|
||||
}
|
||||
|
||||
signed_message.SerializeToString(signed_request);
|
||||
|
||||
@@ -490,8 +503,11 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
||||
// Construct signature and core message.
|
||||
std::string core_message;
|
||||
std::string license_request_signature;
|
||||
bool should_specify_algorithm;
|
||||
OEMCrypto_SignatureHashAlgorithm oec_algorithm = OEMCrypto_SHA1;
|
||||
const CdmResponseType status = crypto_session_->PrepareAndSignRenewalRequest(
|
||||
serialized_license_req, &core_message, &license_request_signature);
|
||||
serialized_license_req, &core_message, &license_request_signature,
|
||||
should_specify_algorithm, oec_algorithm);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
if (license_request_signature.empty()) {
|
||||
@@ -505,6 +521,14 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
||||
signed_message.set_signature(license_request_signature);
|
||||
signed_message.set_msg(serialized_license_req);
|
||||
signed_message.set_oemcrypto_core_message(core_message);
|
||||
if (should_specify_algorithm) {
|
||||
HashAlgorithmProto proto_algorithm =
|
||||
HashAlgorithmProto::HASH_ALGORITHM_UNSPECIFIED;
|
||||
if (!OecAlgorithmToProtoAlgorithm(oec_algorithm, proto_algorithm)) {
|
||||
return CdmResponseType(UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_2);
|
||||
}
|
||||
signed_message.set_hash_algorithm(proto_algorithm);
|
||||
}
|
||||
|
||||
signed_message.SerializeToString(signed_request);
|
||||
*server_url = server_url_;
|
||||
|
||||
30
libwvdrmengine/cdm/core/src/license_protocol_conversions.cpp
Normal file
30
libwvdrmengine/cdm/core/src/license_protocol_conversions.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// 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 "license_protocol_conversions.h"
|
||||
|
||||
namespace wvcdm {
|
||||
// Protobuf generated classes.
|
||||
using video_widevine::HashAlgorithmProto;
|
||||
|
||||
bool OecAlgorithmToProtoAlgorithm(
|
||||
OEMCrypto_SignatureHashAlgorithm oec_algorithm,
|
||||
HashAlgorithmProto& proto_algorithm) {
|
||||
switch (oec_algorithm) {
|
||||
case OEMCrypto_SHA1:
|
||||
proto_algorithm = HashAlgorithmProto::HASH_ALGORITHM_SHA_1;
|
||||
return true;
|
||||
case OEMCrypto_SHA2_256:
|
||||
proto_algorithm = HashAlgorithmProto::HASH_ALGORITHM_SHA_256;
|
||||
return true;
|
||||
case OEMCrypto_SHA2_384:
|
||||
proto_algorithm = HashAlgorithmProto::HASH_ALGORITHM_SHA_384;
|
||||
return true;
|
||||
case OEMCrypto_SHA2_512:
|
||||
// TODO(b/259268439): The service does not support SHA-512
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace wvcdm
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "service_certificate.h"
|
||||
|
||||
#include "cdm_random.h"
|
||||
#include "crypto_key.h"
|
||||
#include "crypto_session.h"
|
||||
#include "license_protocol.pb.h"
|
||||
@@ -238,27 +239,11 @@ CdmResponseType ServiceCertificate::EncryptClientId(
|
||||
encrypted_client_id->set_provider_id(provider_id_);
|
||||
encrypted_client_id->set_service_certificate_serial_number(serial_number_);
|
||||
|
||||
std::string iv(KEY_IV_SIZE, 0);
|
||||
std::string key(SERVICE_KEY_SIZE, 0);
|
||||
|
||||
CdmResponseType status = crypto_session->GetRandom(
|
||||
key.size(), reinterpret_cast<uint8_t*>(&key[0]));
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("GetRandom failed for key: status = %d", static_cast<int>(status));
|
||||
return (status == RANDOM_GENERATION_ERROR)
|
||||
? CdmResponseType(CLIENT_ID_GENERATE_RANDOM_ERROR)
|
||||
: status;
|
||||
}
|
||||
|
||||
status =
|
||||
crypto_session->GetRandom(iv.size(), reinterpret_cast<uint8_t*>(&iv[0]));
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("GetRandom failed for IV: status = %d", static_cast<int>(status));
|
||||
return (status == RANDOM_GENERATION_ERROR)
|
||||
? CdmResponseType(CLIENT_ID_GENERATE_RANDOM_ERROR)
|
||||
: status;
|
||||
std::string iv = wvutil::CdmRandom::RandomData(KEY_IV_SIZE);
|
||||
std::string key = wvutil::CdmRandom::RandomData(SERVICE_KEY_SIZE);
|
||||
if (key.length() != SERVICE_KEY_SIZE || iv.length() != KEY_IV_SIZE) {
|
||||
LOGE("RandomData failed for key or iv.");
|
||||
return CdmResponseType(CLIENT_ID_GENERATE_RANDOM_ERROR);
|
||||
}
|
||||
std::string id, enc_id, enc_key;
|
||||
clear_client_id->SerializeToString(&id);
|
||||
|
||||
@@ -819,6 +819,20 @@ const char* CdmResponseEnumToString(CdmResponseEnum cdm_response_enum) {
|
||||
return "PROVISIONING_4_FAILED_TO_STORE_DRM_CERTIFICATE";
|
||||
case PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_3:
|
||||
return "PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_3";
|
||||
case GET_SIGNATURE_HASH_ALGORITHM_ERROR_1:
|
||||
return "GET_SIGNATURE_HASH_ALGORITHM_ERROR_1";
|
||||
case GET_SIGNATURE_HASH_ALGORITHM_ERROR_2:
|
||||
return "GET_SIGNATURE_HASH_ALGORITHM_ERROR_2";
|
||||
case GET_SIGNATURE_HASH_ALGORITHM_ERROR_3:
|
||||
return "GET_SIGNATURE_HASH_ALGORITHM_ERROR_3";
|
||||
case UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_1:
|
||||
return "UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_1";
|
||||
case UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_2:
|
||||
return "UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_2";
|
||||
case UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_3:
|
||||
return "UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_3";
|
||||
case UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_4:
|
||||
return "UNSUPPORTED_SIGNATURE_HASH_ALGORITHM_4";
|
||||
}
|
||||
return UnknownEnumValueToString(cdm_response_enum);
|
||||
}
|
||||
|
||||
@@ -1510,6 +1510,51 @@ TEST_P(CdmUseCase_LimitedDurationLicense, Case6) {
|
||||
AllowPlayback(start_of_playback_, end_of_play);
|
||||
}
|
||||
|
||||
// Limited Duration License with Clear lead. (See above for notes on Use Case
|
||||
// tests). The user has 15 minutes to begin watching the movie. If a renewal is
|
||||
// not received, playback is terminated after 30 seconds. If a renewal is
|
||||
// received, playback may continue for two hours from playback start.
|
||||
class CdmUseCase_RenewOnLicenseLoad : public RenewalTest {
|
||||
public:
|
||||
CdmUseCase_RenewOnLicenseLoad() : RenewalTest("CDM_RenewOnLicenseLoad") {
|
||||
renewal_delay_ = 5u;
|
||||
renewal_recovery_ = 15;
|
||||
|
||||
// Pick a start of playback that is within the rental window, but so that
|
||||
// the initial renewal window is after rental window.
|
||||
start_of_playback_ = 10;
|
||||
|
||||
timer_limits_.soft_enforce_rental_duration = true;
|
||||
timer_limits_.rental_duration_seconds = 20;
|
||||
timer_limits_.soft_enforce_playback_duration = false;
|
||||
timer_limits_.total_playback_duration_seconds = 50;
|
||||
timer_limits_.initial_renewal_duration_seconds =
|
||||
renewal_delay_ + renewal_recovery_;
|
||||
|
||||
// Load the renewal just before the cutoff:
|
||||
renewal_load_time_ =
|
||||
start_of_playback_ + renewal_delay_ + renewal_recovery_ - 1;
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
RenewalTest::SetUp();
|
||||
// The Renew on License Load feature is only supported on v18+ servers.
|
||||
if (config_.ServerOlderThan(18)) {
|
||||
GTEST_SKIP() << "Renew on License Load supported on v18+ servers only.";
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t renewal_delay_;
|
||||
uint64_t renewal_load_time_;
|
||||
uint64_t renewal_recovery_;
|
||||
};
|
||||
|
||||
// TODO(b/253513745): Replace this with some real tests.
|
||||
TEST_P(CdmUseCase_RenewOnLicenseLoad, FakeTest) {
|
||||
FAIL() << "This test will fail on a v18 server, but "
|
||||
<< "should be skipped on all existing servers.";
|
||||
}
|
||||
|
||||
// Heartbeat Playback Window License. (See above for notes on Use Case tests).
|
||||
// This is similar to the renewal, but the renewal recovery is larger than the
|
||||
// renewal delay.
|
||||
@@ -1751,6 +1796,8 @@ INSTANTIATE_TEST_SUITE_P(Both, CdmUseCase_LicenseWithRenewalPlayback,
|
||||
::testing::Values(false, true));
|
||||
INSTANTIATE_TEST_SUITE_P(Both, CdmUseCase_LimitedDurationLicense,
|
||||
::testing::Values(false, true));
|
||||
INSTANTIATE_TEST_SUITE_P(Both, CdmUseCase_RenewOnLicenseLoad,
|
||||
::testing::Values(false, true));
|
||||
INSTANTIATE_TEST_SUITE_P(Both, CdmUseCase_InfiniteRenewal,
|
||||
::testing::Values(false, true));
|
||||
INSTANTIATE_TEST_SUITE_P(Both, CdmUseCase_LicenseDuration,
|
||||
|
||||
@@ -335,7 +335,7 @@ bool FakeProvisioningServer::MakeResponse(
|
||||
std::string core_response;
|
||||
oemcrypto_core_message::serialize::CreateCoreProvisioningResponseFromProto(
|
||||
oemcrypto_core_message::features::CoreMessageFeatures::kDefaultFeatures,
|
||||
message, core_request_data, &core_response);
|
||||
message, core_request_data, OEMCrypto_RSA_Private_Key, &core_response);
|
||||
signed_response.set_oemcrypto_core_message(core_response);
|
||||
// Also, the signature should be over the concatenation of the core message
|
||||
// and the message body. This is done to ensure that neither the message
|
||||
|
||||
@@ -151,7 +151,9 @@ class MockCryptoSession : public TestCryptoSession {
|
||||
MOCK_METHOD(bool, GetApiVersion, (uint32_t*), (override));
|
||||
MOCK_METHOD(CdmResponseType, GenerateNonce, (uint32_t*), (override));
|
||||
MOCK_METHOD(CdmResponseType, PrepareAndSignLicenseRequest,
|
||||
(const std::string&, std::string*, std::string*), (override));
|
||||
(const std::string&, std::string*, std::string*, bool&,
|
||||
OEMCrypto_SignatureHashAlgorithm&),
|
||||
(override));
|
||||
MOCK_METHOD(CdmResponseType, LoadEntitledContentKeys,
|
||||
(const std::vector<CryptoKey>& key_array), (override));
|
||||
MOCK_METHOD(bool, GetResourceRatingTier, (uint32_t*), (override));
|
||||
@@ -194,6 +196,7 @@ using ::testing::PrintToStringParamName;
|
||||
using ::testing::Return;
|
||||
using ::testing::ReturnRef;
|
||||
using ::testing::SetArgPointee;
|
||||
using ::testing::SetArgReferee;
|
||||
using ::testing::UnorderedElementsAre;
|
||||
using ::testing::Values;
|
||||
|
||||
@@ -322,9 +325,10 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(kNonce), Return(CdmResponseType(NO_ERROR))));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
PrepareAndSignLicenseRequest(_, NotNull(), NotNull()))
|
||||
PrepareAndSignLicenseRequest(_, NotNull(), NotNull(), _, _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(kFakeCoreMessage),
|
||||
SetArgPointee<2>(kLicenseRequestSignature),
|
||||
SetArgReferee<3>(false),
|
||||
Return(CdmResponseType(NO_ERROR))));
|
||||
EXPECT_CALL(*crypto_session_, GetBuildInformation(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kFakeBuildInfo), Return(true)));
|
||||
@@ -455,9 +459,10 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) {
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(kNonce), Return(CdmResponseType(NO_ERROR))));
|
||||
EXPECT_CALL(*crypto_session_,
|
||||
PrepareAndSignLicenseRequest(_, NotNull(), NotNull()))
|
||||
PrepareAndSignLicenseRequest(_, NotNull(), NotNull(), _, _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(kFakeCoreMessage),
|
||||
SetArgPointee<2>(kLicenseRequestSignature),
|
||||
SetArgReferee<3>(false),
|
||||
Return(CdmResponseType(NO_ERROR))));
|
||||
EXPECT_CALL(*crypto_session_, GetBuildInformation(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kFakeBuildInfo), Return(true)));
|
||||
|
||||
Reference in New Issue
Block a user