Merge "Validate Service Certificates Before Accepting Them" into mnc-dev

This commit is contained in:
John "Juce" Bruce
2015-06-12 19:49:45 +00:00
committed by Android (Google) Code Review
5 changed files with 36 additions and 14 deletions

View File

@@ -59,6 +59,9 @@ class CdmLicense {
return provider_session_token_; return provider_session_token_;
} }
static CdmResponseType VerifySignedServiceCertificate(
const std::string& signed_service_certificate);
private: private:
bool PrepareServiceCertificateRequest(CdmKeyMessage* signed_request, bool PrepareServiceCertificateRequest(CdmKeyMessage* signed_request,
std::string* server_url); std::string* server_url);
@@ -74,7 +77,7 @@ class CdmLicense {
bool PrepareContentId(const CdmLicenseType license_type, bool PrepareContentId(const CdmLicenseType license_type,
const std::string& request_id, T* content_id); const std::string& request_id, T* content_id);
CdmResponseType VerifySignedServiceCertificate( static CdmResponseType VerifyAndExtractSignedServiceCertificate(
const std::string& signed_service_certificate, const std::string& signed_service_certificate,
std::string* service_certificate); std::string* service_certificate);
bool GetServiceCertificate(const CdmSessionId& session_id, bool GetServiceCertificate(const CdmSessionId& session_id,

View File

@@ -442,7 +442,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
case SignedMessage::LICENSE: case SignedMessage::LICENSE:
break; break;
case SignedMessage::SERVICE_CERTIFICATE: { case SignedMessage::SERVICE_CERTIFICATE: {
CdmResponseType status = CdmLicense::VerifySignedServiceCertificate( CdmResponseType status = VerifyAndExtractSignedServiceCertificate(
signed_response.msg(), &service_certificate_); signed_response.msg(), &service_certificate_);
return status == NO_ERROR ? NEED_KEY : status; return status == NO_ERROR ? NEED_KEY : status;
} }
@@ -553,7 +553,7 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
case SignedMessage::LICENSE: case SignedMessage::LICENSE:
break; break;
case SignedMessage::SERVICE_CERTIFICATE: { case SignedMessage::SERVICE_CERTIFICATE: {
CdmResponseType status = CdmLicense::VerifySignedServiceCertificate( CdmResponseType status = VerifyAndExtractSignedServiceCertificate(
signed_response.msg(), &service_certificate_); signed_response.msg(), &service_certificate_);
return status == NO_ERROR ? NEED_KEY : status; return status == NO_ERROR ? NEED_KEY : status;
} }
@@ -783,6 +783,12 @@ bool CdmLicense::IsKeyLoaded(const KeyId& key_id) {
return loaded_keys_.find(key_id) != loaded_keys_.end(); return loaded_keys_.find(key_id) != loaded_keys_.end();
} }
CdmResponseType CdmLicense::VerifySignedServiceCertificate(
const std::string& signed_service_certificate) {
return VerifyAndExtractSignedServiceCertificate(signed_service_certificate,
NULL);
}
bool CdmLicense::PrepareServiceCertificateRequest(CdmKeyMessage* signed_request, bool CdmLicense::PrepareServiceCertificateRequest(CdmKeyMessage* signed_request,
std::string* server_url) { std::string* server_url) {
if (!initialized_) { if (!initialized_) {
@@ -809,12 +815,12 @@ bool CdmLicense::PrepareServiceCertificateRequest(CdmKeyMessage* signed_request,
return true; return true;
} }
CdmResponseType CdmLicense::VerifySignedServiceCertificate( CdmResponseType CdmLicense::VerifyAndExtractSignedServiceCertificate(
const std::string& signed_certificate, std::string* certificate) { const std::string& signed_certificate, std::string* certificate) {
SignedDeviceCertificate signed_service_certificate; SignedDeviceCertificate signed_service_certificate;
if (!signed_service_certificate.ParseFromString(signed_certificate)) { if (!signed_service_certificate.ParseFromString(signed_certificate)) {
LOGE( LOGE(
"CdmLicense::VerifySignedServiceCertificate: unable to parse" "CdmLicense::VerifyAndExtractSignedServiceCertificate: unable to parse "
"signed device certificate"); "signed device certificate");
return DEVICE_CERTIFICATE_ERROR_1; return DEVICE_CERTIFICATE_ERROR_1;
} }
@@ -825,7 +831,7 @@ CdmResponseType CdmLicense::VerifySignedServiceCertificate(
&kServiceCertificateCAPublicKey[sizeof(kServiceCertificateCAPublicKey)]); &kServiceCertificateCAPublicKey[sizeof(kServiceCertificateCAPublicKey)]);
if (!root_ca_key.Init(ca_public_key)) { if (!root_ca_key.Init(ca_public_key)) {
LOGE( LOGE(
"CdmLicense::VerifySignedServiceCertificate: public key " "CdmLicense::VerifyAndExtractSignedServiceCertificate: public key "
"initialization failed"); "initialization failed");
return DEVICE_CERTIFICATE_ERROR_2; return DEVICE_CERTIFICATE_ERROR_2;
} }
@@ -834,7 +840,7 @@ CdmResponseType CdmLicense::VerifySignedServiceCertificate(
signed_service_certificate.device_certificate(), signed_service_certificate.device_certificate(),
signed_service_certificate.signature())) { signed_service_certificate.signature())) {
LOGE( LOGE(
"CdmLicense::VerifySignedServiceCertificate: service " "CdmLicense::VerifyAndExtractSignedServiceCertificate: service "
"certificate verification failed"); "certificate verification failed");
return DEVICE_CERTIFICATE_ERROR_3; return DEVICE_CERTIFICATE_ERROR_3;
} }
@@ -843,7 +849,7 @@ CdmResponseType CdmLicense::VerifySignedServiceCertificate(
if (!service_certificate.ParseFromString( if (!service_certificate.ParseFromString(
signed_service_certificate.device_certificate())) { signed_service_certificate.device_certificate())) {
LOGE( LOGE(
"CdmLicense::VerifySignedServiceCertificate: unable to parse " "CdmLicense::VerifyAndExtractSignedServiceCertificate: unable to parse "
"retrieved service certificate"); "retrieved service certificate");
return DEVICE_CERTIFICATE_ERROR_4; return DEVICE_CERTIFICATE_ERROR_4;
} }
@@ -851,13 +857,15 @@ CdmResponseType CdmLicense::VerifySignedServiceCertificate(
if (service_certificate.type() != if (service_certificate.type() !=
video_widevine_server::sdk::DeviceCertificate_CertificateType_SERVICE) { video_widevine_server::sdk::DeviceCertificate_CertificateType_SERVICE) {
LOGE( LOGE(
"CdmLicense::VerifySignedServiceCertificate: certificate not of type" "CdmLicense::VerifyAndExtractSignedServiceCertificate: certificate not "
" service, %d", "of type service, %d",
service_certificate.type()); service_certificate.type());
return INVALID_DEVICE_CERTIFICATE_TYPE; return INVALID_DEVICE_CERTIFICATE_TYPE;
} }
*certificate = signed_service_certificate.device_certificate(); if (certificate != NULL) {
*certificate = signed_service_certificate.device_certificate();
}
return NO_ERROR; return NO_ERROR;
} }
@@ -1055,8 +1063,8 @@ bool CdmLicense::GetServiceCertificate(const CdmSessionId& session_id,
if (!Properties::GetServiceCertificate(session_id, if (!Properties::GetServiceCertificate(session_id,
&signed_service_certificate) || &signed_service_certificate) ||
signed_service_certificate.empty() || signed_service_certificate.empty() ||
NO_ERROR != VerifySignedServiceCertificate(signed_service_certificate, NO_ERROR != VerifyAndExtractSignedServiceCertificate(
service_certificate)) { signed_service_certificate, service_certificate)) {
*service_certificate = service_certificate_; *service_certificate = service_certificate_;
} }

View File

@@ -25,6 +25,7 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler {
static bool IsSupported(const std::string& init_data_type); static bool IsSupported(const std::string& init_data_type);
static bool IsCenc(const std::string& init_data_type); static bool IsCenc(const std::string& init_data_type);
static bool IsWebm(const std::string& init_data_type); static bool IsWebm(const std::string& init_data_type);
static bool IsValidServiceCertificate(const std::string& certificate);
// Session related methods // Session related methods
virtual CdmResponseType OpenSession(const CdmKeySystem& key_system, virtual CdmResponseType OpenSession(const CdmKeySystem& key_system,

View File

@@ -5,6 +5,7 @@
#include "cdm_client_property_set.h" #include "cdm_client_property_set.h"
#include "cdm_engine.h" #include "cdm_engine.h"
#include "initialization_data.h" #include "initialization_data.h"
#include "license.h"
#include "log.h" #include "log.h"
#include "properties.h" #include "properties.h"
#include "wv_cdm_constants.h" #include "wv_cdm_constants.h"
@@ -37,6 +38,11 @@ bool WvContentDecryptionModule::IsWebm(const std::string& init_data_type) {
return InitializationData(init_data_type).is_webm(); return InitializationData(init_data_type).is_webm();
} }
bool WvContentDecryptionModule::IsValidServiceCertificate(
const std::string& certificate) {
return CdmLicense::VerifySignedServiceCertificate(certificate) == NO_ERROR;
}
CdmResponseType WvContentDecryptionModule::OpenSession( CdmResponseType WvContentDecryptionModule::OpenSession(
const CdmKeySystem& key_system, CdmClientPropertySet* property_set, const CdmKeySystem& key_system, CdmClientPropertySet* property_set,
const std::string& origin, WvCdmEventListener* event_listener, const std::string& origin, WvCdmEventListener* event_listener,

View File

@@ -585,7 +585,11 @@ status_t WVDrmPlugin::setPropertyByteArray(const String8& name,
const Vector<uint8_t>& value) { const Vector<uint8_t>& value) {
if (name == "serviceCertificate") { if (name == "serviceCertificate") {
std::string cert(value.begin(), value.end()); std::string cert(value.begin(), value.end());
mPropertySet.set_service_certificate(cert); if (WvContentDecryptionModule::IsValidServiceCertificate(cert)) {
mPropertySet.set_service_certificate(cert);
} else {
return android::BAD_VALUE;
}
} else { } else {
ALOGE("App set unknown byte array property %s", name.string()); ALOGE("App set unknown byte array property %s", name.string());
return android::ERROR_DRM_CANNOT_HANDLE; return android::ERROR_DRM_CANNOT_HANDLE;