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:
parent
e72d12c54f
commit
dd2ada2026
|
@ -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"
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -35,32 +35,29 @@ void DumpStreamInfo(const std::vector<MediaStream*>& streams) {
|
|||
|
||||
scoped_ptr<RequestSigner> CreateSigner() {
|
||||
scoped_ptr<RequestSigner> 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<RequestSigner>();
|
||||
}
|
||||
} 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<RequestSigner>();
|
||||
}
|
||||
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<RequestSigner>();
|
||||
}
|
||||
|
||||
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<RequestSigner>();
|
||||
}
|
||||
} 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<RequestSigner>();
|
||||
}
|
||||
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<RequestSigner>();
|
||||
}
|
||||
}
|
||||
return signer.Pass();
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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',
|
||||
],
|
||||
|
|
Loading…
Reference in New Issue