Add a few more checks for "key length" and "iv length".

-------------
Pad key value when crypto_mode is DVB_CSA, so that the key length is always 16 bytes.

-------------
Minor comment and example code update.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=219860612
This commit is contained in:
Fang Yu
2018-11-02 14:22:06 -07:00
parent 5ac3c5a95b
commit 0441c0b8d4
5 changed files with 128 additions and 38 deletions

View File

@@ -60,6 +60,7 @@ static constexpr int kNumBitsUnusedField = 6;
static constexpr size_t kKeyIdSizeBytes = 16;
static constexpr size_t kKeyDataSizeBytes = 16;
static constexpr size_t kWrappedKeyIvSizeBytes = 16;
static constexpr size_t kWrappingKeySizeBytes = 32; // entitlement key
static constexpr size_t kWrappingKeyIvSizeBytes = 16;
// BitField constants for the ECM payload
@@ -302,21 +303,39 @@ util::Status CasEcm::WrapEntitledKeys(
if (entitled_key->wrapped_key_iv.empty()) {
CHECK(RandomBytes(kWrappedKeyIvSizeBytes, &entitled_key->wrapped_key_iv));
}
entitled_key->wrapped_key_value =
util::Status status =
WrapKey(entitlement_key->key_value, entitled_key->wrapped_key_iv,
entitled_key->key_value);
entitled_key->key_value, &entitled_key->wrapped_key_value);
if (!status.ok()) {
return status;
}
entitlement_key++;
}
return util::OkStatus();
}
std::string CasEcm::WrapKey(const std::string& wrapping_key, const std::string& iv,
const std::string& key_value) {
if (iv.size() != kWrappingKeyIvSizeBytes) {
LOG(WARNING) << "Incorrect iv size for WrapKey(): " << iv.size();
util::Status CasEcm::WrapKey(const std::string& wrapping_key,
const std::string& wrapping_iv, const std::string& key_value,
std::string* wrapped_key) {
util::Status status = ValidateKeyValue(wrapping_key, kWrappingKeySizeBytes);
if (!status.ok()) {
return status;
}
status = ValidateIv(wrapping_iv, kWrappingKeyIvSizeBytes);
if (!status.ok()) {
return status;
}
status = ValidateKeyValue(key_value, kKeyDataSizeBytes);
if (!status.ok()) {
return status;
}
// Wrapped key IV is always 16 bytes.
return crypto_util::EncryptAesCbcNoPad(wrapping_key, iv, key_value);
*wrapped_key =
crypto_util::EncryptAesCbcNoPad(wrapping_key, wrapping_iv, key_value);
if (wrapped_key->empty()) {
return util::Status(util::error::INTERNAL, "Failed to wrap key");
}
return util::OkStatus();
}
util::Status CasEcm::ValidateKeys(const std::vector<EntitledKeyInfo*>& keys) {
@@ -326,6 +345,10 @@ util::Status CasEcm::ValidateKeys(const std::vector<EntitledKeyInfo*>& keys) {
if (!status.ok()) {
return status;
}
status = ValidateKeyValue(key->key_value, kKeyDataSizeBytes);
if (!status.ok()) {
return status;
}
status = ValidateIv(key->content_iv, content_iv_size_);
if (!status.ok()) {
return status;
@@ -342,7 +365,7 @@ util::Status CasEcm::ValidateWrappedKeys(
if (!status.ok()) {
return status;
}
status = ValidateKeyValue(key->wrapped_key_value);
status = ValidateKeyValue(key->wrapped_key_value, kKeyDataSizeBytes);
if (!status.ok()) {
LOG(ERROR) << "Wrapped key is bad.";
return status;
@@ -366,9 +389,10 @@ util::Status CasEcm::ValidateKeyId(const std::string& key_id) {
return util::OkStatus();
}
util::Status CasEcm::ValidateKeyValue(const std::string& key_value) {
if (key_value.size() != kKeyDataSizeBytes) {
util::Status(
util::Status CasEcm::ValidateKeyValue(const std::string& key_value,
size_t key_value_size) {
if (key_value.size() != key_value_size) {
return util::Status(
util::error::INVALID_ARGUMENT,
absl::StrCat("Key is wrong size (", key_value.size(), " bytes)."));
}
@@ -390,6 +414,9 @@ std::string CasEcm::SerializeEcm(const std::vector<EntitledKeyInfo*>& keys) {
generation());
std::bitset<kNumBitsDecryptModeField> decrypt_mode(
static_cast<int>(crypto_mode()));
if (decrypt_mode.to_string() == "00") {
LOG(FATAL) << "Invalid decrypt mode \"00\"";
}
std::bitset<kNumBitsRotationEnabledField> rotation_enabled(
RotationFieldValue(paired_keys_required()));
std::bitset<kNumBitsWrappedKeyIvSizeField> wrapped_key_iv_size(
@@ -490,6 +517,10 @@ util::Status CasEcm::ParseEntitlementResponse(const std::string& response_string
EntitlementKeyInfo ekey;
ekey.key_id = key.key_id();
ekey.key_value = key.key();
util::Status status = ValidateKeyValue(key.key(), kWrappingKeySizeBytes);
if (!status.ok()) {
return status;
}
// Using only keys with correct KeySlot
if (!key.has_key_slot()) {

View File

@@ -198,17 +198,19 @@ class CasEcm {
const std::vector<EntitledKeyInfo*>& keys, const std::string& track_type,
std::string* serialized_ecm, uint32_t* generation);
// Wrap a |key_value| using |wrapping_key| (entitlement key) and |iv|.
// Returns the resulting wrapped key.
virtual std::string WrapKey(const std::string& wrapping_key, const std::string& iv,
const std::string& key_value);
// Wrap |key_value| using |wrapping_key| (entitlement key) and |wrapping_iv|.
// Returns the resulting wrapped key in |wrapped_key|.
// Return a status indicating whether there has been any error.
virtual util::Status WrapKey(const std::string& wrapping_key,
const std::string& wrapping_iv,
const std::string& key_value, std::string* wrapped_key);
virtual util::Status ValidateKeys(const std::vector<EntitledKeyInfo*>& keys);
virtual util::Status ValidateWrappedKeys(
const std::vector<EntitledKeyInfo*>& keys);
util::Status ValidateKeyId(const std::string& key_id);
util::Status ValidateKeyValue(const std::string& key_value);
util::Status ValidateKeyValue(const std::string& key_value, size_t key_value_size);
util::Status ValidateIv(const std::string& iv, size_t size);
// TODO(user): need unit tests for CreateEntitlementRequest.