From c823a85e7d3e541ad6dfce15b9be49ba15dfe904 Mon Sep 17 00:00:00 2001 From: "John \"Juce\" Bruce" Date: Wed, 20 Apr 2022 14:10:20 -0700 Subject: [PATCH] First-stage Provisioning 4.0 client ID encryption (This is a merge of http://go/wvgerrit/150131 to the Android repo.) This patch changes the code path in the CDM so that the first-stage provisioning request for Provisioning 4.0 is always encrypted with the Widevine service certificate instead of the client-set service certificate, reflecting that the first-stage provisioning is always handled by Widevine. This patch also makes several methods on the ServiceCertificate class const. This has no impact on their behavior. Bug: 221443151 Test: prov40 tests Change-Id: Ide4c3927afadcd45ae7fb629b99e2f55cc29d56e --- .../core/include/certificate_provisioning.h | 3 +- .../cdm/core/include/service_certificate.h | 8 ++-- .../cdm/core/src/certificate_provisioning.cpp | 38 ++++++++++++------- .../cdm/core/src/service_certificate.cpp | 8 ++-- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/libwvdrmengine/cdm/core/include/certificate_provisioning.h b/libwvdrmengine/cdm/core/include/certificate_provisioning.h index 097a8006..05c0cad5 100644 --- a/libwvdrmengine/cdm/core/include/certificate_provisioning.h +++ b/libwvdrmengine/cdm/core/include/certificate_provisioning.h @@ -86,7 +86,8 @@ class CertificateProvisioning { std::string* default_url); CdmResponseType FillEncryptedClientId( const std::string& client_token, - video_widevine::ProvisioningRequest& provisioning_request); + video_widevine::ProvisioningRequest& provisioning_request, + const ServiceCertificate& service_certificate); CdmResponseType HandleProvisioning40Response( wvutil::FileSystem* file_system, const std::string& response_message); diff --git a/libwvdrmengine/cdm/core/include/service_certificate.h b/libwvdrmengine/cdm/core/include/service_certificate.h index 7bd80b26..ced4f4c1 100644 --- a/libwvdrmengine/cdm/core/include/service_certificate.h +++ b/libwvdrmengine/cdm/core/include/service_certificate.h @@ -38,8 +38,8 @@ class ServiceCertificate { const std::string& provider_id() const { return provider_id_; } // Verify the signature for a message. - virtual CdmResponseType VerifySignedMessage(const std::string& message, - const std::string& signature); + virtual CdmResponseType VerifySignedMessage( + const std::string& message, const std::string& signature) const; // Encrypt the ClientIdentification message for a provisioning or // licensing request. Encryption is performed using the current @@ -50,7 +50,7 @@ class ServiceCertificate { virtual CdmResponseType EncryptClientId( CryptoSession* crypto_session, const video_widevine::ClientIdentification* clear_client_id, - video_widevine::EncryptedClientIdentification* encrypted_client_id); + video_widevine::EncryptedClientIdentification* encrypted_client_id) const; // Helper methods static bool GetRequest(CdmKeyMessage* request); @@ -63,7 +63,7 @@ class ServiceCertificate { // string to contain the decrypted data on return, and may not be null. // returns NO_ERROR if successful or an appropriate error code otherwise. virtual CdmResponseType EncryptRsaOaep(const std::string& plaintext, - std::string* ciphertext); + std::string* ciphertext) const; // Track whether object holds valid certificate bool has_certificate_; diff --git a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp index 77e20747..2f2f2339 100644 --- a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp +++ b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp @@ -218,7 +218,8 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal( // Prepare device provisioning request. ProvisioningRequest provisioning_request; - status = FillEncryptedClientId(/*client_token=*/"", provisioning_request); + status = FillEncryptedClientId(/*client_token=*/"", provisioning_request, + *service_certificate_); if (status != NO_ERROR) return status; uint32_t nonce; @@ -339,24 +340,33 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal( } } + CdmResponseType status = NO_ERROR; if (stored_oem_cert.empty()) { // This is the first stage provisioning. default_url->assign(kProvisioningServerUrl + kProv40FirstStageServerUrlSuffix); + + // First-stage provisioning always uses the WV production service cert for + // encryption. + ServiceCertificate wv_service_cert; + status = wv_service_cert.Init(kCpProductionServiceCertificate); + if (status != NO_ERROR) return status; + + // Since |stored_oem_cert| is empty, the client identification token will be + // retrieved from OEMCrypto, which is the BCC in this case. + status = FillEncryptedClientId(stored_oem_cert, provisioning_request, + wv_service_cert); + if (status != NO_ERROR) return status; } else { // This is the second stage provisioning. default_url->assign(kProvisioningServerUrl); + // Since |stored_oem_cert| is non-empty, it will be used as the client + // identification token. + status = FillEncryptedClientId(stored_oem_cert, provisioning_request, + *service_certificate_); + if (status != NO_ERROR) return status; } - // If this is the first stage, |stored_oem_cert| remains empty. In this case, - // the client identification token will be retrieved from OEMCrypto, which is - // the BCC in this case. - // If this is the second stage, |stored_oem_cert| is non-empty and will be - // used as the client identification token. - CdmResponseType status = - FillEncryptedClientId(stored_oem_cert, provisioning_request); - if (status != NO_ERROR) return status; - std::string public_key; std::string public_key_signature; provisioning_40_wrapped_private_key_.clear(); @@ -396,8 +406,8 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal( } CdmResponseType CertificateProvisioning::FillEncryptedClientId( - const std::string& client_token, - ProvisioningRequest& provisioning_request) { + const std::string& client_token, ProvisioningRequest& provisioning_request, + const ServiceCertificate& service_certificate) { if (!crypto_session_->IsOpen()) { return UNKNOWN_ERROR; } @@ -412,13 +422,13 @@ CdmResponseType CertificateProvisioning::FillEncryptedClientId( status = id.Prepare(app_parameter, kEmptyString, &client_id); if (status != NO_ERROR) return status; - if (!service_certificate_->has_certificate()) { + if (!service_certificate.has_certificate()) { LOGE("Service certificate not staged"); return CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE; } // Encrypt client identification - return service_certificate_->EncryptClientId( + return service_certificate.EncryptClientId( crypto_session_.get(), &client_id, provisioning_request.mutable_encrypted_client_id()); } diff --git a/libwvdrmengine/cdm/core/src/service_certificate.cpp b/libwvdrmengine/cdm/core/src/service_certificate.cpp index 47625a7a..2d2947bf 100644 --- a/libwvdrmengine/cdm/core/src/service_certificate.cpp +++ b/libwvdrmengine/cdm/core/src/service_certificate.cpp @@ -206,7 +206,7 @@ CdmResponseType ServiceCertificate::Init(const std::string& certificate) { } CdmResponseType ServiceCertificate::VerifySignedMessage( - const std::string& message, const std::string& signature) { + const std::string& message, const std::string& signature) const { if (!public_key_) { LOGE("Service certificate not set"); return DEVICE_CERTIFICATE_ERROR_4; @@ -218,8 +218,8 @@ CdmResponseType ServiceCertificate::VerifySignedMessage( return NO_ERROR; } -CdmResponseType ServiceCertificate::EncryptRsaOaep(const std::string& plaintext, - std::string* ciphertext) { +CdmResponseType ServiceCertificate::EncryptRsaOaep( + const std::string& plaintext, std::string* ciphertext) const { if (!public_key_) { LOGE("Service certificate not set"); return DEVICE_CERTIFICATE_ERROR_4; @@ -233,7 +233,7 @@ CdmResponseType ServiceCertificate::EncryptRsaOaep(const std::string& plaintext, CdmResponseType ServiceCertificate::EncryptClientId( CryptoSession* crypto_session, const ClientIdentification* clear_client_id, - EncryptedClientIdentification* encrypted_client_id) { + EncryptedClientIdentification* encrypted_client_id) const { encrypted_client_id->set_provider_id(provider_id_); encrypted_client_id->set_service_certificate_serial_number(serial_number_);