Make signer optional in packager app

Also refactor the command line flag validation app to make it cleaner.

Change-Id: Idb7bb33bd3060aaf25765c1575ceddd901b90c4d
This commit is contained in:
KongQun Yang 2014-10-13 15:06:48 -07:00
parent e72d12c54f
commit dd2ada2026
10 changed files with 261 additions and 140 deletions

View File

@ -353,7 +353,7 @@ packager input=sintel.wvm,stream=video,output=encrypted_sintel.mp4 \
--enable_widevine_decryption \ --enable_widevine_decryption \
--enable_widevine_encryption \ --enable_widevine_encryption \
--key_server_url "https://license.uat.widevine.com/cenc/getcontentkey/widevine_test" \ --key_server_url "https://license.uat.widevine.com/cenc/getcontentkey/widevine_test" \
--content_id "content_sintel" \ --content_id "01020304050607" \
--signer "widevine_test" \ --signer "widevine_test" \
--rsa_signing_key_path "widevine_test_private.der" --rsa_signing_key_path "widevine_test_private.der"
``` ```

View File

@ -4,10 +4,12 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd // 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/fixed_key_encryption_flags.h"
#include "packager/app/validate_flag.h"
DEFINE_bool(enable_fixed_key_encryption, DEFINE_bool(enable_fixed_key_encryption,
false, false,
"Enable encryption with fixed key."); "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(key, "", "Key in hex string format.");
DEFINE_string(pssh, "", "PSSH in hex string format."); DEFINE_string(pssh, "", "PSSH in hex string format.");
static bool IsNotEmptyWithFixedKeyEncryption(const char* flag_name, namespace edash_packager {
const std::string& flag_value) {
if (FLAGS_enable_fixed_key_encryption && flag_value.empty()) bool ValidateFixedCryptoFlags() {
return false; bool success = true;
std::string flag_name_str(flag_name);
if (FLAGS_enable_fixed_key_decryption && (flag_name_str != "pssh") && const bool fixed_crypto =
flag_value.empty()) FLAGS_enable_fixed_key_encryption || FLAGS_enable_fixed_key_decryption;
return false; const char fixed_crypto_label[] = "--enable_fixed_key_encryption/decryption";
return true; // --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 = } // namespace edash_packager
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);

View File

@ -17,4 +17,12 @@ DECLARE_string(key_id);
DECLARE_string(key); DECLARE_string(key);
DECLARE_string(pssh); 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_ #endif // APP_FIXED_KEY_ENCRYPTION_FLAGS_H_

View File

@ -49,6 +49,14 @@ const char kUsage[] =
"content bit rate for the stream, in bits/sec. If specified, this value is " "content bit rate for the stream, in bits/sec. If specified, this value is "
"propagated to the $Bandwidth$ template parameter for segment names. " "propagated to the $Bandwidth$ template parameter for segment names. "
"If not specified, its value may be estimated.\n"; "If not specified, its value may be estimated.\n";
enum ExitStatus {
kSuccess = 0,
kNoArgument,
kArgumentValidationFailed,
kPackagingFailed,
kInternalError,
};
} // namespace } // namespace
namespace edash_packager { namespace edash_packager {
@ -286,21 +294,25 @@ int PackagerMain(int argc, char** argv) {
google::ParseCommandLineFlags(&argc, &argv, true); google::ParseCommandLineFlags(&argc, &argv, true);
if (argc < 2) { if (argc < 2) {
google::ShowUsageWithFlags(argv[0]); google::ShowUsageWithFlags(argv[0]);
return 1; return kNoArgument;
} }
if (!ValidateWidevineCryptoFlags() || !ValidateFixedCryptoFlags())
return kArgumentValidationFailed;
edash_packager::media::LibcryptoThreading libcrypto_threading; edash_packager::media::LibcryptoThreading libcrypto_threading;
if (!libcrypto_threading.Initialize()) { if (!libcrypto_threading.Initialize()) {
LOG(ERROR) << "Could not initialize libcrypto threading."; LOG(ERROR) << "Could not initialize libcrypto threading.";
return 1; return kInternalError;
} }
// TODO(tinskip): Make InsertStreamDescriptor a member of // TODO(tinskip): Make InsertStreamDescriptor a member of
// StreamDescriptorList. // StreamDescriptorList.
StreamDescriptorList stream_descriptors; StreamDescriptorList stream_descriptors;
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
if (!InsertStreamDescriptor(argv[i], &stream_descriptors)) if (!InsertStreamDescriptor(argv[i], &stream_descriptors))
return 1; return kArgumentValidationFailed;
} }
return RunPackager(stream_descriptors) ? 0 : 1; return RunPackager(stream_descriptors) ? kSuccess : kPackagingFailed;
} }
} // namespace media } // namespace media

View File

