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
This commit is contained in:
@@ -86,7 +86,8 @@ class CertificateProvisioning {
|
|||||||
std::string* default_url);
|
std::string* default_url);
|
||||||
CdmResponseType FillEncryptedClientId(
|
CdmResponseType FillEncryptedClientId(
|
||||||
const std::string& client_token,
|
const std::string& client_token,
|
||||||
video_widevine::ProvisioningRequest& provisioning_request);
|
video_widevine::ProvisioningRequest& provisioning_request,
|
||||||
|
const ServiceCertificate& service_certificate);
|
||||||
CdmResponseType HandleProvisioning40Response(
|
CdmResponseType HandleProvisioning40Response(
|
||||||
wvutil::FileSystem* file_system, const std::string& response_message);
|
wvutil::FileSystem* file_system, const std::string& response_message);
|
||||||
|
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ class ServiceCertificate {
|
|||||||
const std::string& provider_id() const { return provider_id_; }
|
const std::string& provider_id() const { return provider_id_; }
|
||||||
|
|
||||||
// Verify the signature for a message.
|
// Verify the signature for a message.
|
||||||
virtual CdmResponseType VerifySignedMessage(const std::string& message,
|
virtual CdmResponseType VerifySignedMessage(
|
||||||
const std::string& signature);
|
const std::string& message, const std::string& signature) const;
|
||||||
|
|
||||||
// Encrypt the ClientIdentification message for a provisioning or
|
// Encrypt the ClientIdentification message for a provisioning or
|
||||||
// licensing request. Encryption is performed using the current
|
// licensing request. Encryption is performed using the current
|
||||||
@@ -50,7 +50,7 @@ class ServiceCertificate {
|
|||||||
virtual CdmResponseType EncryptClientId(
|
virtual CdmResponseType EncryptClientId(
|
||||||
CryptoSession* crypto_session,
|
CryptoSession* crypto_session,
|
||||||
const video_widevine::ClientIdentification* clear_client_id,
|
const video_widevine::ClientIdentification* clear_client_id,
|
||||||
video_widevine::EncryptedClientIdentification* encrypted_client_id);
|
video_widevine::EncryptedClientIdentification* encrypted_client_id) const;
|
||||||
|
|
||||||
// Helper methods
|
// Helper methods
|
||||||
static bool GetRequest(CdmKeyMessage* request);
|
static bool GetRequest(CdmKeyMessage* request);
|
||||||
@@ -63,7 +63,7 @@ class ServiceCertificate {
|
|||||||
// string to contain the decrypted data on return, and may not be null.
|
// string to contain the decrypted data on return, and may not be null.
|
||||||
// returns NO_ERROR if successful or an appropriate error code otherwise.
|
// returns NO_ERROR if successful or an appropriate error code otherwise.
|
||||||
virtual CdmResponseType EncryptRsaOaep(const std::string& plaintext,
|
virtual CdmResponseType EncryptRsaOaep(const std::string& plaintext,
|
||||||
std::string* ciphertext);
|
std::string* ciphertext) const;
|
||||||
|
|
||||||
// Track whether object holds valid certificate
|
// Track whether object holds valid certificate
|
||||||
bool has_certificate_;
|
bool has_certificate_;
|
||||||
|
|||||||
@@ -218,7 +218,8 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
|||||||
// Prepare device provisioning request.
|
// Prepare device provisioning request.
|
||||||
ProvisioningRequest 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;
|
if (status != NO_ERROR) return status;
|
||||||
|
|
||||||
uint32_t nonce;
|
uint32_t nonce;
|
||||||
@@ -339,24 +340,33 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CdmResponseType status = NO_ERROR;
|
||||||
if (stored_oem_cert.empty()) {
|
if (stored_oem_cert.empty()) {
|
||||||
// This is the first stage provisioning.
|
// This is the first stage provisioning.
|
||||||
default_url->assign(kProvisioningServerUrl +
|
default_url->assign(kProvisioningServerUrl +
|
||||||
kProv40FirstStageServerUrlSuffix);
|
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 {
|
} else {
|
||||||
// This is the second stage provisioning.
|
// This is the second stage provisioning.
|
||||||
default_url->assign(kProvisioningServerUrl);
|
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;
|
||||||
std::string public_key_signature;
|
std::string public_key_signature;
|
||||||
provisioning_40_wrapped_private_key_.clear();
|
provisioning_40_wrapped_private_key_.clear();
|
||||||
@@ -396,8 +406,8 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CertificateProvisioning::FillEncryptedClientId(
|
CdmResponseType CertificateProvisioning::FillEncryptedClientId(
|
||||||
const std::string& client_token,
|
const std::string& client_token, ProvisioningRequest& provisioning_request,
|
||||||
ProvisioningRequest& provisioning_request) {
|
const ServiceCertificate& service_certificate) {
|
||||||
if (!crypto_session_->IsOpen()) {
|
if (!crypto_session_->IsOpen()) {
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
@@ -412,13 +422,13 @@ CdmResponseType CertificateProvisioning::FillEncryptedClientId(
|
|||||||
status = id.Prepare(app_parameter, kEmptyString, &client_id);
|
status = id.Prepare(app_parameter, kEmptyString, &client_id);
|
||||||
if (status != NO_ERROR) return status;
|
if (status != NO_ERROR) return status;
|
||||||
|
|
||||||
if (!service_certificate_->has_certificate()) {
|
if (!service_certificate.has_certificate()) {
|
||||||
LOGE("Service certificate not staged");
|
LOGE("Service certificate not staged");
|
||||||
return CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE;
|
return CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt client identification
|
// Encrypt client identification
|
||||||
return service_certificate_->EncryptClientId(
|
return service_certificate.EncryptClientId(
|
||||||
crypto_session_.get(), &client_id,
|
crypto_session_.get(), &client_id,
|
||||||
provisioning_request.mutable_encrypted_client_id());
|
provisioning_request.mutable_encrypted_client_id());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ CdmResponseType ServiceCertificate::Init(const std::string& certificate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType ServiceCertificate::VerifySignedMessage(
|
CdmResponseType ServiceCertificate::VerifySignedMessage(
|
||||||
const std::string& message, const std::string& signature) {
|
const std::string& message, const std::string& signature) const {
|
||||||
if (!public_key_) {
|
if (!public_key_) {
|
||||||
LOGE("Service certificate not set");
|
LOGE("Service certificate not set");
|
||||||
return DEVICE_CERTIFICATE_ERROR_4;
|
return DEVICE_CERTIFICATE_ERROR_4;
|
||||||
@@ -218,8 +218,8 @@ CdmResponseType ServiceCertificate::VerifySignedMessage(
|
|||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType ServiceCertificate::EncryptRsaOaep(const std::string& plaintext,
|
CdmResponseType ServiceCertificate::EncryptRsaOaep(
|
||||||
std::string* ciphertext) {
|
const std::string& plaintext, std::string* ciphertext) const {
|
||||||
if (!public_key_) {
|
if (!public_key_) {
|
||||||
LOGE("Service certificate not set");
|
LOGE("Service certificate not set");
|
||||||
return DEVICE_CERTIFICATE_ERROR_4;
|
return DEVICE_CERTIFICATE_ERROR_4;
|
||||||
@@ -233,7 +233,7 @@ CdmResponseType ServiceCertificate::EncryptRsaOaep(const std::string& plaintext,
|
|||||||
|
|
||||||
CdmResponseType ServiceCertificate::EncryptClientId(
|
CdmResponseType ServiceCertificate::EncryptClientId(
|
||||||
CryptoSession* crypto_session, const ClientIdentification* clear_client_id,
|
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_provider_id(provider_id_);
|
||||||
encrypted_client_id->set_service_certificate_serial_number(serial_number_);
|
encrypted_client_id->set_service_certificate_serial_number(serial_number_);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user