// Copyright 2017 Google Inc. All Rights Reserved. // These tests validate features supported by the CDM that may not be // supported by the OEM supplied L1 OEMCrypto implementation. These test use // the modifiable/mock OEMCrypto. OEMCrypto configuration flags // are enabled/disabled when validating features in tests. // // Instructions to build and use the modifiable OEMCrypto are here // https://docs.google.com/a/google.com/document/d/1hLK7ThUsBBKkokPhKh8urU1Zo9a8U4dX3bBKDgOU_iY/edit?usp=sharing // // Use the install script to backup the OEM supplied L1 OEMCrypto and // replace with the modifiable/mock OEMCrypto. Use default configuration // amd modify flags as mentioned by the tests. #include #include #include #include #include #include #include "config_test_env.h" #include "log.h" #include "oemcrypto_adapter.h" #include "OEMCryptoCENC.h" #include "string_conversions.h" #include "test_base.h" #include "test_printers.h" #include "url_request.h" #include "wv_cdm_constants.h" #include "wv_content_decryption_module.h" using ::testing::_; namespace { #define N_ELEM(a) (sizeof(a)/sizeof(a[0])) const char kPathDelimiter = '/'; // HTTP response codes. const int kHttpOk = 200; const int kHttpBadRequest = 400; const int kHttpInternalServerError = 500; // Default license server, can be configured using --server command line option // Default key id (pssh), can be configured using --keyid command line option std::string g_client_auth; wvcdm::ConfigTestEnv* g_config = NULL; wvcdm::KeyId g_key_id; wvcdm::CdmKeySystem g_key_system; std::string g_license_server; wvcdm::KeyId g_wrong_key_id; wvcdm::LicenseServerId g_license_server_id = wvcdm::kContentProtectionUatServer; std::string g_service_certificate; } // namespace namespace wvcdm { // Protobuf generated classes class WvCdmFeatureTest : public WvCdmTestBase { public: WvCdmFeatureTest() {} ~WvCdmFeatureTest() {} void LogResponseError(const std::string& message, int http_status_code) { LOGD("HTTP Status code = %d", http_status_code); LOGD("HTTP response(%d): %s", message.size(), b2a_hex(message).c_str()); } // Post a request and extract the signed provisioning message from // the HTTP response. std::string GetCertRequestResponse(const std::string& server_url) { // Use secure connection and chunk transfer coding. UrlRequest url_request(server_url); EXPECT_TRUE(url_request.is_connected()) << "Fail to connect to " << server_url; url_request.PostCertRequestInQueryString(key_msg_); std::string message; EXPECT_TRUE(url_request.GetResponse(&message)); int http_status_code = url_request.GetStatusCode(message); if (kHttpOk != http_status_code) { LogResponseError(message, http_status_code); } EXPECT_EQ(kHttpOk, http_status_code); return message; } protected: wvcdm::WvContentDecryptionModule decryptor_; CdmKeyMessage key_msg_; CdmSessionId session_id_; }; // To run this test set options, // use_keybox 0 TEST_F(WvCdmFeatureTest, OEMCertificateProvisioning) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, 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, kDefaultCdmIdentifier, &key_msg_, &provisioning_server_url)); EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url()); provisioning_server_url = "https://staging-www.sandbox.googleapis.com/" "certificateprovisioning/v1/devicecertificates/create" "?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE"; std::string response = GetCertRequestResponse(provisioning_server_url); //GetCertRequestResponse(g_config->provisioning_server_url()); EXPECT_NE(0, static_cast(response.size())); EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse( kDefaultCdmIdentifier, response, &cert, &wrapped_key)); EXPECT_EQ(0, static_cast(cert.size())); EXPECT_EQ(0, static_cast(wrapped_key.size())); decryptor_.CloseSession(session_id_); } // To run this test set options, // use_keybox 1 TEST_F(WvCdmFeatureTest, KeyboxProvisioning) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, 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, kDefaultCdmIdentifier, &key_msg_, &provisioning_server_url)); EXPECT_EQ(provisioning_server_url, g_config->provisioning_server_url()); provisioning_server_url = "https://staging-www.sandbox.googleapis.com/" "certificateprovisioning/v1/devicecertificates/create" "?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE"; std::string response = GetCertRequestResponse(provisioning_server_url); //GetCertRequestResponse(g_config->provisioning_server_url()); EXPECT_NE(0, static_cast(response.size())); EXPECT_EQ(wvcdm::NO_ERROR, decryptor_.HandleProvisioningResponse( kDefaultCdmIdentifier, response, &cert, &wrapped_key)); EXPECT_EQ(0, static_cast(cert.size())); EXPECT_EQ(0, static_cast(wrapped_key.size())); decryptor_.CloseSession(session_id_); } } // namespace wvcdm void show_menu(char* prog_name) { std::cout << std::endl; std::cout << "usage: " << prog_name << " [options]" << std::endl << std::endl; std::cout << " enclose multiple arguments in '' when using adb shell" << std::endl; std::cout << " e.g. adb shell '" << prog_name << " --server=\"url\"'" << std::endl; std::cout << " or adb shell '" << prog_name << " -u\"url\"'" << std::endl << std::endl; std::cout << " -i/--license_server_id=" << std::endl; std::cout << " specifies which default server settings to use: " << std::endl; std::cout << " gp for GooglePlay server" << std::endl; std::cout << " cp for Content Protection UAT server" << std::endl; std::cout << " st for Content Protection Staging server" << std::endl << std::endl; std::cout << " -k/--keyid=" << std::endl; std::cout << " configure the key id or pssh, in hex format" << std::endl << std::endl; std::cout << " -s/--cert=" << std::endl; std::cout << " configure the signed service certificate" << std::endl; std::cout << " Specify the SignedDeviceCertificate (from " << "device_certificate.proto) " << std::endl; std::cout << " in hex format." << std::endl; std::cout << " Due to the length of the argument use, " << std::endl; std::cout << " echo \"/system/bin/request_license_test -s \\\"" << "0ABF02...A29914\\\"\" \\" << std::endl; std::cout << " > run_request_license_test.sh" << std::endl; std::cout << " chmod +x run_request_license_test.sh" << std::endl; std::cout << " adb push run_request_license_test.sh /system/bin" << std::endl; std::cout << " adb shell sh /system/bin/run_request_license_test.sh" << std::endl << std::endl; std::cout << " -u/--server=" << std::endl; std::cout << " configure the license server url, please include http[s]" << " in the url" << std::endl << std::endl; } int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); bool show_usage = false; static const struct option long_options[] = { {"keyid", required_argument, NULL, 'k'}, {"license_server_id", required_argument, NULL, 'i'}, {"service_certificate", required_argument, NULL, 's'}, {"license_server_url", required_argument, NULL, 'u'}, {NULL, 0, NULL, '\0'}}; int option_index = 0; int opt = 0; while ((opt = getopt_long(argc, argv, "i:k:s:u:", long_options, &option_index)) != -1) { switch (opt) { case 'i': { std::string license_id(optarg); if (!license_id.compare("gp")) { g_license_server_id = wvcdm::kGooglePlayServer; } else if (!license_id.compare("cp")) { g_license_server_id = wvcdm::kContentProtectionUatServer; } else if (!license_id.compare("st")) { g_license_server_id = wvcdm::kContentProtectionStagingServer; } else { std::cout << "Invalid license server id" << optarg << std::endl; show_usage = true; } break; } case 'k': { g_key_id.clear(); g_key_id.assign(optarg); break; } case 's': { g_service_certificate.clear(); g_service_certificate.assign(optarg); break; } case 'u': { g_license_server.clear(); g_license_server.assign(optarg); break; } case '?': { show_usage = true; break; } } } if (show_usage) { show_menu(argv[0]); return 0; } g_config = new wvcdm::ConfigTestEnv(g_license_server_id); g_client_auth.assign(g_config->client_auth()); g_key_system.assign(g_config->key_system()); g_wrong_key_id.assign(g_config->wrong_key_id()); // The following variables are configurable through command line // options. If the command line arguments are absent, use the settings // in kLicenseServers[] pointed to by g_config. if (g_key_id.empty()) { g_key_id.assign(g_config->key_id()); } if (g_service_certificate.empty()) { g_service_certificate.assign(g_config->service_certificate()); } if (g_license_server.empty()) { g_license_server.assign(g_config->license_server_url()); } // Displays server url, port and key Id being used std::cout << std::endl; std::cout << "Server: " << g_license_server << std::endl; std::cout << "KeyID: " << g_key_id << std::endl << std::endl; g_key_id = wvcdm::a2bs_hex(g_key_id); g_config->set_license_server(g_license_server); int status = RUN_ALL_TESTS(); delete g_config; return status; }