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:
Jeff Tinker
2014-03-10 12:41:14 -07:00
parent f111bea1b1
commit 3db90f54c1
26 changed files with 864 additions and 44 deletions

View File

@@ -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);

View File

@@ -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);
};

View File

@@ -64,6 +64,11 @@ enum CdmSecurityLevel {
kSecurityLevelUnknown
};
enum CdmCertificateType {
kCertificateWidevine,
kCertificateX509,
};
struct CdmDecryptionParameters {
bool is_encrypted;
bool is_secure;

View File

@@ -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(

View File

@@ -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();

View File

@@ -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.

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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(

View File

@@ -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_));