Merge latest oemcrypto-v17 change

No-Typo-Check: Not related to this change.

Bug: 161477208
Change-Id: I99e4780f6855b7045aa0cd5a49c13d2d0d51ed64
This commit is contained in:
Kyle Zhang
2022-01-21 05:58:12 +00:00
committed by Fred Gylys-Colwell
parent c924960962
commit 642965c678
176 changed files with 301013 additions and 296749 deletions

View File

@@ -28,7 +28,7 @@ const std::string kProvisioningServerUrl =
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
// NOTE: Provider ID = widevine.com
const std::string kCpProductionServiceCertificate = wvcdm::a2bs_hex(
const std::string kCpProductionServiceCertificate = wvutil::a2bs_hex(
"0ab9020803121051434fe2a44c763bcc2c826a2d6ef9a718f7d793d005228e02"
"3082010a02820101009e27088659dbd9126bc6ed594caf652b0eaab82abb9862"
"ada1ee6d2cb5247e94b28973fef5a3e11b57d0b0872c930f351b5694354a8c77"
@@ -51,6 +51,30 @@ const std::string kCpProductionServiceCertificate = wvcdm::a2bs_hex(
"26e0c050f3fd3ebe68cef9903ef6405b25fc6e31f93559fcff05657662b3653a"
"8598ed5751b38694419242a875d9e00d5a5832933024b934859ec8be78adccbb"
"1ec7127ae9afeef9c5cd2e15bd3048e8ce652f7d8c5d595a0323238c598a28");
// Retrieves |stored_oem_cert| from |file_handle|, and load the OEM private key
// to |crypto_session|. Returns true if all operations are successful.
bool RetrieveOemCertificateAndLoadPrivateKey(CryptoSession& crypto_session,
DeviceFiles& file_handle,
std::string& stored_oem_cert) {
stored_oem_cert.clear();
CryptoWrappedKey wrapped_private_key;
if (file_handle.RetrieveOemCertificate(&stored_oem_cert,
&wrapped_private_key) !=
DeviceFiles::kCertificateValid) {
LOGE("An invalid stored OEM certificated is retrieved");
stored_oem_cert.clear();
return false;
}
if (crypto_session.LoadOemCertificatePrivateKey(wrapped_private_key) !=
NO_ERROR) {
LOGE("Can not load the OEM private key");
stored_oem_cert.clear();
return false;
}
return true;
}
} // namespace
// Protobuf generated classes.
using video_widevine::ClientIdentification_ClientCapabilities;
@@ -60,6 +84,7 @@ using video_widevine::EncryptedClientIdentification;
using video_widevine::ProvisioningOptions;
using video_widevine::ProvisioningRequest;
using video_widevine::ProvisioningResponse;
using video_widevine::PublicKeyToCertify;
using video_widevine::SignedDrmCertificate;
using video_widevine::SignedProvisioningMessage;
using video_widevine::
@@ -130,10 +155,14 @@ CdmResponseType CertificateProvisioning::SetSpoidParameter(
*/
SignedProvisioningMessage::ProvisioningType
CertificateProvisioning::GetProvisioningType() {
if (crypto_session_->GetPreProvisionTokenType() == kClientTokenOemCert)
return SignedProvisioningMessage::PROVISIONING_30;
else
return SignedProvisioningMessage::PROVISIONING_20;
switch (crypto_session_->GetPreProvisionTokenType()) {
case kClientTokenBootCertChain:
return SignedProvisioningMessage::PROVISIONING_40;
case kClientTokenOemCert:
return SignedProvisioningMessage::PROVISIONING_30;
default:
return SignedProvisioningMessage::PROVISIONING_20;
}
}
/*
@@ -144,20 +173,20 @@ CertificateProvisioning::GetProvisioningType() {
* Returns NO_ERROR for success and CERT_PROVISIONING_REQUEST_ERROR_? if fails.
*/
CdmResponseType CertificateProvisioning::GetProvisioningRequest(
SecurityLevel requested_security_level, CdmCertificateType cert_type,
const std::string& cert_authority, const std::string& origin,
const std::string& spoid, CdmProvisioningRequest* request,
std::string* default_url) {
wvutil::FileSystem* file_system, SecurityLevel requested_security_level,
CdmCertificateType cert_type, const std::string& cert_authority,
const std::string& origin, const std::string& spoid,
CdmProvisioningRequest* request, std::string* default_url) {
return CloseSessionOnError(GetProvisioningRequestInternal(
requested_security_level, cert_type, cert_authority, origin, spoid,
request, default_url));
file_system, requested_security_level, cert_type, cert_authority, origin,
spoid, request, default_url));
}
CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
SecurityLevel requested_security_level, CdmCertificateType cert_type,
const std::string& cert_authority, const std::string& origin,
const std::string& spoid, CdmProvisioningRequest* request,
std::string* default_url) {
wvutil::FileSystem* file_system, SecurityLevel requested_security_level,
CdmCertificateType cert_type, const std::string& cert_authority,
const std::string& origin, const std::string& spoid,
CdmProvisioningRequest* request, std::string* default_url) {
if (!request || !default_url) {
LOGE("Output parameter |%s| is not provided",
request ? "default_url" : "request");
@@ -174,30 +203,17 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
return status;
}
if (crypto_session_->GetPreProvisionTokenType() ==
kClientTokenBootCertChain) {
return GetProvisioning40RequestInternal(file_system, request);
}
// Prepare device provisioning request.
ProvisioningRequest provisioning_request;
wvcdm::ClientIdentification id;
status = id.InitForProvisioning(crypto_session_.get());
status = FillEncryptedClientId(/*client_token=*/"", provisioning_request);
if (status != NO_ERROR) return status;
video_widevine::ClientIdentification client_id;
CdmAppParameterMap app_parameter;
status = id.Prepare(app_parameter, kEmptyString, &client_id);
if (status != NO_ERROR) return status;
if (!service_certificate_->has_certificate()) {
LOGE("Service certificate not staged");
return CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE;
}
// Encrypt client identification
EncryptedClientIdentification* encrypted_client_id =
provisioning_request.mutable_encrypted_client_id();
status = service_certificate_->EncryptClientId(
crypto_session_.get(), &client_id, encrypted_client_id);
uint32_t nonce;
status = crypto_session_->GenerateNonce(&nonce);
@@ -272,13 +288,184 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
if (!wvcdm::Properties::provisioning_messages_are_binary()) {
// Return request as web-safe base64 string
*request = Base64SafeEncodeNoPad(serialized_request);
*request = wvutil::Base64SafeEncodeNoPad(serialized_request);
} else {
*request = std::move(serialized_request);
}
return NO_ERROR;
}
CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
wvutil::FileSystem* file_system, CdmProvisioningRequest* request) {
if (!crypto_session_->IsOpen()) {
LOGE("Crypto session is not open");
return PROVISIONING_4_CRYPTO_SESSION_NOT_OPEN;
}
if (file_system == nullptr) {
LOGE("file_system is nullptr but is required in provisioning 4");
return PROVISIONING_4_FILE_SYSTEM_IS_NULL;
}
const CdmSecurityLevel security_level = crypto_session_->GetSecurityLevel();
DeviceFiles file_handle(file_system);
if (!file_handle.Init(security_level)) {
LOGE("Failed to initialize DeviceFiles");
return PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES;
}
ProvisioningRequest provisioning_request;
// Determine the current stage by checking if OEM cert exists.
std::string stored_oem_cert;
if (file_handle.HasOemCertificate()) {
// This is second stage requesting for DRM cert. We try to use the stored
// OEM cert. In case of error, we just fall back to the first stage
// provisioning (request for an OEM cert).
if (!RetrieveOemCertificateAndLoadPrivateKey(*crypto_session_, file_handle,
stored_oem_cert)) {
stored_oem_cert.clear();
LOGD("Deleting the stored OEM certificate due to unsuccessful read");
if (!file_handle.RemoveOemCertificate()) {
// This should not happen.
LOGE("Failed to delete the OEM certificate certificate");
}
}
}
// 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();
provisioning_40_key_type_ = CryptoWrappedKey::kUninitialized;
status = crypto_session_->GenerateCertificateKeyPair(
&public_key, &public_key_signature, &provisioning_40_wrapped_private_key_,
&provisioning_40_key_type_);
if (status != NO_ERROR) return status;
PublicKeyToCertify* key_to_certify =
provisioning_request.mutable_certificate_public_key();
key_to_certify->set_public_key(public_key);
key_to_certify->set_signature(public_key_signature);
key_to_certify->set_key_type(provisioning_40_key_type_ ==
CryptoWrappedKey::kRsa
? PublicKeyToCertify::RSA
: PublicKeyToCertify::ECC);
// In provisioning 4, the message is not signed.
SignedProvisioningMessage signed_provisioning_msg;
provisioning_request.SerializeToString(
signed_provisioning_msg.mutable_message());
signed_provisioning_msg.set_provisioning_type(GetProvisioningType());
signed_provisioning_msg.set_protocol_version(
SignedProvisioningMessage_ProvisioningProtocolVersion_VERSION_1_1);
std::string serialized_request;
signed_provisioning_msg.SerializeToString(&serialized_request);
if (!wvcdm::Properties::provisioning_messages_are_binary()) {
// Return request as web-safe base64 string
*request = wvutil::Base64SafeEncodeNoPad(serialized_request);
} else {
*request = std::move(serialized_request);
}
return NO_ERROR;
}
CdmResponseType CertificateProvisioning::FillEncryptedClientId(
const std::string& client_token,
ProvisioningRequest& provisioning_request) {
if (!crypto_session_->IsOpen()) {
return UNKNOWN_ERROR;
}
wvcdm::ClientIdentification id;
CdmResponseType status =
id.InitForProvisioningRequest(client_token, crypto_session_.get());
if (status != NO_ERROR) return status;
video_widevine::ClientIdentification client_id;
CdmAppParameterMap app_parameter;
status = id.Prepare(app_parameter, kEmptyString, &client_id);
if (status != NO_ERROR) return status;
if (!service_certificate_->has_certificate()) {
LOGE("Service certificate not staged");
return CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE;
}
// Encrypt client identification
return service_certificate_->EncryptClientId(
crypto_session_.get(), &client_id,
provisioning_request.mutable_encrypted_client_id());
}
CdmResponseType CertificateProvisioning::HandleProvisioning40Response(
wvutil::FileSystem* file_system, const std::string& response_message) {
ProvisioningResponse provisioning_response;
if (response_message.empty() ||
!provisioning_response.ParseFromString(response_message)) {
return PROVISIONING_4_RESPONSE_FAILED_TO_PARSE_MESSAGE;
}
if (provisioning_response.has_status() &&
provisioning_response.status() != ProvisioningResponse::NO_ERROR) {
LOGE("Provisioning Response status: %d", provisioning_response.status());
switch (provisioning_response.status()) {
case ProvisioningResponse::REVOKED_DEVICE_CREDENTIALS:
case ProvisioningResponse::REVOKED_DEVICE_SERIES:
return DEVICE_REVOKED;
default:
return PROVISIONING_4_RESPONSE_HAS_ERROR_STATUS;
}
}
const std::string& device_certificate =
provisioning_response.device_certificate();
if (device_certificate.empty()) {
LOGE("Provisioning response has no certificate");
return PROVISIONING_4_RESPONSE_HAS_NO_CERTIFICATE;
}
if (provisioning_40_wrapped_private_key_.empty()) {
LOGE("No private key was generated");
return PROVISIONING_4_NO_PRIVATE_KEY;
}
const CryptoWrappedKey private_key(provisioning_40_key_type_,
provisioning_40_wrapped_private_key_);
const CdmSecurityLevel security_level = crypto_session_->GetSecurityLevel();
CloseSession();
DeviceFiles file_handle(file_system);
if (!file_handle.Init(security_level)) {
LOGE("Failed to initialize DeviceFiles");
return PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_2;
}
// Check the stage of the provisioning by checking if an OEM cert is already
// stored in the file system.
if (!file_handle.HasOemCertificate()) {
// No OEM cert already stored => the response is expected to be an OEM cert.
if (!file_handle.StoreOemCertificate(device_certificate, private_key)) {
LOGE("Failed to store provisioning 4 OEM certificate");
return PROVISIONING_4_FAILED_TO_STORE_OEM_CERTIFICATE;
}
} else {
// The response is assumed to be an DRM cert.
if (!file_handle.StoreCertificate(device_certificate, private_key)) {
LOGE("Failed to store provisioning 4 DRM certificate");
return PROVISIONING_4_FAILED_TO_STORE_DRM_CERTIFICATE;
}
}
return NO_ERROR;
}
/*
* The response message consists of a device certificate and the device RSA key.
* The device RSA key is stored in the T.E.E. The device certificate is stored
@@ -287,8 +474,9 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
* Returns NO_ERROR for success and CERT_PROVISIONING_RESPONSE_ERROR_? if fails.
*/
CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
FileSystem* file_system, const CdmProvisioningResponse& response_message,
std::string* cert, std::string* wrapped_key) {
wvutil::FileSystem* file_system,
const CdmProvisioningResponse& response_message, std::string* cert,
std::string* wrapped_key) {
if (response_message.empty()) {
LOGE("Provisioning response message is empty");
return CERT_PROVISIONING_RESPONSE_ERROR_1;
@@ -317,6 +505,11 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
return CERT_PROVISIONING_RESPONSE_ERROR_2;
}
if (signed_response.provisioning_type() ==
SignedProvisioningMessage::PROVISIONING_40) {
return HandleProvisioning40Response(file_system, signed_response.message());
}
bool error = false;
if (!signed_response.has_signature()) {
LOGE("Signed response does not have signature");
@@ -491,7 +684,7 @@ bool CertificateProvisioning::ExtractAndDecodeSignedMessage(
// Decode the base64-encoded message.
const std::vector<uint8_t> decoded_message =
wvcdm::Base64SafeDecode(message_string);
wvutil::Base64SafeDecode(message_string);
result->assign(decoded_message.begin(), decoded_message.end());
return true;
}