Source release v3.3.0

This commit is contained in:
Gene Morgan
2017-05-04 14:01:27 -07:00
parent baa7b133d3
commit 8082775924
678 changed files with 51264 additions and 14200 deletions

View File

@@ -19,37 +19,64 @@ const std::string kProvisioningServerUrl =
"https://www.googleapis.com/"
"certificateprovisioning/v1/devicecertificates/create"
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
/*
* Provisioning response is a base64-encoded protobuf, optionally within a
* JSON wrapper. If the JSON wrapper is present, extract the embedded response
* message. Then perform the base64 decode and return the result.
*
* If an error occurs during the parse or the decode, return an empty string.
*/
void ExtractAndDecodeSignedMessage(const std::string& provisioning_response,
std::string* result) {
const std::string json_start_substr("\"signedResponse\": \"");
const std::string json_end_substr("\"");
std::string message_string;
size_t start = provisioning_response.find(json_start_substr);
if (start == provisioning_response.npos) {
// Message is not properly wrapped - reject it.
LOGE("ExtractAndDecodeSignedMessage: cannot locate start substring");
result->clear();
return;
} else {
// Appears to be JSON-wrapped protobuf - find end of protobuf portion.
size_t end = provisioning_response.find(json_end_substr,
start + json_start_substr.length());
if (end == provisioning_response.npos) {
LOGE("ExtractAndDecodeSignedMessage: cannot locate end substring");
result->clear();
return;
}
size_t b64_string_size = end - start - json_start_substr.length();
message_string.assign(provisioning_response,
start + json_start_substr.length(), b64_string_size);
}
if (message_string.empty()) {
LOGE("ExtractAndDecodeSignedMessage: CdmProvisioningResponse is empty");
result->clear();
return;
}
// Decode the base64-encoded message.
const std::vector<uint8_t> decoded_message =
wvcdm::Base64SafeDecode(message_string);
result->assign(decoded_message.begin(), decoded_message.end());
}
}
namespace wvcdm {
// Protobuf generated classes.
using video_widevine::ClientIdentification;
using video_widevine::EncryptedClientIdentification;
using video_widevine::ProvisioningOptions;
using video_widevine::ProvisioningRequest;
using video_widevine::ProvisioningResponse;
using video_widevine::SignedProvisioningMessage;
/*
* This function converts SignedProvisioningRequest into base64 string. It then
* wraps it in JSON format expected by the frontend. This server requires a
* "web-safe" base 64 encoding, where '+' becomes '-' and '/' becomes '_'.
*
* Returns the JSON formated string in *request. The JSON string will be
* appended as a query parameter, i.e. signedRequest=<base 64 encoded
* SignedProvisioningRequest>. All base64 '=' padding chars must be removed.
*
* The JSON formated request takes the following format:
*
* base64 encoded message
*/
void CertificateProvisioning::ComposeJsonRequestAsQueryString(
const std::string& message, CdmProvisioningRequest* request) {
// Performs base64 encoding for message
std::vector<uint8_t> message_vector(message.begin(), message.end());
std::string message_b64 = Base64SafeEncodeNoPad(message_vector);
request->assign(message_b64);
}
/*
* Return the ClientIdentification message token type for provisioning request.
* NOTE: a DRM Cert should never be presented to the provisioning server.
@@ -88,7 +115,7 @@ bool CertificateProvisioning::SetSpoidParameter(
// Use the SPOID that has been pre-provided
request->set_spoid(spoid);
} else if (Properties::UseProviderIdInProvisioningRequest()) {
if (service_certificate_->HasProviderId()) {
if (!service_certificate_->provider_id().empty()) {
request->set_provider_id(service_certificate_->provider_id());
} else {
LOGE("CertificateProvisioning::SetSpoidParameter: Failure getting "
@@ -121,9 +148,9 @@ SignedProvisioningMessage::ProtocolVersion
}
/*
* Composes a device provisioning request and output the request in JSON format
* in *request. It also returns the default url for the provisioning server
* in *default_url.
* Compose a device provisioning request and output *request in a
* JSON-compatible format (web-safe base64).
* Also return *default_url of the provisioning server.
*
* Returns NO_ERROR for success and CERT_PROVISIONING_REQUEST_ERROR_? if fails.
*/
@@ -162,17 +189,17 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
client_id->set_token(token);
client_id->set_type(token_type);
#if 0 // TODO(gmorgan) in progress - encrypt ClientIdentification.
if (service_certificate_->HasCertificate()) {
#if 0 // TODO(gmorgan) Encrypt ClientIdentification. Pending Design.
if (service_certificate_->has_certificate()) {
EncryptedClientIdentification* encrypted_client_id =
provisioning_request->mutable_encrypted_client_id();
provisioning_request.mutable_encrypted_client_id();
CdmResponseType status;
status = service_certificate_->EncryptClientId(&crypto_session_, client_id,
encrypted_client_id);
if (status == NO_ERROR) {
provisioning_request->clear_client_id();
provisioning_request.clear_client_id();
} else {
provisioning_request->clear_encrypted_client_id();
provisioning_request.clear_encrypted_client_id();
}
return status;
}
@@ -234,43 +261,17 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
std::string serialized_request;
signed_provisioning_msg.SerializeToString(&serialized_request);
// Converts request into JSON string
ComposeJsonRequestAsQueryString(serialized_request, request);
if (!wvcdm::Properties::provisioning_messages_are_binary()) {
// Return request as web-safe base64 string
std::vector<uint8_t> request_vector(serialized_request.begin(),
serialized_request.end());
request->assign(Base64SafeEncodeNoPad(request_vector));
} else {
request->swap(serialized_request);
}
return NO_ERROR;
}
/*
* Parses the input json_str and locates substring using start_substr and
* end_stubstr. The found base64 substring is then decoded and returns
* in *result.
*
* Returns true for success and false if fails.
*/
bool CertificateProvisioning::ParseJsonResponse(
const CdmProvisioningResponse& json_str, const std::string& start_substr,
const std::string& end_substr, std::string* result) {
std::string b64_string;
size_t start = json_str.find(start_substr);
if (start == json_str.npos) {
LOGE("ParseJsonResponse: cannot find start substring");
return false;
}
size_t end = json_str.find(end_substr, start + start_substr.length());
if (end == json_str.npos) {
LOGE("ParseJsonResponse cannot locate end substring");
return false;
}
size_t b64_string_size = end - start - start_substr.length();
b64_string.assign(json_str, start + start_substr.length(), b64_string_size);
// Decodes base64 substring and returns it in *result
std::vector<uint8_t> result_vector = Base64SafeDecode(b64_string);
result->assign(result_vector.begin(), result_vector.end());
return true;
}
/*
* The response message consists of a device certificate and the device RSA key.
* The device RSA key is stored in the T.E.E. The device certificate is stored
@@ -281,13 +282,19 @@ bool CertificateProvisioning::ParseJsonResponse(
CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
FileSystem* file_system, const CdmProvisioningResponse& response,
std::string* cert, std::string* wrapped_key) {
// 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");
std::string raw_string;
if (!wvcdm::Properties::provisioning_messages_are_binary()) {
// The response is base64 encoded in a JSON wrapper.
// Extract it and decode it. If errors, return an empty string.
ExtractAndDecodeSignedMessage(response, &raw_string);
} else {
raw_string.assign(response);
}
if (raw_string.empty()) {
LOGE("HandleProvisioningResponse: response message is empty or "
"an invalid JSON/base64 string.");
return CERT_PROVISIONING_RESPONSE_ERROR_1;
}
@@ -295,7 +302,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
// 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)) {
if (!signed_response.ParseFromString(raw_string)) {
LOGE("HandleProvisioningResponse: fails to parse signed response");
return CERT_PROVISIONING_RESPONSE_ERROR_2;
}
@@ -314,6 +321,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
if (error) return CERT_PROVISIONING_RESPONSE_ERROR_3;
const std::string& signed_message = signed_response.message();
const std::string& signature = signed_response.signature();
ProvisioningResponse provisioning_response;
if (!provisioning_response.ParseFromString(signed_message)) {
@@ -326,15 +334,29 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
return CERT_PROVISIONING_RESPONSE_ERROR_5;
}
const std::string& enc_rsa_key = provisioning_response.device_rsa_key();
// If Provisioning 3.0 (OEM Cert provisioned), verify that the
// message is properly signed.
if (crypto_session_.GetPreProvisionTokenType() == kClientTokenOemCert) {
if (service_certificate_->VerifySignedMessage(signed_message, signature)
!= NO_ERROR) {
LOGE("HandleProvisioningResponse: message not properly signed");
return CERT_PROVISIONING_RESPONSE_ERROR_6;
}
}
const std::string& new_private_key = provisioning_response.device_rsa_key();
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, signature, nonce,
enc_rsa_key, rsa_key_iv,
&wrapped_rsa_key)) {
LOGE("HandleProvisioningResponse: RewrapDeviceRSAKey fails");
const std::string& iv = provisioning_response.device_rsa_key_iv();
const std::string& wrapping_key = (provisioning_response.has_wrapping_key()) ?
provisioning_response.wrapping_key() : std::string();
std::string wrapped_private_key;
if (!crypto_session_.RewrapCertificate(signed_message, signature, nonce,
new_private_key, iv, wrapping_key,
&wrapped_private_key)) {
LOGE("HandleProvisioningResponse: RewrapCertificate fails");
return CERT_PROVISIONING_RESPONSE_ERROR_6;
}
@@ -342,7 +364,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
if (cert_type_ == kCertificateX509) {
*cert = provisioning_response.device_certificate();
*wrapped_key = wrapped_rsa_key;
*wrapped_key = wrapped_private_key;
return NO_ERROR;
}
@@ -357,7 +379,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
LOGE("HandleProvisioningResponse: failed to init DeviceFiles");
return CERT_PROVISIONING_RESPONSE_ERROR_7;
}
if (!handle.StoreCertificate(device_certificate, wrapped_rsa_key)) {
if (!handle.StoreCertificate(device_certificate, wrapped_private_key)) {
LOGE("HandleProvisioningResponse: failed to save provisioning certificate");
return CERT_PROVISIONING_RESPONSE_ERROR_8;
}