Add Cdm support for Cast provision 4.0 flow
[ Merge of http://go/wvgerrit/178135 ] Bug: 259455235 Test: CorePIGTest.CastReceiverProvisioning* Test: com.google.android.wvts Change-Id: I8d546a73a64a71a4d61225d9c6d14d893decce22 (cherry picked from commit 494da3dddf0f47e516e6fc1a73e19b091e6c2abd)
This commit is contained in:
@@ -82,7 +82,8 @@ class CertificateProvisioning {
|
||||
CdmResponseType GetProvisioning40RequestInternal(
|
||||
wvutil::FileSystem* file_system, const std::string& origin,
|
||||
const std::string& spoid, CdmProvisioningRequest* request,
|
||||
std::string* default_url);
|
||||
std::string* default_url, CdmCertificateType cert_type,
|
||||
const std::string& cert_authority);
|
||||
CdmResponseType FillEncryptedClientId(
|
||||
const std::string& client_token,
|
||||
video_widevine::ProvisioningRequest& provisioning_request,
|
||||
@@ -93,7 +94,14 @@ class CertificateProvisioning {
|
||||
video_widevine::ProvisioningRequest& provisioning_request,
|
||||
const ServiceCertificate& service_certificate);
|
||||
CdmResponseType HandleProvisioning40Response(
|
||||
wvutil::FileSystem* file_system, const std::string& response_message);
|
||||
wvutil::FileSystem* file_system,
|
||||
const video_widevine::SignedProvisioningMessage& signed_message,
|
||||
std::string* cert, std::string* wrapped_key);
|
||||
// Assign the cert type for provisioning request
|
||||
// Required by Cast cert provisioning flow
|
||||
CdmResponseType CertTypeAssign(
|
||||
video_widevine::ProvisioningRequest& provisioning_request,
|
||||
CdmCertificateType cert_type, const std::string& cert_authority);
|
||||
|
||||
CdmResponseType SetSpoidParameter(
|
||||
const std::string& origin, const std::string& spoid,
|
||||
@@ -120,6 +128,8 @@ class CertificateProvisioning {
|
||||
std::string provisioning_40_wrapped_private_key_;
|
||||
// Key type of the generated key pair in provisioning 4.
|
||||
CryptoWrappedKey::Type provisioning_40_key_type_;
|
||||
// Store the last provisioning request message
|
||||
std::string provisioning_request_message_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(CertificateProvisioning);
|
||||
};
|
||||
|
||||
@@ -1310,8 +1310,7 @@ CdmResponseType CdmSession::LoadCastPrivateKey(
|
||||
CdmResponseType CdmSession::GenerateRsaSignature(const std::string& message,
|
||||
std::string* signature,
|
||||
RSA_Padding_Scheme scheme) {
|
||||
return crypto_session_->GenerateRsaSignature(message, signature,
|
||||
scheme);
|
||||
return crypto_session_->GenerateRsaSignature(message, signature, scheme);
|
||||
}
|
||||
|
||||
// For testing only - takes ownership of pointers
|
||||
|
||||
@@ -209,7 +209,8 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
||||
if (crypto_session_->GetPreProvisionTokenType() ==
|
||||
kClientTokenBootCertChain) {
|
||||
return GetProvisioning40RequestInternal(file_system, origin, spoid, request,
|
||||
default_url);
|
||||
default_url, cert_type,
|
||||
cert_authority);
|
||||
}
|
||||
|
||||
// Prepare device provisioning request.
|
||||
@@ -235,21 +236,8 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
||||
sizeof(nonce));
|
||||
provisioning_request.set_nonce(encoded_nonce);
|
||||
|
||||
ProvisioningOptions* options = provisioning_request.mutable_options();
|
||||
switch (cert_type) {
|
||||
case kCertificateWidevine:
|
||||
options->set_certificate_type(ProvisioningOptions::WIDEVINE_DRM);
|
||||
break;
|
||||
case kCertificateX509:
|
||||
options->set_certificate_type(ProvisioningOptions::X509);
|
||||
break;
|
||||
default:
|
||||
LOGE("Unknown certificate type: %d", static_cast<int>(cert_type));
|
||||
return CdmResponseType(CERT_PROVISIONING_INVALID_CERT_TYPE);
|
||||
}
|
||||
|
||||
cert_type_ = cert_type;
|
||||
options->set_certificate_authority(cert_authority);
|
||||
status = CertTypeAssign(provisioning_request, cert_type, cert_authority);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
status = SetSpoidParameter(origin, spoid, &provisioning_request);
|
||||
if (status != NO_ERROR) return status;
|
||||
@@ -308,7 +296,8 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
||||
CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
||||
wvutil::FileSystem* file_system, const std::string& origin,
|
||||
const std::string& spoid, CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
std::string* default_url, CdmCertificateType cert_type,
|
||||
const std::string& cert_authority) {
|
||||
if (!crypto_session_->IsOpen()) {
|
||||
LOGE("Crypto session is not open");
|
||||
return CdmResponseType(PROVISIONING_4_CRYPTO_SESSION_NOT_OPEN);
|
||||
@@ -391,6 +380,29 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
||||
stored_oem_cert, additional_parameter, provisioning_request,
|
||||
*service_certificate_);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
// If cert type is X509, provisioning Cast cert.
|
||||
if (cert_type == kCertificateX509) {
|
||||
uint32_t nonce;
|
||||
status = crypto_session_->GenerateNonce(&nonce);
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to generate a nonce: status = %d",
|
||||
static_cast<int>(status));
|
||||
return status == NONCE_GENERATION_ERROR
|
||||
? CdmResponseType(CERT_PROVISIONING_NONCE_GENERATION_ERROR)
|
||||
: status;
|
||||
}
|
||||
|
||||
// The provisioning server does not convert the nonce to uint32_t, it just
|
||||
// passes the binary data to the response message.
|
||||
const std::string encoded_nonce(reinterpret_cast<char*>(&nonce),
|
||||
sizeof(nonce));
|
||||
provisioning_request.set_nonce(encoded_nonce);
|
||||
|
||||
status = CertTypeAssign(provisioning_request, cert_type, cert_authority);
|
||||
if (status != NO_ERROR) return status;
|
||||
}
|
||||
}
|
||||
|
||||
std::string public_key;
|
||||
@@ -413,6 +425,7 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
||||
|
||||
std::string serialized_message;
|
||||
provisioning_request.SerializeToString(&serialized_message);
|
||||
provisioning_request_message_ = serialized_message;
|
||||
|
||||
SignedProvisioningMessage signed_provisioning_msg;
|
||||
signed_provisioning_msg.set_message(serialized_message);
|
||||
@@ -509,8 +522,11 @@ CertificateProvisioning::FillEncryptedClientIdWithAdditionalParameter(
|
||||
}
|
||||
|
||||
CdmResponseType CertificateProvisioning::HandleProvisioning40Response(
|
||||
wvutil::FileSystem* file_system, const std::string& response_message) {
|
||||
wvutil::FileSystem* file_system,
|
||||
const SignedProvisioningMessage& signed_response, std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
ProvisioningResponse provisioning_response;
|
||||
const std::string response_message = signed_response.message();
|
||||
if (response_message.empty() ||
|
||||
!provisioning_response.ParseFromString(response_message)) {
|
||||
return CdmResponseType(PROVISIONING_4_RESPONSE_FAILED_TO_PARSE_MESSAGE);
|
||||
@@ -538,9 +554,44 @@ CdmResponseType CertificateProvisioning::HandleProvisioning40Response(
|
||||
LOGE("No private key was generated");
|
||||
return CdmResponseType(PROVISIONING_4_NO_PRIVATE_KEY);
|
||||
}
|
||||
|
||||
const CryptoWrappedKey private_key(provisioning_40_key_type_,
|
||||
provisioning_40_wrapped_private_key_);
|
||||
|
||||
if (cert_type_ == kCertificateX509) {
|
||||
// Load csr private key to decrypt session key
|
||||
auto status = crypto_session_->LoadCertificatePrivateKey(private_key);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to load x509 certificate.");
|
||||
return status;
|
||||
}
|
||||
|
||||
status = crypto_session_->GenerateDerivedKeys(
|
||||
provisioning_request_message_, signed_response.session_key());
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to generate derived keys.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Get wrapped private key for cast cert
|
||||
CryptoWrappedKey cast_cert_private_key;
|
||||
const std::string signature = signed_response.signature();
|
||||
const std::string core_message = signed_response.oemcrypto_core_message();
|
||||
status = crypto_session_->LoadProvisioning(response_message, core_message,
|
||||
signature,
|
||||
&cast_cert_private_key.key());
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to generate wrapped key for cast cert.");
|
||||
return status;
|
||||
}
|
||||
|
||||
CloseSession();
|
||||
|
||||
*cert = device_certificate;
|
||||
*wrapped_key = cast_cert_private_key.key();
|
||||
return CdmResponseType(NO_ERROR);
|
||||
}
|
||||
|
||||
const CdmSecurityLevel security_level = crypto_session_->GetSecurityLevel();
|
||||
CloseSession();
|
||||
wvutil::FileSystem global_file_system;
|
||||
@@ -619,7 +670,8 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
|
||||
if (signed_response.provisioning_type() ==
|
||||
SignedProvisioningMessage::PROVISIONING_40) {
|
||||
return HandleProvisioning40Response(file_system, signed_response.message());
|
||||
return HandleProvisioning40Response(file_system, signed_response, cert,
|
||||
wrapped_key);
|
||||
}
|
||||
|
||||
bool error = false;
|
||||
@@ -839,4 +891,25 @@ CdmResponseType CertificateProvisioning::CloseSessionOnError(
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CertificateProvisioning::CertTypeAssign(
|
||||
video_widevine::ProvisioningRequest& provisioning_request,
|
||||
CdmCertificateType cert_type, const std::string& cert_authority) {
|
||||
ProvisioningOptions* options = provisioning_request.mutable_options();
|
||||
switch (cert_type) {
|
||||
case kCertificateWidevine:
|
||||
options->set_certificate_type(ProvisioningOptions::WIDEVINE_DRM);
|
||||
break;
|
||||
case kCertificateX509:
|
||||
options->set_certificate_type(ProvisioningOptions::X509);
|
||||
break;
|
||||
default:
|
||||
LOGE("Unknown certificate type: %d", static_cast<int>(cert_type));
|
||||
return CdmResponseType(CERT_PROVISIONING_INVALID_CERT_TYPE);
|
||||
}
|
||||
|
||||
cert_type_ = cert_type;
|
||||
options->set_certificate_authority(cert_authority);
|
||||
return CdmResponseType(NO_ERROR);
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -1030,6 +1030,14 @@ message SignedProvisioningMessage {
|
||||
INTEL_SIGMA_210 = 210; // Intel Sigma 2.1.0 protocol.
|
||||
}
|
||||
|
||||
// Used by provisioning 4.0 to deliver cast certificates in which the server
|
||||
// delivers a new rsa private key that must be encrypted and signed.
|
||||
enum SessionKeyType {
|
||||
UNDEFINED = 0;
|
||||
WRAPPED_AES_KEY = 1;
|
||||
EPHEMERAL_ECC_PUBLIC_KEY = 2;
|
||||
}
|
||||
|
||||
// Serialized protobuf message for the corresponding protocol and stage of
|
||||
// the provisioning exchange. ProvisioningRequest or ProvisioningResponse
|
||||
// in the case of Provisioning 2.0, 3.0, 4.0 and ARCPP_PROVISIONING. Required.
|
||||
@@ -1056,6 +1064,21 @@ message SignedProvisioningMessage {
|
||||
optional HashAlgorithmProto hash_algorithm = 7;
|
||||
// Indicates which version of the protocol is in use.
|
||||
optional ProvisioningProtocolVersion protocol_version = 8;
|
||||
// If populated, the contents of this field will be signaled by the
|
||||
// |session_key_type| type. If the |session_key_type| is WRAPPED_AES_KEY the
|
||||
// key is the bytes of an encrypted AES key. If the |session_key_type| is
|
||||
// EPHEMERAL_ECC_PUBLIC_KEY the field contains the bytes of an RFC5208 ASN1
|
||||
// serialized ECC public key.
|
||||
// This field is only required to be set in a success response to
|
||||
// Provisioning 4.0 X509 (cast) certificate request.
|
||||
optional bytes session_key = 9;
|
||||
// Optional field that contains the algorithm type used to generate the
|
||||
// session_key and signature in a ProvisioningResponse message. This value is
|
||||
// populated in a success response to a request for a X509 (cast) certificate.
|
||||
// The value used depends on the key type of the PublicKeyToCertify contained
|
||||
// in Provisioning 4.0 ProvisioningMessage.
|
||||
// This value must be populated if session_key is populated.
|
||||
optional SessionKeyType session_key_type = 10;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user