Add Privacy Mode and Serivce Certificate Support
This merges the following changes from the Widevine CDM repository:
da001b6 Add Privacy mode and service certificate
This adds support to the CDM for privacy mode and service certificates.
92bf200 Add support for using Youtube Content Protection server for testing
Enables testing with Youtube Content Protection server. Google Play license
server is still the default. Select YTCP server by using the flag -icp
e.g. adb shell '/system/bin/request_license_test -icp'
85dcd60 Fixes to enable privacy mode
These includes changes to use PKCS7 padding, corrected root CA formatting
and changes to integration test. Also refactored service certificate
handling.
989971c Correction to request license test
Corrected PropertySetTest to provision when needed. Also added disabled
privacy tests to run against YTCP staging server until GooglePlay
integration is complete.
Bug: 10109249
Change-Id: If81d68c65d743d77a485406f48d1be41a74de0af
This commit is contained in:
@@ -443,9 +443,6 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (service_certificate_response_pending_)
|
||||
return CdmLicense::HandleServiceCertificateResponse(license_response);
|
||||
|
||||
SignedMessage signed_response;
|
||||
if (!signed_response.ParseFromString(license_response)) {
|
||||
LOGE(
|
||||
@@ -454,8 +451,17 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (signed_response.type() == SignedMessage::ERROR) {
|
||||
return HandleKeyErrorResponse(signed_response);
|
||||
switch (signed_response.type()) {
|
||||
case SignedMessage::LICENSE:
|
||||
break;
|
||||
case SignedMessage::SERVICE_CERTIFICATE:
|
||||
return CdmLicense::HandleServiceCertificateResponse(signed_response);
|
||||
case SignedMessage::ERROR:
|
||||
return HandleKeyErrorResponse(signed_response);
|
||||
default:
|
||||
LOGE("CdmLicense::HandleKeyResponse: unrecognized signed message type: %d"
|
||||
, signed_response.type());
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
if (!signed_response.has_signature()) {
|
||||
@@ -652,40 +658,12 @@ bool CdmLicense::PrepareServiceCertificateRequest(CdmKeyMessage* signed_request,
|
||||
signed_message.set_type(SignedMessage::SERVICE_CERTIFICATE_REQUEST);
|
||||
signed_message.SerializeToString(signed_request);
|
||||
*server_url = server_url_;
|
||||
service_certificate_response_pending_ = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::HandleServiceCertificateResponse(
|
||||
const CdmKeyResponse& service_certificate_response) {
|
||||
if (!initialized_) {
|
||||
LOGE("CdmLicense::HandleServiceCertificateResponse: not initialized");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
if (service_certificate_response.empty()) {
|
||||
LOGE(
|
||||
"CdmLicense::HandleServiceCertificateResponse: empty service "
|
||||
"certificate response");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
SignedMessage signed_response;
|
||||
if (!signed_response.ParseFromString(service_certificate_response))
|
||||
return KEY_ERROR;
|
||||
|
||||
switch (signed_response.type()) {
|
||||
case SignedMessage::ERROR:
|
||||
return HandleKeyErrorResponse(signed_response);
|
||||
case SignedMessage::SERVICE_CERTIFICATE:
|
||||
break; // expected message type
|
||||
default:
|
||||
LOGE(
|
||||
"CdmLicense::HandleServiceCertificateResponse: unexpected signed"
|
||||
"message type: %d",
|
||||
signed_response.type());
|
||||
return KEY_ERROR;
|
||||
}
|
||||
const video_widevine_server::sdk::SignedMessage& signed_response) {
|
||||
|
||||
SignedDeviceCertificate signed_service_certificate;
|
||||
if (!signed_service_certificate.ParseFromString(signed_response.msg())) {
|
||||
@@ -696,12 +674,12 @@ CdmResponseType CdmLicense::HandleServiceCertificateResponse(
|
||||
}
|
||||
|
||||
RsaPublicKey root_ca_key;
|
||||
std::vector<uint8_t> ca_public_key(
|
||||
std::string ca_public_key(
|
||||
&kServiceCertificateCAPublicKey[0],
|
||||
&kServiceCertificateCAPublicKey[sizeof(kServiceCertificateCAPublicKey)]);
|
||||
if (!root_ca_key.Init(b2a_hex(ca_public_key))) {
|
||||
if (!root_ca_key.Init(ca_public_key)) {
|
||||
LOGE(
|
||||
"CdmLicense::HandleServiceCertificateResponse: public key"
|
||||
"CdmLicense::HandleServiceCertificateResponse: public key "
|
||||
"initialization failed");
|
||||
return KEY_ERROR;
|
||||
}
|
||||
|
||||
@@ -11,17 +11,15 @@
|
||||
#include "privacy_crypto.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "openssl/aes.h"
|
||||
#include "openssl/bio.h"
|
||||
#include "openssl/err.h"
|
||||
#include "openssl/evp.h"
|
||||
#include "openssl/pem.h"
|
||||
#include "openssl/rsa.h"
|
||||
#include "openssl/sha.h"
|
||||
|
||||
namespace {
|
||||
const int kPssSaltLength = 20;
|
||||
const int kRsaPkcs1OaepPaddingLength = 41;
|
||||
const int kBitsInAByte = 8;
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -35,8 +33,10 @@ bool AesCbcKey::Init(const std::string& key) {
|
||||
LOGE("AesCbcKey::Init: unexpected key size: %d", key.size());
|
||||
return false;
|
||||
}
|
||||
if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(&key[0]),
|
||||
key.size() * kBitsInAByte, &key_) != 0) {
|
||||
|
||||
EVP_CIPHER_CTX_init(&ctx_);
|
||||
if (EVP_EncryptInit(&ctx_, EVP_aes_128_cbc(),
|
||||
reinterpret_cast<const uint8_t*>(&key[0]), NULL) == 0) {
|
||||
LOGE("AesCbcKey::Init: AES CBC key setup failure: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
@@ -51,10 +51,6 @@ bool AesCbcKey::Encrypt(const std::string& in, std::string* out,
|
||||
LOGE("AesCbcKey::Encrypt: no cleartext provided");
|
||||
return false;
|
||||
}
|
||||
if (in.size() % AES_BLOCK_SIZE) {
|
||||
LOGE("AesCbcKey::Encrypt: cleartext not a block multiple: %d", in.size());
|
||||
return false;
|
||||
}
|
||||
if (iv == NULL) {
|
||||
LOGE("AesCbcKey::Encrypt: initialization vector destination not provided");
|
||||
return false;
|
||||
@@ -72,11 +68,33 @@ bool AesCbcKey::Encrypt(const std::string& in, std::string* out,
|
||||
return false;
|
||||
}
|
||||
|
||||
out->resize(in.size());
|
||||
if (EVP_EncryptInit(&ctx_, NULL, NULL,
|
||||
reinterpret_cast<const uint8_t*>(iv->data())) == 0) {
|
||||
LOGE("AesCbcKey::Encrypt: AES CBC iv setup failure: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
AES_cbc_encrypt(reinterpret_cast<const uint8_t*>(&in[0]),
|
||||
reinterpret_cast<uint8_t*>(&out[0]), in.size(), &key_,
|
||||
reinterpret_cast<uint8_t*>(&iv[0]), AES_ENCRYPT);
|
||||
out->resize(in.size() + AES_BLOCK_SIZE);
|
||||
int out_length = out->size();
|
||||
if (EVP_EncryptUpdate(
|
||||
&ctx_, reinterpret_cast<uint8_t*>(&(*out)[0]), &out_length,
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(in.data())),
|
||||
in.size()) == 0) {
|
||||
LOGE("AesCbcKey::Encrypt: encryption failure: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
int padding = 0;
|
||||
if (EVP_EncryptFinal(&ctx_, reinterpret_cast<uint8_t*>(&(*out)[out_length]),
|
||||
&padding) == 0) {
|
||||
LOGE("AesCbcKey::Encrypt: PKCS7 padding failure: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
out->resize(out_length + padding);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -103,7 +121,8 @@ bool RsaPublicKey::Init(const std::string& serialized_key) {
|
||||
BIO_free(bio);
|
||||
|
||||
if (key_ == NULL) {
|
||||
LOGE("RsaPublicKey::Init: RSA key deserialization failure");
|
||||
LOGE("RsaPublicKey::Init: RSA key deserialization failure: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user