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:
Jeff Tinker
2013-04-24 12:12:43 -07:00
parent 4b0963de96
commit b7debfe2a1
7 changed files with 95 additions and 49 deletions

View File

@@ -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();

View File

@@ -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);
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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 \