diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index 981f72a0..b60bd4ab 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -62,8 +62,6 @@ class CdmLicense { private: bool PrepareServiceCertificateRequest(CdmKeyMessage* signed_request, std::string* server_url); - CdmResponseType HandleServiceCertificateResponse( - const video_widevine_server::sdk::SignedMessage& signed_message); CdmResponseType HandleKeyErrorResponse( const video_widevine_server::sdk::SignedMessage& signed_message); @@ -76,6 +74,9 @@ class CdmLicense { bool PrepareContentId(const CdmLicenseType license_type, const std::string& request_id, T* content_id); + CdmResponseType VerifySignedServiceCertificate( + const std::string& signed_service_certificate, + std::string* service_certificate); bool GetServiceCertificate(const CdmSessionId& session_id, std::string* service_certificate); diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index 369d3da0..f494130e 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -441,8 +441,11 @@ CdmResponseType CdmLicense::HandleKeyResponse( switch (signed_response.type()) { case SignedMessage::LICENSE: break; - case SignedMessage::SERVICE_CERTIFICATE: - return CdmLicense::HandleServiceCertificateResponse(signed_response); + case SignedMessage::SERVICE_CERTIFICATE: { + CdmResponseType status = CdmLicense::VerifySignedServiceCertificate( + signed_response.msg(), &service_certificate_); + return status == NO_ERROR ? NEED_KEY : status; + } case SignedMessage::ERROR_RESPONSE: return HandleKeyErrorResponse(signed_response); default: @@ -549,8 +552,11 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse( switch (signed_response.type()) { case SignedMessage::LICENSE: break; - case SignedMessage::SERVICE_CERTIFICATE: - return CdmLicense::HandleServiceCertificateResponse(signed_response); + case SignedMessage::SERVICE_CERTIFICATE: { + CdmResponseType status = CdmLicense::VerifySignedServiceCertificate( + signed_response.msg(), &service_certificate_); + return status == NO_ERROR ? NEED_KEY : status; + } case SignedMessage::ERROR_RESPONSE: return HandleKeyErrorResponse(signed_response); default: @@ -803,12 +809,12 @@ bool CdmLicense::PrepareServiceCertificateRequest(CdmKeyMessage* signed_request, return true; } -CdmResponseType CdmLicense::HandleServiceCertificateResponse( - const video_widevine_server::sdk::SignedMessage& signed_response) { +CdmResponseType CdmLicense::VerifySignedServiceCertificate( + const std::string& signed_certificate, std::string* certificate) { SignedDeviceCertificate signed_service_certificate; - if (!signed_service_certificate.ParseFromString(signed_response.msg())) { + if (!signed_service_certificate.ParseFromString(signed_certificate)) { LOGE( - "CdmLicense::HandleServiceCertificateResponse: unable to parse" + "CdmLicense::VerifySignedServiceCertificate: unable to parse" "signed device certificate"); return DEVICE_CERTIFICATE_ERROR_1; } @@ -819,7 +825,7 @@ CdmResponseType CdmLicense::HandleServiceCertificateResponse( &kServiceCertificateCAPublicKey[sizeof(kServiceCertificateCAPublicKey)]); if (!root_ca_key.Init(ca_public_key)) { LOGE( - "CdmLicense::HandleServiceCertificateResponse: public key " + "CdmLicense::VerifySignedServiceCertificate: public key " "initialization failed"); return DEVICE_CERTIFICATE_ERROR_2; } @@ -828,7 +834,7 @@ CdmResponseType CdmLicense::HandleServiceCertificateResponse( signed_service_certificate.device_certificate(), signed_service_certificate.signature())) { LOGE( - "CdmLicense::HandleServiceCertificateResponse: service " + "CdmLicense::VerifySignedServiceCertificate: service " "certificate verification failed"); return DEVICE_CERTIFICATE_ERROR_3; } @@ -837,7 +843,7 @@ CdmResponseType CdmLicense::HandleServiceCertificateResponse( if (!service_certificate.ParseFromString( signed_service_certificate.device_certificate())) { LOGE( - "CdmLicense::HandleServiceCertificateResponse: unable to parse " + "CdmLicense::VerifySignedServiceCertificate: unable to parse " "retrieved service certificate"); return DEVICE_CERTIFICATE_ERROR_4; } @@ -845,14 +851,14 @@ CdmResponseType CdmLicense::HandleServiceCertificateResponse( if (service_certificate.type() != video_widevine_server::sdk::DeviceCertificate_CertificateType_SERVICE) { LOGE( - "CdmLicense::HandleServiceCertificateResponse: certificate not of type" + "CdmLicense::VerifySignedServiceCertificate: certificate not of type" " service, %d", service_certificate.type()); return INVALID_DEVICE_CERTIFICATE_TYPE; } - service_certificate_ = signed_service_certificate.device_certificate(); - return NEED_KEY; + *certificate = signed_service_certificate.device_certificate(); + return NO_ERROR; } CdmResponseType CdmLicense::HandleKeyErrorResponse( @@ -1045,9 +1051,14 @@ CdmResponseType CdmLicense::PrepareClientId( bool CdmLicense::GetServiceCertificate(const CdmSessionId& session_id, std::string* service_certificate) { - if (!Properties::GetServiceCertificate(session_id, service_certificate) || - service_certificate->empty()) + std::string signed_service_certificate; + if (!Properties::GetServiceCertificate(session_id, + &signed_service_certificate) || + signed_service_certificate.empty() || + NO_ERROR != VerifySignedServiceCertificate(signed_service_certificate, + service_certificate)) { *service_certificate = service_certificate_; + } if (service_certificate->size() > 0) return true; return false; diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index 55e43264..a669898b 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -54,16 +54,26 @@ wvcdm::KeyId g_wrong_key_id; wvcdm::LicenseServerId g_license_server_id = wvcdm::kContentProtectionServer; std::string kServiceCertificate = - "0803121028703454C008F63618ADE7443DB6C4C8188BE7F99005228E023082010" - "A0282010100B52112B8D05D023FCC5D95E2C251C1C649B4177CD8D2BEEF355BB0" - "6743DE661E3D2ABC3182B79946D55FDC08DFE95407815E9A6274B322A2C7F5E06" - "7BB5F0AC07A89D45AEA94B2516F075B66EF811D0D26E1B9A6B894F2B9857962AA" - "171C4F66630D3E4C602718897F5E1EF9B6AAF5AD4DBA2A7E14176DF134A1D3185" - "B5A218AC05A4C41F081EFFF80A3A040C50B09BBC740EEDCD8F14D675A91980F92" - "CA7DDC646A06ADAD5101F74A0E498CC01F00532BAC217850BD905E90923656B7D" - "FEFEF42486767F33EF6283D4F4254AB72589390BEE55808F1D668080D45D893C2" - "BCA2F74D60A0C0D0A0993CEF01604703334C3638139486BC9DAF24FD67A07F9AD" - "94302030100013A1273746167696E672E676F6F676C652E636F6D"; + "0ABF020803121028703454C008F63618ADE7443DB6C4C8188BE7F99005228E023082010A02" + "82010100B52112B8D05D023FCC5D95E2C251C1C649B4177CD8D2BEEF355BB06743DE661E3D" + "2ABC3182B79946D55FDC08DFE95407815E9A6274B322A2C7F5E067BB5F0AC07A89D45AEA94" + "B2516F075B66EF811D0D26E1B9A6B894F2B9857962AA171C4F66630D3E4C602718897F5E1E" + "F9B6AAF5AD4DBA2A7E14176DF134A1D3185B5A218AC05A4C41F081EFFF80A3A040C50B09BB" + "C740EEDCD8F14D675A91980F92CA7DDC646A06ADAD5101F74A0E498CC01F00532BAC217850" + "BD905E90923656B7DFEFEF42486767F33EF6283D4F4254AB72589390BEE55808F1D668080D" + "45D893C2BCA2F74D60A0C0D0A0993CEF01604703334C3638139486BC9DAF24FD67A07F9AD9" + "4302030100013A1273746167696E672E676F6F676C652E636F6D128003983E30352675F40B" + "A715FC249BDAE5D4AC7249A2666521E43655739529721FF880E0AAEFC5E27BC980DAEADABF" + "3FC386D084A02C82537848CC753FF497B011A7DA97788A00E2AA6B84CD7D71C07A48EBF616" + "02CCA5A3F32030A7295C30DA915B91DC18B9BC9593B8DE8BB50F0DEDC12938B8E9E039CDDE" + "18FA82E81BB032630FE955D85A566CE154300BF6D4C1BD126966356B287D657B18CE63D0EF" + "D45FC5269E97EAB11CB563E55643B26FF49F109C2101AFCAF35B832F288F0D9D45960E259E" + "85FB5D24DBD2CF82764C5DD9BF727EFBE9C861F869321F6ADE18905F4D92F9A6DA6536DB84" + "75871D168E870BB2303CF70C6E9784C93D2DE845AD8262BE7E0D4E2E4A0759CEF82D109D25" + "92C72429F8C01742BAE2B3DECADBC33C3E5F4BAF5E16ECB74EADBAFCB7C6705F7A9E3B6F39" + "40383F9C5116D202A20C9229EE969C2519718303B50D0130C3352E06B014D838540F8A0C22" + "7C0011E0F5B38E4E298ED2CB301EB4564965F55C5D79757A250A4EB9C84AB3E6539F6B6FDF" + "56899EA29914"; // TODO(rfrias): refactor to print out the decryption test names struct SubSampleInfo {