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(
|
CdmResponseType GetProvisioning40RequestInternal(
|
||||||
wvutil::FileSystem* file_system, const std::string& origin,
|
wvutil::FileSystem* file_system, const std::string& origin,
|
||||||
const std::string& spoid, CdmProvisioningRequest* request,
|
const std::string& spoid, CdmProvisioningRequest* request,
|
||||||
std::string* default_url);
|
std::string* default_url, CdmCertificateType cert_type,
|
||||||
|
const std::string& cert_authority);
|
||||||
CdmResponseType FillEncryptedClientId(
|
CdmResponseType FillEncryptedClientId(
|
||||||
const std::string& client_token,
|
const std::string& client_token,
|
||||||
video_widevine::ProvisioningRequest& provisioning_request,
|
video_widevine::ProvisioningRequest& provisioning_request,
|
||||||
@@ -93,7 +94,14 @@ class CertificateProvisioning {
|
|||||||
video_widevine::ProvisioningRequest& provisioning_request,
|
video_widevine::ProvisioningRequest& provisioning_request,
|
||||||
const ServiceCertificate& service_certificate);
|
const ServiceCertificate& service_certificate);
|
||||||
CdmResponseType HandleProvisioning40Response(
|
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(
|
CdmResponseType SetSpoidParameter(
|
||||||
const std::string& origin, const std::string& spoid,
|
const std::string& origin, const std::string& spoid,
|
||||||
@@ -120,6 +128,8 @@ class CertificateProvisioning {
|
|||||||
std::string provisioning_40_wrapped_private_key_;
|
std::string provisioning_40_wrapped_private_key_;
|
||||||
// Key type of the generated key pair in provisioning 4.
|
// Key type of the generated key pair in provisioning 4.
|
||||||
CryptoWrappedKey::Type provisioning_40_key_type_;
|
CryptoWrappedKey::Type provisioning_40_key_type_;
|
||||||
|
// Store the last provisioning request message
|
||||||
|
std::string provisioning_request_message_;
|
||||||
|
|
||||||
CORE_DISALLOW_COPY_AND_ASSIGN(CertificateProvisioning);
|
CORE_DISALLOW_COPY_AND_ASSIGN(CertificateProvisioning);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1310,8 +1310,7 @@ CdmResponseType CdmSession::LoadCastPrivateKey(
|
|||||||
CdmResponseType CdmSession::GenerateRsaSignature(const std::string& message,
|
CdmResponseType CdmSession::GenerateRsaSignature(const std::string& message,
|
||||||
std::string* signature,
|
std::string* signature,
|
||||||
RSA_Padding_Scheme scheme) {
|
RSA_Padding_Scheme scheme) {
|
||||||
return crypto_session_->GenerateRsaSignature(message, signature,
|
return crypto_session_->GenerateRsaSignature(message, signature, scheme);
|
||||||
scheme);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For testing only - takes ownership of pointers
|
// For testing only - takes ownership of pointers
|
||||||
|
|||||||
@@ -209,7 +209,8 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
|||||||
if (crypto_session_->GetPreProvisionTokenType() ==
|
if (crypto_session_->GetPreProvisionTokenType() ==
|
||||||
kClientTokenBootCertChain) {
|
kClientTokenBootCertChain) {
|
||||||
return GetProvisioning40RequestInternal(file_system, origin, spoid, request,
|
return GetProvisioning40RequestInternal(file_system, origin, spoid, request,
|
||||||
default_url);
|
default_url, cert_type,
|
||||||
|
cert_authority);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare device provisioning request.
|
// Prepare device provisioning request.
|
||||||
@@ -235,21 +236,8 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
|||||||
sizeof(nonce));
|
sizeof(nonce));
|
||||||
provisioning_request.set_nonce(encoded_nonce);
|
provisioning_request.set_nonce(encoded_nonce);
|
||||||
|
|
||||||
ProvisioningOptions* options = provisioning_request.mutable_options();
|
status = CertTypeAssign(provisioning_request, cert_type, cert_authority);
|
||||||
switch (cert_type) {
|
if (status != NO_ERROR) return status;
|
||||||
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 = SetSpoidParameter(origin, spoid, &provisioning_request);
|
status = SetSpoidParameter(origin, spoid, &provisioning_request);
|
||||||
if (status != NO_ERROR) return status;
|
if (status != NO_ERROR) return status;
|
||||||
@@ -308,7 +296,8 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
|||||||
CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
||||||
wvutil::FileSystem* file_system, const std::string& origin,
|
wvutil::FileSystem* file_system, const std::string& origin,
|
||||||
const std::string& spoid, CdmProvisioningRequest* request,
|
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()) {
|
if (!crypto_session_->IsOpen()) {
|
||||||
LOGE("Crypto session is not open");
|
LOGE("Crypto session is not open");
|
||||||
return CdmResponseType(PROVISIONING_4_CRYPTO_SESSION_NOT_OPEN);
|
return CdmResponseType(PROVISIONING_4_CRYPTO_SESSION_NOT_OPEN);
|
||||||
@@ -391,6 +380,29 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
|||||||
stored_oem_cert, additional_parameter, provisioning_request,
|
stored_oem_cert, additional_parameter, provisioning_request,
|
||||||
*service_certificate_);
|
*service_certificate_);
|
||||||
if (status != NO_ERROR) return status;
|
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;
|
std::string public_key;
|
||||||
@@ -413,6 +425,7 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
|||||||
|
|
||||||
std::string serialized_message;
|
std::string serialized_message;
|
||||||
provisioning_request.SerializeToString(&serialized_message);
|
provisioning_request.SerializeToString(&serialized_message);
|
||||||
|
provisioning_request_message_ = serialized_message;
|
||||||
|
|
||||||
SignedProvisioningMessage signed_provisioning_msg;
|
SignedProvisioningMessage signed_provisioning_msg;
|
||||||
signed_provisioning_msg.set_message(serialized_message);
|
signed_provisioning_msg.set_message(serialized_message);
|
||||||
@@ -509,8 +522,11 @@ CertificateProvisioning::FillEncryptedClientIdWithAdditionalParameter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CertificateProvisioning::HandleProvisioning40Response(
|
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;
|
ProvisioningResponse provisioning_response;
|
||||||
|
const std::string response_message = signed_response.message();
|
||||||
if (response_message.empty() ||
|
if (response_message.empty() ||
|
||||||
!provisioning_response.ParseFromString(response_message)) {
|
!provisioning_response.ParseFromString(response_message)) {
|
||||||
return CdmResponseType(PROVISIONING_4_RESPONSE_FAILED_TO_PARSE_MESSAGE);
|
return CdmResponseType(PROVISIONING_4_RESPONSE_FAILED_TO_PARSE_MESSAGE);
|
||||||
@@ -538,9 +554,44 @@ CdmResponseType CertificateProvisioning::HandleProvisioning40Response(
|
|||||||
LOGE("No private key was generated");
|
LOGE("No private key was generated");
|
||||||
return CdmResponseType(PROVISIONING_4_NO_PRIVATE_KEY);
|
return CdmResponseType(PROVISIONING_4_NO_PRIVATE_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CryptoWrappedKey private_key(provisioning_40_key_type_,
|
const CryptoWrappedKey private_key(provisioning_40_key_type_,
|
||||||
provisioning_40_wrapped_private_key_);
|
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();
|
const CdmSecurityLevel security_level = crypto_session_->GetSecurityLevel();
|
||||||
CloseSession();
|
CloseSession();
|
||||||
wvutil::FileSystem global_file_system;
|
wvutil::FileSystem global_file_system;
|
||||||
@@ -619,7 +670,8 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
|||||||
|
|
||||||
if (signed_response.provisioning_type() ==
|
if (signed_response.provisioning_type() ==
|
||||||
SignedProvisioningMessage::PROVISIONING_40) {
|
SignedProvisioningMessage::PROVISIONING_40) {
|
||||||
return HandleProvisioning40Response(file_system, signed_response.message());
|
return HandleProvisioning40Response(file_system, signed_response, cert,
|
||||||
|
wrapped_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
@@ -839,4 +891,25 @@ CdmResponseType CertificateProvisioning::CloseSessionOnError(
|
|||||||
return status;
|
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
|
} // namespace wvcdm
|
||||||
|
|||||||
@@ -1030,6 +1030,14 @@ message SignedProvisioningMessage {
|
|||||||
INTEL_SIGMA_210 = 210; // Intel Sigma 2.1.0 protocol.
|
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
|
// Serialized protobuf message for the corresponding protocol and stage of
|
||||||
// the provisioning exchange. ProvisioningRequest or ProvisioningResponse
|
// the provisioning exchange. ProvisioningRequest or ProvisioningResponse
|
||||||
// in the case of Provisioning 2.0, 3.0, 4.0 and ARCPP_PROVISIONING. Required.
|
// 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;
|
optional HashAlgorithmProto hash_algorithm = 7;
|
||||||
// Indicates which version of the protocol is in use.
|
// Indicates which version of the protocol is in use.
|
||||||
optional ProvisioningProtocolVersion protocol_version = 8;
|
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