@ -35,32 +35,29 @@ void DumpStreamInfo(const std::vector<MediaStream*>& streams) {
scoped_ptr<RequestSigner> CreateSigner() { scoped_ptr<RequestSigner> CreateSigner() {
scoped_ptr<RequestSigner> signer; scoped_ptr<RequestSigner> signer;
if (FLAGS_enable_widevine_encryption || FLAGS_enable_widevine_decryption) {
if (!FLAGS_aes_signing_key.empty()) { if (!FLAGS_aes_signing_key.empty()) {
signer.reset( signer.reset(AesRequestSigner::CreateSigner(
AesRequestSigner::CreateSigner(FLAGS_signer, FLAGS_aes_signing_key, FLAGS_signer, FLAGS_aes_signing_key, FLAGS_aes_signing_iv));
FLAGS_aes_signing_iv)); if (!signer) {
if (!signer) { LOG(ERROR) << "Cannot create an AES signer object from '"
LOG(ERROR) << "Cannot create an AES signer object from '" << FLAGS_aes_signing_key << "':'" << FLAGS_aes_signing_iv
<< FLAGS_aes_signing_key << "':'" << FLAGS_aes_signing_iv << "'.";
<< "'."; return scoped_ptr<RequestSigner>();
return scoped_ptr<RequestSigner>(); }
} } else if (!FLAGS_rsa_signing_key_path.empty()) {
} else if (!FLAGS_rsa_signing_key_path.empty()) { std::string rsa_private_key;
std::string rsa_private_key; if (!File::ReadFileToString(FLAGS_rsa_signing_key_path.c_str(),
if (!File::ReadFileToString(FLAGS_rsa_signing_key_path.c_str(), &rsa_private_key)) {
&rsa_private_key)) { LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path
LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path << "'.";
<< "'."; return scoped_ptr<RequestSigner>();
return scoped_ptr<RequestSigner>(); }
} signer.reset(RsaRequestSigner::CreateSigner(FLAGS_signer, rsa_private_key));
signer.reset( if (!signer) {
RsaRequestSigner::CreateSigner(FLAGS_signer, rsa_private_key)); LOG(ERROR) << "Cannot create a RSA signer object from '"
if (!signer) { << FLAGS_rsa_signing_key_path << "'.";
LOG(ERROR) << "Cannot create a RSA signer object from '" return scoped_ptr<RequestSigner>();
<< FLAGS_rsa_signing_key_path << "'.";
return scoped_ptr<RequestSigner>();
}
} }
} }
return signer.Pass(); return signer.Pass();

View File

@ -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 <stdio.h>
#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

View File

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

View File

@ -8,8 +8,9 @@
#include "packager/app/widevine_encryption_flags.h" #include "packager/app/widevine_encryption_flags.h"
#include "packager/app/validate_flag.h"
#include "packager/base/logging.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, DEFINE_bool(enable_widevine_encryption,
false, false,
@ -49,98 +50,105 @@ DEFINE_int32(crypto_period_duration,
"Crypto period duration in seconds. If it is non-zero, key " "Crypto period duration in seconds. If it is non-zero, key "
"rotation is enabled."); "rotation is enabled.");
namespace { namespace edash_packager {
static bool VerifyEncryptionAndDecryptionParams(const char* flag_name, bool ValidateWidevineCryptoFlags() {
const std::string& flag_value) { bool success = true;
DCHECK(flag_name);
const std::string flag_name_str = flag_name; const bool widevine_crypto =
bool is_common_param = (flag_name_str == "key_server_url") || FLAGS_enable_widevine_encryption || FLAGS_enable_widevine_decryption;
(flag_name_str == "signer"); const char widevine_crypto_label[] =
if (FLAGS_enable_widevine_encryption) { "--enable_widevine_encryption/decryption";
if (flag_value.empty()) { // key_server_url and signer (optional) are associated with
fprintf(stderr, // enable_widevine_encryption and enable_widevine_descryption.
"ERROR: %s required if enable_widevine_encryption is true\n", if (!ValidateFlag("key_server_url",
flag_name); FLAGS_key_server_url,
return false; widevine_crypto,
} false,
} else if (FLAGS_enable_widevine_decryption) { widevine_crypto_label)) {
if (is_common_param) { success = false;
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;
}
} }
return true; if (!ValidateFlag("signer",
} FLAGS_signer,
widevine_crypto,
static bool IsPositive(const char* flag_name, int flag_value) { true,
return flag_value > 0; widevine_crypto_label)) {
} success = false;
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;
}
} }
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 = } // namespace edash_packager
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

View File

@ -23,4 +23,12 @@ DECLARE_string(aes_signing_iv);
DECLARE_string(rsa_signing_key_path); DECLARE_string(rsa_signing_key_path);
DECLARE_int32(crypto_period_duration); 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_ #endif // APP_WIDEVINE_ENCRYPTION_FLAGS_H_

View File

@ -26,6 +26,8 @@
'app/packager_util.h', 'app/packager_util.h',
'app/stream_descriptor.cc', 'app/stream_descriptor.cc',
'app/stream_descriptor.h', 'app/stream_descriptor.h',
'app/validate_flag.cc',
'app/validate_flag.h',
'app/widevine_encryption_flags.cc', 'app/widevine_encryption_flags.cc',
'app/widevine_encryption_flags.h', 'app/widevine_encryption_flags.h',
], ],