Changes JSON format for provisioning request and response to match server change.
This new format uses the SignedProvisioningMessage proto buffer definition so the client does not have to parse the message and signature from the JSON response separately. This change makes it more flexible to extend the fields in the SignedProvisioningMessage. Adds Apiary API key to the default provisioning server url. Fixes a bug in GetCertRequestResponse() where a LOGD() can generate a fault if there is no response data. Bug: 8620943 Merge of https://widevine-internal-review.googlesource.com/#/c/5230/ from Widevine CDM repository Change-Id: I4945ee2d16f88666e41edf990dd07102a9271105
This commit is contained in:
@@ -102,7 +102,6 @@ class CdmEngine : public TimerHandler {
|
||||
bool CancelSessions();
|
||||
void CleanupProvisioningSession(const CdmSessionId& cdm_session_id);
|
||||
void ComposeJsonRequest(const std::string& message,
|
||||
const std::string& signature,
|
||||
CdmProvisioningRequest* request);
|
||||
|
||||
// Parse a blob of multiple concatenated PSSH atoms to extract the first
|
||||
|
||||
@@ -22,7 +22,9 @@
|
||||
|
||||
namespace {
|
||||
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"
|
||||
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
|
||||
}
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -340,38 +342,29 @@ void CdmEngine::CleanupProvisioningSession(const CdmSessionId& cdm_session_id) {
|
||||
}
|
||||
|
||||
/*
|
||||
* This function converts message and signature into base64 format.
|
||||
* This function converts SignedProvisioningRequest into base64 format.
|
||||
* It then wraps it in JSON format expected by the Apiary frontend.
|
||||
* Apiary requires the base64 encoding to replace '+' with minus '-',
|
||||
* and '/' with underscore '_'; opposite to stubby's.
|
||||
*
|
||||
* Returns the JSON formated string in *request.
|
||||
* The JSON formated request takes the following format:
|
||||
* {
|
||||
* 'signedRequest': {
|
||||
* 'message': 'base64 encoded message',
|
||||
* 'signature': 'base64 encoded signature'
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* {'signedRequest':'base64 encoded message'}
|
||||
*/
|
||||
void CdmEngine::ComposeJsonRequest(
|
||||
const std::string& message,
|
||||
const std::string& signature,
|
||||
CdmProvisioningRequest* request) {
|
||||
|
||||
// performs base64 encoding for message
|
||||
std::vector<uint8_t> message_vector(message.begin(), message.end());
|
||||
std::string message_b64 = Base64SafeEncode(message_vector);
|
||||
|
||||
// performs base64 encoding for signature
|
||||
std::vector<uint8_t> signature_vector(signature.begin(), signature.end());
|
||||
std::string signature_b64 = Base64SafeEncode(signature_vector);
|
||||
|
||||
request->assign("{'signedRequest':{'message':'");
|
||||
request->assign("{'signedRequest':'");
|
||||
request->append(message_b64);
|
||||
request->append("','signature':'");
|
||||
request->append(signature_b64);
|
||||
request->append("'}}");
|
||||
request->append("'}");
|
||||
|
||||
LOGD("json request:\r\n%s", request->c_str());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -458,27 +451,33 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
std::string the_nonce(reinterpret_cast<char*>(&nonce), sizeof(nonce));
|
||||
provisioning_request.set_nonce(the_nonce);
|
||||
|
||||
// Serializes the provisioning request.
|
||||
std::string serialized_request;
|
||||
provisioning_request.SerializeToString(&serialized_request);
|
||||
std::string serialized_message;
|
||||
provisioning_request.SerializeToString(&serialized_message);
|
||||
|
||||
// Derives signing and encryption keys and constructs signature.
|
||||
std::string request_signature;
|
||||
if (!crypto_session->PrepareRequest(serialized_request,
|
||||
if (!crypto_session->PrepareRequest(serialized_message,
|
||||
&request_signature, true)) {
|
||||
request->clear();
|
||||
CleanupProvisioningSession(cdm_session_id);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if (request_signature.empty()) {
|
||||
request->clear();
|
||||
CleanupProvisioningSession(cdm_session_id);
|
||||
return UNKNOWN_ERROR;
|
||||
request->clear();
|
||||
CleanupProvisioningSession(cdm_session_id);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
SignedProvisioningMessage signed_provisioning_msg;
|
||||
signed_provisioning_msg.set_message(serialized_message);
|
||||
signed_provisioning_msg.set_signature(request_signature);
|
||||
|
||||
std::string serialized_request;
|
||||
signed_provisioning_msg.SerializeToString(&serialized_request);
|
||||
|
||||
// converts request into JSON string
|
||||
ComposeJsonRequest(serialized_request, request_signature, request);
|
||||
ComposeJsonRequest(serialized_request, request);
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -527,26 +526,18 @@ bool CdmEngine::ParseJsonResponse(
|
||||
CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
CdmProvisioningResponse& response) {
|
||||
if (response.empty()) {
|
||||
LOGE("CdmEngine::HandleProvisioningResponse: Empty provisioning response.");
|
||||
LOGE("Empty provisioning response.");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Extracts response from JSON string, decodes base64 signed message
|
||||
const std::string kMessageStart = "\"message\": \"";
|
||||
const std::string kMessageEnd = "\",";
|
||||
std::string signed_message;
|
||||
if (!ParseJsonResponse(response, kMessageStart, kMessageEnd, &signed_message)) {
|
||||
LOGE("Fails to extract signed message from JSON response");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
// Extracts signature from JSON string, decodes base64 signature
|
||||
const std::string kSignatureStart = "\"signature\": \"";
|
||||
const std::string kSignatureEnd = "\"";
|
||||
std::string signature;
|
||||
if (!ParseJsonResponse(response, kSignatureStart, kSignatureEnd, &signature)) {
|
||||
LOGE("Fails to extract signature from JSON response");
|
||||
// Extracts signed response from JSON string, decodes base64 signed response
|
||||
const std::string kMessageStart = "\"signedResponse\": \"";
|
||||
const std::string kMessageEnd = "\"";
|
||||
std::string serialized_signed_response;
|
||||
if (!ParseJsonResponse(response, kMessageStart, kMessageEnd,
|
||||
&serialized_signed_response)) {
|
||||
LOGE("Fails to extract signed serialized response from JSON response");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
@@ -568,7 +559,8 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
CdmSessionId cdm_session_id = provisioning_session_->session_id();
|
||||
CryptoSession* crypto_session = crypto_engine->FindSession(cdm_session_id);
|
||||
if (!crypto_session) {
|
||||
LOGE("HandleProvisioningResponse: fails to find %s", cdm_session_id.c_str());
|
||||
LOGE("HandleProvisioningResponse: fails to find %s",
|
||||
cdm_session_id.c_str());
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
@@ -576,23 +568,38 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
// Authenticates provisioning response using D1s (server key derived from
|
||||
// the provisioing request's input). Validate provisioning response and
|
||||
// stores private device RSA key and certificate.
|
||||
SignedProvisioningMessage signed_response;
|
||||
if (!signed_response.ParseFromString(serialized_signed_response)) {
|
||||
LOGE("Fails to parse signed serialized response");
|
||||
CleanupProvisioningSession(cdm_session_id);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if (!signed_response.has_signature() || !signed_response.has_message()) {
|
||||
LOGE("Invalid response - signature or message not found");
|
||||
CleanupProvisioningSession(cdm_session_id);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
const std::string& signed_message = signed_response.message();
|
||||
ProvisioningResponse provisioning_response;
|
||||
|
||||
if (!provisioning_response.ParseFromString(signed_message)) {
|
||||
LOGE("HandleProvisioningResponse: fails to parse signed message");
|
||||
LOGE("Fails to parse signed message");
|
||||
CleanupProvisioningSession(cdm_session_id);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if (!provisioning_response.has_device_rsa_key()) {
|
||||
LOGE("HandleProvisioningResponse: invalid response - key not found");
|
||||
LOGE("Invalid response - key not found");
|
||||
CleanupProvisioningSession(cdm_session_id);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
const std::string& enc_rsa_key = provisioning_response.device_rsa_key();
|
||||
const std::string& rsa_key_iv = provisioning_response.device_rsa_key_iv();
|
||||
const std::string& nonce = provisioning_response.nonce();
|
||||
const std::string& rsa_key_iv = provisioning_response.device_rsa_key_iv();
|
||||
const std::string& signature = signed_response.signature();
|
||||
|
||||
std::string wrapped_rsa_key;
|
||||
if (!crypto_session->RewrapDeviceRSAKey(signed_message,
|
||||
|
||||
@@ -25,7 +25,9 @@ wvcdm::KeyId g_wrong_key_id;
|
||||
int g_use_full_path = 0; // cannot use boolean in getopt_long
|
||||
|
||||
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"
|
||||
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -56,7 +58,7 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
app_parameters,
|
||||
&key_msg_,
|
||||
&server_url), wvcdm::KEY_MESSAGE);
|
||||
EXPECT_EQ((size_t)0, server_url.size());
|
||||
EXPECT_EQ(0, static_cast<int>(server_url.size()));
|
||||
}
|
||||
|
||||
void GenerateRenewalRequest(const std::string& key_system,
|
||||
@@ -71,7 +73,7 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
app_parameters,
|
||||
&key_msg_,
|
||||
&server_url), wvcdm::KEY_MESSAGE);
|
||||
EXPECT_NE((size_t)0, server_url.size());
|
||||
EXPECT_NE(0, static_cast<int>(server_url.size()));
|
||||
}
|
||||
|
||||
// posts a request and extracts the drm message from the response
|
||||
@@ -122,9 +124,11 @@ class WvCdmRequestLicenseTest : public testing::Test {
|
||||
url_request.PostCertRequest(key_msg_);
|
||||
std::string response;
|
||||
int resp_bytes = url_request.GetResponse(response);
|
||||
LOGD("size=%u, response start: %s", response.size(),
|
||||
response.substr(0, 1024).c_str());
|
||||
LOGD("end: %s", response.substr(response.size() - 256).c_str());
|
||||
if (resp_bytes) {
|
||||
LOGD("size=%u, response start:\t\rn%s", response.size(),
|
||||
response.substr(0, 1024).c_str());
|
||||
LOGD("end:\r\n%s", response.substr(response.size() - 256).c_str());
|
||||
}
|
||||
LOGD("end %d bytes response dump", resp_bytes);
|
||||
|
||||
// Youtube server returns 400 for invalid message while play server returns
|
||||
|
||||
Reference in New Issue
Block a user