From b5a782bdb22cb5698302665640f72cdc0b753f84 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Thu, 25 Apr 2013 03:34:31 -0700 Subject: [PATCH] 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 --- libwvdrmengine/cdm/core/include/cdm_engine.h | 1 - libwvdrmengine/cdm/core/src/cdm_engine.cpp | 99 ++++++++++--------- .../cdm/test/request_license_test.cpp | 16 +-- 3 files changed, 63 insertions(+), 53 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/cdm_engine.h b/libwvdrmengine/cdm/core/include/cdm_engine.h index e7e50db2..6b3c792c 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -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 diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index a53f90a9..2a5c5493 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -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 message_vector(message.begin(), message.end()); std::string message_b64 = Base64SafeEncode(message_vector); - // performs base64 encoding for signature - std::vector 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(&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, diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index e363c321..9abab09e 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -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(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(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