// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/at_exit.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "string_conversions.h" #include "wv_content_decryption_module.h" namespace { // Default license server to play server, can be configured using --server command line option std::string gGpLicenseServer = "https://jmt17.google.com/video-dev/license/GetCencLicense"; std::string gYtLicenseServer = "https://www.youtube.com/api/drm/widevine?video_id=03681262dc412c06&source=YOUTUBE"; std::string gLicenseServer(gYtLicenseServer); // Default key id (pssh), can be configured using --keyid command line option std::string gKeyID = "000000347073736800000000" // blob size and pssh "EDEF8BA979D64ACEA3C827DCD51D21ED00000014" // Widevine system id "08011210e02562e04cd55351b14b3d748d36ed8e"; // pssh data // An invalid key id, expected to fail std::string kWrongKeyID = "000000347073736800000000" // blob size and psshb "EDEF8BA979D64ACEA3C827DCD51D21ED00000014" // Widevine system id "0901121094889920E8D6520098577DF8F2DD5546"; // pssh data static const char kWidevineKeySystem[] = "com.widevine.alpha"; } // namespace namespace wvcdm_test { class WvCdmDecryptorTest : public testing::Test { public: WvCdmDecryptorTest() {} ~WvCdmDecryptorTest() {} protected: void GenerateKeyRequest(const std::string& key_system, const std::string& init_data) { EXPECT_EQ(decryptor_.GenerateKeyRequest(key_system, init_data, &key_msg_, &session_id_), wvcdm::KEY_MESSAGE); } void GenerateRenewalRequest(const std::string& key_system, const std::string& init_data) { EXPECT_EQ(decryptor_.GenerateRenewalRequest(key_system, init_data, session_id_, &key_msg_), wvcdm::KEY_MESSAGE); } std::string GetKeyRequestResponse(const std::string& server_url, int expected_response) { net::TestDelegate d; net::TestNetworkDelegate network_delegate; net::TestURLRequestContext context(true); context.set_network_delegate(&network_delegate); scoped_ptr resolver( net::HostResolver::CreateDefaultResolver(NULL)); context.set_host_resolver(resolver.get()); context.Init(); net::URLRequest r(GURL(server_url), &d, &context); r.EnableChunkedUpload(); r.set_method("POST"); r.AppendChunkToUpload(key_msg_.data(), key_msg_.size(), true); r.Start(); EXPECT_TRUE(r.is_pending()); MessageLoop::current()->Run(); std::string data = d.data_received(); // Youtube server returns 400 for invalid message while play server returns // 500, so just test inequity here for invalid message if (expected_response == 200) { EXPECT_EQ(200, r.GetResponseCode()) << data; } else { EXPECT_NE(200, r.GetResponseCode()) << data; } EXPECT_EQ(net::URLRequestStatus::SUCCESS, r.status().status()); EXPECT_TRUE(d.bytes_received() > 0); // Extract DRM message: // https://docs.google.com/a/google.com/document/d/1Xue3bgwv2qIAnuFIZ-HCcix43dvH2UxsOEA_8FCBO3I/edit# if (r.status().status() == net::URLRequestStatus::SUCCESS) { size_t pos = data.find("\r\n"); if (pos != data.npos) data = data.substr(pos+2); } return data; } void VerifyKeyRequestResponse(const std::string& server_url, std::string& init_data, bool is_renewal) { std::string resp = GetKeyRequestResponse(server_url, 200); std::cout << "Message: " << wvcdm::b2a_hex(key_msg_) << std::endl; std::cout << "Response: " << wvcdm::b2a_hex(resp) << std::endl; if (is_renewal) { EXPECT_EQ(decryptor_.RenewKey(kWidevineKeySystem, init_data, resp, session_id_), wvcdm::KEY_ADDED); } else { EXPECT_EQ(decryptor_.AddKey(kWidevineKeySystem, init_data, resp, session_id_), wvcdm::KEY_ADDED); } std::cout << "back from AddKey" << std::endl; } wvcdm::WvContentDecryptionModule decryptor_; std::string key_msg_; std::string session_id_; }; TEST_F(WvCdmDecryptorTest, BaseMessageTest) { GenerateKeyRequest(kWidevineKeySystem, gKeyID); GetKeyRequestResponse(gLicenseServer, 200); } TEST_F(WvCdmDecryptorTest, WrongMessageTest) { std::string wrong_message = wvcdm::a2b_hex(kWrongKeyID); GenerateKeyRequest(kWidevineKeySystem, wrong_message); GetKeyRequestResponse(gLicenseServer, 500); } TEST_F(WvCdmDecryptorTest, NormalWebMDecryption) { GenerateKeyRequest(kWidevineKeySystem, gKeyID); VerifyKeyRequestResponse(gLicenseServer, gKeyID, false); } TEST_F(WvCdmDecryptorTest, LicenseRenewal) { GenerateKeyRequest(kWidevineKeySystem, gKeyID); VerifyKeyRequestResponse(gLicenseServer, gKeyID, false); GenerateRenewalRequest(kWidevineKeySystem, gKeyID); VerifyKeyRequestResponse(gLicenseServer, gKeyID, true); } } // namespace wvcdm_test int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); std::string temp; std::string license_server(gLicenseServer); std::string key_id(gKeyID); for (int i=1; i"; std::cout << "configure the license server url, please include http[s] in the url" << std::endl; std::cout << std::setw(30) << std::left << " "; std::cout << "default: " << license_server << std::endl; std::cout << std::setw(30) << std::left << " --keyid="; std::cout << "configure the key id or pssh, in hex format" << std::endl; std::cout << std::setw(30) << std::left << " "; std::cout << "default: " << key_id << std::endl << std::endl; return 0; } } std::cout << std::endl; std::cout << "Server: " << gLicenseServer << std::endl; std::cout << "KeyID: " << gKeyID << std::endl << std::endl; gKeyID = wvcdm::a2b_hex(gKeyID); base::AtExitManager exit; MessageLoop ttr(MessageLoop::TYPE_IO); return RUN_ALL_TESTS(); }