Enable certificate based licensing
Includes fixes for provisioning and license renewal signature generation. bug: 8620943 Merge of: https://widevine-internal-review.googlesource.com/#/c/5231/ https://widevine-internal-review.googlesource.com/#/c/5200/ from the Widevine CDM repository. Change-Id: I2928c9d59ad5337ca34b4ef7ed58272d34755d2d
This commit is contained in:
@@ -35,7 +35,8 @@ class CryptoSession {
|
|||||||
// Key request/response
|
// Key request/response
|
||||||
void GenerateRequestId(std::string& req_id_str);
|
void GenerateRequestId(std::string& req_id_str);
|
||||||
bool PrepareRequest(const std::string& key_deriv_message,
|
bool PrepareRequest(const std::string& key_deriv_message,
|
||||||
std::string* signature);
|
std::string* signature,
|
||||||
|
bool is_provisioning);
|
||||||
bool PrepareRenewalRequest(const std::string& message,
|
bool PrepareRenewalRequest(const std::string& message,
|
||||||
std::string* signature);
|
std::string* signature);
|
||||||
bool LoadKeys(const std::string& message,
|
bool LoadKeys(const std::string& message,
|
||||||
@@ -53,16 +54,13 @@ class CryptoSession {
|
|||||||
bool GenerateDerivedKeys(const std::string& message);
|
bool GenerateDerivedKeys(const std::string& message);
|
||||||
bool GenerateDerivedKeys(const std::string& message,
|
bool GenerateDerivedKeys(const std::string& message,
|
||||||
const std::string& session_key);
|
const std::string& session_key);
|
||||||
bool GenerateSignature(const std::string& message,
|
|
||||||
std::string* signature);
|
|
||||||
bool RewrapDeviceRSAKey(const std::string& message,
|
bool RewrapDeviceRSAKey(const std::string& message,
|
||||||
const std::string& signature,
|
const std::string& signature,
|
||||||
const std::string& nonce,
|
const std::string& nonce,
|
||||||
const std::string& enc_rsa_key,
|
const std::string& enc_rsa_key,
|
||||||
size_t enc_rsa_key_length,
|
size_t enc_rsa_key_length,
|
||||||
const std::string& rsa_key_iv,
|
const std::string& rsa_key_iv,
|
||||||
uint8_t* wrapped_rsa_key,
|
std::string* wrapped_rsa_key);
|
||||||
size_t* wrapped_rsa_key_length);
|
|
||||||
|
|
||||||
// Media data path
|
// Media data path
|
||||||
bool SelectKey(const std::string& key_id);
|
bool SelectKey(const std::string& key_id);
|
||||||
@@ -83,6 +81,9 @@ class CryptoSession {
|
|||||||
std::string* deriv_context);
|
std::string* deriv_context);
|
||||||
void GenerateEncryptContext(const std::string& input_context,
|
void GenerateEncryptContext(const std::string& input_context,
|
||||||
std::string* deriv_context);
|
std::string* deriv_context);
|
||||||
|
bool GenerateSignature(const std::string& message,
|
||||||
|
std::string* signature,
|
||||||
|
bool use_rsa);
|
||||||
size_t GetOffset(std::string message, std::string field);
|
size_t GetOffset(std::string message, std::string field);
|
||||||
bool SetDestinationBufferType();
|
bool SetDestinationBufferType();
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,11 @@
|
|||||||
#define CDM_POLICY_TIMER_DURATION_SECONDS 1
|
#define CDM_POLICY_TIMER_DURATION_SECONDS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
const std::string kDefaultProvisioningServerUrl =
|
||||||
|
"http://www-googleapis-test.sandbox.google.com/certificateprovisioning/v1/devicecertificates/create";
|
||||||
|
}
|
||||||
|
|
||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
|
|
||||||
// Protobuf generated classes.
|
// Protobuf generated classes.
|
||||||
@@ -384,6 +389,8 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
|||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default_url->assign(kDefaultProvisioningServerUrl);
|
||||||
|
|
||||||
if (provisioning_session_) {
|
if (provisioning_session_) {
|
||||||
LOGE("GetProvisioningRequest: duplicate provisioning request?");
|
LOGE("GetProvisioningRequest: duplicate provisioning request?");
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
@@ -457,7 +464,8 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
|||||||
|
|
||||||
// Derives signing and encryption keys and constructs signature.
|
// Derives signing and encryption keys and constructs signature.
|
||||||
std::string request_signature;
|
std::string request_signature;
|
||||||
if (!crypto_session->PrepareRequest(serialized_request, &request_signature)) {
|
if (!crypto_session->PrepareRequest(serialized_request,
|
||||||
|
&request_signature, true)) {
|
||||||
request->clear();
|
request->clear();
|
||||||
CleanupProvisioningSession(cdm_session_id);
|
CleanupProvisioningSession(cdm_session_id);
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
@@ -471,11 +479,6 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
|||||||
|
|
||||||
// converts request into JSON string
|
// converts request into JSON string
|
||||||
ComposeJsonRequest(serialized_request, request_signature, request);
|
ComposeJsonRequest(serialized_request, request_signature, request);
|
||||||
|
|
||||||
static const std::string kDefaultProvisioningServerUrl =
|
|
||||||
"http://www-googleapis-test.sandbox.google.com/certificateprovisioning/v1/devicecertificates/create";
|
|
||||||
default_url->assign(kDefaultProvisioningServerUrl);
|
|
||||||
|
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -591,27 +594,21 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
|||||||
const std::string& rsa_key_iv = provisioning_response.device_rsa_key_iv();
|
const std::string& rsa_key_iv = provisioning_response.device_rsa_key_iv();
|
||||||
const std::string& nonce = provisioning_response.nonce();
|
const std::string& nonce = provisioning_response.nonce();
|
||||||
|
|
||||||
const int kRsaKeySize = 256;
|
std::string wrapped_rsa_key;
|
||||||
size_t wrapped_rsa_key_length = kRsaKeySize + enc_rsa_key.length();
|
|
||||||
std::vector<uint8_t> wrapped_rsa_key;
|
|
||||||
wrapped_rsa_key.resize(wrapped_rsa_key_length);
|
|
||||||
|
|
||||||
if (!crypto_session->RewrapDeviceRSAKey(signed_message,
|
if (!crypto_session->RewrapDeviceRSAKey(signed_message,
|
||||||
signature,
|
signature,
|
||||||
nonce.data(),
|
nonce.data(),
|
||||||
enc_rsa_key,
|
enc_rsa_key,
|
||||||
enc_rsa_key.size(),
|
enc_rsa_key.size(),
|
||||||
rsa_key_iv,
|
rsa_key_iv,
|
||||||
&wrapped_rsa_key[0],
|
&wrapped_rsa_key)) {
|
||||||
&wrapped_rsa_key_length)) {
|
|
||||||
LOGE("HandleProvisioningResponse: RewrapDeviceRSAKey fails");
|
LOGE("HandleProvisioningResponse: RewrapDeviceRSAKey fails");
|
||||||
CleanupProvisioningSession(cdm_session_id);
|
CleanupProvisioningSession(cdm_session_id);
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& device_certificate = provisioning_response.device_certificate();
|
const std::string& device_certificate = provisioning_response.device_certificate();
|
||||||
std::string the_wrapped_rsa_key(wrapped_rsa_key.begin(), wrapped_rsa_key.end());
|
DeviceFiles::StoreCertificate(device_certificate, wrapped_rsa_key);
|
||||||
DeviceFiles::StoreCertificate(device_certificate, the_wrapped_rsa_key);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const uint32_t kMaxSignatureBufLength = 256;
|
|
||||||
// Encode unsigned integer into a big endian formatted string
|
// Encode unsigned integer into a big endian formatted string
|
||||||
std::string EncodeUint32(unsigned int u) {
|
std::string EncodeUint32(unsigned int u) {
|
||||||
std::string s;
|
std::string s;
|
||||||
@@ -106,7 +105,8 @@ void CryptoSession::GenerateRequestId(std::string& req_id_str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CryptoSession::PrepareRequest(const std::string& message,
|
bool CryptoSession::PrepareRequest(const std::string& message,
|
||||||
std::string* signature) {
|
std::string* signature,
|
||||||
|
bool is_provisioning) {
|
||||||
LOGV("CryptoSession::PrepareRequest: Lock");
|
LOGV("CryptoSession::PrepareRequest: Lock");
|
||||||
CryptoEngine* crypto_engine = CryptoEngine::GetInstance();
|
CryptoEngine* crypto_engine = CryptoEngine::GetInstance();
|
||||||
AutoLock auto_lock(crypto_engine->crypto_lock_);
|
AutoLock auto_lock(crypto_engine->crypto_lock_);
|
||||||
@@ -116,15 +116,15 @@ bool CryptoSession::PrepareRequest(const std::string& message,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
OEMCryptoResult sts;
|
if (!Properties::use_certificates_as_identification() || is_provisioning) {
|
||||||
|
if (!GenerateDerivedKeys(message))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!Properties::use_certificates_as_identification()) {
|
if (!GenerateSignature(message, signature, false))
|
||||||
if (!GenerateDerivedKeys(message)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
else {
|
||||||
|
if (!GenerateSignature(message, signature, true))
|
||||||
if (!GenerateSignature(message, signature)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ bool CryptoSession::PrepareRenewalRequest(const std::string& message,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!GenerateSignature(message, signature)) {
|
if (!GenerateSignature(message, signature, false)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,17 +356,20 @@ bool CryptoSession::GenerateDerivedKeys(const std::string& message,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CryptoSession::GenerateSignature(const std::string& message,
|
bool CryptoSession::GenerateSignature(const std::string& message,
|
||||||
std::string* signature) {
|
std::string* signature,
|
||||||
|
bool use_rsa) {
|
||||||
LOGV("GenerateSignature: id=%ld", (uint32_t) oec_session_id_);
|
LOGV("GenerateSignature: id=%ld", (uint32_t) oec_session_id_);
|
||||||
uint8_t signature_buf[kMaxSignatureBufLength];
|
if (!signature)
|
||||||
size_t length = kMaxSignatureBufLength;
|
return false;
|
||||||
|
|
||||||
|
size_t length = 0;
|
||||||
OEMCryptoResult sts;
|
OEMCryptoResult sts;
|
||||||
if (Properties::use_certificates_as_identification()) {
|
if (use_rsa) {
|
||||||
sts = OEMCrypto_GenerateRSASignature(
|
sts = OEMCrypto_GenerateRSASignature(
|
||||||
oec_session_id_,
|
oec_session_id_,
|
||||||
reinterpret_cast<const uint8_t*>(message.data()),
|
reinterpret_cast<const uint8_t*>(message.data()),
|
||||||
message.size(),
|
message.size(),
|
||||||
signature_buf,
|
NULL,
|
||||||
&length);
|
&length);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -374,7 +377,31 @@ bool CryptoSession::GenerateSignature(const std::string& message,
|
|||||||
oec_session_id_,
|
oec_session_id_,
|
||||||
reinterpret_cast<const uint8_t*>(message.data()),
|
reinterpret_cast<const uint8_t*>(message.data()),
|
||||||
message.size(),
|
message.size(),
|
||||||
signature_buf,
|
NULL,
|
||||||
|
&length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||||
|
LOGD("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
signature->resize(length);
|
||||||
|
|
||||||
|
if (use_rsa) {
|
||||||
|
sts = OEMCrypto_GenerateRSASignature(
|
||||||
|
oec_session_id_,
|
||||||
|
reinterpret_cast<const uint8_t*>(message.data()),
|
||||||
|
message.size(),
|
||||||
|
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||||
|
&length);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sts = OEMCrypto_GenerateSignature(
|
||||||
|
oec_session_id_,
|
||||||
|
reinterpret_cast<const uint8_t*>(message.data()),
|
||||||
|
message.size(),
|
||||||
|
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||||
&length);
|
&length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,7 +410,6 @@ bool CryptoSession::GenerateSignature(const std::string& message,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
signature->assign(reinterpret_cast<const char*>(signature_buf), length);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,8 +507,7 @@ bool CryptoSession::RewrapDeviceRSAKey(const std::string& message,
|
|||||||
const std::string& enc_rsa_key,
|
const std::string& enc_rsa_key,
|
||||||
size_t enc_rsa_key_length,
|
size_t enc_rsa_key_length,
|
||||||
const std::string& rsa_key_iv,
|
const std::string& rsa_key_iv,
|
||||||
uint8_t* wrapped_rsa_key,
|
std::string* wrapped_rsa_key) {
|
||||||
size_t* wrapped_rsa_key_length) {
|
|
||||||
LOGV("CryptoSession::RewrapDeviceRSAKey: Lock+++");
|
LOGV("CryptoSession::RewrapDeviceRSAKey: Lock+++");
|
||||||
CryptoEngine* crypto_engine = CryptoEngine::GetInstance();
|
CryptoEngine* crypto_engine = CryptoEngine::GetInstance();
|
||||||
AutoLock auto_lock(crypto_engine->crypto_lock_);
|
AutoLock auto_lock(crypto_engine->crypto_lock_);
|
||||||
@@ -496,9 +521,13 @@ bool CryptoSession::RewrapDeviceRSAKey(const std::string& message,
|
|||||||
if (enc_rsa_key.size() >= MAC_KEY_SIZE && rsa_key_iv.size() >= KEY_IV_SIZE) {
|
if (enc_rsa_key.size() >= MAC_KEY_SIZE && rsa_key_iv.size() >= KEY_IV_SIZE) {
|
||||||
msg_rsa_key = signed_msg + GetOffset(message, enc_rsa_key);
|
msg_rsa_key = signed_msg + GetOffset(message, enc_rsa_key);
|
||||||
msg_rsa_key_iv = signed_msg + GetOffset(message, rsa_key_iv);
|
msg_rsa_key_iv = signed_msg + GetOffset(message, rsa_key_iv);
|
||||||
msg_nonce = reinterpret_cast<const uint32_t*>(signed_msg + GetOffset(message, nonce));
|
msg_nonce = reinterpret_cast<const uint32_t*>(
|
||||||
|
signed_msg + GetOffset(message, nonce));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gets wrapped_rsa_key_length by passing NULL as uint8_t* wrapped_rsa_key
|
||||||
|
// and 0 as wrapped_rsa_key_length.
|
||||||
|
size_t wrapped_rsa_key_length = 0;
|
||||||
OEMCryptoResult status = OEMCrypto_RewrapDeviceRSAKey(
|
OEMCryptoResult status = OEMCrypto_RewrapDeviceRSAKey(
|
||||||
oec_session_id_,
|
oec_session_id_,
|
||||||
signed_msg, message.size(),
|
signed_msg, message.size(),
|
||||||
@@ -506,13 +535,32 @@ bool CryptoSession::RewrapDeviceRSAKey(const std::string& message,
|
|||||||
msg_nonce,
|
msg_nonce,
|
||||||
msg_rsa_key, enc_rsa_key_length,
|
msg_rsa_key, enc_rsa_key_length,
|
||||||
msg_rsa_key_iv,
|
msg_rsa_key_iv,
|
||||||
wrapped_rsa_key,
|
NULL,
|
||||||
wrapped_rsa_key_length);
|
&wrapped_rsa_key_length);
|
||||||
|
if (status != OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||||
|
LOGE("OEMCrypto_RewrapDeviceRSAKey fails to get wrapped_rsa_key_length");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapped_rsa_key->resize(wrapped_rsa_key_length);
|
||||||
|
status = OEMCrypto_RewrapDeviceRSAKey(
|
||||||
|
oec_session_id_,
|
||||||
|
signed_msg,
|
||||||
|
message.size(),
|
||||||
|
reinterpret_cast<const uint8_t*>(signature.data()),
|
||||||
|
signature.size(),
|
||||||
|
msg_nonce,
|
||||||
|
msg_rsa_key,
|
||||||
|
enc_rsa_key_length,
|
||||||
|
msg_rsa_key_iv,
|
||||||
|
reinterpret_cast<uint8_t*>(const_cast<char*>(wrapped_rsa_key->data())),
|
||||||
|
&wrapped_rsa_key_length);
|
||||||
|
|
||||||
if (OEMCrypto_SUCCESS != status) {
|
if (OEMCrypto_SUCCESS != status) {
|
||||||
LOGE("OEMCrypto_RewrapDeviceRSAKey fails with %d", status);
|
LOGE("OEMCrypto_RewrapDeviceRSAKey fails with %d", status);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ bool CdmLicense::PrepareKeyRequest(const CdmInitData& init_data,
|
|||||||
// Derive signing and encryption keys and construct signature.
|
// Derive signing and encryption keys and construct signature.
|
||||||
std::string license_request_signature;
|
std::string license_request_signature;
|
||||||
if (!session_->PrepareRequest(serialized_license_req,
|
if (!session_->PrepareRequest(serialized_license_req,
|
||||||
&license_request_signature)) {
|
&license_request_signature, false)) {
|
||||||
signed_request->clear();
|
signed_request->clear();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const bool kPropertyOemCryptoUseUserSpaceBuffers = false;
|
|||||||
|
|
||||||
// If false, keyboxes will be used as client identification
|
// If false, keyboxes will be used as client identification
|
||||||
// and passed as the token in the license request
|
// and passed as the token in the license request
|
||||||
const bool kPropertyUseCertificatesAsIdentification = false;
|
const bool kPropertyUseCertificatesAsIdentification = true;
|
||||||
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ std::string g_port;
|
|||||||
wvcdm::KeyId g_wrong_key_id;
|
wvcdm::KeyId g_wrong_key_id;
|
||||||
int g_use_full_path = 0; // cannot use boolean in getopt_long
|
int g_use_full_path = 0; // cannot use boolean in getopt_long
|
||||||
|
|
||||||
static const std::string kDefaultProvisioningServerUrl =
|
const std::string kDefaultProvisioningServerUrl =
|
||||||
"http://www-googleapis-test.sandbox.google.com/certificateprovisioning/v1/devicecertificates/create";
|
"http://www-googleapis-test.sandbox.google.com/certificateprovisioning/v1/devicecertificates/create";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
|||||||
app_parameters,
|
app_parameters,
|
||||||
&key_msg_,
|
&key_msg_,
|
||||||
&server_url), wvcdm::KEY_MESSAGE);
|
&server_url), wvcdm::KEY_MESSAGE);
|
||||||
EXPECT_EQ(0, server_url.size());
|
EXPECT_EQ((size_t)0, server_url.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateRenewalRequest(const std::string& key_system,
|
void GenerateRenewalRequest(const std::string& key_system,
|
||||||
@@ -71,7 +71,7 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
|||||||
app_parameters,
|
app_parameters,
|
||||||
&key_msg_,
|
&key_msg_,
|
||||||
&server_url), wvcdm::KEY_MESSAGE);
|
&server_url), wvcdm::KEY_MESSAGE);
|
||||||
EXPECT_NE(0, server_url.size());
|
EXPECT_NE((size_t)0, server_url.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// posts a request and extracts the drm message from the response
|
// posts a request and extracts the drm message from the response
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ LOCAL_STATIC_LIBRARIES := \
|
|||||||
LOCAL_WHOLE_STATIC_LIBRARIES := libcdm_protos
|
LOCAL_WHOLE_STATIC_LIBRARIES := libcdm_protos
|
||||||
|
|
||||||
LOCAL_SHARED_LIBRARIES := \
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
libchromium_net \
|
|
||||||
libcrypto \
|
libcrypto \
|
||||||
|
libcutils \
|
||||||
libdl \
|
libdl \
|
||||||
liblog \
|
liblog \
|
||||||
libstlport \
|
libstlport \
|
||||||
|
|||||||
Reference in New Issue
Block a user