From c400a37d190d9793fd0b90f5c54aeeb00dcfd8b6 Mon Sep 17 00:00:00 2001 From: "John \"Juce\" Bruce" Date: Fri, 12 Jun 2015 11:46:32 -0700 Subject: [PATCH] Validate Service Certificates Before Accepting Them (This is a merge of http://go/wvgerrit/14630) To create a better flow when an application sets a service certificate manually, we will now validate the certificate when it is given to us, and if it is invalid, we will not allow the property to be set. Bug: 21307186 Change-Id: If980ad075604223fc962a859fae93e98d86a7f4f --- libwvdrmengine/cdm/core/include/license.h | 5 ++- libwvdrmengine/cdm/core/src/license.cpp | 32 ++++++++++++------- .../include/wv_content_decryption_module.h | 1 + .../cdm/src/wv_content_decryption_module.cpp | 6 ++++ libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp | 6 +++- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index b60bd4ab..b9b5621e 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -59,6 +59,9 @@ class CdmLicense { return provider_session_token_; } + static CdmResponseType VerifySignedServiceCertificate( + const std::string& signed_service_certificate); + private: bool PrepareServiceCertificateRequest(CdmKeyMessage* signed_request, std::string* server_url); @@ -74,7 +77,7 @@ class CdmLicense { bool PrepareContentId(const CdmLicenseType license_type, const std::string& request_id, T* content_id); - CdmResponseType VerifySignedServiceCertificate( + static CdmResponseType VerifyAndExtractSignedServiceCertificate( const std::string& signed_service_certificate, std::string* service_certificate); bool GetServiceCertificate(const CdmSessionId& session_id, diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index f494130e..16d3e886 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -442,7 +442,7 @@ CdmResponseType CdmLicense::HandleKeyResponse( case SignedMessage::LICENSE: break; case SignedMessage::SERVICE_CERTIFICATE: { - CdmResponseType status = CdmLicense::VerifySignedServiceCertificate( + CdmResponseType status = VerifyAndExtractSignedServiceCertificate( signed_response.msg(), &service_certificate_); return status == NO_ERROR ? NEED_KEY : status; } @@ -553,7 +553,7 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse( case SignedMessage::LICENSE: break; case SignedMessage::SERVICE_CERTIFICATE: { - CdmResponseType status = CdmLicense::VerifySignedServiceCertificate( + CdmResponseType status = VerifyAndExtractSignedServiceCertificate( signed_response.msg(), &service_certificate_); 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(); } +CdmResponseType CdmLicense::VerifySignedServiceCertificate( + const std::string& signed_service_certificate) { + return VerifyAndExtractSignedServiceCertificate(signed_service_certificate, + NULL); +} + bool CdmLicense::PrepareServiceCertificateRequest(CdmKeyMessage* signed_request, std::string* server_url) { if (!initialized_) { @@ -809,12 +815,12 @@ bool CdmLicense::PrepareServiceCertificateRequest(CdmKeyMessage* signed_request, return true; } -CdmResponseType CdmLicense::VerifySignedServiceCertificate( +CdmResponseType CdmLicense::VerifyAndExtractSignedServiceCertificate( const std::string& signed_certificate, std::string* certificate) { SignedDeviceCertificate signed_service_certificate; if (!signed_service_certificate.ParseFromString(signed_certificate)) { LOGE( - "CdmLicense::VerifySignedServiceCertificate: unable to parse" + "CdmLicense::VerifyAndExtractSignedServiceCertificate: unable to parse " "signed device certificate"); return DEVICE_CERTIFICATE_ERROR_1; } @@ -825,7 +831,7 @@ CdmResponseType CdmLicense::VerifySignedServiceCertificate( &kServiceCertificateCAPublicKey[sizeof(kServiceCertificateCAPublicKey)]); if (!root_ca_key.Init(ca_public_key)) { LOGE( - "CdmLicense::VerifySignedServiceCertificate: public key " + "CdmLicense::VerifyAndExtractSignedServiceCertificate: public key " "initialization failed"); return DEVICE_CERTIFICATE_ERROR_2; } @@ -834,7 +840,7 @@ CdmResponseType CdmLicense::VerifySignedServiceCertificate( signed_service_certificate.device_certificate(), signed_service_certificate.signature())) { LOGE( - "CdmLicense::VerifySignedServiceCertificate: service " + "CdmLicense::VerifyAndExtractSignedServiceCertificate: service " "certificate verification failed"); return DEVICE_CERTIFICATE_ERROR_3; } @@ -843,7 +849,7 @@ CdmResponseType CdmLicense::VerifySignedServiceCertificate( if (!service_certificate.ParseFromString( signed_service_certificate.device_certificate())) { LOGE( - "CdmLicense::VerifySignedServiceCertificate: unable to parse " + "CdmLicense::VerifyAndExtractSignedServiceCertificate: unable to parse " "retrieved service certificate"); return DEVICE_CERTIFICATE_ERROR_4; } @@ -851,13 +857,15 @@ CdmResponseType CdmLicense::VerifySignedServiceCertificate( if (service_certificate.type() != video_widevine_server::sdk::DeviceCertificate_CertificateType_SERVICE) { LOGE( - "CdmLicense::VerifySignedServiceCertificate: certificate not of type" - " service, %d", + "CdmLicense::VerifyAndExtractSignedServiceCertificate: certificate not " + "of type service, %d", service_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; } @@ -1055,8 +1063,8 @@ bool CdmLicense::GetServiceCertificate(const CdmSessionId& session_id, if (!Properties::GetServiceCertificate(session_id, &signed_service_certificate) || signed_service_certificate.empty() || - NO_ERROR != VerifySignedServiceCertificate(signed_service_certificate, - service_certificate)) { + NO_ERROR != VerifyAndExtractSignedServiceCertificate( + signed_service_certificate, service_certificate)) { *service_certificate = service_certificate_; } diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index de877338..1bcb10ff 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -25,6 +25,7 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { static bool IsSupported(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 IsValidServiceCertificate(const std::string& certificate); // Session related methods virtual CdmResponseType OpenSession(const CdmKeySystem& key_system, diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 770238da..a5e8b3ce 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -5,6 +5,7 @@ #include "cdm_client_property_set.h" #include "cdm_engine.h" #include "initialization_data.h" +#include "license.h" #include "log.h" #include "properties.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(); } +bool WvContentDecryptionModule::IsValidServiceCertificate( + const std::string& certificate) { + return CdmLicense::VerifySignedServiceCertificate(certificate) == NO_ERROR; +} + CdmResponseType WvContentDecryptionModule::OpenSession( const CdmKeySystem& key_system, CdmClientPropertySet* property_set, const std::string& origin, WvCdmEventListener* event_listener, diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index 4dac6fed..9560dbb3 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -585,7 +585,11 @@ status_t WVDrmPlugin::setPropertyByteArray(const String8& name, const Vector& value) { if (name == "serviceCertificate") { 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 { ALOGE("App set unknown byte array property %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE;