diff --git a/README.md b/README.md index ac5e71ec67..209b82a794 100644 --- a/README.md +++ b/README.md @@ -353,7 +353,7 @@ packager input=sintel.wvm,stream=video,output=encrypted_sintel.mp4 \ --enable_widevine_decryption \ --enable_widevine_encryption \ --key_server_url "https://license.uat.widevine.com/cenc/getcontentkey/widevine_test" \ ---content_id "content_sintel" \ +--content_id "01020304050607" \ --signer "widevine_test" \ --rsa_signing_key_path "widevine_test_private.der" ``` diff --git a/packager/app/fixed_key_encryption_flags.cc b/packager/app/fixed_key_encryption_flags.cc index 63cda83395..2553fb06f8 100644 --- a/packager/app/fixed_key_encryption_flags.cc +++ b/packager/app/fixed_key_encryption_flags.cc @@ -4,10 +4,12 @@ // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd // -// Defines command line flags for fixed key encryption. +// Defines command line flags for fixed key encryption/decryption. #include "packager/app/fixed_key_encryption_flags.h" +#include "packager/app/validate_flag.h" + DEFINE_bool(enable_fixed_key_encryption, false, "Enable encryption with fixed key."); @@ -18,23 +20,34 @@ DEFINE_string(key_id, "", "Key id in hex string format."); DEFINE_string(key, "", "Key in hex string format."); DEFINE_string(pssh, "", "PSSH in hex string format."); -static bool IsNotEmptyWithFixedKeyEncryption(const char* flag_name, - const std::string& flag_value) { - if (FLAGS_enable_fixed_key_encryption && flag_value.empty()) - return false; - std::string flag_name_str(flag_name); - if (FLAGS_enable_fixed_key_decryption && (flag_name_str != "pssh") && - flag_value.empty()) - return false; - return true; +namespace edash_packager { + +bool ValidateFixedCryptoFlags() { + bool success = true; + + const bool fixed_crypto = + FLAGS_enable_fixed_key_encryption || FLAGS_enable_fixed_key_decryption; + const char fixed_crypto_label[] = "--enable_fixed_key_encryption/decryption"; + // --key_id and --key are associated with --enable_fixed_key_encryption and + // --enable_fixed_key_decryption. + if (!ValidateFlag( + "key_id", FLAGS_key_id, fixed_crypto, false, fixed_crypto_label)) { + success = false; + } + if (!ValidateFlag( + "key", FLAGS_key, fixed_crypto, false, fixed_crypto_label)) { + success = false; + } + + // --pssh is associated with --enable_fix_key_encryption. + if (!ValidateFlag("pssh", + FLAGS_pssh, + FLAGS_enable_fixed_key_encryption, + false, + "--enable_fixed_key_encryption")) { + success = false; + } + return success; } -static bool dummy_key_id_validator = - google::RegisterFlagValidator(&FLAGS_key_id, - &IsNotEmptyWithFixedKeyEncryption); -static bool dummy_key_validator = - google::RegisterFlagValidator(&FLAGS_key, - &IsNotEmptyWithFixedKeyEncryption); -static bool dummy_pssh_validator = - google::RegisterFlagValidator(&FLAGS_pssh, - &IsNotEmptyWithFixedKeyEncryption); +} // namespace edash_packager diff --git a/packager/app/fixed_key_encryption_flags.h b/packager/app/fixed_key_encryption_flags.h index d5d6e00b42..032da12f31 100644 --- a/packager/app/fixed_key_encryption_flags.h +++ b/packager/app/fixed_key_encryption_flags.h @@ -17,4 +17,12 @@ DECLARE_string(key_id); DECLARE_string(key); DECLARE_string(pssh); +namespace edash_packager { + +/// Validate fixed encryption/decryption flags. +/// @return true on success, false otherwise. +bool ValidateFixedCryptoFlags(); + +} // namespace edash_packager + #endif // APP_FIXED_KEY_ENCRYPTION_FLAGS_H_ diff --git a/packager/app/packager_main.cc b/packager/app/packager_main.cc index 2b4efc5716..04acf761d4 100644 --- a/packager/app/packager_main.cc +++ b/packager/app/packager_main.cc @@ -49,6 +49,14 @@ const char kUsage[] = "content bit rate for the stream, in bits/sec. If specified, this value is " "propagated to the $Bandwidth$ template parameter for segment names. " "If not specified, its value may be estimated.\n"; + +enum ExitStatus { + kSuccess = 0, + kNoArgument, + kArgumentValidationFailed, + kPackagingFailed, + kInternalError, +}; } // namespace namespace edash_packager { @@ -286,21 +294,25 @@ int PackagerMain(int argc, char** argv) { google::ParseCommandLineFlags(&argc, &argv, true); if (argc < 2) { google::ShowUsageWithFlags(argv[0]); - return 1; + return kNoArgument; } + + if (!ValidateWidevineCryptoFlags() || !ValidateFixedCryptoFlags()) + return kArgumentValidationFailed; + edash_packager::media::LibcryptoThreading libcrypto_threading; if (!libcrypto_threading.Initialize()) { LOG(ERROR) << "Could not initialize libcrypto threading."; - return 1; + return kInternalError; } // TODO(tinskip): Make InsertStreamDescriptor a member of // StreamDescriptorList. StreamDescriptorList stream_descriptors; for (int i = 1; i < argc; ++i) { if (!InsertStreamDescriptor(argv[i], &stream_descriptors)) - return 1; + return kArgumentValidationFailed; } - return RunPackager(stream_descriptors) ? 0 : 1; + return RunPackager(stream_descriptors) ? kSuccess : kPackagingFailed; } } // namespace media diff --git a/packager/app/packager_util.cc b/packager/app/packager_util.cc index 27daeea970..556bbf1ba4 100644 --- a/packager/app/packager_util.cc +++ b/packager/app/packager_util.cc @@ -35,32 +35,29 @@ void DumpStreamInfo(const std::vector& streams) { scoped_ptr CreateSigner() { scoped_ptr signer; - if (FLAGS_enable_widevine_encryption || FLAGS_enable_widevine_decryption) { - if (!FLAGS_aes_signing_key.empty()) { - signer.reset( - AesRequestSigner::CreateSigner(FLAGS_signer, FLAGS_aes_signing_key, - FLAGS_aes_signing_iv)); - if (!signer) { - LOG(ERROR) << "Cannot create an AES signer object from '" - << FLAGS_aes_signing_key << "':'" << FLAGS_aes_signing_iv - << "'."; - return scoped_ptr(); - } - } else if (!FLAGS_rsa_signing_key_path.empty()) { - std::string rsa_private_key; - if (!File::ReadFileToString(FLAGS_rsa_signing_key_path.c_str(), - &rsa_private_key)) { - LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path - << "'."; - return scoped_ptr(); - } - signer.reset( - RsaRequestSigner::CreateSigner(FLAGS_signer, rsa_private_key)); - if (!signer) { - LOG(ERROR) << "Cannot create a RSA signer object from '" - << FLAGS_rsa_signing_key_path << "'."; - return scoped_ptr(); - } + + if (!FLAGS_aes_signing_key.empty()) { + signer.reset(AesRequestSigner::CreateSigner( + FLAGS_signer, FLAGS_aes_signing_key, FLAGS_aes_signing_iv)); + if (!signer) { + LOG(ERROR) << "Cannot create an AES signer object from '" + << FLAGS_aes_signing_key << "':'" << FLAGS_aes_signing_iv + << "'."; + return scoped_ptr(); + } + } else if (!FLAGS_rsa_signing_key_path.empty()) { + std::string rsa_private_key; + if (!File::ReadFileToString(FLAGS_rsa_signing_key_path.c_str(), + &rsa_private_key)) { + LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path + << "'."; + return scoped_ptr(); + } + signer.reset(RsaRequestSigner::CreateSigner(FLAGS_signer, rsa_private_key)); + if (!signer) { + LOG(ERROR) << "Cannot create a RSA signer object from '" + << FLAGS_rsa_signing_key_path << "'."; + return scoped_ptr(); } } return signer.Pass(); diff --git a/packager/app/validate_flag.cc b/packager/app/validate_flag.cc new file mode 100644 index 0000000000..09e3396535 --- /dev/null +++ b/packager/app/validate_flag.cc @@ -0,0 +1,40 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd +// +// Flag validation help functions. + +#include "packager/app/validate_flag.h" + +#include + +#include "packager/base/strings/stringprintf.h" + +namespace edash_packager { + +bool ValidateFlag(const char* flag_name, + const std::string& flag_value, + bool condition, + bool optional, + const char* label) { + if (flag_value.empty()) { + if (!optional && condition) { + PrintError( + base::StringPrintf("--%s is required if %s.", flag_name, label)); + return false; + } + } else if (!condition) { + PrintError(base::StringPrintf( + "--%s should be specified only if %s.", flag_name, label)); + return false; + } + return true; +} + +void PrintError(const std::string& error_message) { + fprintf(stderr, "ERROR: %s\n", error_message.c_str()); +} + +} // namespace edash_packager diff --git a/packager/app/validate_flag.h b/packager/app/validate_flag.h new file mode 100644 index 0000000000..280dde70e3 --- /dev/null +++ b/packager/app/validate_flag.h @@ -0,0 +1,33 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd +// +// Flag validation help functions. + +#include + +namespace edash_packager { + +/// Validate a flag against the given condition. +/// @param flag_name is the name of the flag. +/// @param flag_value is the value of the flag. +/// @param condition,optional determines how the flag should be validated. If +/// condition is true and optional is false, then this flag is required +// and cannot be empty; If condition is false, then this flag should +// not be set. +/// @param label specifies the label associated with the condition. It is used +/// to generate the error message on validation failure. +/// @return true on success, false otherwise. +bool ValidateFlag(const char* flag_name, + const std::string& flag_value, + bool condition, + bool optional, + const char* label); + +/// Format and print error message. +/// @param error_message specifies the error message. +void PrintError(const std::string& error_message); + +} // namespace edash_packager diff --git a/packager/app/widevine_encryption_flags.cc b/packager/app/widevine_encryption_flags.cc index dc18062b44..ed6e6635f3 100644 --- a/packager/app/widevine_encryption_flags.cc +++ b/packager/app/widevine_encryption_flags.cc @@ -8,8 +8,9 @@ #include "packager/app/widevine_encryption_flags.h" +#include "packager/app/validate_flag.h" #include "packager/base/logging.h" -#include "packager/base/strings/string_number_conversions.h" +#include "packager/base/strings/string_util.h" DEFINE_bool(enable_widevine_encryption, false, @@ -49,98 +50,105 @@ DEFINE_int32(crypto_period_duration, "Crypto period duration in seconds. If it is non-zero, key " "rotation is enabled."); -namespace { +namespace edash_packager { -static bool VerifyEncryptionAndDecryptionParams(const char* flag_name, - const std::string& flag_value) { - DCHECK(flag_name); +bool ValidateWidevineCryptoFlags() { + bool success = true; - const std::string flag_name_str = flag_name; - bool is_common_param = (flag_name_str == "key_server_url") || - (flag_name_str == "signer"); - if (FLAGS_enable_widevine_encryption) { - if (flag_value.empty()) { - fprintf(stderr, - "ERROR: %s required if enable_widevine_encryption is true\n", - flag_name); - return false; - } - } else if (FLAGS_enable_widevine_decryption) { - if (is_common_param) { - if (flag_value.empty()) { - fprintf(stderr, - "ERROR: %s required if --enable_widevine_encryption or " - "--enable_widevine_decryption is true\n", - flag_name); - return false; - } - } else { - if (!flag_value.empty()) { - fprintf(stderr, "ERROR: %s should only be specified if " - "--enable_widevine_decryption is true\n", flag_name); - return false; - } - } - } else { - if (!flag_value.empty()) { - fprintf(stderr, "ERROR: %s should only be specified if %s" - " is true\n", flag_name, is_common_param ? - "--enable_widevine_encryption or --enable_widevine_decryption" : - "--enable_widevine_encryption"); - return false; - } + const bool widevine_crypto = + FLAGS_enable_widevine_encryption || FLAGS_enable_widevine_decryption; + const char widevine_crypto_label[] = + "--enable_widevine_encryption/decryption"; + // key_server_url and signer (optional) are associated with + // enable_widevine_encryption and enable_widevine_descryption. + if (!ValidateFlag("key_server_url", + FLAGS_key_server_url, + widevine_crypto, + false, + widevine_crypto_label)) { + success = false; } - return true; -} - -static bool IsPositive(const char* flag_name, int flag_value) { - return flag_value > 0; -} - -static bool VerifyAesRsaKey(const char* flag_name, - const std::string& flag_value) { - if (!FLAGS_enable_widevine_encryption) - return true; - const std::string flag_name_str = flag_name; - if (flag_name_str == "aes_signing_iv") { - if (!FLAGS_aes_signing_key.empty() && flag_value.empty()) { - fprintf(stderr, - "ERROR: --aes_signing_iv is required for --aes_signing_key.\n"); - return false; - } - } else if (flag_name_str == "rsa_signing_key_path") { - if (FLAGS_aes_signing_key.empty() && flag_value.empty()) { - fprintf(stderr, - "ERROR: --aes_signing_key or --rsa_signing_key_path is " - "required.\n"); - return false; - } - if (!FLAGS_aes_signing_key.empty() && !flag_value.empty()) { - fprintf(stderr, - "ERROR: --aes_signing_key and --rsa_signing_key_path are " - "exclusive.\n"); - return false; - } + if (!ValidateFlag("signer", + FLAGS_signer, + widevine_crypto, + true, + widevine_crypto_label)) { + success = false; } - return true; + if (widevine_crypto && FLAGS_signer.empty() && + StartsWithASCII(FLAGS_key_server_url, "http", false)) { + LOG(WARNING) << "--signer is likely required with " + "--enable_widevine_encryption/decryption."; + } + + const char widevine_encryption_label[] = "--enable_widevine_encryption"; + // content_id and policy (optional) are associated with + // enable_widevine_encryption. + if (!ValidateFlag("content_id", + FLAGS_content_id, + FLAGS_enable_widevine_encryption, + false, + widevine_encryption_label)) { + success = false; + } + if (!ValidateFlag("policy", + FLAGS_policy, + FLAGS_enable_widevine_encryption, + true, + widevine_encryption_label)) { + success = false; + } + + if (FLAGS_max_sd_pixels <= 0) { + PrintError("--max_sd_pixels must be positive."); + success = false; + } + + const bool aes = !FLAGS_signer.empty() && FLAGS_rsa_signing_key_path.empty(); + const char aes_label[] = + "--signer is specified and exclusive with --rsa_signing_key_path"; + // aes_signer_key and aes_signing_iv are associated with aes signing. + if (!ValidateFlag( + "aes_signing_key", FLAGS_aes_signing_key, aes, true, aes_label)) { + success = false; + } + if (!ValidateFlag( + "aes_signing_iv", FLAGS_aes_signing_iv, aes, true, aes_label)) { + success = false; + } + + const bool rsa = !FLAGS_signer.empty() && FLAGS_aes_signing_key.empty() && + FLAGS_aes_signing_iv.empty(); + const char rsa_label[] = + "--signer is specified and exclusive with --aes_signing_key/iv"; + // rsa_signing_key_path is associated with rsa_signing. + if (!ValidateFlag("rsa_signing_key_path", + FLAGS_rsa_signing_key_path, + rsa, + true, + rsa_label)) { + success = false; + } + + if (!FLAGS_signer.empty() && + (FLAGS_aes_signing_key.empty() || FLAGS_aes_signing_iv.empty()) && + FLAGS_rsa_signing_key_path.empty()) { + PrintError( + "--aes_signing_key/iv or --rsa_signing_key_path is required with " + "--signer."); + success = false; + } + + if (FLAGS_crypto_period_duration < 0) { + PrintError("--crypto_period_duration should not be negative."); + success = false; + } else if (FLAGS_crypto_period_duration > 0 && !FLAGS_enable_widevine_encryption) { + PrintError( + "--crypto_period_duration should be specified only if " + "--enable_widevine_encryption."); + success = false; + } + return success; } -bool dummy_key_server_url_validator = - google::RegisterFlagValidator(&FLAGS_key_server_url, - &VerifyEncryptionAndDecryptionParams); -bool dummy_content_id_validator = - google::RegisterFlagValidator(&FLAGS_content_id, - &VerifyEncryptionAndDecryptionParams); -bool dummy_track_type_validator = - google::RegisterFlagValidator(&FLAGS_max_sd_pixels, &IsPositive); -bool dummy_signer_validator = - google::RegisterFlagValidator(&FLAGS_signer, - &VerifyEncryptionAndDecryptionParams); -bool dummy_aes_iv_validator = - google::RegisterFlagValidator(&FLAGS_aes_signing_iv, - &VerifyAesRsaKey); -bool dummy_rsa_key_file_validator = - google::RegisterFlagValidator(&FLAGS_rsa_signing_key_path, - &VerifyAesRsaKey); - -} // anonymous namespace +} // namespace edash_packager diff --git a/packager/app/widevine_encryption_flags.h b/packager/app/widevine_encryption_flags.h index 249eebb7c8..8eeb9927bf 100644 --- a/packager/app/widevine_encryption_flags.h +++ b/packager/app/widevine_encryption_flags.h @@ -23,4 +23,12 @@ DECLARE_string(aes_signing_iv); DECLARE_string(rsa_signing_key_path); DECLARE_int32(crypto_period_duration); +namespace edash_packager { + +/// Validate widevine encryption/decryption flags. +/// @return true on success, false otherwise. +bool ValidateWidevineCryptoFlags(); + +} // namespace edash_packager + #endif // APP_WIDEVINE_ENCRYPTION_FLAGS_H_ diff --git a/packager/packager.gyp b/packager/packager.gyp index e13a355345..4ec1bfe60f 100644 --- a/packager/packager.gyp +++ b/packager/packager.gyp @@ -26,6 +26,8 @@ 'app/packager_util.h', 'app/stream_descriptor.cc', 'app/stream_descriptor.h', + 'app/validate_flag.cc', + 'app/validate_flag.h', 'app/widevine_encryption_flags.cc', 'app/widevine_encryption_flags.h', ],