Support CAST V2 authentication
bug: 12702350 Squashed commit of these CLs from the widevine cdm repo: Cast V2 cdm support https://widevine-internal-review.googlesource.com/#/c/9190/ Add CASTv2 Support to DrmPlugin https://widevine-internal-review.googlesource.com/#/c/9228/ Test for CastV2 authentication APIs https://widevine-internal-review.googlesource.com/9550 Change-Id: I6d66bc1bbd653db5542c68687b30b441dd20617f
This commit is contained in:
@@ -80,11 +80,15 @@ class CdmEngine : public TimerHandler {
|
||||
|
||||
// Provisioning related methods
|
||||
virtual CdmResponseType GetProvisioningRequest(
|
||||
CdmCertificateType cert_type,
|
||||
const std::string& cert_authority,
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url);
|
||||
|
||||
virtual CdmResponseType HandleProvisioningResponse(
|
||||
CdmProvisioningResponse& response);
|
||||
CdmProvisioningResponse& response,
|
||||
std::string* cert,
|
||||
std::string* wrapped_key);
|
||||
|
||||
// Secure stop related methods
|
||||
virtual CdmResponseType GetSecureStops(CdmSecureStops* secure_stops);
|
||||
|
||||
@@ -13,14 +13,18 @@ class CdmSession;
|
||||
|
||||
class CertificateProvisioning {
|
||||
public:
|
||||
CertificateProvisioning() {};
|
||||
CertificateProvisioning() : cert_type_(kCertificateWidevine) {};
|
||||
~CertificateProvisioning() {};
|
||||
|
||||
// Provisioning related methods
|
||||
CdmResponseType GetProvisioningRequest(SecurityLevel requested_security_level,
|
||||
CdmCertificateType cert_type,
|
||||
const std::string& cert_authority,
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url);
|
||||
CdmResponseType HandleProvisioningResponse(CdmProvisioningResponse& response);
|
||||
CdmResponseType HandleProvisioningResponse(CdmProvisioningResponse& response,
|
||||
std::string* cert,
|
||||
std::string* wrapped_key);
|
||||
|
||||
private:
|
||||
void ComposeJsonRequestAsQueryString(const std::string& message,
|
||||
@@ -30,6 +34,7 @@ class CertificateProvisioning {
|
||||
const std::string& end_substr,
|
||||
std::string* result);
|
||||
CryptoSession crypto_session_;
|
||||
CdmCertificateType cert_type_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(CertificateProvisioning);
|
||||
};
|
||||
|
||||
@@ -64,6 +64,11 @@ enum CdmSecurityLevel {
|
||||
kSecurityLevelUnknown
|
||||
};
|
||||
|
||||
enum CdmCertificateType {
|
||||
kCertificateWidevine,
|
||||
kCertificateX509,
|
||||
};
|
||||
|
||||
struct CdmDecryptionParameters {
|
||||
bool is_encrypted;
|
||||
bool is_secure;
|
||||
|
||||
@@ -446,6 +446,8 @@ CdmResponseType CdmEngine::QueryKeyControlInfo(
|
||||
* Returns NO_ERROR for success and UNKNOWN_ERROR if fails.
|
||||
*/
|
||||
CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
CdmCertificateType cert_type,
|
||||
const std::string& cert_authority,
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
if (!request || !default_url) {
|
||||
@@ -454,6 +456,8 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
}
|
||||
return cert_provisioning_.GetProvisioningRequest(
|
||||
cert_provisioning_requested_security_level_,
|
||||
cert_type,
|
||||
cert_authority,
|
||||
request,
|
||||
default_url);
|
||||
}
|
||||
@@ -466,12 +470,25 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
* Returns NO_ERROR for success and UNKNOWN_ERROR if fails.
|
||||
*/
|
||||
CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
CdmProvisioningResponse& response) {
|
||||
CdmProvisioningResponse& response,
|
||||
std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
if (response.empty()) {
|
||||
LOGE("CdmEngine::HandleProvisioningResponse: Empty provisioning response.");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return cert_provisioning_.HandleProvisioningResponse(response);
|
||||
if (NULL == cert) {
|
||||
LOGE("CdmEngine::HandleProvisioningResponse: invalid certificate "
|
||||
"destination");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
if (NULL == wrapped_key) {
|
||||
LOGE("CdmEngine::HandleProvisioningResponse: invalid wrapped key "
|
||||
"destination");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return cert_provisioning_.HandleProvisioningResponse(response, cert,
|
||||
wrapped_key);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GetSecureStops(
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "license_protocol.pb.h"
|
||||
#include "log.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
const std::string kDefaultProvisioningServerUrl =
|
||||
@@ -17,6 +18,7 @@ const std::string kDefaultProvisioningServerUrl =
|
||||
namespace wvcdm {
|
||||
// Protobuf generated classes.
|
||||
using video_widevine_server::sdk::ClientIdentification;
|
||||
using video_widevine_server::sdk::ProvisioningOptions;
|
||||
using video_widevine_server::sdk::ProvisioningRequest;
|
||||
using video_widevine_server::sdk::ProvisioningResponse;
|
||||
using video_widevine_server::sdk::SignedProvisioningMessage;
|
||||
@@ -54,6 +56,8 @@ void CertificateProvisioning::ComposeJsonRequestAsQueryString(
|
||||
*/
|
||||
CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
SecurityLevel requested_security_level,
|
||||
CdmCertificateType cert_type,
|
||||
const std::string& cert_authority,
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
default_url->assign(kDefaultProvisioningServerUrl);
|
||||
@@ -86,6 +90,24 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
std::string the_nonce(reinterpret_cast<char*>(&nonce), sizeof(nonce));
|
||||
provisioning_request.set_nonce(the_nonce);
|
||||
|
||||
ProvisioningOptions* options = provisioning_request.mutable_options();
|
||||
switch (cert_type) {
|
||||
case kCertificateWidevine:
|
||||
options->set_certificate_type(
|
||||
video_widevine_server::sdk::ProvisioningOptions_CertificateType_RSA_WIDEVINE);
|
||||
break;
|
||||
case kCertificateX509:
|
||||
options->set_certificate_type(
|
||||
video_widevine_server::sdk::ProvisioningOptions_CertificateType_X509);
|
||||
break;
|
||||
default:
|
||||
LOGE("GetProvisioningRequest: unknown certificate type %ld", cert_type);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
cert_type_ = cert_type;
|
||||
options->set_certificate_authority(cert_authority);
|
||||
|
||||
std::string serialized_message;
|
||||
provisioning_request.SerializeToString(&serialized_message);
|
||||
|
||||
@@ -155,7 +177,9 @@ bool CertificateProvisioning::ParseJsonResponse(
|
||||
* Returns NO_ERROR for success and UNKNOWN_ERROR if fails.
|
||||
*/
|
||||
CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
CdmProvisioningResponse& response) {
|
||||
CdmProvisioningResponse& response,
|
||||
std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
|
||||
// Extracts signed response from JSON string, decodes base64 signed response
|
||||
const std::string kMessageStart = "\"signedResponse\": \"";
|
||||
@@ -211,6 +235,12 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
|
||||
crypto_session_.Close();
|
||||
|
||||
if (cert_type_ == kCertificateX509) {
|
||||
*cert = provisioning_response.device_certificate();
|
||||
*wrapped_key = wrapped_rsa_key;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
const std::string& device_certificate =
|
||||
provisioning_response.device_certificate();
|
||||
|
||||
|
||||
@@ -292,15 +292,38 @@ message SessionState {
|
||||
// Public protocol buffer definitions for Widevine Device Certificate
|
||||
// Provisioning protocol.
|
||||
|
||||
// PROPOSED message for customizing provisioning request.
|
||||
// This could support requesting specificy types of certificates.
|
||||
// E.g. Cast X.509 certs.
|
||||
message ProvisioningOptions {
|
||||
// PROPOSED enum identifying the certificate type.
|
||||
enum CertificateType {
|
||||
RSA_WIDEVINE = 0; // Default. The original certificate type.
|
||||
X509 = 1; // X.509 certificate.
|
||||
}
|
||||
|
||||
optional CertificateType certificate_type = 1;
|
||||
|
||||
// OPEN QUESTION: How does the client specify the cert root authority?
|
||||
// Should this be the cert authority's domain? E.g. foo.com?
|
||||
optional string certificate_authority = 2;
|
||||
}
|
||||
|
||||
// Provisioning request sent by client devices to provisioning service.
|
||||
message ProvisioningRequest {
|
||||
// Device root of trust and other client identification. Required.
|
||||
optional ClientIdentification client_id = 1;
|
||||
// Nonce value used to prevent replay attacks. Required.
|
||||
optional bytes nonce = 2;
|
||||
// Options for type of certificate to generate. Optional.
|
||||
optional ProvisioningOptions options = 3;
|
||||
}
|
||||
|
||||
// Provisioning response sent by the provisioning server to client devices.
|
||||
//
|
||||
// PROPOSAL: The contents of this message vary depending upon the value of
|
||||
// CertificateType in options. TODO(blueeyes): Determine the right way to
|
||||
// transfer X.509 certs.
|
||||
message ProvisioningResponse {
|
||||
// AES-128 encrypted device private RSA key. PKCS#1 ASN.1 DER-encoded.
|
||||
// Required.
|
||||
|
||||
@@ -188,9 +188,14 @@ TEST(WvCdmProvisioningTest, ProvisioningTest) {
|
||||
CdmEngine cdm_engine;
|
||||
CdmProvisioningRequest prov_request;
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority;
|
||||
std::string cert, wrapped_key;
|
||||
|
||||
cdm_engine.GetProvisioningRequest(&prov_request, &provisioning_server_url);
|
||||
cdm_engine.HandleProvisioningResponse(kValidJsonProvisioningResponse);
|
||||
cdm_engine.GetProvisioningRequest(cert_type, cert_authority,
|
||||
&prov_request, &provisioning_server_url);
|
||||
cdm_engine.HandleProvisioningResponse(kValidJsonProvisioningResponse,
|
||||
&cert, &wrapped_key);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmEngineTest, BaseIsoBmffMessageTest) {
|
||||
|
||||
@@ -64,10 +64,15 @@ class WvContentDecryptionModule {
|
||||
|
||||
// Provisioning related methods
|
||||
virtual CdmResponseType GetProvisioningRequest(
|
||||
CdmProvisioningRequest* request, std::string* default_url);
|
||||
CdmCertificateType cert_type,
|
||||
const std::string& cert_authority,
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url);
|
||||
|
||||
virtual CdmResponseType HandleProvisioningResponse(
|
||||
CdmProvisioningResponse& response);
|
||||
CdmProvisioningResponse& response,
|
||||
std::string* cert,
|
||||
std::string* wrapped_key);
|
||||
|
||||
// Secure stop related methods
|
||||
virtual CdmResponseType GetSecureStops(CdmSecureStops* secure_stops);
|
||||
|
||||
@@ -102,13 +102,19 @@ CdmResponseType WvContentDecryptionModule::QueryKeyControlInfo(
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::GetProvisioningRequest(
|
||||
CdmProvisioningRequest* request, std::string* default_url) {
|
||||
return cdm_engine_->GetProvisioningRequest(request, default_url);
|
||||
CdmCertificateType cert_type,
|
||||
const std::string& cert_authority,
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
return cdm_engine_->GetProvisioningRequest(cert_type, cert_authority,
|
||||
request, default_url);
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse(
|
||||
CdmProvisioningResponse& response) {
|
||||
return cdm_engine_->HandleProvisioningResponse(response);
|
||||
CdmProvisioningResponse& response,
|
||||
std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
return cdm_engine_->HandleProvisioningResponse(response, cert, wrapped_key);
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::GetSecureStops(
|
||||
|
||||
@@ -423,40 +423,82 @@ class WvCdmSessionSharingTest
|
||||
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
||||
cert_type, cert_authority,
|
||||
&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
|
||||
std::string response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||
decryptor_.HandleProvisioningResponse(response, &cert,
|
||||
&wrapped_key));
|
||||
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
||||
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, ProvisioningRetryTest) {
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
||||
cert_type, cert_authority,
|
||||
&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
||||
cert_type, cert_authority,
|
||||
&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
|
||||
std::string response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||
decryptor_.HandleProvisioningResponse(response, &cert,
|
||||
&wrapped_key));
|
||||
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
||||
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
||||
|
||||
response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::UNKNOWN_ERROR,
|
||||
decryptor_.HandleProvisioningResponse(response));
|
||||
decryptor_.HandleProvisioningResponse(response, &cert,
|
||||
&wrapped_key));
|
||||
EXPECT_EQ(0, static_cast<int>(cert.size()));
|
||||
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, DISABLED_X509ProvisioningTest) {
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateX509;
|
||||
// TODO(rfrias): insert appropriate CA here
|
||||
std::string cert_authority = "cast.google.com";
|
||||
std::string cert, wrapped_key;
|
||||
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
||||
cert_type, cert_authority,
|
||||
&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
|
||||
std::string response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||
decryptor_.HandleProvisioningResponse(response, &cert,
|
||||
&wrapped_key));
|
||||
EXPECT_NE(0, static_cast<int>(cert.size()));
|
||||
EXPECT_NE(0, static_cast<int>(wrapped_key.size()));
|
||||
decryptor_.CloseSession(session_id_);
|
||||
}
|
||||
|
||||
@@ -479,14 +521,19 @@ TEST_F(WvCdmRequestLicenseTest, PropertySetTest) {
|
||||
|
||||
if (NEED_PROVISIONING == sts) {
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
EXPECT_EQ(
|
||||
NO_ERROR,
|
||||
decryptor_.GetProvisioningRequest(&key_msg_, &provisioning_server_url));
|
||||
decryptor_.GetProvisioningRequest(cert_type, cert_authority,
|
||||
&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
std::string response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_.HandleProvisioningResponse(response, &cert,
|
||||
&wrapped_key));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set_L3,
|
||||
&session_id_L3));
|
||||
} else {
|
||||
@@ -523,14 +570,19 @@ TEST_F(WvCdmRequestLicenseTest, ForceL3Test) {
|
||||
EXPECT_EQ(NEED_PROVISIONING,
|
||||
decryptor_.OpenSession(g_key_system, &property_set, &session_id_));
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_.GetProvisioningRequest(&key_msg_,
|
||||
decryptor_.GetProvisioningRequest(cert_type, cert_authority,
|
||||
&key_msg_,
|
||||
&provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
std::string response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_.HandleProvisioningResponse(response, &cert,
|
||||
&wrapped_key));
|
||||
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set,
|
||||
&session_id_));
|
||||
@@ -912,13 +964,18 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
|
||||
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority, cert, wrapped_key;
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.GetProvisioningRequest(
|
||||
cert_type, cert_authority,
|
||||
&key_msg_, &provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
std::string response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
EXPECT_EQ(wvcdm::NO_ERROR,
|
||||
decryptor_.HandleProvisioningResponse(response, &cert,
|
||||
&wrapped_key));
|
||||
decryptor_.CloseSession(session_id_);
|
||||
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
@@ -969,13 +1026,16 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
|
||||
app_parameters, &key_msg_,
|
||||
&server_url));
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_.GetProvisioningRequest(&key_msg_,
|
||||
decryptor_.GetProvisioningRequest(cert_type, cert_authority,
|
||||
&key_msg_,
|
||||
&provisioning_server_url));
|
||||
EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url());
|
||||
response =
|
||||
GetCertRequestResponse(g_config->provisioning_test_server_url(), 200);
|
||||
EXPECT_NE(0, static_cast<int>(response.size()));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.HandleProvisioningResponse(response));
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
decryptor_.HandleProvisioningResponse(response, &cert,
|
||||
&wrapped_key));
|
||||
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.OpenSession(g_key_system, &property_set,
|
||||
&session_id_));
|
||||
|
||||
Reference in New Issue
Block a user