Add support for Widevine ECM v3
Widevine ECM v3 is redesigned mainly based on protobuf, and supports new features including carrying fingerprinting and service blocking information. Existing clients must upgrade the Widevine CAS plugin to use the new ECM v3.
This commit is contained in:
113
common/BUILD
113
common/BUILD
@@ -16,7 +16,7 @@ filegroup(
|
||||
name = "binary_release_files",
|
||||
srcs = [
|
||||
"certificate_type.h",
|
||||
"default_device_security_profile_list.h",
|
||||
"hash_algorithm.h",
|
||||
"security_profile_list.h",
|
||||
"status.h",
|
||||
],
|
||||
@@ -96,6 +96,11 @@ cc_library(
|
||||
deps = [
|
||||
":client_id_util",
|
||||
":device_status_list",
|
||||
":error_space",
|
||||
":hash_algorithm",
|
||||
":hash_algorithm_util",
|
||||
":rsa_key",
|
||||
":status",
|
||||
"//base",
|
||||
"//external:protobuf",
|
||||
"@abseil_repo//absl/synchronization",
|
||||
@@ -103,6 +108,8 @@ cc_library(
|
||||
"//protos/public:device_certificate_status_cc_proto",
|
||||
"//protos/public:device_common_cc_proto",
|
||||
"//protos/public:device_security_profile_data_cc_proto",
|
||||
"//protos/public:device_security_profile_list_cc_proto",
|
||||
"//protos/public:errors_cc_proto",
|
||||
"//protos/public:provisioned_device_info_cc_proto",
|
||||
"//protos/public:security_profile_cc_proto",
|
||||
],
|
||||
@@ -114,47 +121,21 @@ cc_test(
|
||||
srcs = ["security_profile_list_test.cc"],
|
||||
deps = [
|
||||
":client_id_util",
|
||||
":error_space",
|
||||
":hash_algorithm",
|
||||
":hash_algorithm_util",
|
||||
":rsa_key",
|
||||
":rsa_test_keys",
|
||||
":security_profile_list",
|
||||
":status",
|
||||
"//base",
|
||||
"//external:protobuf",
|
||||
"//testing:gunit_main",
|
||||
"@abseil_repo//absl/memory",
|
||||
"//protos/public:device_common_cc_proto",
|
||||
"//protos/public:device_security_profile_data_cc_proto",
|
||||
"//protos/public:security_profile_cc_proto",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "default_device_security_profile_list",
|
||||
srcs = ["default_device_security_profile_list.cc"],
|
||||
hdrs = ["default_device_security_profile_list.h"],
|
||||
deps = [
|
||||
":client_id_util",
|
||||
":device_status_list",
|
||||
":security_profile_list",
|
||||
"//base",
|
||||
"//external:protobuf",
|
||||
"//protos/public:client_identification_cc_proto",
|
||||
"//protos/public:device_certificate_status_cc_proto",
|
||||
"//protos/public:device_common_cc_proto",
|
||||
"//protos/public:provisioned_device_info_cc_proto",
|
||||
"//protos/public:security_profile_cc_proto",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "default_device_security_profile_list_test",
|
||||
timeout = "short",
|
||||
srcs = ["default_device_security_profile_list_test.cc"],
|
||||
deps = [
|
||||
":client_id_util",
|
||||
":default_device_security_profile_list",
|
||||
"//base",
|
||||
"//external:protobuf",
|
||||
"//testing:gunit_main",
|
||||
"@abseil_repo//absl/memory",
|
||||
"//protos/public:device_common_cc_proto",
|
||||
"//protos/public:device_security_profile_list_cc_proto",
|
||||
"//protos/public:errors_cc_proto",
|
||||
"//protos/public:security_profile_cc_proto",
|
||||
],
|
||||
)
|
||||
@@ -189,8 +170,6 @@ cc_library(
|
||||
"certificate_client_cert.cc",
|
||||
"certificate_client_cert.h",
|
||||
"client_cert.cc",
|
||||
"dual_certificate_client_cert.cc",
|
||||
"dual_certificate_client_cert.h",
|
||||
"keybox_client_cert.cc",
|
||||
],
|
||||
hdrs = [
|
||||
@@ -426,7 +405,6 @@ cc_library(
|
||||
":sha_util",
|
||||
"//base",
|
||||
"@abseil_repo//absl/base:core_headers",
|
||||
"@abseil_repo//absl/strings",
|
||||
"//external:openssl",
|
||||
],
|
||||
)
|
||||
@@ -494,7 +472,7 @@ cc_test(
|
||||
"//base",
|
||||
"//testing:gunit",
|
||||
"//testing:gunit_main",
|
||||
"@abseil_repo//absl/strings",
|
||||
"//external:openssl",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -871,6 +849,7 @@ cc_library(
|
||||
"@abseil_repo//absl/base:core_headers",
|
||||
"@abseil_repo//absl/strings",
|
||||
"@abseil_repo//absl/synchronization",
|
||||
"//external:openssl",
|
||||
"//protos/public:client_identification_cc_proto",
|
||||
"//protos/public:errors_cc_proto",
|
||||
"//protos/public:remote_attestation_cc_proto",
|
||||
@@ -944,11 +923,13 @@ cc_library(
|
||||
srcs = ["x509_cert.cc"],
|
||||
hdrs = ["x509_cert.h"],
|
||||
deps = [
|
||||
":ec_key",
|
||||
":openssl_util",
|
||||
":rsa_key",
|
||||
":status",
|
||||
"//base",
|
||||
"@abseil_repo//absl/base:core_headers",
|
||||
"@abseil_repo//absl/memory",
|
||||
"@abseil_repo//absl/strings",
|
||||
"@abseil_repo//absl/synchronization",
|
||||
"//external:openssl",
|
||||
@@ -973,6 +954,7 @@ cc_test(
|
||||
srcs = ["x509_cert_test.cc"],
|
||||
deps = [
|
||||
":rsa_key",
|
||||
":status",
|
||||
":test_utils",
|
||||
":x509_cert",
|
||||
"//testing:gunit_main",
|
||||
@@ -1174,6 +1156,16 @@ cc_library(
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "raw_ec_key_util",
|
||||
srcs = ["raw_ec_key_util.cc"],
|
||||
hdrs = ["raw_ec_key_util.h"],
|
||||
deps = [
|
||||
":x509_cert",
|
||||
"//base",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "hash_algorithm_util_test",
|
||||
srcs = ["hash_algorithm_util_test.cc"],
|
||||
@@ -1183,3 +1175,46 @@ cc_test(
|
||||
"//testing:gunit_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "raw_ec_key_util_test",
|
||||
srcs = ["raw_ec_key_util_test.cc"],
|
||||
deps = [
|
||||
":ec_key",
|
||||
":ec_test_keys",
|
||||
":raw_ec_key_util",
|
||||
":rsa_test_keys",
|
||||
":x509_test_certificates",
|
||||
"//base",
|
||||
"//testing:gunit_main",
|
||||
"@abseil_repo//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "x509_test_certificates",
|
||||
testonly = 1,
|
||||
srcs = ["x509_test_certificates.cc"],
|
||||
hdrs = ["x509_test_certificates.h"],
|
||||
deps = [
|
||||
"//base",
|
||||
"@abseil_repo//absl/strings",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "remote_attestation_verifier_test",
|
||||
srcs = ["remote_attestation_verifier_test.cc"],
|
||||
deps = [
|
||||
":drm_service_certificate",
|
||||
":remote_attestation_verifier",
|
||||
":status",
|
||||
":x509_test_certificates",
|
||||
"//testing:gunit_main",
|
||||
"@abseil_repo//absl/memory",
|
||||
"@abseil_repo//absl/strings",
|
||||
"//protos/public:client_identification_cc_proto",
|
||||
"//protos/public:errors_cc_proto",
|
||||
"//protos/public:remote_attestation_cc_proto",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "openssl/aes.h"
|
||||
#include "openssl/cmac.h"
|
||||
#include "openssl/digest.h"
|
||||
#include "openssl/evp.h"
|
||||
#include "openssl/hmac.h"
|
||||
#include "openssl/sha.h"
|
||||
@@ -59,12 +60,28 @@ const uint32_t kCBCSSchemeID =
|
||||
// Creates a SHA-256 HMAC signature for the given message.
|
||||
std::string CreateSignatureHmacSha256(absl::string_view key,
|
||||
absl::string_view message) {
|
||||
unsigned char digest[SHA256_DIGEST_LENGTH];
|
||||
return CreateSignatureHmac(EVP_sha256(), digest, key, message);
|
||||
}
|
||||
|
||||
// Creates a SHA-384 HMAC signature for the given message.
|
||||
std::string CreateSignatureHmacSha384(absl::string_view key,
|
||||
absl::string_view message) {
|
||||
unsigned char digest[SHA384_DIGEST_LENGTH];
|
||||
return CreateSignatureHmac(EVP_sha384(), digest, key, message);
|
||||
}
|
||||
|
||||
std::string CreateSignatureHmac(const EVP_MD* hash_algorithm,
|
||||
unsigned char* digest, absl::string_view key,
|
||||
absl::string_view message) {
|
||||
if (hash_algorithm == nullptr || digest == nullptr) {
|
||||
return "";
|
||||
}
|
||||
HMAC_CTX ctx;
|
||||
HMAC_CTX_init(&ctx);
|
||||
HMAC_Init(&ctx, key.data(), key.size(), EVP_sha256());
|
||||
HMAC_Init(&ctx, key.data(), key.size(), hash_algorithm);
|
||||
HMAC_Update(&ctx, reinterpret_cast<const unsigned char*>(message.data()),
|
||||
message.size());
|
||||
unsigned char digest[SHA256_DIGEST_LENGTH];
|
||||
unsigned int digest_len;
|
||||
HMAC_Final(&ctx, digest, &digest_len);
|
||||
HMAC_CTX_cleanup(&ctx);
|
||||
@@ -79,20 +96,18 @@ bool VerifySignatureHmacSha256(absl::string_view key,
|
||||
return CreateSignatureHmacSha256(key, message) == signature;
|
||||
}
|
||||
|
||||
// Compares the SHA-384 HMAC against the provided signature.
|
||||
bool VerifySignatureHmacSha384(absl::string_view key,
|
||||
absl::string_view signature,
|
||||
absl::string_view message) {
|
||||
return CreateSignatureHmacSha384(key, message) == signature;
|
||||
}
|
||||
|
||||
// Creates a SHA-1 HMAC signature for the given message.
|
||||
std::string CreateSignatureHmacSha1(absl::string_view key,
|
||||
absl::string_view message) {
|
||||
HMAC_CTX ctx;
|
||||
HMAC_CTX_init(&ctx);
|
||||
HMAC_Init(&ctx, key.data(), key.size(), EVP_sha1());
|
||||
HMAC_Update(&ctx, reinterpret_cast<const unsigned char*>(message.data()),
|
||||
message.size());
|
||||
unsigned char digest[SHA_DIGEST_LENGTH];
|
||||
unsigned int digest_len;
|
||||
HMAC_Final(&ctx, digest, &digest_len);
|
||||
HMAC_CTX_cleanup(&ctx);
|
||||
std::string s(reinterpret_cast<char*>(digest), digest_len);
|
||||
return s;
|
||||
return CreateSignatureHmac(EVP_sha1(), digest, key, message);
|
||||
}
|
||||
|
||||
// Compares the SHA-1 HMAC against the provided signature.
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/escaping.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "openssl/digest.h"
|
||||
|
||||
namespace widevine {
|
||||
namespace crypto_util {
|
||||
@@ -64,12 +66,27 @@ std::string DeriveSigningKey(absl::string_view key, absl::string_view context,
|
||||
std::string CreateSignatureHmacSha256(absl::string_view key,
|
||||
absl::string_view message);
|
||||
|
||||
// Helper function to create a SHA-384 HMAC signature for the given message.
|
||||
std::string CreateSignatureHmacSha384(absl::string_view key,
|
||||
absl::string_view message);
|
||||
// Helper function to create a HMAC signature for the specified hash algorithm
|
||||
// and message.
|
||||
std::string CreateSignatureHmac(const EVP_MD* hash_algorithm,
|
||||
unsigned char* digest, absl::string_view key,
|
||||
absl::string_view message);
|
||||
|
||||
// Helper function which compares the SHA-256 HMAC against the provided
|
||||
// signature.
|
||||
bool VerifySignatureHmacSha256(absl::string_view key,
|
||||
absl::string_view signature,
|
||||
absl::string_view message);
|
||||
|
||||
// Helper function which compares the SHA-384 HMAC against the provided
|
||||
// signature.
|
||||
bool VerifySignatureHmacSha384(absl::string_view key,
|
||||
absl::string_view signature,
|
||||
absl::string_view message);
|
||||
|
||||
// Helper function to create a SHA-1 HMAC signature for the given message.
|
||||
std::string CreateSignatureHmacSha1(absl::string_view key,
|
||||
absl::string_view message);
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2020 Google LLC.
|
||||
//
|
||||
// This software is licensed under the terms defined in the Widevine Master
|
||||
// License Agreement. For a copy of this agreement, please contact
|
||||
// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Description:
|
||||
// Container of Widevine default security profiless.
|
||||
|
||||
#ifndef COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_
|
||||
#define COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_
|
||||
|
||||
#include "common/security_profile_list.h"
|
||||
|
||||
namespace widevine {
|
||||
|
||||
class DefaultDeviceSecurityProfileList : public SecurityProfileList {
|
||||
public:
|
||||
DefaultDeviceSecurityProfileList();
|
||||
~DefaultDeviceSecurityProfileList() override {}
|
||||
|
||||
// Initialize the security profile list. The list is initially empty, this
|
||||
// function will populate the list with default profiles. The size of the
|
||||
// list is returned.
|
||||
int Init() override;
|
||||
|
||||
private:
|
||||
// Initialize the list with Widevine default profiles. The size of the
|
||||
// profile list after the additions is returned.
|
||||
virtual int AddDefaultProfiles();
|
||||
virtual int GetDefaultProfileStrings(
|
||||
std::vector<std::string>* default_profile_strings) const;
|
||||
};
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
#endif // COMMON_DEFAULT_DEVICE_SECURITY_PROFILE_LIST_H_
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#include "common/ec_key.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "glog/logging.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "openssl/base.h"
|
||||
@@ -203,6 +205,34 @@ bool ECPrivateKey::SerializedKey(std::string* serialized_key) const {
|
||||
return ec_util::SerializeECPrivateKey(key_.get(), serialized_key);
|
||||
}
|
||||
|
||||
bool ECPrivateKey::GetRawPrivateKey(std::string* raw_private_key) const {
|
||||
if (raw_private_key == nullptr) {
|
||||
LOG(WARNING) << "|raw_private_key| cannot be nullptr.";
|
||||
return false;
|
||||
}
|
||||
const EC_GROUP* group = EC_KEY_get0_group(key());
|
||||
if (group == nullptr) {
|
||||
LOG(WARNING) << "Failed to load EC key group.";
|
||||
return false;
|
||||
}
|
||||
int key_size_bits = EC_GROUP_get_degree(group);
|
||||
if (key_size_bits == 0) {
|
||||
LOG(WARNING) << "Key size is 0.";
|
||||
return false;
|
||||
}
|
||||
const BIGNUM* key_bn = EC_KEY_get0_private_key(key());
|
||||
int key_size_bytes = (key_size_bits + 7) / 8;
|
||||
std::vector<uint8_t> tmp_raw_private_key_data(key_size_bytes);
|
||||
int num_bytes = BN_bn2bin(key_bn, tmp_raw_private_key_data.data());
|
||||
if (num_bytes != key_size_bytes) {
|
||||
LOG(WARNING) << "Failed to convert EC private key BIGNUM to binary data.";
|
||||
return false;
|
||||
}
|
||||
raw_private_key->assign(tmp_raw_private_key_data.begin(),
|
||||
tmp_raw_private_key_data.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
ECPublicKey::ECPublicKey(EC_KEY* ec_key) : key_(ec_key) {
|
||||
CHECK(key() != nullptr);
|
||||
CHECK(EC_KEY_get0_private_key(key()) == nullptr);
|
||||
@@ -310,4 +340,24 @@ bool ECPublicKey::GetPointEncodedKey(std::string* encoded_key) const {
|
||||
return ec_util::GetPublicKeyPoint(key_.get(), encoded_key);
|
||||
}
|
||||
|
||||
bool ECPublicKey::GetRawPublicKey(std::string* raw_public_key) const {
|
||||
if (raw_public_key == nullptr) {
|
||||
LOG(WARNING) << "|raw_public_key| cannot be nullptr.";
|
||||
return false;
|
||||
}
|
||||
std::string tmp_raw_public_key;
|
||||
if (!ec_util::GetPublicKeyPoint(key(), &tmp_raw_public_key) ||
|
||||
tmp_raw_public_key.empty()) {
|
||||
LOG(WARNING) << "Failed to encoded EC_KEY";
|
||||
}
|
||||
CHECK_EQ(tmp_raw_public_key[0], POINT_CONVERSION_UNCOMPRESSED);
|
||||
// Public key is X9.62 uncompressed format. Expected structure is <tag><X><Y>,
|
||||
// where tag = 0x04 indicating uncompressed, and X and Y lengths are equal but
|
||||
// dependent on ECC curve. Tag is removed because Intel Sigma 2.1.0 library
|
||||
// requires only X and Y bytes.
|
||||
raw_public_key->assign(tmp_raw_public_key.begin() + 1,
|
||||
tmp_raw_public_key.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
@@ -83,6 +83,11 @@ class ECPrivateKey {
|
||||
|
||||
virtual bool SerializedKey(std::string* serialized_key) const;
|
||||
|
||||
// Gets raw private key bytes.
|
||||
// |raw_private_key| is where the raw bytes are stored.
|
||||
// Returns true on success and false on error.
|
||||
virtual bool GetRawPrivateKey(std::string* raw_private_key) const;
|
||||
|
||||
private:
|
||||
friend class ECPublicKey;
|
||||
|
||||
@@ -135,6 +140,11 @@ class ECPublicKey {
|
||||
// octets for the X and Y coordinates.
|
||||
virtual bool GetPointEncodedKey(std::string* encoded_key) const;
|
||||
|
||||
// Gets raw public key bytes.
|
||||
// |raw_public_key| is where the raw bytes are stored.
|
||||
// Returns true on success and false on error.
|
||||
virtual bool GetRawPublicKey(std::string* raw_public_key) const;
|
||||
|
||||
private:
|
||||
friend class ECPrivateKey;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "glog/logging.h"
|
||||
#include "openssl/bn.h"
|
||||
#include "openssl/digest.h"
|
||||
#include "openssl/err.h"
|
||||
#include "openssl/evp.h"
|
||||
#include "openssl/rsa.h"
|
||||
@@ -67,6 +68,32 @@ std::string GetMessageDigest(const std::string& message,
|
||||
return "";
|
||||
}
|
||||
|
||||
const EVP_MD* GetHashMd(widevine::HashAlgorithm hash_algorithm) {
|
||||
switch (hash_algorithm) {
|
||||
case widevine::HashAlgorithm::kUnspecified:
|
||||
case widevine::HashAlgorithm::kSha1:
|
||||
return EVP_sha1();
|
||||
case widevine::HashAlgorithm::kSha256:
|
||||
return EVP_sha256();
|
||||
}
|
||||
LOG(FATAL) << "Unexpected hash algorithm: "
|
||||
<< static_cast<int>(hash_algorithm);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IsMessageTooSmall(const std::string& message) {
|
||||
DCHECK(!message.empty());
|
||||
// The most significant byte is encoded first in the message. See
|
||||
// https://tools.ietf.org/html/rfc8017. To make sure the big number is greater
|
||||
// than 2^64, we need to make sure there is at least a non-zero number in the
|
||||
// first "LENGTH_IN_BITS - 64" bits of the message,
|
||||
// i.e. "LENGTH_IN_BYTES - 8" bytes of the message.
|
||||
const int kMinimumSizeInBytes = 8;
|
||||
for (int i = 0; i < message.length() - kMinimumSizeInBytes; i++) {
|
||||
if (message[i] != 0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace widevine {
|
||||
@@ -117,7 +144,6 @@ bool RsaPrivateKey::Decrypt(const std::string& encrypted_message,
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RsaPrivateKey::GenerateSignature(const std::string& message,
|
||||
HashAlgorithm hash_algorithm,
|
||||
std::string* signature) const {
|
||||
@@ -134,12 +160,18 @@ bool RsaPrivateKey::GenerateSignature(const std::string& message,
|
||||
return false;
|
||||
}
|
||||
|
||||
const EVP_MD* hash = GetHashMd(hash_algorithm);
|
||||
if (hash == nullptr) {
|
||||
LOG(ERROR) << "No hash md";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add PSS padding.
|
||||
size_t rsa_size = RSA_size(key_);
|
||||
std::string padded_digest(rsa_size, 0);
|
||||
if (!RSA_padding_add_PKCS1_PSS_mgf1(
|
||||
key_, reinterpret_cast<unsigned char*>(&padded_digest[0]),
|
||||
reinterpret_cast<unsigned char*>(&message_digest[0]), EVP_sha1(),
|
||||
reinterpret_cast<unsigned char*>(&message_digest[0]), hash,
|
||||
EVP_sha1(), kPssSaltLength)) {
|
||||
LOG(ERROR) << "RSA padding failure: "
|
||||
<< OpenSSLErrorString(ERR_get_error());
|
||||
@@ -222,17 +254,22 @@ bool RsaPublicKey::Encrypt(const std::string& clear_message,
|
||||
}
|
||||
size_t rsa_size = RSA_size(key_);
|
||||
encrypted_message->assign(rsa_size, 0);
|
||||
if (RSA_public_encrypt(
|
||||
clear_message.size(),
|
||||
const_cast<unsigned char*>(
|
||||
reinterpret_cast<const unsigned char*>(clear_message.data())),
|
||||
reinterpret_cast<unsigned char*>(&(*encrypted_message)[0]), key_,
|
||||
RSA_PKCS1_OAEP_PADDING) != static_cast<int>(rsa_size)) {
|
||||
LOG(ERROR) << "RSA public encrypt failure: "
|
||||
<< OpenSSLErrorString(ERR_get_error());
|
||||
return false;
|
||||
const int kRetryAttempt = 1;
|
||||
for (int i = 0; i < 1 + kRetryAttempt; i++) {
|
||||
if (RSA_public_encrypt(
|
||||
clear_message.size(),
|
||||
const_cast<unsigned char*>(
|
||||
reinterpret_cast<const unsigned char*>(clear_message.data())),
|
||||
reinterpret_cast<unsigned char*>(&(*encrypted_message)[0]), key_,
|
||||
RSA_PKCS1_OAEP_PADDING) != static_cast<int>(rsa_size)) {
|
||||
LOG(ERROR) << "RSA public encrypt failure: "
|
||||
<< OpenSSLErrorString(ERR_get_error());
|
||||
return false;
|
||||
}
|
||||
if (!IsMessageTooSmall(*encrypted_message)) return true;
|
||||
}
|
||||
return true;
|
||||
LOG(ERROR) << "RSA public encryption randomness error";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RsaPublicKey::VerifySignature(const std::string& message,
|
||||
@@ -261,18 +298,23 @@ bool RsaPublicKey::VerifySignature(const std::string& message,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hash the message using SHA1 using corresponding hash algorithm.
|
||||
// Hash the message using the corresponding hash algorithm.
|
||||
std::string message_digest = GetMessageDigest(message, hash_algorithm);
|
||||
if (message_digest.empty()) {
|
||||
LOG(ERROR) << "Empty message digest";
|
||||
return false;
|
||||
}
|
||||
|
||||
const EVP_MD* hash = GetHashMd(hash_algorithm);
|
||||
if (hash == nullptr) {
|
||||
LOG(ERROR) << "No hash md";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify PSS padding.
|
||||
if (RSA_verify_PKCS1_PSS_mgf1(
|
||||
key_, reinterpret_cast<unsigned char*>(&message_digest[0]),
|
||||
EVP_sha1(), EVP_sha1(),
|
||||
reinterpret_cast<unsigned char*>(&padded_digest[0]),
|
||||
key_, reinterpret_cast<unsigned char*>(&message_digest[0]), hash,
|
||||
EVP_sha1(), reinterpret_cast<unsigned char*>(&padded_digest[0]),
|
||||
kPssSaltLength) == 0) {
|
||||
LOG(ERROR) << "RSA Verify PSS padding failure: "
|
||||
<< OpenSSLErrorString(ERR_get_error());
|
||||
|
||||
@@ -15,25 +15,32 @@
|
||||
#define COMMON_SECURITY_PROFILE_LIST_H_
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "common/hash_algorithm.h"
|
||||
#include "common/status.h"
|
||||
#include "protos/public/client_identification.pb.h"
|
||||
#include "protos/public/device_security_profile_data.pb.h"
|
||||
#include "protos/public/device_security_profile_list.pb.h"
|
||||
#include "protos/public/provisioned_device_info.pb.h"
|
||||
#include "protos/public/security_profile.pb.h"
|
||||
|
||||
namespace widevine {
|
||||
using ClientCapabilities = ClientIdentification::ClientCapabilities;
|
||||
|
||||
const char kDefaultProfileOwnerName[] = "Widevine";
|
||||
|
||||
// The SecurityProfileList will hold all security profiles. During license
|
||||
// acquisition, information from the client and information from the server are
|
||||
// combined to deternmine the device's security profile level.
|
||||
|
||||
// TODO(user): Clean up the virtual/protected functions once subclass
|
||||
// default_device_security_profile_list gets removed.
|
||||
class SecurityProfileList {
|
||||
public:
|
||||
explicit SecurityProfileList(const std::string& profile_namespace);
|
||||
virtual ~SecurityProfileList() {}
|
||||
|
||||
// Initialize the security profile list. The size of the profile list is
|
||||
// returned.
|
||||
// Initialize the security profile list with Widevine default profiles. The
|
||||
// size of the profile list is returned.
|
||||
virtual int Init();
|
||||
|
||||
// Add the specified profile to the existing list of profiles. Returns true
|
||||
@@ -45,7 +52,7 @@ class SecurityProfileList {
|
||||
// The number of profiles is returned.
|
||||
virtual int GetQualifiedProfilesFromSpecifiedProfiles(
|
||||
const std::vector<std::string>& profiles_to_check,
|
||||
const ClientIdentification& client_id,
|
||||
const std::string& owner, const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
std::vector<std::string>* qualified_profiles) const;
|
||||
|
||||
@@ -53,14 +60,28 @@ class SecurityProfileList {
|
||||
// requirements for the this device. The number of profiles is returned.
|
||||
virtual int GetQualifiedProfiles(
|
||||
const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
const ProvisionedDeviceInfo& device_info, const std::string& owner,
|
||||
std::vector<std::string>* qualified_profiles) const;
|
||||
|
||||
// Return true if a profile exist matching the specified |name|.
|
||||
// |security_profile| is owned by the caller and is populated if a profile
|
||||
// exist.
|
||||
bool GetProfileByName(const std::string& name,
|
||||
SecurityProfile* security_profile) const;
|
||||
// Return true if a profile exist matching the specified parameters {|name|,
|
||||
// |owner|}. |security_profiles| is owned by the caller and is populated if
|
||||
// one or more profile exist. For default DSP, the output profiles should
|
||||
// contain single record. For custom DSP, it may contain multiple records
|
||||
// since active dsp and inactive dsp could share the same dsp_name under the
|
||||
// same owner.
|
||||
bool GetProfileByNameAndOwner(
|
||||
const std::string& name, const std::string& owner,
|
||||
std::vector<SecurityProfile>* security_profiles) const;
|
||||
|
||||
// Populates |security_profiles| owned by the content owner.
|
||||
int GetProfilesByOwner(const std::string& owner,
|
||||
std::vector<SecurityProfile>* security_profiles) const;
|
||||
|
||||
// Populates |owner_list| for security profiles. |is_default_dsp| boolean
|
||||
// indicates the owner_list for default dsp or custom dsp.
|
||||
int GetProfilesOwnerList(const bool is_default_dsp,
|
||||
std::vector<std::string>* owner_list) const;
|
||||
|
||||
// Return the device security capabilities. |drm_info| is populated with
|
||||
// data from |client_id| and |device_info|. |drm_info| must not be null and
|
||||
// is owned by the caller.
|
||||
@@ -74,10 +95,33 @@ class SecurityProfileList {
|
||||
// Return a list of profile names.
|
||||
virtual void GetProfileNames(std::vector<std::string>* profile_names) const;
|
||||
|
||||
// Deserialized SignedDeviceSecurityProfiles for custom DSPs.
|
||||
static Status DeserializeSignedDeviceSecurityProfiles(
|
||||
const std::string& serialized_signed_device_security_profiles,
|
||||
std::string* serialized_device_security_profiles,
|
||||
HashAlgorithm* hash_algorithm, std::string* signature);
|
||||
|
||||
// Validate signature and update security profile list for custom dsps.
|
||||
Status ValidateAndUpdateProfileList(
|
||||
const std::string& root_certificate_public_key,
|
||||
const std::string& serialized_device_security_profiles,
|
||||
HashAlgorithm hash_algorithm, const std::string& signature,
|
||||
int* added_profile_num);
|
||||
|
||||
protected:
|
||||
void ClearAllProfiles();
|
||||
|
||||
private:
|
||||
// Add Widevine default profiles into profile_list. The number of added
|
||||
// default profiles will be returned.
|
||||
virtual int AddDefaultProfiles();
|
||||
// Add Widevine custom profiles into profile_list. The number of added custom
|
||||
// profiles will be returned.
|
||||
virtual int AddCustomProfiles(
|
||||
const DeviceSecurityProfileList& device_security_profile_list);
|
||||
virtual int GetDefaultProfileStrings(
|
||||
std::vector<std::string>* default_profile_strings) const;
|
||||
|
||||
bool DoesProfileQualify(const SecurityProfile& profile,
|
||||
const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info) const;
|
||||
@@ -87,9 +131,19 @@ class SecurityProfileList {
|
||||
bool IsProfileActive(const SecurityProfile& profile,
|
||||
int64_t current_time_seconds) const;
|
||||
|
||||
bool InsertProfileLocked(const SecurityProfile& profile_to_insert)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
// Return true if a profile already exists in the profile_list.
|
||||
bool DoesProfileExistLocked(const SecurityProfile& profile) const
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
|
||||
void ClearAllDefaultProfilesLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
void ClearAllCustomProfilesLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
||||
mutable absl::Mutex mutex_;
|
||||
// Security profiles
|
||||
std::string profile_namespace_;
|
||||
// TODO(user): Modify as Map<owner, DSPs>.
|
||||
std::vector<SecurityProfile> security_profiles_ ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user