Fix media_cas_proxy_sdk build issue.

Add example binary for testing building the SDK after 'git clone' from our repo.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=227583629
This commit is contained in:
Fang Yu
2019-01-02 14:37:34 -08:00
parent a991e2dbb3
commit 79f14e6e0b
76 changed files with 2072 additions and 1513 deletions

View File

@@ -16,6 +16,8 @@ filegroup(
name = "binary_release_files",
srcs = [
"certificate_type.h",
"drm_root_certificate.h",
"status.h",
],
)
@@ -31,6 +33,27 @@ cc_library(
hdrs = ["certificate_type.h"],
)
cc_library(
name = "status",
srcs = ["status.cc"],
hdrs = ["status.h"],
deps = [
"//base",
"@abseil_repo//absl/base:core_headers",
"@abseil_repo//absl/strings",
"//util:error_space",
],
)
cc_test(
name = "status_test",
srcs = ["status_test.cc"],
deps = [
":status",
"//testing:gunit_main",
],
)
cc_library(
name = "client_cert",
srcs = ["client_cert.cc"],
@@ -41,7 +64,9 @@ cc_library(
":error_space",
":random_util",
":rsa_key",
":sha_util",
":signing_key_util",
":status",
":wvm_token_handler",
"//base",
"//strings",
@@ -49,7 +74,6 @@ cc_library(
"@abseil_repo//absl/synchronization",
"@abseil_repo//absl/time",
"//util/gtl:map_util",
"//util:status",
"//protos/public:client_identification_proto",
"//protos/public:drm_certificate_proto",
"//protos/public:errors_proto",
@@ -65,6 +89,8 @@ cc_test(
":client_cert",
":drm_root_certificate",
":error_space",
":sha_util",
":test_drm_certificates",
":wvm_test_keys",
"//base",
"//strings",
@@ -88,15 +114,16 @@ cc_library(
":client_cert",
":crypto_util",
":drm_root_certificate",
":drm_service_certificate",
":error_space",
":random_util",
":rsa_key",
":signing_key_util",
":status",
"//base",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//util/gtl:map_util",
"//util:status",
"//protos/public:client_identification_proto",
"//protos/public:device_certificate_status_proto",
"//protos/public:errors_proto",
@@ -132,12 +159,12 @@ cc_library(
":error_space",
":rsa_key",
":sha_util",
":status",
"//base",
"@abseil_repo//absl/memory",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//external:openssl",
"//util:status",
"//protos/public:drm_certificate_proto",
"//protos/public:errors_proto",
"//protos/public:signed_drm_certificate_proto",
@@ -171,9 +198,9 @@ cc_library(
":aes_cbc_util",
":drm_service_certificate",
":error_space",
":status",
"//base",
"@abseil_repo//absl/strings",
"//util:status",
"//protos/public:client_identification_proto",
"//protos/public:errors_proto",
],
@@ -393,8 +420,8 @@ cc_library(
":aes_cbc_util",
":rsa_key",
":sha_util",
":status",
"//base",
"//util:status",
],
)
@@ -442,12 +469,12 @@ cc_library(
":aes_cbc_util",
":ecb_util",
":sha_util",
":status",
"//base",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//util/endian",
"//util/gtl:map_util",
"//util:status",
],
)
@@ -481,7 +508,7 @@ cc_library(
srcs = ["error_space.cc"],
hdrs = ["error_space.h"],
deps = [
"//util:status",
"//util:error_space",
"//util:proto_status",
"//protos/public:errors_proto",
],
@@ -496,11 +523,11 @@ cc_library(
":drm_service_certificate",
":error_space",
":rsa_key",
":status",
":x509_cert",
"//base",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//util:status",
"//protos/public:client_identification_proto",
"//protos/public:errors_proto",
"//protos/public:remote_attestation_proto",
@@ -518,11 +545,11 @@ cc_library(
":error_space",
":rsa_key",
":rsa_util",
":status",
"//base",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//util/gtl:map_util",
"//util:status",
"//protos/public:client_identification_proto",
"//protos/public:drm_certificate_proto",
"//protos/public:errors_proto",
@@ -559,10 +586,10 @@ cc_library(
srcs = ["verified_media_pipeline.cc"],
hdrs = ["verified_media_pipeline.h"],
deps = [
":status",
":vmp_checker",
"//base",
"@abseil_repo//absl/strings",
"//util:status",
"//protos/public:license_protocol_proto",
],
)
@@ -572,13 +599,14 @@ cc_library(
srcs = ["x509_cert.cc"],
hdrs = ["x509_cert.h"],
deps = [
":error_space",
":openssl_util",
":rsa_key",
":status",
"//base",
"@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization",
"//external:openssl",
"//util:status",
],
)
@@ -588,9 +616,9 @@ cc_library(
srcs = ["test_utils.cc"],
hdrs = ["test_utils.h"],
deps = [
":status",
"//base",
"//external:openssl",
"//util:status",
],
)
@@ -616,9 +644,9 @@ cc_library(
":certificate_type",
":error_space",
":rsa_key",
":status",
":x509_cert",
"//base",
"//util:status",
"//protos/public:errors_proto",
"//protos/public:verified_media_pipeline_proto",
],
@@ -644,8 +672,8 @@ cc_library(
srcs = ["string_util.cc"],
hdrs = ["string_util.h"],
deps = [
":status",
"//base",
"//util:status",
],
)

View File

@@ -17,19 +17,18 @@
#include "absl/strings/escaping.h"
#include "absl/synchronization/mutex.h"
#include "util/gtl/map_util.h"
#include "util/status.h"
#include "common/crypto_util.h"
#include "common/drm_root_certificate.h"
#include "common/error_space.h"
#include "common/random_util.h"
#include "common/sha_util.h"
#include "common/signing_key_util.h"
#include "common/status.h"
#include "common/wvm_token_handler.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/errors.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
// TODO(user): Get rid of this horror.
namespace widevine {
namespace {
@@ -37,45 +36,44 @@ const int kKeyboxSizeBytes = 72;
} // namespace
// TODO(user): change to util::StatusOr<std::unique_ptr<ClientCert>>
// instead of ClientCert** to explicitly assigning ownership of the created
// object to the caller.
util::Status ClientCert::Create(const DrmRootCertificate* root_certificate,
ClientIdentification::TokenType token_type,
const std::string& token, ClientCert** client_cert) {
Status ClientCert::Create(const DrmRootCertificate* root_certificate,
ClientIdentification::TokenType token_type,
const std::string& token, ClientCert** client_cert) {
DCHECK(client_cert);
if (token_type == ClientIdentification::KEYBOX) {
*client_cert = nullptr;
if (token.size() < kKeyboxSizeBytes) {
return util::Status(error_space, INVALID_KEYBOX_TOKEN,
"keybox-token-is-too-short");
return Status(error_space, INVALID_KEYBOX_TOKEN,
"keybox-token-is-too-short");
}
return ClientCert::CreateWithKeybox(token, client_cert);
} else if (token_type == ClientIdentification::DRM_DEVICE_CERTIFICATE) {
return CreateWithDrmCertificate(root_certificate, token, client_cert);
} else {
return util::Status(error_space, util::error::UNIMPLEMENTED,
"client-type-not-implemented");
return Status(error_space, error::UNIMPLEMENTED,
"client-type-not-implemented");
}
}
util::Status ClientCert::CreateWithKeybox(const std::string& keybox_token,
ClientCert** client_cert) {
Status ClientCert::CreateWithKeybox(const std::string& keybox_token,
ClientCert** client_cert) {
CHECK(client_cert);
*client_cert = nullptr;
std::unique_ptr<KeyboxClientCert> new_client_cert(new KeyboxClientCert);
util::Status status = new_client_cert->Initialize(keybox_token);
Status status = new_client_cert->Initialize(keybox_token);
if (!status.ok()) {
return status;
}
*client_cert = new_client_cert.release();
return util::OkStatus();
return OkStatus();
}
util::Status ClientCert::CreateWithDrmCertificate(
Status ClientCert::CreateWithDrmCertificate(
const DrmRootCertificate* root_certificate, const std::string& drm_certificate,
ClientCert** client_cert) {
CHECK(client_cert);
@@ -83,14 +81,14 @@ util::Status ClientCert::CreateWithDrmCertificate(
std::unique_ptr<CertificateClientCert> new_client_cert(
new CertificateClientCert);
util::Status status =
Status status =
new_client_cert->Initialize(root_certificate, drm_certificate);
if (!status.ok()) {
return status;
}
*client_cert = new_client_cert.release();
return util::OkStatus();
return OkStatus();
}
void ClientCert::CreateSignature(const std::string& message, std::string* signature) {
@@ -110,8 +108,10 @@ void ClientCert::GenerateSigningKey(const std::string& message,
DCHECK(!key().empty());
using crypto_util::DeriveKey;
using crypto_util::kSigningKeyLabel;
set_signing_key(DeriveKey(key(), kSigningKeyLabel, message,
SigningKeyMaterialSize(protocol_version)));
set_signing_key(
DeriveKey(key(), kSigningKeyLabel,
protocol_version < VERSION_2_2 ? message : Sha512_Hash(message),
SigningKeyMaterialSizeBits(protocol_version)));
}
KeyboxClientCert::KeyboxClientCert() {}
@@ -139,51 +139,51 @@ uint32_t KeyboxClientCert::GetSystemId(const std::string& keybox_bytes) {
return WvmTokenHandler::GetSystemId(keybox_bytes);
}
util::Status KeyboxClientCert::Initialize(const std::string& keybox_bytes) {
Status KeyboxClientCert::Initialize(const std::string& keybox_bytes) {
if (keybox_bytes.size() < kKeyboxSizeBytes) {
return util::Status(error_space, INVALID_KEYBOX_TOKEN,
"keybox-token-is-too-short");
return Status(error_space, INVALID_KEYBOX_TOKEN,
"keybox-token-is-too-short");
}
set_system_id(WvmTokenHandler::GetSystemId(keybox_bytes));
set_serial_number(WvmTokenHandler::GetEncryptedUniqueId(keybox_bytes));
bool insecure_keybox = false;
util::Status status = WvmTokenHandler::DecryptDeviceKey(
keybox_bytes, &device_key_, nullptr, &insecure_keybox);
Status status = WvmTokenHandler::DecryptDeviceKey(keybox_bytes, &device_key_,
nullptr, &insecure_keybox);
if (!status.ok()) {
Errors new_code = status.error_code() == util::error::NOT_FOUND
Errors new_code = status.error_code() == error::NOT_FOUND
? MISSING_PRE_PROV_KEY
: KEYBOX_DECRYPT_ERROR;
return util::Status(error_space, new_code, status.error_message());
return Status(error_space, new_code, status.error_message());
}
return util::OkStatus();
return OkStatus();
}
util::Status KeyboxClientCert::VerifySignature(
const std::string& message, const std::string& signature,
ProtocolVersion protocol_version) {
Status KeyboxClientCert::VerifySignature(const std::string& message,
const std::string& signature,
ProtocolVersion protocol_version) {
DCHECK(!signing_key().empty());
using crypto_util::VerifySignatureHmacSha256;
if (!VerifySignatureHmacSha256(
GetClientSigningKey(signing_key(), protocol_version), signature,
message)) {
return util::Status(error_space, INVALID_SIGNATURE, "invalid-keybox-mac");
return Status(error_space, INVALID_SIGNATURE, "invalid-keybox-mac");
}
return util::OkStatus();
return OkStatus();
}
CertificateClientCert::CertificateClientCert() {}
CertificateClientCert::~CertificateClientCert() {}
util::Status CertificateClientCert::Initialize(
Status CertificateClientCert::Initialize(
const DrmRootCertificate* drm_root_certificate,
const std::string& serialized_certificate) {
CHECK(drm_root_certificate);
SignedDrmCertificate signed_device_cert;
DrmCertificate device_cert;
util::Status status = drm_root_certificate->VerifyCertificate(
Status status = drm_root_certificate->VerifyCertificate(
serialized_certificate, &signed_device_cert, &device_cert);
if (!status.ok()) {
return status;
@@ -192,12 +192,12 @@ util::Status CertificateClientCert::Initialize(
const SignedDrmCertificate& signer = signed_device_cert.signer();
DrmCertificate model_certificate;
if (!model_certificate.ParseFromString(signer.drm_certificate())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"drm-certificate-invalid-signer");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"drm-certificate-invalid-signer");
}
if (!model_certificate.has_serial_number()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-signer-serial-number");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-signer-serial-number");
}
// Check to see if this model certificate is signed by a
// provisioner (entity using Widevine Provisioning Server SDK).
@@ -205,56 +205,58 @@ util::Status CertificateClientCert::Initialize(
DrmCertificate provisioner_certificate;
if (!provisioner_certificate.ParseFromString(
signer.signer().drm_certificate())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"model-certificate-invalid-signer");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"model-certificate-invalid-signer");
}
if (provisioner_certificate.type() == DrmCertificate::PROVISIONER) {
set_signed_by_provisioner(true);
} else {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"expected-provisioning-provider-certificate-type");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"expected-provisioning-provider-certificate-type");
}
if (!provisioner_certificate.has_provider_id() ||
provisioner_certificate.provider_id().empty()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-provisioning-service-id");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-provisioning-service-id");
}
set_service_id(provisioner_certificate.provider_id());
}
set_signer_serial_number(model_certificate.serial_number());
set_signer_creation_time_seconds(model_certificate.creation_time_seconds());
if (!model_certificate.has_system_id()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"model-certificate-missing-system-id");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"model-certificate-missing-system-id");
}
set_system_id(model_certificate.system_id());
set_serial_number(device_cert.serial_number());
set_public_key(device_cert.public_key());
rsa_public_key_.reset(RsaPublicKey::Create(public_key()));
if (rsa_public_key_ == nullptr) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"drm-certificate-public-key-failed");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"drm-certificate-public-key-failed");
}
// TODO(user): Move this somewhere else. It is license protocol.
set_key(Random16Bytes());
if (!rsa_public_key_->Encrypt(key(), &encrypted_session_key_)) {
return util::Status(error_space, ENCRYPT_ERROR,
"drm-certificate-failed-encrypt-session-key");
return Status(error_space, ENCRYPT_ERROR,
"drm-certificate-failed-encrypt-session-key");
}
return util::OkStatus();
return OkStatus();
}
util::Status CertificateClientCert::VerifySignature(
Status CertificateClientCert::VerifySignature(
const std::string& message, const std::string& signature,
ProtocolVersion protocol_version) {
CHECK(rsa_public_key_);
if (!rsa_public_key_->VerifySignature(message, signature)) {
return util::Status(error_space, INVALID_SIGNATURE, "");
if (!rsa_public_key_->VerifySignature(
protocol_version < VERSION_2_2 ? message : Sha512_Hash(message),
signature)) {
return Status(error_space, INVALID_SIGNATURE, "");
}
return util::OkStatus();
return OkStatus();
}
} // namespace widevine

View File

@@ -13,8 +13,8 @@
#include <memory>
#include <string>
#include "util/status.h"
#include "common/rsa_key.h"
#include "common/status.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/license_protocol.pb.h"
@@ -29,15 +29,15 @@ class SignedDrmCertificate;
class ClientCert {
public:
virtual ~ClientCert() {}
static util::Status Create(
static Status Create(
const DrmRootCertificate* root_certificate,
widevine::ClientIdentification::TokenType token_type,
const std::string& token, ClientCert** client_cert);
// Creates a Keybox based ClientCert.
static util::Status CreateWithKeybox(const std::string& keybox_token,
ClientCert** client_cert);
static Status CreateWithKeybox(const std::string& keybox_token,
ClientCert** client_cert);
// Creates a Device Certificate based ClientCert.
static util::Status CreateWithDrmCertificate(
static Status CreateWithDrmCertificate(
const DrmRootCertificate* root_certificate, const std::string& drm_certificate,
ClientCert** client_cert);
// Creates a HMAC SHA256 signature based on the message and the key().
@@ -46,9 +46,8 @@ class ClientCert {
// Checks the passed in signature against a signature created used the
// classes information and the passed in message. Returns OK if signature
// is valid.
virtual util::Status VerifySignature(const std::string& message,
const std::string& signature,
ProtocolVersion protocol_version) = 0;
virtual Status VerifySignature(const std::string& message, const std::string& signature,
ProtocolVersion protocol_version) = 0;
// Creates a signing_key that is accessible using signing_key(). Signing_key
// is constructed by doing a key derivation using the key() and message.
virtual void GenerateSigningKey(const std::string& message,
@@ -118,10 +117,10 @@ class KeyboxClientCert : public ClientCert {
static bool IsSystemIdKnown(const uint32_t system_id);
static uint32_t GetSystemId(const std::string& keybox_bytes);
util::Status Initialize(const std::string& keybox_bytes);
Status Initialize(const std::string& keybox_bytes);
util::Status VerifySignature(const std::string& message, const std::string& signature,
ProtocolVersion protocol_version) override;
Status VerifySignature(const std::string& message, const std::string& signature,
ProtocolVersion protocol_version) override;
const std::string& key() const override { return device_key_; }
void set_key(const std::string& key) override { device_key_ = key; }
const std::string& encrypted_key() const override { return encrypted_device_key_; }
@@ -148,8 +147,8 @@ class CertificateClientCert : public ClientCert {
public:
~CertificateClientCert() override;
util::Status VerifySignature(const std::string& message, const std::string& signature,
ProtocolVersion protocol_version) override;
Status VerifySignature(const std::string& message, const std::string& signature,
ProtocolVersion protocol_version) override;
const std::string& key() const override { return session_key_; }
void set_key(const std::string& key) override { session_key_ = key; }
const std::string& encrypted_key() const override {
@@ -162,8 +161,8 @@ class CertificateClientCert : public ClientCert {
protected:
friend class ClientCert;
friend class MockCertificateClientCert;
util::Status Initialize(const DrmRootCertificate* drm_root_certificate,
const std::string& serialized_certificate);
Status Initialize(const DrmRootCertificate* drm_root_certificate,
const std::string& serialized_certificate);
virtual void set_public_key(const std::string& public_key) {
public_key_ = public_key;
}

View File

@@ -24,6 +24,8 @@
#include "common/drm_root_certificate.h"
#include "common/error_space.h"
#include "common/rsa_test_keys.h"
#include "common/sha_util.h"
#include "common/test_drm_certificates.h"
#include "common/wvm_test_keys.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/errors.pb.h"
@@ -31,7 +33,7 @@
// TODO(user): Change these tests to use on-the-fly generated intermediate
// and device certificates based on RsaTestKeys.
// TODO(user): Add testcase(s) VerifySignature, CreateSignature,
// TODO(user): Add testcase(s) CreateSignature,
// and GenerateSigningKey.
namespace widevine {
@@ -73,11 +75,10 @@ class ClientCertTest : public ::testing::Test {
const std::string certificate_;
const std::string expected_serial_number_;
uint32_t expected_system_id_;
util::Status expected_status_;
Status expected_status_;
TestCertificateAndData(const std::string& certificate,
const std::string& expected_serial_number,
uint32_t expected_system_id,
util::Status expected_status)
uint32_t expected_system_id, Status expected_status)
: certificate_(certificate),
expected_serial_number_(expected_serial_number),
expected_system_id_(expected_system_id),
@@ -111,7 +112,8 @@ class ClientCertTest : public ::testing::Test {
SignedDrmCertificate* signer, uint32_t system_id,
const std::string& serial_number);
RsaTestKeys test_keys_;
RsaTestKeys test_rsa_keys_;
TestDrmCertificates test_drm_certs_;
std::unique_ptr<DrmRootCertificate> root_cert_;
static bool setup_preprov_keys_;
};
@@ -121,7 +123,7 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation,
const bool expect_success,
const bool compare_device_key) {
// Test validation of a valid request.
util::Status status;
Status status;
ClientCert* client_cert_ptr = nullptr;
// Two ways to create a client cert object, test both.
@@ -136,7 +138,7 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation,
}
std::unique_ptr<ClientCert> keybox_cert(client_cert_ptr);
if (expect_success) {
ASSERT_EQ(util::OkStatus(), status);
ASSERT_EQ(OkStatus(), status);
ASSERT_TRUE(keybox_cert.get());
EXPECT_EQ(expectation.expected_system_id_, keybox_cert->system_id());
EXPECT_EQ(expectation.expected_serial_number_,
@@ -145,7 +147,7 @@ void ClientCertTest::TestBasicValidation(const TestTokenAndKeys& expectation,
EXPECT_EQ(expectation.expected_device_key_, keybox_cert->key());
}
} else {
EXPECT_NE(util::OkStatus(), status);
EXPECT_NE(OkStatus(), status);
EXPECT_FALSE(keybox_cert);
}
}
@@ -159,7 +161,7 @@ void ClientCertTest::TestBasicValidationDrmCertificate(
DrmRootCertificate::CreateByType(kCertificateTypeTesting, &root_cert_));
// Test validation of a valid request.
util::Status status;
Status status;
ClientCert* client_cert_ptr = nullptr;
status = ClientCert::Create(root_cert_.get(),
ClientIdentification::DRM_DEVICE_CERTIFICATE,
@@ -209,7 +211,7 @@ DrmCertificate* ClientCertTest::GenerateIntermediateCertificate(
intermediate_certificate->set_type(DrmCertificate::DEVICE_MODEL);
intermediate_certificate->set_serial_number(serial_number);
intermediate_certificate->set_public_key(
test_keys_.public_test_key_2_2048_bits());
test_rsa_keys_.public_test_key_2_2048_bits());
intermediate_certificate->set_system_id(system_id);
intermediate_certificate->set_creation_time_seconds(1234);
return intermediate_certificate.release();
@@ -221,7 +223,7 @@ SignedDrmCertificate* ClientCertTest::GenerateSignedIntermediateCertificate(
std::unique_ptr<DrmCertificate> intermediate_certificate(
GenerateIntermediateCertificate(system_id, serial_number));
return SignCertificate(*intermediate_certificate, signer,
test_keys_.private_test_key_1_3072_bits());
test_rsa_keys_.private_test_key_1_3072_bits());
}
DrmCertificate* ClientCertTest::GenerateDrmCertificate(
@@ -230,7 +232,7 @@ DrmCertificate* ClientCertTest::GenerateDrmCertificate(
drm_certificate->set_type(DrmCertificate::DEVICE);
drm_certificate->set_serial_number(serial_number);
drm_certificate->set_system_id(system_id);
drm_certificate->set_public_key(test_keys_.public_test_key_3_2048_bits());
drm_certificate->set_public_key(test_rsa_keys_.public_test_key_3_2048_bits());
drm_certificate->set_creation_time_seconds(4321);
return drm_certificate.release();
}
@@ -241,7 +243,7 @@ SignedDrmCertificate* ClientCertTest::GenerateSignedDrmCertificate(
std::unique_ptr<DrmCertificate> drm_certificate(
GenerateDrmCertificate(system_id, serial_number));
std::unique_ptr<SignedDrmCertificate> signed_drm_certificate(SignCertificate(
*drm_certificate, signer, test_keys_.private_test_key_2_2048_bits()));
*drm_certificate, signer, test_rsa_keys_.private_test_key_2_2048_bits()));
return signed_drm_certificate.release();
}
@@ -252,7 +254,7 @@ DrmCertificate* ClientCertTest::GenerateProvisionerCertificate(
provisioner_certificate->set_serial_number(serial_number);
// TODO(user): Need to generate 3072 bit test for provisioner certificates.
provisioner_certificate->set_public_key(
test_keys_.public_test_key_1_3072_bits());
test_rsa_keys_.public_test_key_1_3072_bits());
provisioner_certificate->set_system_id(system_id);
provisioner_certificate->set_provider_id(provider_id);
provisioner_certificate->set_creation_time_seconds(1234);
@@ -264,7 +266,7 @@ SignedDrmCertificate* ClientCertTest::GenerateSignedProvisionerCertificate(
std::unique_ptr<DrmCertificate> provisioner_certificate(
GenerateProvisionerCertificate(system_id, serial_number, service_id));
return SignCertificate(*provisioner_certificate, nullptr,
test_keys_.private_test_key_1_3072_bits());
test_rsa_keys_.private_test_key_1_3072_bits());
}
TEST_F(ClientCertTest, BasicValidation) {
@@ -302,8 +304,7 @@ TEST_F(ClientCertTest, BasicCertValidation) {
nullptr, system_id, serial_number),
system_id, serial_number + "-device"));
const TestCertificateAndData kValidCertificateAndExpectedData(
signed_cert->SerializeAsString(), serial_number, system_id,
util::OkStatus());
signed_cert->SerializeAsString(), serial_number, system_id, OkStatus());
const bool compare_data = true;
TestBasicValidationDrmCertificate(kValidCertificateAndExpectedData,
compare_data);
@@ -347,7 +348,7 @@ TEST_F(ClientCertTest, InvalidCertificate) {
new SignedDrmCertificate);
invalid_drm_cert->set_drm_certificate("bad-serialized-cert");
GenerateSignature(invalid_drm_cert->drm_certificate(),
test_keys_.private_test_key_2_2048_bits(),
test_rsa_keys_.private_test_key_2_2048_bits(),
invalid_drm_cert->mutable_signature());
invalid_drm_cert->set_allocated_signer(
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn));
@@ -357,18 +358,18 @@ TEST_F(ClientCertTest, InvalidCertificate) {
std::unique_ptr<SignedDrmCertificate> bad_device_public_key(SignCertificate(
*dev_cert,
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn),
test_keys_.private_test_key_2_2048_bits()));
test_rsa_keys_.private_test_key_2_2048_bits()));
// Invalid serialized intermediate certificate.
signed_signer.reset(
GenerateSignedIntermediateCertificate(nullptr, system_id, signer_sn));
signed_signer->set_drm_certificate("bad-serialized-cert");
GenerateSignature(signed_signer->drm_certificate(),
test_keys_.private_test_key_1_3072_bits(),
test_rsa_keys_.private_test_key_1_3072_bits(),
signed_signer->mutable_signature());
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
std::unique_ptr<SignedDrmCertificate> invalid_signer(
SignCertificate(*dev_cert, signed_signer.release(),
test_keys_.private_test_key_2_2048_bits()));
test_rsa_keys_.private_test_key_2_2048_bits()));
// Invalid signer public key.
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
signer_cert.reset(GenerateIntermediateCertificate(system_id, signer_sn));
@@ -376,8 +377,8 @@ TEST_F(ClientCertTest, InvalidCertificate) {
std::unique_ptr<SignedDrmCertificate> bad_signer_public_key(SignCertificate(
*dev_cert,
SignCertificate(*signer_cert, nullptr,
test_keys_.private_test_key_1_3072_bits()),
test_keys_.private_test_key_2_2048_bits()));
test_rsa_keys_.private_test_key_1_3072_bits()),
test_rsa_keys_.private_test_key_2_2048_bits()));
// Invalid device certificate signature.
std::unique_ptr<SignedDrmCertificate> bad_device_signature(
GenerateSignedDrmCertificate(
@@ -391,8 +392,8 @@ TEST_F(ClientCertTest, InvalidCertificate) {
std::unique_ptr<SignedDrmCertificate> missing_model_sn(SignCertificate(
*dev_cert,
SignCertificate(*signer_cert, nullptr,
test_keys_.private_test_key_1_3072_bits()),
test_keys_.private_test_key_2_2048_bits()));
test_rsa_keys_.private_test_key_1_3072_bits()),
test_rsa_keys_.private_test_key_2_2048_bits()));
// Missing signer serial number.
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
signer_cert.reset(GenerateIntermediateCertificate(system_id, signer_sn));
@@ -400,8 +401,8 @@ TEST_F(ClientCertTest, InvalidCertificate) {
std::unique_ptr<SignedDrmCertificate> missing_signer_sn(SignCertificate(
*dev_cert,
SignCertificate(*signer_cert, nullptr,
test_keys_.private_test_key_1_3072_bits()),
test_keys_.private_test_key_2_2048_bits()));
test_rsa_keys_.private_test_key_1_3072_bits()),
test_rsa_keys_.private_test_key_2_2048_bits()));
// Invalid serialized intermediate certificate.
dev_cert.reset(GenerateDrmCertificate(system_id, device_sn));
signed_signer.reset(
@@ -409,37 +410,36 @@ TEST_F(ClientCertTest, InvalidCertificate) {
signed_signer->set_signature("bad-signature");
std::unique_ptr<SignedDrmCertificate> bad_signer_signature(
SignCertificate(*dev_cert, signed_signer.release(),
test_keys_.private_test_key_2_2048_bits()));
test_rsa_keys_.private_test_key_2_2048_bits()));
const TestCertificateAndData kInvalidCertificate[] = {
TestCertificateAndData("f", "", 0,
util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signed-drm-certificate")),
Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signed-drm-certificate")),
TestCertificateAndData(invalid_drm_cert->SerializeAsString(), "", 0,
util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-drm-certificate")),
Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-drm-certificate")),
TestCertificateAndData(bad_device_public_key->SerializeAsString(), "", 0,
util::Status(error_space, INVALID_DRM_CERTIFICATE,
"drm-certificate-public-key-failed")),
Status(error_space, INVALID_DRM_CERTIFICATE,
"drm-certificate-public-key-failed")),
TestCertificateAndData(invalid_signer->SerializeAsString(), "", 0,
util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-certificate")),
Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-certificate")),
TestCertificateAndData(bad_signer_public_key->SerializeAsString(), "", 0,
util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-leaf-signer-public-key")),
Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-leaf-signer-public-key")),
TestCertificateAndData(bad_device_signature->SerializeAsString(), "", 0,
util::Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature")),
TestCertificateAndData(
missing_model_sn->SerializeAsString(), "", 0,
util::Status(error_space, INVALID_DRM_CERTIFICATE,
"model-certificate-missing-system-id")),
Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature")),
TestCertificateAndData(missing_model_sn->SerializeAsString(), "", 0,
Status(error_space, INVALID_DRM_CERTIFICATE,
"model-certificate-missing-system-id")),
TestCertificateAndData(missing_signer_sn->SerializeAsString(), "", 0,
util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-signer-serial-number")),
Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-signer-serial-number")),
TestCertificateAndData(bad_signer_signature->SerializeAsString(), "", 0,
util::Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature")),
Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature")),
};
for (size_t i = 0; i < ABSL_ARRAYSIZE(kInvalidCertificate); ++i) {
@@ -454,7 +454,7 @@ TEST_F(ClientCertTest, MissingPreProvKey) {
"beaa24924907e128f9ff49b54a165cd9c33e6547537eb4d29fb7e8df3c2c1cd9"
"2517a12f4922953e"));
ClientCert* client_cert_ptr = nullptr;
util::Status status = ClientCert::CreateWithKeybox(token, &client_cert_ptr);
Status status = ClientCert::CreateWithKeybox(token, &client_cert_ptr);
ASSERT_EQ(MISSING_PRE_PROV_KEY, status.error_code());
}
@@ -563,4 +563,55 @@ TEST_F(ClientCertTest, InvalidProvisionerDeviceCertChain) {
EXPECT_FALSE(client_cert_ptr);
}
TEST_F(ClientCertTest, Protocol21WithDrmCert) {
const char message[] = "A weekend wasted is a weekend well spent.";
ClientCert* client_cert_ptr = nullptr;
ASSERT_OK(ClientCert::Create(
root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE,
test_drm_certs_.test_user_device_certificate(), &client_cert_ptr));
std::unique_ptr<ClientCert> client_cert(client_cert_ptr);
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(test_rsa_keys_.private_test_key_3_2048_bits()));
ASSERT_TRUE(private_key);
// Success
std::string signature;
ASSERT_TRUE(private_key->GenerateSignature(message, &signature));
EXPECT_OK(client_cert->VerifySignature(message, signature, VERSION_2_1));
// Failure
ASSERT_EQ(256, signature.size());
++signature[127];
EXPECT_FALSE(
client_cert->VerifySignature(message, signature, VERSION_2_1).ok());
}
TEST_F(ClientCertTest, Protocol22WithDrmCert) {
const char message[] = "There is nothing permanent except change.";
const std::string message_hash(Sha512_Hash(message));
ClientCert* client_cert_ptr = nullptr;
ASSERT_OK(ClientCert::Create(
root_cert_.get(), ClientIdentification::DRM_DEVICE_CERTIFICATE,
test_drm_certs_.test_user_device_certificate(), &client_cert_ptr));
std::unique_ptr<ClientCert> client_cert(client_cert_ptr);
std::unique_ptr<RsaPrivateKey> private_key(
RsaPrivateKey::Create(test_rsa_keys_.private_test_key_3_2048_bits()));
ASSERT_TRUE(private_key);
// Success
std::string signature;
ASSERT_TRUE(private_key->GenerateSignature(message_hash, &signature));
EXPECT_OK(client_cert->VerifySignature(message, signature, VERSION_2_2));
// Failure
ASSERT_EQ(256, signature.size());
++signature[127];
EXPECT_FALSE(
client_cert->VerifySignature(message, signature, VERSION_2_2).ok());
}
} // namespace widevine

View File

@@ -51,39 +51,39 @@ std::string GetClientInfo(const ClientIdentification& client_id,
return default_value;
}
util::Status DecryptEncryptedClientIdentification(
Status DecryptEncryptedClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id) {
return DrmServiceCertificate::DecryptClientIdentification(encrypted_client_id,
client_id);
}
util::Status DecryptEncryptedClientIdentification(
Status DecryptEncryptedClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
const std::string& privacy_key, ClientIdentification* client_id) {
DCHECK(client_id);
if (!encrypted_client_id.has_encrypted_client_id() ||
encrypted_client_id.encrypted_client_id().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id");
}
if (!encrypted_client_id.has_encrypted_client_id_iv() ||
encrypted_client_id.encrypted_client_id_iv().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id-iv");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id-iv");
}
std::string serialized_client_id(crypto_util::DecryptAesCbc(
privacy_key, encrypted_client_id.encrypted_client_id_iv(),
encrypted_client_id.encrypted_client_id()));
if (serialized_client_id.empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-decryption-failed");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-decryption-failed");
}
if (!client_id->ParseFromString(serialized_client_id)) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-parse-failed");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-parse-failed");
}
return util::OkStatus();
return OkStatus();
}
} // namespace widevine

View File

@@ -14,7 +14,7 @@
#define COMMON_CLIENT_ID_UTIL_H_
#include "absl/strings/string_view.h"
#include "util/status.h"
#include "common/status.h"
#include "protos/public/client_identification.pb.h"
namespace widevine {
@@ -43,16 +43,16 @@ std::string GetClientInfo(const ClientIdentification& client_id,
// |client_id| using the private key for the service certificate which was
// used to encrypt the information.
// |client_id| is owned by caller.
// Returns util::Status::OK, if successful, else an error.
util::Status DecryptEncryptedClientIdentification(
// Returns Status::OK, if successful, else an error.
Status DecryptEncryptedClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id);
// Decrypts the encrypted client identification in |encrypted_client_id| into
// |client_id| using |privacy_key|.
// |client_id| is owned by caller.
// Returns util::Status::OK, if successful, else an error.
util::Status DecryptEncryptedClientIdentification(
// Returns Status::OK, if successful, else an error.
Status DecryptEncryptedClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
const std::string& privacy_key, ClientIdentification* client_id);

View File

@@ -22,8 +22,8 @@
namespace widevine {
namespace crypto_util {
const char kEncryptionKeyLabel[] = "ENCRYPTION";
const int kEncryptionKeySizeBits = 128;
const char kWrappingKeyLabel[] = "ENCRYPTION";
const int kWrappingKeySizeBits = 128;
const char kSigningKeyLabel[] = "AUTHENTICATION";
const int kSigningKeySizeBits = 256;
const size_t kSigningKeySizeBytes = 32;

View File

@@ -22,8 +22,8 @@ namespace crypto_util {
// Default constants used for key derivation for encryption and signing.
// TODO(user): These are duplicated in session.cc in the sdk. de-dup.
extern const char kEncryptionKeyLabel[];
extern const int kEncryptionKeySizeBits;
extern const char kWrappingKeyLabel[];
extern const int kWrappingKeySizeBits;
extern const char kSigningKeyLabel[];
extern const int kSigningKeySizeBits;
extern const size_t kSigningKeySizeBytes;

View File

@@ -21,6 +21,7 @@
#include "absl/synchronization/mutex.h"
#include "util/gtl/map_util.h"
#include "common/client_cert.h"
#include "common/drm_service_certificate.h"
#include "common/error_space.h"
#include "common/rsa_key.h"
#include "protos/public/client_identification.pb.h"
@@ -51,47 +52,47 @@ DeviceStatusList::DeviceStatusList()
DeviceStatusList::~DeviceStatusList() {}
util::Status DeviceStatusList::UpdateStatusList(
Status DeviceStatusList::UpdateStatusList(
const std::string& root_certificate_public_key,
const std::string& serialized_certificate_status_list,
uint32_t expiration_period_seconds) {
SignedDeviceCertificateStatusList signed_certificate_status_list;
if (!signed_certificate_status_list.ParseFromString(
serialized_certificate_status_list)) {
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"signed-certificate-status-list-parse-error");
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"signed-certificate-status-list-parse-error");
}
if (!signed_certificate_status_list.has_certificate_status_list()) {
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list");
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list");
}
if (!signed_certificate_status_list.has_signature()) {
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list-signature");
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list-signature");
}
std::unique_ptr<RsaPublicKey> root_key(
RsaPublicKey::Create(root_certificate_public_key));
if (root_key == nullptr) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-public-key");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-public-key");
}
if (!root_key->VerifySignature(
signed_certificate_status_list.certificate_status_list(),
signed_certificate_status_list.signature())) {
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"invalid-status-list-signature");
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"invalid-status-list-signature");
}
DeviceCertificateStatusList certificate_status_list;
if (!certificate_status_list.ParseFromString(
signed_certificate_status_list.certificate_status_list())) {
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"certificate-status-list-parse-error");
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"certificate-status-list-parse-error");
}
if (expiration_period_seconds &&
(GetCurrentTime() > (certificate_status_list.creation_time_seconds() +
expiration_period_seconds))) {
return util::Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST,
"certificate-status-list-expired");
return Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST,
"certificate-status-list-expired");
}
absl::WriterMutexLock lock(&status_map_lock_);
@@ -105,44 +106,44 @@ util::Status DeviceStatusList::UpdateStatusList(
if (device_info.has_system_id()) {
device_status_map_[device_info.system_id()] = cert_status;
} else {
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"device-info-missing-system-id");
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"device-info-missing-system-id");
}
}
}
creation_time_seconds_ = certificate_status_list.creation_time_seconds();
expiration_period_seconds_ = expiration_period_seconds;
return util::OkStatus();
return OkStatus();
}
util::Status DeviceStatusList::GetCertStatus(
const ClientCert& client_cert, ProvisionedDeviceInfo* device_info) {
Status DeviceStatusList::GetCertStatus(const ClientCert& client_cert,
ProvisionedDeviceInfo* device_info) {
CHECK(device_info);
// Keybox checks.
if (client_cert.type() == ClientIdentification::KEYBOX) {
if (!KeyboxClientCert::IsSystemIdKnown(client_cert.system_id())) {
return util::Status(error_space, UNSUPPORTED_SYSTEM_ID,
"keybox-unsupported-system-id");
return Status(error_space, UNSUPPORTED_SYSTEM_ID,
"keybox-unsupported-system-id");
}
// Get device information from certificate status list if available.
if (!GetDeviceInfo(client_cert, device_info)) {
device_info->Clear();
}
return util::OkStatus();
return OkStatus();
}
// DRM certificate checks.
if (client_cert.type() != ClientIdentification::DRM_DEVICE_CERTIFICATE) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"device-certificate-unsupported-token-type");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"device-certificate-unsupported-token-type");
}
absl::ReaderMutexLock lock(&status_map_lock_);
if (expiration_period_seconds_ &&
(GetCurrentTime() >
(creation_time_seconds_ + expiration_period_seconds_))) {
return util::Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST,
"certificate-status-list-expired");
return Status(error_space, EXPIRED_CERTIFICATE_STATUS_LIST,
"certificate-status-list-expired");
}
DeviceCertificateStatus* device_cert_status =
gtl::FindOrNull(device_status_map_, client_cert.system_id());
@@ -154,15 +155,15 @@ util::Status DeviceStatusList::GetCertStatus(
LOG(WARNING) << "Allowing REVOKED device: "
<< device_info->ShortDebugString();
} else {
return util::Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED,
"device-certificate-revoked");
return Status(error_space, DRM_DEVICE_CERTIFICATE_REVOKED,
"device-certificate-revoked");
}
}
if ((device_cert_status->status() ==
DeviceCertificateStatus::STATUS_TEST_ONLY) &&
!allow_test_only_devices_) {
return util::Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
"test-only-drm-certificate-not-allowed");
return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
"test-only-drm-certificate-not-allowed");
}
if (!client_cert.signed_by_provisioner() &&
(client_cert.signer_serial_number() !=
@@ -174,21 +175,21 @@ util::Status DeviceStatusList::GetCertStatus(
// list is older than the certificate, the certificate is for all purposes
// unknown.
if (client_cert.signer_creation_time_seconds() < creation_time_seconds_) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"intermediate-certificate-serial-number-mismatch");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"intermediate-certificate-serial-number-mismatch");
}
return util::Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
"device-certificate-status-unknown");
return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
"device-certificate-status-unknown");
}
} else {
if (!allow_unknown_devices_) {
return util::Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
"device-certificate-status-unknown");
return Status(error_space, DRM_DEVICE_CERTIFICATE_UNKNOWN,
"device-certificate-status-unknown");
}
device_info->Clear();
}
return util::OkStatus();
return OkStatus();
}
bool DeviceStatusList::GetDeviceInfo(const ClientCert& client_cert,
@@ -246,18 +247,18 @@ bool DeviceStatusList::IsRevokedSystemIdAllowed(uint32_t system_id) {
return it;
}
util::Status DeviceStatusList::ExtractFromProvisioningServiceResponse(
Status DeviceStatusList::ExtractFromProvisioningServiceResponse(
const std::string& certificate_provisioning_service_response,
std::string* signed_certificate_status_list, std::string* certificate_status_list) {
util::Status status = util::OkStatus();
Status status = OkStatus();
size_t signed_list_start =
certificate_provisioning_service_response.find(kSignedList);
if (signed_list_start != std::string::npos) {
size_t signed_list_end = certificate_provisioning_service_response.find(
kSignedListTerminator, signed_list_start);
if (signed_list_end == std::string::npos) {
return util::Status(
error_space, util::error::INVALID_ARGUMENT,
return Status(
error_space, error::INVALID_ARGUMENT,
"Unable to parse the certificate_provisioning_service_response. "
"SignedList not terminated.");
}
@@ -283,8 +284,8 @@ util::Status DeviceStatusList::ExtractFromProvisioningServiceResponse(
if (!absl::WebSafeBase64Unescape(signed_list,
signed_certificate_status_list)) {
if (!absl::Base64Unescape(signed_list, signed_certificate_status_list)) {
return util::Status(error_space, util::error::INVALID_ARGUMENT,
"Base64 decode of signedlist failed.");
return Status(error_space, error::INVALID_ARGUMENT,
"Base64 decode of signedlist failed.");
}
}
} else {
@@ -294,28 +295,68 @@ util::Status DeviceStatusList::ExtractFromProvisioningServiceResponse(
signed_certificate_status_list)) {
if (!absl::Base64Unescape(certificate_provisioning_service_response,
signed_certificate_status_list)) {
return util::Status(error_space, util::error::INVALID_ARGUMENT,
"Base64 decode of certList failed.");
return Status(error_space, error::INVALID_ARGUMENT,
"Base64 decode of certList failed.");
}
}
}
SignedDeviceCertificateStatusList signed_status_list;
if (!signed_status_list.ParseFromString(*signed_certificate_status_list)) {
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"signed-certificate-status-list-parse-error");
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"signed-certificate-status-list-parse-error");
}
if (!signed_status_list.has_certificate_status_list()) {
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list");
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list");
}
DeviceCertificateStatusList device_certificate_status_list;
if (!device_certificate_status_list.ParseFromString(
signed_status_list.certificate_status_list())) {
return util::Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"certificate-status-list-parse-error");
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"certificate-status-list-parse-error");
}
*certificate_status_list = signed_status_list.certificate_status_list();
return util::OkStatus();
return OkStatus();
}
Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest(
const std::string& version,
std::string* signed_device_certificate_status_list_request) {
if (version.empty()) {
return Status(error_space, error::INVALID_ARGUMENT, "SDK version is empty");
}
DCHECK(signed_device_certificate_status_list_request);
if (signed_device_certificate_status_list_request == nullptr) {
return Status(error_space, error::INVALID_ARGUMENT,
"Signed_device_certificate_status_list_request is empty");
}
// Construct SignedDeviceCertificateStatusListRequest.
DeviceCertificateStatusListRequest request;
request.set_sdk_version(version);
request.set_sdk_time_seconds(DeviceStatusList::Instance()->GetCurrentTime());
std::string device_certificate_status_list_request;
request.SerializeToString(&device_certificate_status_list_request);
SignedDeviceCertificateStatusListRequest signed_request;
signed_request.set_device_certificate_status_list_request(
device_certificate_status_list_request);
const DrmServiceCertificate* sc =
DrmServiceCertificate::GetDefaultDrmServiceCertificate();
if (sc == nullptr) {
signed_device_certificate_status_list_request->clear();
return Status(error_space, widevine::INVALID_SERVICE_CERTIFICATE,
"Drm service certificate is not loaded.");
}
const RsaPrivateKey* private_key = sc->private_key();
if (private_key == nullptr) {
return Status(error_space, widevine::INVALID_SERVICE_CERTIFICATE,
"Private key in the service certificate is null.");
}
std::string signature;
private_key->GenerateSignature(device_certificate_status_list_request,
&signature);
signed_request.set_signature(signature);
signed_request.SerializeToString(
signed_device_certificate_status_list_request);
return OkStatus();
}
} // namespace widevine

View File

@@ -16,7 +16,7 @@
#include "base/macros.h"
#include "absl/synchronization/mutex.h"
#include "util/status.h"
#include "common/status.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/provisioned_device_info.pb.h"
@@ -37,12 +37,12 @@ class DeviceStatusList {
DeviceStatusList();
virtual ~DeviceStatusList();
// Takes |signed_certificate_status_list| and copies to an internal map of
// Takes |serialized_certificate_status_list| and copies to an internal map of
// device certifcate status list. The internal map is used to verify
// a device was not revoked. Returns true is the list was successfully parsed.
util::Status UpdateStatusList(const std::string& root_certificate_public_key,
const std::string& signed_certificate_status_list,
uint32_t expiration_period_seconds);
Status UpdateStatusList(const std::string& root_certificate_public_key,
const std::string& serialized_certificate_status_list,
uint32_t expiration_period_seconds);
void set_allow_unknown_devices(bool flag) { allow_unknown_devices_ = flag; }
bool allow_unknown_devices() const { return allow_unknown_devices_; }
void set_allow_test_only_devices(bool allow) {
@@ -58,9 +58,8 @@ class DeviceStatusList {
// DRM_DEVICE_CERTIFICATE_UNKNOWN
// If status is OK, a copy of the provisioned device info is copied
// into |device_info|. Caller owns |device_info| and it must not be null.
util::Status GetCertStatus(
const ClientCert& client_cert,
widevine::ProvisionedDeviceInfo* device_info);
Status GetCertStatus(const ClientCert& client_cert,
widevine::ProvisionedDeviceInfo* device_info);
// Returns true if the pre-provisioning key or certificate for the specified
// system ID are active (not disallowed or revoked).
bool IsSystemIdActive(uint32_t system_id);
@@ -86,9 +85,19 @@ class DeviceStatusList {
* @param certificate_status_list
* @return WvPLStatus - Status::OK if success, else error.
*/
static util::Status ExtractFromProvisioningServiceResponse(
static Status ExtractFromProvisioningServiceResponse(
const std::string& certificate_provisioning_service_response,
std::string* signed_certificate_status_list, std::string* certificate_status_list);
/**
* Constructs signed device certificate status list request string.
*
* @param signed_device_certificate_status_list_request
* @param version
* @return Status - Status::OK if success, else error.
*/
static Status GenerateSignedDeviceCertificateStatusListRequest(
const std::string& version,
std::string* signed_device_certificate_status_list_request);
private:
// Returns true if the system ID is allowed to be revoked.

View File

@@ -114,10 +114,9 @@ class DeviceStatusListTest : public ::testing::Test {
ASSERT_TRUE(
signed_cert_status_list_.SerializeToString(&serialized_status_list_));
ASSERT_EQ(util::OkStatus(),
device_status_list_.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_status_list_, kDefaultExpirePeriod));
ASSERT_EQ(OkStatus(), device_status_list_.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_status_list_, kDefaultExpirePeriod));
}
DeviceStatusList device_status_list_;
@@ -140,7 +139,7 @@ TEST_F(DeviceStatusListTest, CheckForValidAndRevokedCert) {
.WillRepeatedly(Return(kValidCertSystemId));
EXPECT_CALL(valid_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(valid_drm_serial_number));
EXPECT_EQ(util::OkStatus(),
EXPECT_EQ(OkStatus(),
device_status_list_.GetCertStatus(valid_client_cert, &device_info));
EXPECT_TRUE(device_info.has_model());
EXPECT_EQ(kDeviceModel, device_info.model());
@@ -191,8 +190,8 @@ TEST_F(DeviceStatusListTest, TestOnlyCertNotAllowed) {
.WillRepeatedly(Return(kTestOnlyCertSystemId));
EXPECT_CALL(test_only_client_cert, signer_serial_number())
.WillRepeatedly(ReturnRef(test_only_drm_serial_number));
EXPECT_EQ(util::OkStatus(), device_status_list_.GetCertStatus(
test_only_client_cert, &device_info));
EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus(test_only_client_cert,
&device_info));
}
TEST_F(DeviceStatusListTest, ValidAndUnknownKeybox) {
@@ -208,8 +207,8 @@ TEST_F(DeviceStatusListTest, ValidAndUnknownKeybox) {
.WillRepeatedly(Return(ClientIdentification::KEYBOX));
EXPECT_CALL(valid_client_keybox, system_id())
.WillRepeatedly(Return(kValidCertSystemId));
EXPECT_EQ(util::OkStatus(), device_status_list_.GetCertStatus(
valid_client_keybox, &device_info));
EXPECT_EQ(OkStatus(), device_status_list_.GetCertStatus(valid_client_keybox,
&device_info));
EXPECT_TRUE(device_info.has_model());
EXPECT_EQ(kDeviceModel, device_info.model());
@@ -249,7 +248,7 @@ TEST_F(DeviceStatusListTest, SignerSerialNumberMismatch) {
// We allow this case only for certs signed by a provisioner cert.
EXPECT_CALL(older_client_cert, signed_by_provisioner())
.WillOnce(Return(true));
EXPECT_EQ(util::OkStatus(),
EXPECT_EQ(OkStatus(),
device_status_list_.GetCertStatus(older_client_cert, &device_info));
EXPECT_TRUE(device_info.has_system_id());
EXPECT_EQ(kValidCertSystemId, device_info.system_id());
@@ -314,9 +313,9 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnSet) {
.Times(2)
.WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 101));
EXPECT_EQ(util::OkStatus(), mock_device_status_list.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_status_list_, 100));
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_status_list_, 100));
EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST,
mock_device_status_list
.UpdateStatusList(test_keys_.public_test_key_1_3072_bits(),
@@ -331,9 +330,9 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnCertCheck) {
.WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 101));
EXPECT_EQ(util::OkStatus(), mock_device_status_list.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_status_list_, 100));
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList(
test_keys_.public_test_key_1_3072_bits(),
serialized_status_list_, 100));
ProvisionedDeviceInfo device_info;
MockCertificateClientCert valid_client_cert;
@@ -346,8 +345,8 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnCertCheck) {
.WillRepeatedly(ReturnRef(valid_drm_serial_number));
EXPECT_CALL(valid_client_cert, signer_creation_time_seconds())
.WillRepeatedly(Return(kStatusListCreationTime - 1));
EXPECT_EQ(util::OkStatus(), mock_device_status_list.GetCertStatus(
valid_client_cert, &device_info));
EXPECT_EQ(OkStatus(), mock_device_status_list.GetCertStatus(valid_client_cert,
&device_info));
EXPECT_EQ(
EXPIRED_CERTIFICATE_STATUS_LIST,

View File

@@ -265,10 +265,10 @@ class VerifiedCertSignatureCache {
// Checks cache, on miss, uses public key. If successful, adds to
// cache.
util::Status VerifySignature(const std::string& cert, const std::string& serial_number,
const std::string& signature,
const std::string& signer_public_key,
const std::string& signer_serial_number) {
Status VerifySignature(const std::string& cert, const std::string& serial_number,
const std::string& signature,
const std::string& signer_public_key,
const std::string& signer_serial_number) {
{
VerifiedCertSignatures::iterator cached_signature;
absl::ReaderMutexLock read_lock(&signature_cache_mutex_);
@@ -279,11 +279,11 @@ class VerifiedCertSignatureCache {
(signature != cached_signature->second.signature) ||
(signer_serial_number != cached_signature->second.signer_serial)) {
// Cached signature mismatch.
return util::Status(error_space, INVALID_SIGNATURE,
"cached-signature-mismatch");
return Status(error_space, INVALID_SIGNATURE,
"cached-signature-mismatch");
}
// Cached signature match.
return util::OkStatus();
return OkStatus();
}
}
@@ -291,12 +291,12 @@ class VerifiedCertSignatureCache {
std::unique_ptr<RsaPublicKey> signer_key(
key_factory_->CreateFromPkcs1PublicKey(signer_public_key));
if (!signer_key) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-public-key");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-public-key");
}
if (!signer_key->VerifySignature(cert, signature)) {
return util::Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature");
return Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature");
}
// Add signature to cache.
@@ -304,7 +304,7 @@ class VerifiedCertSignatureCache {
signature_cache_.emplace(
serial_number,
VerifiedCertSignature(cert, signature, signer_serial_number));
return util::OkStatus();
return OkStatus();
}
private:
@@ -313,7 +313,7 @@ class VerifiedCertSignatureCache {
const RsaKeyFactory* key_factory_;
};
util::Status DrmRootCertificate::CreateByType(
Status DrmRootCertificate::CreateByType(
CertificateType cert_type, std::unique_ptr<DrmRootCertificate>* cert) {
CHECK(cert);
@@ -321,7 +321,7 @@ util::Status DrmRootCertificate::CreateByType(
}
std::unique_ptr<DrmRootCertificate> DrmRootCertificate::CreateByType(
CertificateType cert_type, util::Status* status) {
CertificateType cert_type, Status* status) {
CHECK(status);
std::unique_ptr<DrmRootCertificate> new_root_cert;
@@ -329,7 +329,7 @@ std::unique_ptr<DrmRootCertificate> DrmRootCertificate::CreateByType(
return new_root_cert;
}
util::Status DrmRootCertificate::CreateByTypeString(
Status DrmRootCertificate::CreateByTypeString(
const std::string& cert_type_string, std::unique_ptr<DrmRootCertificate>* cert) {
CHECK(cert);
@@ -341,17 +341,16 @@ util::Status DrmRootCertificate::CreateByTypeString(
} else if (cert_type_string == kTestingString) {
cert_type = kCertificateTypeTesting;
} else {
return util::Status(
error_space, INVALID_PARAMETER,
absl::StrCat("invalid-certificate-type ", cert_type_string));
return Status(error_space, INVALID_PARAMETER,
absl::StrCat("invalid-certificate-type ", cert_type_string));
}
return CreateByType(cert_type, cert);
}
util::Status DrmRootCertificate::Create(
CertificateType cert_type, std::unique_ptr<RsaKeyFactory> key_factory,
std::unique_ptr<DrmRootCertificate>* cert) {
Status DrmRootCertificate::Create(CertificateType cert_type,
std::unique_ptr<RsaKeyFactory> key_factory,
std::unique_ptr<DrmRootCertificate>* cert) {
DCHECK(cert);
std::string serialized_certificate;
@@ -375,49 +374,48 @@ util::Status DrmRootCertificate::Create(
break;
}
default:
return util::Status(error_space, INVALID_PARAMETER,
"invalid-certificate-type");
return Status(error_space, INVALID_PARAMETER, "invalid-certificate-type");
}
SignedDrmCertificate signed_root_cert;
if (!signed_root_cert.ParseFromString(serialized_certificate)) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"signed-root-cert-deserialize-fail");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"signed-root-cert-deserialize-fail");
}
DrmCertificate root_cert;
if (!signed_root_cert.has_drm_certificate()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-device-certificate");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-device-certificate");
}
if (!root_cert.ParseFromString(signed_root_cert.drm_certificate())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"root-cert-deserialize-fail");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"root-cert-deserialize-fail");
}
if (!root_cert.has_public_key()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-cert-public-key");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-cert-public-key");
}
if (!signed_root_cert.has_signature()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-certificate-signature");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-root-certificate-signature");
}
std::unique_ptr<RsaPublicKey> public_key(
key_factory->CreateFromPkcs1PublicKey(root_cert.public_key()));
if (!public_key) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-public-key");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-public-key");
}
if (!public_key->VerifySignature(signed_root_cert.drm_certificate(),
signed_root_cert.signature())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-certificate-signature");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-certificate-signature");
}
cert->reset(new DrmRootCertificate(
cert_type, serialized_certificate, root_cert.serial_number(),
root_cert.public_key(), std::move(key_factory)));
return util::OkStatus();
return OkStatus();
}
DrmRootCertificate::DrmRootCertificate(
@@ -437,7 +435,7 @@ std::string DrmRootCertificate::GetDigest() const {
return absl::BytesToHexString(Sha256_Hash(serialized_certificate_));
}
util::Status DrmRootCertificate::VerifyCertificate(
Status DrmRootCertificate::VerifyCertificate(
const std::string& serialized_certificate,
SignedDrmCertificate* signed_certificate,
DrmCertificate* certificate) const {
@@ -447,8 +445,8 @@ util::Status DrmRootCertificate::VerifyCertificate(
signed_certificate = local_signed_certificate.get();
}
if (!signed_certificate->ParseFromString(serialized_certificate)) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signed-drm-certificate");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signed-drm-certificate");
}
std::unique_ptr<DrmCertificate> local_certificate;
@@ -458,20 +456,19 @@ util::Status DrmRootCertificate::VerifyCertificate(
}
if (signed_certificate->drm_certificate().empty() ||
!certificate->ParseFromString(signed_certificate->drm_certificate())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-drm-certificate");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-drm-certificate");
}
if (certificate->serial_number().empty()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-serial-number");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-serial-number");
}
if (!certificate->has_creation_time_seconds()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-creation-time");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-creation-time");
}
if (certificate->public_key().empty()) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-public-key");
return Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key");
}
// Verify signature chain, but do not use cache for leaf certificates.
@@ -485,7 +482,7 @@ util::Status DrmRootCertificate::VerifyCertificate(
// the case of device-unique device certificates.
// Signatures for root-signed certificates are always cached, even if they are
// leaf certificates. For example service, and provisioner certificates.
util::Status DrmRootCertificate::VerifySignatures(
Status DrmRootCertificate::VerifySignatures(
const SignedDrmCertificate& signed_cert, const std::string& cert_serial_number,
bool use_cache) const {
if (!signed_cert.has_signer()) {
@@ -497,12 +494,12 @@ util::Status DrmRootCertificate::VerifySignatures(
DrmCertificate signer;
if (!signer.ParseFromString(signed_cert.signer().drm_certificate())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-certificate");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-certificate");
}
// Verify the signer before verifying signed_cert.
util::Status status =
Status status =
VerifySignatures(signed_cert.signer(), signer.serial_number(), kUseCache);
if (!status.ok()) {
return status;
@@ -519,17 +516,17 @@ util::Status DrmRootCertificate::VerifySignatures(
std::unique_ptr<RsaPublicKey> signer_public_key(
key_factory_->CreateFromPkcs1PublicKey(signer.public_key()));
if (!signer_public_key) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-leaf-signer-public-key");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-leaf-signer-public-key");
}
if (!signer_public_key->VerifySignature(signed_cert.drm_certificate(),
signed_cert.signature())) {
return util::Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature");
return Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature");
}
}
return util::OkStatus();
return OkStatus();
}
} // namespace widevine

View File

@@ -19,7 +19,7 @@
#include <string>
#include "base/macros.h"
#include "util/status.h"
#include "common/status.h"
#include "common/certificate_type.h"
@@ -42,13 +42,13 @@ class DrmRootCertificate {
// std::unique_ptr<DrmRootCertificate> which will be used to return a newly
// created const DrmRootCertificate* if successful. The caller assumes
// ownership of the new DrmRootCertificate. This method returns
// util::Status::OK on success, or appropriate error status otherwise.
static util::Status CreateByType(CertificateType cert_type,
std::unique_ptr<DrmRootCertificate>* cert);
// Status::OK on success, or appropriate error status otherwise.
static Status CreateByType(CertificateType cert_type,
std::unique_ptr<DrmRootCertificate>* cert);
// Variant on the method above to make CLIF happy until b/110539622 is fixed.
static std::unique_ptr<DrmRootCertificate> CreateByType(
CertificateType cert_type, util::Status* status);
CertificateType cert_type, Status* status);
// Creates a DrmRootCertificate object given a certificate type std::string, which
// must be one of "prod", "qa", or "test".
@@ -56,19 +56,16 @@ class DrmRootCertificate {
// std::unique_ptr<DrmRootCertificate> which will be used to return a newly
// created const DrmRootCertificate* if successful. The caller assumes
// ownership of the new DrmRootCertificate. This method returns
// util::Status::OK on success, or appropriate error status otherwise.
static util::Status CreateByTypeString(
const std::string& cert_type_string,
std::unique_ptr<DrmRootCertificate>* cert);
// Status::OK on success, or appropriate error status otherwise.
static Status CreateByTypeString(const std::string& cert_type_string,
std::unique_ptr<DrmRootCertificate>* cert);
// |certificate| will contgain the DRM certificate upon successful return.
// May be null.
// Returns util::Status::OK if successful, or an appropriate error code
// otherwise.
virtual util::Status VerifyCertificate(
const std::string& serialized_certificate,
SignedDrmCertificate* signed_certificate,
DrmCertificate* certificate) const;
// Returns Status::OK if successful, or an appropriate error code otherwise.
virtual Status VerifyCertificate(const std::string& serialized_certificate,
SignedDrmCertificate* signed_certificate,
DrmCertificate* certificate) const;
// Returns the hex-encoded SHA-256 digest for this certificate.
virtual std::string GetDigest() const;
@@ -86,13 +83,13 @@ class DrmRootCertificate {
private:
friend class DrmRootCertificateTest;
static util::Status Create(CertificateType cert_type,
std::unique_ptr<RsaKeyFactory> key_factory,
std::unique_ptr<DrmRootCertificate>* cert);
static Status Create(CertificateType cert_type,
std::unique_ptr<RsaKeyFactory> key_factory,
std::unique_ptr<DrmRootCertificate>* cert);
util::Status VerifySignatures(const SignedDrmCertificate& signed_cert,
const std::string& cert_serial_number,
bool use_cache) const;
Status VerifySignatures(const SignedDrmCertificate& signed_cert,
const std::string& cert_serial_number,
bool use_cache) const;
CertificateType type_;
std::string serialized_certificate_;

View File

@@ -33,8 +33,8 @@ TEST(DrmRootCertificateCreateTest, TestCertificate) {
"49f917b1bdfed78002a58e799a58e940"
"1fffaaed9d8d80752782b066757e2c8c");
std::unique_ptr<DrmRootCertificate> root_cert;
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeTesting, &root_cert));
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeTesting, &root_cert));
ASSERT_TRUE(root_cert != nullptr);
EXPECT_EQ(kTestCertificateHash, root_cert->GetDigest());
}
@@ -44,8 +44,8 @@ TEST(DrmRootCertificateCreateTest, DevCertificate) {
"0e25ee95476a770f30b98ac5ef778b3f"
"137b66c29385b84f547a361b4724b17d");
std::unique_ptr<DrmRootCertificate> root_cert;
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeDevelopment, &root_cert));
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeDevelopment, &root_cert));
ASSERT_TRUE(root_cert != nullptr);
EXPECT_EQ(kDevelopmentCertificateHash, root_cert->GetDigest());
}
@@ -55,8 +55,8 @@ TEST(DrmRootCertificateCreateTest, ProdCertificate) {
"d62fdabc9286648a81f7d3bedaf2f5a5"
"27bbad39bc38da034ba98a21569adb9b");
std::unique_ptr<DrmRootCertificate> root_cert;
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeProduction, &root_cert));
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeProduction, &root_cert));
ASSERT_TRUE(root_cert != nullptr);
EXPECT_EQ(kProductionCertificateHash, root_cert->GetDigest());
}
@@ -111,8 +111,8 @@ class DrmRootCertificateTest : public testing::Test {
drm_certificates_[2].set_public_key(
test_keys_.public_test_key_3_2048_bits());
ASSERT_EQ(util::OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeTesting, &root_cert_));
ASSERT_EQ(OkStatus(), DrmRootCertificate::CreateByType(
kCertificateTypeTesting, &root_cert_));
}
void GenerateSignedDrmCertificate() {
@@ -144,7 +144,7 @@ class DrmRootCertificateTest : public testing::Test {
TEST_F(DrmRootCertificateTest, SuccessNoOutput) {
GenerateSignedDrmCertificate();
ASSERT_EQ(util::OkStatus(),
ASSERT_EQ(OkStatus(),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
}
@@ -153,25 +153,25 @@ TEST_F(DrmRootCertificateTest, SuccessWithOutput) {
GenerateSignedDrmCertificate();
SignedDrmCertificate out_signed_cert;
DrmCertificate out_cert;
ASSERT_EQ(util::OkStatus(), root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(),
&out_signed_cert, &out_cert));
ASSERT_EQ(OkStatus(), root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(),
&out_signed_cert, &out_cert));
EXPECT_TRUE(
MessageDifferencer::Equals(out_signed_cert, signed_drm_certificate_));
EXPECT_TRUE(MessageDifferencer::Equals(out_cert, drm_certificates_[2]));
}
TEST_F(DrmRootCertificateTest, InvalidSignedDrmCertificate) {
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signed-drm-certificate"),
EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signed-drm-certificate"),
root_cert_->VerifyCertificate("pure garbage", nullptr, nullptr));
}
TEST_F(DrmRootCertificateTest, InvalidSignerCertificate) {
GenerateSignedDrmCertificate();
signed_drm_certificate_.mutable_signer()->set_drm_certificate("more garbage");
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-certificate"),
EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-certificate"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
}
@@ -179,86 +179,84 @@ TEST_F(DrmRootCertificateTest, InvalidSignerCertificate) {
TEST_F(DrmRootCertificateTest, MissingDrmCertificate) {
GenerateSignedDrmCertificate();
signed_drm_certificate_.clear_drm_certificate();
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-drm-certificate"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
EXPECT_EQ(
Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-drm-certificate"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_F(DrmRootCertificateTest, InvalidDrmCertificate) {
GenerateSignedDrmCertificate();
signed_drm_certificate_.set_drm_certificate("junk");
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-drm-certificate"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
EXPECT_EQ(
Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-drm-certificate"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_F(DrmRootCertificateTest, InvalidPublicKey) {
drm_certificates_[0].set_public_key("rubbish");
GenerateSignedDrmCertificate();
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-signer-public-key"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
EXPECT_EQ(
Status(error_space, INVALID_DRM_CERTIFICATE, "invalid-signer-public-key"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_F(DrmRootCertificateTest, MissingPublicKey) {
drm_certificates_[2].clear_public_key();
GenerateSignedDrmCertificate();
EXPECT_EQ(
util::Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
EXPECT_EQ(Status(error_space, INVALID_DRM_CERTIFICATE, "missing-public-key"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
}
TEST_F(DrmRootCertificateTest, MissingCreationTime) {
drm_certificates_[2].clear_creation_time_seconds();
GenerateSignedDrmCertificate();
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-creation-time"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
EXPECT_EQ(
Status(error_space, INVALID_DRM_CERTIFICATE, "missing-creation-time"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_F(DrmRootCertificateTest, MissingSerialNumber) {
drm_certificates_[2].set_serial_number("");
GenerateSignedDrmCertificate();
EXPECT_EQ(util::Status(error_space, INVALID_DRM_CERTIFICATE,
"missing-serial-number"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
EXPECT_EQ(
Status(error_space, INVALID_DRM_CERTIFICATE, "missing-serial-number"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_F(DrmRootCertificateTest, InvalidSignatureWithNoCache) {
GenerateSignedDrmCertificate();
signed_drm_certificate_.mutable_signer()->set_signature(
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
EXPECT_EQ(util::Status(error_space, INVALID_SIGNATURE,
"cache-miss-invalid-signature"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
EXPECT_EQ(
Status(error_space, INVALID_SIGNATURE, "cache-miss-invalid-signature"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
}
TEST_F(DrmRootCertificateTest, InvalidSignatureWithCache) {
GenerateSignedDrmCertificate();
// Verify and cache.
ASSERT_EQ(util::OkStatus(),
ASSERT_EQ(OkStatus(),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
// Verify success using cache.
ASSERT_EQ(util::OkStatus(),
ASSERT_EQ(OkStatus(),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
// Verify failure using cache.
signed_drm_certificate_.mutable_signer()->set_signature(
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
EXPECT_EQ(
util::Status(error_space, INVALID_SIGNATURE, "cached-signature-mismatch"),
root_cert_->VerifyCertificate(signed_drm_certificate_.SerializeAsString(),
nullptr, nullptr));
EXPECT_EQ(Status(error_space, INVALID_SIGNATURE, "cached-signature-mismatch"),
root_cert_->VerifyCertificate(
signed_drm_certificate_.SerializeAsString(), nullptr, nullptr));
}
} // namespace widevine

View File

@@ -107,41 +107,41 @@ DrmServiceCertificateMap* DrmServiceCertificateMap::GetInstance() {
} // namespace
util::Status DrmServiceCertificate::AddDrmServiceCertificate(
const DrmRootCertificate* root_cert, const std::string& service_certificate,
Status DrmServiceCertificate::AddDrmServiceCertificate(
const DrmRootCertificate* root_drm_cert, const std::string& service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase) {
DrmCertificate drm_cert;
util::Status status =
root_cert->VerifyCertificate(service_certificate, nullptr, &drm_cert);
Status status =
root_drm_cert->VerifyCertificate(service_certificate, nullptr, &drm_cert);
if (!status.ok()) {
return status;
}
if (drm_cert.type() != DrmCertificate::SERVICE) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"not-service-certificate");
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
"not-service-certificate");
}
if (drm_cert.provider_id().empty()) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"missing-certificate-service-id");
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
"missing-certificate-service-id");
}
std::unique_ptr<RsaPublicKey> public_key(
RsaPublicKey::Create(drm_cert.public_key()));
if (!public_key) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"invalid-certificate-public-key");
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
"invalid-certificate-public-key");
}
std::string pkcs1_key;
if (!rsa_util::EncryptedPrivateKeyInfoToRsaPrivateKey(
service_private_key, service_private_key_passphrase, &pkcs1_key)) {
return util::Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
"key-decryption-failed");
return Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
"key-decryption-failed");
}
std::unique_ptr<RsaPrivateKey> private_key(RsaPrivateKey::Create(pkcs1_key));
if (private_key == nullptr) {
return util::Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
"invalid-private-key");
return Status(error_space, INVALID_SERVICE_PRIVATE_KEY,
"invalid-private-key");
}
std::unique_ptr<DrmServiceCertificate> new_cert(new DrmServiceCertificate(
@@ -150,7 +150,7 @@ util::Status DrmServiceCertificate::AddDrmServiceCertificate(
std::move(private_key)));
DrmServiceCertificateMap::GetInstance()->AddCert(std::move(new_cert));
return util::OkStatus();
return OkStatus();
}
const DrmServiceCertificate*
@@ -171,7 +171,7 @@ const DrmServiceCertificate* DrmServiceCertificate::GetDrmServiceCertificate(
return DrmServiceCertificateMap::GetInstance()->GetCert(serial_number);
}
util::Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
const DrmRootCertificate* root_drm_cert, const std::string& service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase) {
@@ -181,36 +181,36 @@ util::Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
service_private_key_passphrase);
}
util::Status DrmServiceCertificate::DecryptClientIdentification(
Status DrmServiceCertificate::DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id) {
DCHECK(client_id);
if (encrypted_client_id.service_certificate_serial_number().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-service-certificate-serial-number");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-service-certificate-serial-number");
}
if (encrypted_client_id.provider_id().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-service-id");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-service-id");
}
if (encrypted_client_id.encrypted_client_id().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id");
}
if (encrypted_client_id.encrypted_client_id_iv().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id-iv");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-client-id-iv");
}
if (encrypted_client_id.encrypted_privacy_key().empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-privacy-key");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"missing-encrypted-privacy-key");
}
std::string privacy_key;
std::string provider_id;
const DrmServiceCertificate* cert = GetDrmServiceCertificate(
encrypted_client_id.service_certificate_serial_number());
if (!cert) {
return util::Status(
return Status(
error_space, SERVICE_CERTIFICATE_NOT_FOUND,
"service-certificate-not-found (SN " +
absl::BytesToHexString(
@@ -219,56 +219,56 @@ util::Status DrmServiceCertificate::DecryptClientIdentification(
}
if (!cert->private_key()->Decrypt(encrypted_client_id.encrypted_privacy_key(),
&privacy_key)) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"privacy-key-decryption-failed");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"privacy-key-decryption-failed");
}
if (cert->provider_id() != encrypted_client_id.provider_id()) {
return util::Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND,
std::string("provider-id-mismatch (") + cert->provider_id() +
" / " + encrypted_client_id.provider_id() + ")");
return Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND,
std::string("provider-id-mismatch (") + cert->provider_id() +
" / " + encrypted_client_id.provider_id() + ")");
}
std::string serialized_client_id(crypto_util::DecryptAesCbc(
privacy_key, encrypted_client_id.encrypted_client_id_iv(),
encrypted_client_id.encrypted_client_id()));
if (serialized_client_id.empty()) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-decryption-failed");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-decryption-failed");
}
if (!client_id->ParseFromString(serialized_client_id)) {
return util::Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-parse-failed");
return Status(error_space, INVALID_ENCRYPTED_CLIENT_IDENTIFICATION,
"client-id-parse-failed");
}
return util::OkStatus();
return OkStatus();
}
void DrmServiceCertificate::ResetServiceCertificates() {
DrmServiceCertificateMap::GetInstance()->Reset();
}
util::Status DrmServiceCertificate::ValidateDrmServiceCertificate() {
Status DrmServiceCertificate::ValidateDrmServiceCertificate() {
const DrmServiceCertificate* service_certificate =
GetDefaultDrmServiceCertificate();
if (!service_certificate) {
return util::Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND,
"drm service certificate is not found.");
return Status(error_space, SERVICE_CERTIFICATE_NOT_FOUND,
"drm service certificate is not found.");
}
SignedDrmCertificate signed_cert;
if (!signed_cert.ParseFromString(service_certificate->certificate())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"signed drm service certificate is failed to parse.");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"signed drm service certificate is failed to parse.");
}
DrmCertificate drm_cert;
if (!drm_cert.ParseFromString(signed_cert.drm_certificate())) {
return util::Status(error_space, INVALID_DRM_CERTIFICATE,
"Drm service certificate is failed to parse.");
return Status(error_space, INVALID_DRM_CERTIFICATE,
"Drm service certificate is failed to parse.");
}
if (!drm_cert.has_creation_time_seconds()) {
return util::Status(error_space, INVALID_SERVICE_CERTIFICATE,
"missing certificate creation time");
return Status(error_space, INVALID_SERVICE_CERTIFICATE,
"missing certificate creation time");
}
// TODO(user): Check creation_time_seconds field in DrmCertificate and also
// export the absl/time dependency through moe.
return util::OkStatus();
return OkStatus();
}
DrmServiceCertificate::DrmServiceCertificate(

View File

@@ -18,9 +18,9 @@
#include <cstdint>
#include "base/macros.h"
#include "util/status.h"
#include "common/certificate_type.h"
#include "common/rsa_key.h"
#include "common/status.h"
namespace widevine {
class RequestInspectorTest;
@@ -48,7 +48,7 @@ class DrmServiceCertificate {
// If the default service certificate is not set, this certificate will be
// used as the default service certificate.
// This method is thread-safe.
static util::Status AddDrmServiceCertificate(
static Status AddDrmServiceCertificate(
const DrmRootCertificate* root_drm_cert,
const std::string& service_certificate, const std::string& service_private_key,
const std::string& service_private_key_passphrase);
@@ -56,7 +56,7 @@ class DrmServiceCertificate {
// Same as AddDrmServiceCertificate(), but will clear the default service
// certificate if it's set. This will result in this service certificate
// being set as the default service certificate.
static util::Status SetDefaultDrmServiceCertificate(
static Status SetDefaultDrmServiceCertificate(
const DrmRootCertificate* root_drm_cert,
const std::string& service_certificate, const std::string& service_private_key,
const std::string& service_private_key_passphrase);
@@ -79,7 +79,7 @@ class DrmServiceCertificate {
// certificate which was used to encrypt the information. |client_id| must
// not be NULL. Returns status::OK if successful, or an appropriate error
// otherwise. This method is thread-safe.
static util::Status DecryptClientIdentification(
static Status DecryptClientIdentification(
const EncryptedClientIdentification& encrypted_client_id,
ClientIdentification* client_id);
@@ -93,18 +93,18 @@ class DrmServiceCertificate {
// status::OK if successful, or in case of error, contact
// widevine-tam@google.com to get the next valid service certificate renewed
// via get deviceCertificate StatusList.
static util::Status ValidateDrmServiceCertificate();
static Status ValidateDrmServiceCertificate();
private:
friend class DrmServiceCertificateTest;
friend class widevine::RequestInspectorTest;
static util::Status AddDrmServiceCertificate(
static Status AddDrmServiceCertificate(
const std::string& root_public_key, const std::string& service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase);
static util::Status SetDefaultDrmServiceCertificate(
static Status SetDefaultDrmServiceCertificate(
const std::string& root_public_key, const std::string& service_certificate,
const std::string& service_private_key,
const std::string& service_private_key_passphrase);

View File

@@ -69,9 +69,9 @@ class DrmServiceCertificateTest : public ::testing::Test {
return serialized_cert;
}
util::Status SetDefaultDrmServiceCertificate(const std::string& serial_number,
const std::string& provider_id,
uint32_t creation_time_seconds) {
Status SetDefaultDrmServiceCertificate(const std::string& serial_number,
const std::string& provider_id,
uint32_t creation_time_seconds) {
std::string signed_cert(GenerateDrmServiceCertificate(
serial_number, provider_id, creation_time_seconds,
test_keys_.public_test_key_2_2048_bits()));
@@ -79,15 +79,15 @@ class DrmServiceCertificateTest : public ::testing::Test {
if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), kPassphrase,
&encrypted_private_key)) {
return util::Status(util::error::INTERNAL, "");
return Status(error::INTERNAL, "");
}
return DrmServiceCertificate::SetDefaultDrmServiceCertificate(
root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase);
}
util::Status AddDrmServiceCertificate(const std::string& serial_number,
const std::string& provider_id,
uint32_t creation_time_seconds) {
Status AddDrmServiceCertificate(const std::string& serial_number,
const std::string& provider_id,
uint32_t creation_time_seconds) {
std::string signed_cert(GenerateDrmServiceCertificate(
serial_number, provider_id, creation_time_seconds,
test_keys_.public_test_key_2_2048_bits()));
@@ -95,7 +95,7 @@ class DrmServiceCertificateTest : public ::testing::Test {
if (!rsa_util::RsaPrivateKeyToEncryptedPrivateKeyInfo(
test_keys_.private_test_key_2_2048_bits(), kPassphrase,
&encrypted_private_key)) {
return util::Status(util::error::INTERNAL, "");
return Status(error::INTERNAL, "");
}
return DrmServiceCertificate::AddDrmServiceCertificate(
root_cert_.get(), signed_cert, encrypted_private_key, kPassphrase);
@@ -140,9 +140,8 @@ TEST_F(DrmServiceCertificateTest, BasicClientIdDecrypt) {
test_keys_.public_test_key_2_2048_bits(),
&encrypted_client_id);
ClientIdentification decrypted_client_id;
EXPECT_EQ(util::OkStatus(),
DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
decrypted_client_id));
}
@@ -220,27 +219,24 @@ TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) {
test_keys_.public_test_key_2_2048_bits(),
&encrypted_client_id);
ClientIdentification decrypted_client_id;
EXPECT_EQ(util::OkStatus(),
DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
decrypted_client_id));
EncryptClientIdentification(serial_number2, provider_id,
test_keys_.public_test_key_2_2048_bits(),
&encrypted_client_id);
EXPECT_EQ(util::OkStatus(),
DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
decrypted_client_id));
EncryptClientIdentification(serial_number3, provider_id,
test_keys_.public_test_key_2_2048_bits(),
&encrypted_client_id);
EXPECT_EQ(util::OkStatus(),
DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
EXPECT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
EXPECT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
decrypted_client_id));
@@ -292,9 +288,8 @@ TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) {
test_keys_.public_test_key_2_2048_bits(),
&encrypted_client_id);
ClientIdentification decrypted_client_id;
ASSERT_EQ(util::OkStatus(),
DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
ASSERT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
decrypted_client_id));
@@ -310,9 +305,8 @@ TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) {
invalid = encrypted_client_id;
++(*invalid.mutable_encrypted_client_id_iv())[4];
EXPECT_NE(util::OkStatus(),
DrmServiceCertificate::DecryptClientIdentification(
invalid, &decrypted_client_id));
EXPECT_NE(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
invalid, &decrypted_client_id));
invalid.clear_encrypted_client_id_iv();
EXPECT_EQ(
@@ -324,9 +318,8 @@ TEST_F(DrmServiceCertificateTest, InvalidEncryptedClientIdentification) {
invalid = encrypted_client_id;
++(*invalid.mutable_encrypted_client_id())[0];
EXPECT_NE(util::OkStatus(),
DrmServiceCertificate::DecryptClientIdentification(
invalid, &decrypted_client_id));
EXPECT_NE(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
invalid, &decrypted_client_id));
invalid.clear_encrypted_client_id();
EXPECT_EQ(
@@ -349,9 +342,8 @@ TEST_F(DrmServiceCertificateTest, PrivateKeyDecryptError) {
test_keys_.public_test_key_2_2048_bits(),
&encrypted_client_id);
ClientIdentification decrypted_client_id;
ASSERT_EQ(util::OkStatus(),
DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
ASSERT_EQ(OkStatus(), DrmServiceCertificate::DecryptClientIdentification(
encrypted_client_id, &decrypted_client_id));
ASSERT_TRUE(google::protobuf::util::MessageDifferencer::Equals(client_id_,
decrypted_client_id));

View File

@@ -113,99 +113,99 @@ void RemoteAttestationVerifier::EnableTestDrmCertificates(bool enable) {
ca_.reset();
}
util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
Status RemoteAttestationVerifier::VerifyRemoteAttestation(
const std::string& message, const RemoteAttestation& remote_attestation,
std::string* remote_attestation_cert_sn) {
DCHECK(remote_attestation_cert_sn);
// Sanity check RemoteAttestation.
if (!remote_attestation.has_certificate()) {
return (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-certificate-missing"));
return (Status(error_space, INVALID_MESSAGE,
"remote-attestation-certificate-missing"));
}
if (!remote_attestation.has_salt()) {
return (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-salt-missing"));
return (Status(error_space, INVALID_MESSAGE,
"remote-attestation-salt-missing"));
}
if (!remote_attestation.has_signature()) {
return (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-signature-missing"));
return (Status(error_space, INVALID_MESSAGE,
"remote-attestation-signature-missing"));
}
// Decrypt ClientIdentification containing remote attestation certificate.
// A service cert would be looked up first, then that cert will be used
// to decrypt the ClientIdentification.
ClientIdentification client_id;
util::Status status = DrmServiceCertificate::DecryptClientIdentification(
Status status = DrmServiceCertificate::DecryptClientIdentification(
remote_attestation.certificate(), &client_id);
if (!status.ok()) return status;
if (client_id.type() !=
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
return (util::Status(error_space, INVALID_MESSAGE,
std::string("remote-attestation-invalid-client-id-type (") +
absl::StrCat(client_id.type()) + ")"));
return (Status(error_space, INVALID_MESSAGE,
std::string("remote-attestation-invalid-client-id-type (") +
absl::StrCat(client_id.type()) + ")"));
}
return VerifyRemoteAttestation(message, remote_attestation, client_id,
remote_attestation_cert_sn);
}
util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
Status RemoteAttestationVerifier::VerifyRemoteAttestation(
const std::string& message, const RemoteAttestation& remote_attestation,
const std::string& privacy_key) {
// Sanity check RemoteAttestation.
if (!remote_attestation.has_certificate()) {
return (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-certificate-missing"));
return (Status(error_space, INVALID_MESSAGE,
"remote-attestation-certificate-missing"));
}
if (!remote_attestation.has_salt()) {
return (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-salt-missing"));
return (Status(error_space, INVALID_MESSAGE,
"remote-attestation-salt-missing"));
}
if (!remote_attestation.has_signature()) {
return (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-signature-missing"));
return (Status(error_space, INVALID_MESSAGE,
"remote-attestation-signature-missing"));
}
// Decrypt ClientIdentification containing remote attestation certificate,
// directly using an explicitly provided key |privacy_key|.
ClientIdentification client_id;
util::Status status = DecryptEncryptedClientIdentification(
Status status = DecryptEncryptedClientIdentification(
remote_attestation.certificate(), privacy_key, &client_id);
if (!status.ok()) return status;
if (client_id.type() !=
ClientIdentification::REMOTE_ATTESTATION_CERTIFICATE) {
return (util::Status(error_space, INVALID_MESSAGE,
std::string("remote-attestation-invalid-client-id-type (") +
absl::StrCat(client_id.type()) + ")"));
return (Status(error_space, INVALID_MESSAGE,
std::string("remote-attestation-invalid-client-id-type (") +
absl::StrCat(client_id.type()) + ")"));
}
std::string remote_attestation_cert_sn;
return VerifyRemoteAttestation(message, remote_attestation, client_id,
&remote_attestation_cert_sn);
}
util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
Status RemoteAttestationVerifier::VerifyRemoteAttestation(
const std::string& message, const RemoteAttestation& remote_attestation,
const ClientIdentification& client_id, std::string* remote_attestation_cert_sn) {
if (!client_id.has_token()) {
return (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-token-missing"));
return (Status(error_space, INVALID_MESSAGE,
"remote-attestation-token-missing"));
}
// Load and verify the certificate chain.
std::unique_ptr<X509CertChain> cert_chain(new X509CertChain);
util::Status status = cert_chain->LoadPem(client_id.token());
Status status = cert_chain->LoadPem(client_id.token());
if (!status.ok()) return status;
if (cert_chain->GetNumCerts() < 1) {
return (util::Status(error_space, INVALID_MESSAGE,
"remote-attestation-empty-certificate-chain"));
return (Status(error_space, INVALID_MESSAGE,
"remote-attestation-empty-certificate-chain"));
}
std::string device_mode_string =
cert_chain->GetCert(0)->GetSubjectNameField(kDeviceModeFieldName);
if (device_mode_string != kExpectedDeviceMode) {
return (util::Status(error_space, REMOTE_ATTESTATION_FAILED,
std::string("remote-attestation-device-not-verified (") +
device_mode_string + " / " + kDeviceModeFieldName +
")"));
return (Status(error_space, REMOTE_ATTESTATION_FAILED,
std::string("remote-attestation-device-not-verified (") +
device_mode_string + " / " + kDeviceModeFieldName +
")"));
}
ca_mutex_.ReaderLock();
if (ca_ == NULL) {
@@ -217,10 +217,9 @@ util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
status = ca_->VerifyCertChain(*cert_chain);
ca_mutex_.ReaderUnlock();
if (!status.ok()) {
return (util::Status(
error_space, REMOTE_ATTESTATION_FAILED,
std::string("remote-attestation-cert-chain-validation-failed: ") +
status.error_message()));
return (Status(error_space, REMOTE_ATTESTATION_FAILED,
std::string("remote-attestation-cert-chain-validation-failed: ") +
status.error_message()));
}
// Verify the remote attestation signature.
std::unique_ptr<RsaPublicKey> leaf_key;
@@ -232,30 +231,30 @@ util::Status RemoteAttestationVerifier::VerifyRemoteAttestation(
}
}
if (!leaf_key) {
return util::Status(error_space, REMOTE_ATTESTATION_FAILED,
"remote-attestation-cert-chain-no-leaf");
return Status(error_space, REMOTE_ATTESTATION_FAILED,
"remote-attestation-cert-chain-no-leaf");
}
if (!leaf_key->VerifySignatureSha256Pkcs7(message_with_salt,
remote_attestation.signature())) {
return (util::Status(error_space, REMOTE_ATTESTATION_FAILED,
"remote-attestation-signature-verification-failed: "));
return (Status(error_space, REMOTE_ATTESTATION_FAILED,
"remote-attestation-signature-verification-failed: "));
}
*remote_attestation_cert_sn = cert_chain->GetCert(0)->GetSerialNumber();
return util::OkStatus();
return OkStatus();
}
util::Status RemoteAttestationVerifier::LoadCa() {
Status RemoteAttestationVerifier::LoadCa() {
absl::WriterMutexLock lock(&ca_mutex_);
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
util::Status status = ca_cert->LoadDer(absl::HexStringToBytes(
Status status = ca_cert->LoadDer(absl::HexStringToBytes(
enable_test_certificates_ ? kTestRootCaDerCert : kProdRootCaDerCert));
if (!status.ok()) {
return status;
}
ca_.reset(new X509CA(ca_cert.release()));
return util::OkStatus();
return OkStatus();
}
} // namespace widevine

View File

@@ -19,7 +19,7 @@
#include "base/macros.h"
#include "base/thread_annotations.h"
#include "absl/synchronization/mutex.h"
#include "util/status.h"
#include "common/status.h"
#include "common/x509_cert.h"
#include "protos/public/client_identification.pb.h"
#include "protos/public/remote_attestation.pb.h"
@@ -50,9 +50,9 @@ class RemoteAttestationVerifier {
// return will contain the serial number for the client's remote attestation
// certificate.
// This method is thread-safe.
util::Status VerifyRemoteAttestation(
const std::string& message, const RemoteAttestation& remote_attestation,
std::string* remote_attestation_cert_sn);
Status VerifyRemoteAttestation(const std::string& message,
const RemoteAttestation& remote_attestation,
std::string* remote_attestation_cert_sn);
// Call to verify a RemoteAttestation challenge response, used in certificate
// provisioning protocol.
@@ -61,9 +61,9 @@ class RemoteAttestationVerifier {
// |privacy_key| is used to decrypt the EncryptedClientIdentification within
// the |remote_attestation| message.
// This method is thread-safe.
util::Status VerifyRemoteAttestation(
const std::string& message, const RemoteAttestation& remote_attestation,
const std::string& privacy_key);
Status VerifyRemoteAttestation(const std::string& message,
const RemoteAttestation& remote_attestation,
const std::string& privacy_key);
private:
// Common subroutine to perform the verification.
@@ -73,12 +73,12 @@ class RemoteAttestationVerifier {
// |remote_attestation_cert_sn| is a pointer to a std::string which on successful
// return will contain the serial number for the client's remote attestation
// certificate.
util::Status VerifyRemoteAttestation(
const std::string& message, const RemoteAttestation& remote_attestation,
const ClientIdentification& client_id,
std::string* remote_attestation_cert_sn);
Status VerifyRemoteAttestation(const std::string& message,
const RemoteAttestation& remote_attestation,
const ClientIdentification& client_id,
std::string* remote_attestation_cert_sn);
util::Status LoadCa();
Status LoadCa();
bool enable_test_certificates_;
absl::Mutex ca_mutex_;

View File

@@ -29,6 +29,14 @@ std::string Sha256_Hash(const std::string& message) {
return digest;
}
std::string Sha512_Hash(const std::string& message) {
std::string digest;
digest.resize(SHA512_DIGEST_LENGTH);
SHA512(reinterpret_cast<const uint8_t*>(message.data()), message.size(),
reinterpret_cast<uint8_t*>(&digest[0]));
return digest;
}
std::string GenerateSha1Uuid(const std::string& name_space, const std::string& name) {
// X.667 14 Setting the fields of a name-based UUID.
// - Allocate a UUID to use as a "name space identifier" for all UUIDs

View File

@@ -21,6 +21,9 @@ std::string Sha1_Hash(const std::string& message);
// Calculates SHA256 hash.
std::string Sha256_Hash(const std::string& message);
// Calculate SHA512 hash.
std::string Sha512_Hash(const std::string& message);
// Generates a UUID as specified in ITU-T X.667 ch. 14, SHA-1 name-based,
// 16-byte binary representation. Name_space is a GUID prefix; name is a unique
// name in the namespace.

View File

@@ -48,6 +48,18 @@ TEST(ShaUtilTest, Sha256) {
Sha256_Hash("random data"));
}
TEST(ShaUtilTest, Sha512) {
const uint8_t kExpected[] = {
0x8f, 0x49, 0x93, 0x1f, 0x4d, 0x4a, 0x67, 0x6f, 0x9a, 0x7e, 0x62,
0x60, 0xea, 0xe1, 0x54, 0xfe, 0xe2, 0x75, 0x3c, 0xec, 0x3b, 0xb2,
0x2e, 0xd7, 0x51, 0xcc, 0x39, 0xf9, 0x89, 0x69, 0xad, 0xd0, 0x14,
0xaa, 0xbe, 0x40, 0xce, 0xe3, 0xab, 0xef, 0x10, 0x2f, 0x24, 0x0e,
0xd8, 0x26, 0x7b, 0xb5, 0x7d, 0x86, 0xce, 0xbd, 0xd7, 0x32, 0x86,
0x3a, 0x5e, 0x9e, 0x8d, 0x23, 0x77, 0x10, 0x80, 0x0c};
EXPECT_EQ(std::string(kExpected, kExpected + sizeof(kExpected)),
Sha512_Hash("random data"));
}
TEST(ShaUtilTest, GenerateSha1Uuid) {
std::string name_space =
absl::HexStringToBytes("4d20ad7dd95bc4b250fae56fb143e774");

View File

@@ -11,55 +11,50 @@
#include <memory>
#include <string>
#include "util/status.h"
#include "common/aes_cbc_util.h"
#include "common/rsa_key.h"
#include "common/sha_util.h"
#include "common/status.h"
namespace widevine {
namespace signature_util {
util::Status GenerateAesSignature(const std::string& message, const std::string& aes_key,
const std::string& aes_iv, std::string* signature) {
Status GenerateAesSignature(const std::string& message, const std::string& aes_key,
const std::string& aes_iv, std::string* signature) {
if (signature == nullptr) {
return util::Status(util::error::INVALID_ARGUMENT, "signature is nullptr");
return Status(error::INVALID_ARGUMENT, "signature is nullptr");
}
std::string hash = Sha1_Hash(message);
if (hash.empty()) {
return util::Status(util::error::INTERNAL, "Computed hash is empty");
return Status(error::INTERNAL, "Computed hash is empty");
}
std::string sig = crypto_util::EncryptAesCbc(aes_key, aes_iv, hash);
if (sig.empty()) {
return util::Status(util::error::INTERNAL,
"Computed AES signature is empty");
return Status(error::INTERNAL, "Computed AES signature is empty");
}
*signature = sig;
return util::OkStatus();
return OkStatus();
}
util::Status GenerateRsaSignature(const std::string& message,
const std::string& private_key,
std::string* signature) {
Status GenerateRsaSignature(const std::string& message, const std::string& private_key,
std::string* signature) {
if (signature == nullptr) {
return util::Status(util::error::INVALID_ARGUMENT, "signature is nullptr");
return Status(error::INVALID_ARGUMENT, "signature is nullptr");
}
std::unique_ptr<RsaPrivateKey> rsa_private_key(
RsaPrivateKey::Create(private_key));
if (rsa_private_key == nullptr) {
return util::Status(util::error::INTERNAL,
"Failed to construct a RsaPrivateKey");
return Status(error::INTERNAL, "Failed to construct a RsaPrivateKey");
}
std::string sig;
if (!rsa_private_key->GenerateSignature(message, &sig)) {
return util::Status(util::error::INTERNAL,
"Failed to generate a RSA signature");
return Status(error::INTERNAL, "Failed to generate a RSA signature");
}
if (sig.empty()) {
return util::Status(util::error::INTERNAL,
"Computed RSA signature is empty");
return Status(error::INTERNAL, "Computed RSA signature is empty");
}
*signature = sig;
return util::OkStatus();
return OkStatus();
}
} // namespace signature_util

View File

@@ -11,7 +11,7 @@
#include <string>
#include "util/status.h"
#include "common/status.h"
namespace widevine {
namespace signature_util {
@@ -19,14 +19,14 @@ namespace signature_util {
// Generates an AES signature of |message| using |aes_key| and |aes_iv|.
// Signature is returned via |signature| if generation was successful.
// Returns a Status that carries the details of error if generation failed.
util::Status GenerateAesSignature(const std::string& message, const std::string& aes_key,
const std::string& aes_iv, std::string* signature);
Status GenerateAesSignature(const std::string& message, const std::string& aes_key,
const std::string& aes_iv, std::string* signature);
// Generates a RSA signature of |message| using |private_key|.
// Signature is returned via |sigature| if generation was successful.
// Returns a Status that carries the details of error if generation failed.
util::Status GenerateRsaSignature(const std::string& message,
const std::string& private_key, std::string* signature);
Status GenerateRsaSignature(const std::string& message, const std::string& private_key,
std::string* signature);
} // namespace signature_util
} // namespace widevine

View File

@@ -16,7 +16,7 @@ namespace widevine {
using crypto_util::kSigningKeySizeBits;
uint32_t SigningKeyMaterialSize(ProtocolVersion protocol_version) {
uint32_t SigningKeyMaterialSizeBits(ProtocolVersion protocol_version) {
if (protocol_version <= VERSION_2_0) {
return kSigningKeySizeBits;
} else {

View File

@@ -20,7 +20,7 @@
// std::string derived_key = DeriveKey(key_str,
// label,
// context,
// SigningKeyMaterialSize(VERSION_2_1));
// SigningKeyMaterialSizeBits(VERSION_2_1));
// std::string server_derived_key = GetServerSigningKey(derived_key);
// std::string client_derived_key = GetClientSigninKey(derived_key);
#ifndef COMMON_SIGNING_KEY_UTIL_H_
@@ -36,7 +36,7 @@ namespace widevine {
// Returns the size of the signing key based on the License Protocol
// Version. Signing keys for version 2.0 have a length of 256. Signing
// keys for version 2.1 have a length of 512.
uint32_t SigningKeyMaterialSize(ProtocolVersion protocol_version);
uint32_t SigningKeyMaterialSizeBits(ProtocolVersion protocol_version);
// Returns the client portion of the derived_key. The client portion
// depend on the size of the key. Keys that are 512 bits in length

View File

@@ -30,14 +30,14 @@ std::string GenerateDerivedKey(widevine::ProtocolVersion protocol_version) {
}
} // namespace
TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeProtocolVersion_2_0) {
TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeBitsProtocolVersion_2_0) {
ASSERT_EQ(crypto_util::kSigningKeySizeBits,
SigningKeyMaterialSize(VERSION_2_0));
SigningKeyMaterialSizeBits(VERSION_2_0));
}
TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeProtocolVersion_2_1) {
TEST(DerivedKeyUtilTest, SigningKeyMaterialSizeBitsProtocolVersion_2_1) {
ASSERT_EQ(crypto_util::kSigningKeySizeBits * 2,
SigningKeyMaterialSize(VERSION_2_1));
SigningKeyMaterialSizeBits(VERSION_2_1));
}
TEST(DerivedKeyUtilTest, GetServerSigningKeyProtocolVersion2_1) {

74
common/status.cc Normal file
View File

@@ -0,0 +1,74 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2017 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.
////////////////////////////////////////////////////////////////////////////////
#include "common/status.h"
#include <string>
#include "absl/base/macros.h"
#include "absl/strings/str_cat.h"
#include "util/error_space.h"
namespace widevine {
namespace {
const char* kGenericErrorStatusMessage[] = {"OK",
"unknown_error",
"unknown_error",
"invalid_argument",
"unknown_error",
"not_found",
"already_exists",
"permission_denied",
"unknown_error",
"unknown_error",
"unknown_error",
"unknown_error",
"unimplemented",
"internal",
"unavailable"};
} // namespace
class GenericErrorSpace : public util::ErrorSpaceImpl<GenericErrorSpace> {
public:
static std::string space_name();
static std::string code_to_string(int code);
};
std::string GenericErrorSpace::space_name() { return "generic"; }
std::string GenericErrorSpace::code_to_string(int code) {
static_assert(
ABSL_ARRAYSIZE(kGenericErrorStatusMessage) == error::NUM_ERRORS,
"mismatching generic error status message and generic error status.");
if (code >= 0 && code < error::NUM_ERRORS)
return kGenericErrorStatusMessage[code];
return std::to_string(code);
}
const util::ErrorSpace* Status::canonical_space() {
return GenericErrorSpace::Get();
}
std::string Status::ToString() const {
if (status_code_ == error::OK) return "OK";
return absl::StrCat("Errors::", error_space_->String(status_code_), ": ",
error_message_);
}
std::ostream& operator<<(std::ostream& os, const Status& x) {
os << x.ToString();
return os;
}
} // namespace widevine

108
common/status.h Normal file
View File

@@ -0,0 +1,108 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2017 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.
////////////////////////////////////////////////////////////////////////////////
#ifndef COMMON_STATUS_H_
#define COMMON_STATUS_H_
#include <string>
#include "util/error_space.h"
namespace widevine {
namespace error {
enum StatusCode {
// Success.
OK = 0,
// Client specified an invalid argument.
INVALID_ARGUMENT = 3,
// Some requested entity (e.g., file or directory) was not found.
NOT_FOUND = 5,
// Some entity that we attempted to create (e.g., file or directory)
// already exists.
ALREADY_EXISTS = 6,
// The caller does not have permission to execute the specified
// operation. PERMISSION_DENIED must not be used for rejections
// caused by exhausting some resource (use RESOURCE_EXHAUSTED
// instead for those errors).
PERMISSION_DENIED = 7,
// Operation is not implemented or not supported/enabled in this service.
UNIMPLEMENTED = 12,
// Internal errors. Means some invariants expected by underlying
// system has been broken. If you see one of these errors,
// something is very broken.
INTERNAL = 13,
// Operation is not implemented or not supported/enabled in this service.
UNAVAILABLE = 14,
// Number of generic (non license related) errors.
NUM_ERRORS,
};
} // namespace error
class Status {
public:
Status() = default;
~Status() = default;
explicit Status(error::StatusCode c) : status_code_(c) {}
Status(error::StatusCode c, const std::string& error_message)
: status_code_(c), error_message_(error_message) {}
Status(const util::ErrorSpace* e, error::StatusCode c,
const std::string& error_message)
: error_space_(e), status_code_(c), error_message_(error_message) {}
Status(const util::ErrorSpace* e, int error, const std::string& error_message)
: error_space_(e), status_code_(error), error_message_(error_message) {}
bool ok() const { return status_code_ == error::OK; }
const util::ErrorSpace* error_space() const { return error_space_; }
static const util::ErrorSpace* canonical_space();
std::string ToString() const;
std::string error_message() const { return error_message_; }
int error_code() const { return status_code_; }
private:
const util::ErrorSpace* error_space_ = canonical_space();
int status_code_ = error::OK;
std::string error_message_;
};
inline Status OkStatus() { return Status(); }
inline bool operator==(const Status& s1, const Status& s2) {
return s1.error_space() == s2.error_space() &&
s1.error_code() == s2.error_code() &&
s1.error_message() == s2.error_message();
}
inline bool operator!=(const Status& s1, const Status& s2) {
return !(s1 == s2);
}
// Prints a human-readable representation of 'x' to 'os'.
std::ostream& operator<<(std::ostream& os, const Status& x);
#define CHECK_OK(expression) CHECK(expression.ok()) << expression.ToString()
} // namespace widevine
#endif // COMMON_STATUS_H_

61
common/status_test.cc Normal file
View File

@@ -0,0 +1,61 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2007 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.
////////////////////////////////////////////////////////////////////////////////
#include "common/status.h"
#include "testing/gunit.h"
namespace widevine {
TEST(StatusTest, OK_Status) {
// test case for ok status.
Status status(error::OK);
EXPECT_EQ("OK", status.ToString());
}
TEST(StatusTest, OK_Status2) {
// test case for ok status.
Status status;
EXPECT_EQ("OK", status.ToString());
}
TEST(StatusTest, ALREADY_EXISTS_Status) {
Status status(error::ALREADY_EXISTS, "it is already exist");
EXPECT_EQ("Errors::already_exists: it is already exist", status.ToString());
}
// test case for status in boundary cases.
TEST(StatusTest, UNAVAILABLE_Status) {
Status status(error::UNAVAILABLE, "unavailable");
EXPECT_EQ("Errors::unavailable: unavailable", status.ToString());
}
TEST(StatusTest, NoNameCode) {
Status status(static_cast<error::StatusCode>(101), "Unknown error");
EXPECT_EQ("Errors::101: Unknown error", status.ToString());
}
TEST(StatusTest, EQUAL_OPERATOR) {
Status status1(error::ALREADY_EXISTS, "already exists 1");
Status status2(error::ALREADY_EXISTS, "already exists 1");
EXPECT_EQ(status1, status2);
}
TEST(StatusTest, NOT_EQUAL_OPERATOR) {
Status status1(error::ALREADY_EXISTS, "already exists");
Status status2(error::UNAVAILABLE, "unavailable");
EXPECT_NE(status1, status2);
}
TEST(StatusTest, NOT_EQUAL_OPERATOR_NONE_MSG) {
Status status1(error::ALREADY_EXISTS);
Status status2(error::UNAVAILABLE);
EXPECT_NE(status1, status2);
}
} // namespace widevine

View File

@@ -11,14 +11,14 @@
#include <bitset>
#include <sstream>
#include <string>
#include "util/status.h"
#include "common/status.h"
namespace widevine {
namespace string_util {
util::Status BitsetStringToBinaryString(const std::string& bitset, std::string* output) {
Status BitsetStringToBinaryString(const std::string& bitset, std::string* output) {
if (output == nullptr) {
return util::Status(util::error::INTERNAL, "output is nullptr.");
return Status(error::INTERNAL, "output is nullptr.");
}
std::stringstream sstream(bitset);
@@ -29,7 +29,7 @@ util::Status BitsetStringToBinaryString(const std::string& bitset, std::string*
*output += c;
}
return util::OkStatus();
return OkStatus();
}
} // namespace string_util

View File

@@ -10,14 +10,14 @@
#define COMMON_STRING_UTIL_H_
#include <string>
#include "util/status.h"
#include "common/status.h"
namespace widevine {
namespace string_util {
// Converts std::string representation of a bitset to its binary equivalent string.
// For example, converts "01110100011001010111001101110100" to "test".
util::Status BitsetStringToBinaryString(const std::string& bitset, std::string* output);
Status BitsetStringToBinaryString(const std::string& bitset, std::string* output);
} // namespace string_util
} // namespace widevine

View File

@@ -18,32 +18,31 @@
namespace widevine {
util::Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
const std::string& message,
std::string* signature) {
Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
const std::string& message,
std::string* signature) {
CHECK(signature);
if (pem_private_key.empty()) {
return util::Status(util::error::INVALID_ARGUMENT, "Empty PEM private key");
return Status(error::INVALID_ARGUMENT, "Empty PEM private key");
}
if (message.empty()) {
return util::Status(util::error::INVALID_ARGUMENT, "Empty message");
return Status(error::INVALID_ARGUMENT, "Empty message");
}
BIO* bio(NULL);
bio = BIO_new_mem_buf(const_cast<char*>(pem_private_key.data()),
pem_private_key.size());
if (bio == NULL) {
return util::Status(util::error::INTERNAL, "BIO allocation failed");
return Status(error::INTERNAL, "BIO allocation failed");
}
util::Status status;
Status status;
RSA* key(NULL);
std::unique_ptr<char[]> sig_buffer;
unsigned int sig_size;
unsigned char digest[SHA256_DIGEST_LENGTH];
key = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, NULL);
if (key == NULL) {
status = util::Status(util::Status::canonical_space(),
util::error::INVALID_ARGUMENT,
"PEM RSA private key load failed");
status = Status(Status::canonical_space(), error::INVALID_ARGUMENT,
"PEM RSA private key load failed");
goto cleanup;
}
SHA256(reinterpret_cast<const unsigned char*>(message.data()), message.size(),
@@ -53,9 +52,8 @@ util::Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
if (RSA_sign(NID_sha256, digest, sizeof(digest),
reinterpret_cast<unsigned char*>(sig_buffer.get()), &sig_size,
key) != 1) {
status =
util::Status(util::Status::canonical_space(), util::error::INTERNAL,
"RSA private encrypt failed");
status = Status(Status::canonical_space(), error::INTERNAL,
"RSA private encrypt failed");
goto cleanup;
}
signature->assign(sig_buffer.get(), sig_size);

View File

@@ -14,7 +14,7 @@
#include <string>
#include "util/status.h"
#include "common/status.h"
namespace widevine {
@@ -23,9 +23,9 @@ namespace widevine {
// |message| is the message to be signed, and |signature| is a pointer to a
// std::string where the signature will be stored. The caller returns ownership of
// all paramters.
util::Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
const std::string& message,
std::string* signature);
Status GenerateRsaSignatureSha256Pkcs1(const std::string& pem_private_key,
const std::string& message,
std::string* signature);
} // namespace widevine

View File

@@ -14,13 +14,11 @@
#include "common/vmp_checker.h"
namespace widevine {
util::Status VerifyVmpData(
const std::string& vmp_data,
PlatformVerificationStatus* platform_verification_status) {
Status VerifyVmpData(const std::string& vmp_data,
PlatformVerificationStatus* platform_verification_status) {
*platform_verification_status = PLATFORM_UNVERIFIED;
VmpChecker::Result vmp_result;
util::Status status =
VmpChecker::Instance()->VerifyVmpData(vmp_data, &vmp_result);
Status status = VmpChecker::Instance()->VerifyVmpData(vmp_data, &vmp_result);
if (status.ok()) {
switch (vmp_result) {
case VmpChecker::kUnverified:

View File

@@ -13,16 +13,15 @@
#define COMMON_VERIFIED_MEDIA_PIPELINE_H_
#include <string>
#include "util/status.h"
#include "common/status.h"
#include "protos/public/license_protocol.pb.h"
namespace widevine {
// Retrieve the PlatformVerificationStatus for |vmp_data|. The
// PlatformVerificationStatus is defined at
util::Status VerifyVmpData(
const std::string& vmp_data,
PlatformVerificationStatus* platform_verification_status);
Status VerifyVmpData(const std::string& vmp_data,
PlatformVerificationStatus* platform_verification_status);
} // namespace widevine
#endif // COMMON_VERIFIED_MEDIA_PIPELINE_H_

View File

@@ -248,9 +248,9 @@ VmpChecker::VmpChecker() : allow_development_vmp_(false) {}
VmpChecker::~VmpChecker() {}
util::Status VmpChecker::SelectCertificateType(CertificateType cert_type) {
Status VmpChecker::SelectCertificateType(CertificateType cert_type) {
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
util::Status status = ca_cert->LoadDer(
Status status = ca_cert->LoadDer(
cert_type == kCertificateTypeProduction
? std::string(reinterpret_cast<const char*>(
kProdVmpCodeSigningDrmRootCertificate),
@@ -262,7 +262,7 @@ util::Status VmpChecker::SelectCertificateType(CertificateType cert_type) {
ca_.reset(new X509CA(ca_cert.release()));
return util::OkStatus();
return OkStatus();
}
VmpChecker* VmpChecker::Instance() {
@@ -271,17 +271,16 @@ VmpChecker* VmpChecker::Instance() {
}
// Verify VMP data and return appropriate result.
util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* result) {
Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* result) {
DCHECK(!vmp_data.empty());
DCHECK(result);
if (!ca_) return util::Status(error_space, CERT_CHAIN_NOT_SELECTED, "");
if (!ca_) return Status(error_space, CERT_CHAIN_NOT_SELECTED, "");
vmp::VmpData vmp_data_obj;
if (!vmp_data_obj.ParseFromString(vmp_data)) {
LOG(INFO) << "Error deserializing VmpData.";
return util::Status(error_space, INVALID_MESSAGE,
"vmp-data-deserialize-failed");
return Status(error_space, INVALID_MESSAGE, "vmp-data-deserialize-failed");
}
std::vector<std::unique_ptr<X509Cert>> code_signing_certs;
@@ -290,7 +289,7 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu
for (int cert_idx = 0; cert_idx < vmp_data_obj.certificates_size();
++cert_idx) {
code_signing_certs.emplace_back(new X509Cert);
util::Status status(code_signing_certs.back()->LoadDer(
Status status(code_signing_certs.back()->LoadDer(
vmp_data_obj.certificates(cert_idx)));
if (!status.ok()) return status;
@@ -299,8 +298,8 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu
if (code_signing_certs.back()->GetV3BooleanExtension(kDevelopmentFlagOid,
&dev_flag) &&
dev_flag) {
return util::Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
"development-vmp-certificate-not-allowed");
return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
"development-vmp-certificate-not-allowed");
}
}
status = ca_->VerifyCert(*code_signing_certs.back());
@@ -324,12 +323,12 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu
if (binary_info.signature().empty()) {
LOG(INFO) << "Unsigned binary \"" << binary_info.file_name() << "\".";
*result = kTampered;
return util::OkStatus();
return OkStatus();
}
if (binary_info.certificate_index() >= code_signing_certs.size()) {
LOG(INFO) << "Invalid code signing certificate index.";
*result = kTampered;
return util::OkStatus();
return OkStatus();
}
X509Cert* cert = code_signing_certs[binary_info.certificate_index()].get();
std::unique_ptr<RsaPublicKey> key(cert->GetRsaPublicKey());
@@ -339,7 +338,7 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu
LOG(INFO) << "Code signature verification failed for file \""
<< binary_info.file_name() << "\".";
*result = kTampered;
return util::OkStatus();
return OkStatus();
}
if (binary_info.flags() & kBlessedBinaryFlag) ++num_blessed_binaries;
}
@@ -347,13 +346,13 @@ util::Status VmpChecker::VerifyVmpData(const std::string& vmp_data, Result* resu
LOG(INFO) << "Invalid number of blessed binaries (" << num_blessed_binaries
<< ").";
*result = kTampered;
return util::OkStatus();
return OkStatus();
}
VLOG(2) << "VMP verification success. Secure storage: "
<< secure_storage_verified;
*result = secure_storage_verified ? kSecureStorageVerified : kVerified;
return util::OkStatus();
return OkStatus();
}
} // namespace widevine

View File

@@ -16,8 +16,8 @@
#include <memory>
#include <string>
#include "util/status.h"
#include "common/certificate_type.h"
#include "common/status.h"
namespace widevine {
class X509CA;
@@ -35,10 +35,10 @@ class VmpChecker {
static VmpChecker* Instance();
// Select the type of root to use. Not thread-safe.
virtual util::Status SelectCertificateType(CertificateType cert_type);
virtual Status SelectCertificateType(CertificateType cert_type);
// Verify VMP data and return appropriate result.
virtual util::Status VerifyVmpData(const std::string& vmp_data, Result* result);
virtual Status VerifyVmpData(const std::string& vmp_data, Result* result);
// Enable/disable development code signing certificates.
void set_allow_development_vmp(bool allow) { allow_development_vmp_ = allow; }

View File

@@ -16,10 +16,10 @@
#include "absl/synchronization/mutex.h"
#include "util/endian/endian.h"
#include "util/gtl/map_util.h"
#include "util/status.h"
#include "common/aes_cbc_util.h"
#include "common/ecb_util.h"
#include "common/sha_util.h"
#include "common/status.h"
namespace widevine {
@@ -108,20 +108,20 @@ bool WvmTokenHandler::IsSystemIdKnown(uint32_t system_id) {
return PreprovKeysMap::GetSingleton()->IsSystemIdKnown(system_id);
}
util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
std::string* device_key_out,
Cipher* cipher_out,
bool* insecure_out) {
Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
std::string* device_key_out,
Cipher* cipher_out,
bool* insecure_out) {
const std::string default_make_model;
return DecryptDeviceKey(token, default_make_model, device_key_out, cipher_out,
insecure_out);
}
util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
const std::string& make_model,
std::string* device_key_out,
Cipher* cipher_out,
bool* insecure_out) {
Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
const std::string& make_model,
std::string* device_key_out,
Cipher* cipher_out,
bool* insecure_out) {
DCHECK(device_key_out);
// DCHECK below is commented out because preprov_keys_ being nullptr
// is a valid test in wvm_token_handler_test.cc. If we have
@@ -129,12 +129,11 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
// presubmit because evidently Kokoro does debug build.
// DCHECK(preprov_keys_);
if (token.size() < kKeyboxSizeBytes) {
return util::Status(util::error::INVALID_ARGUMENT,
"Keybox token is too short.");
return Status(error::INVALID_ARGUMENT, "Keybox token is too short.");
}
if (PreprovKeysMap::GetSingleton()->IsEmpty()) {
return util::Status(util::error::INVALID_ARGUMENT,
"Pre-provisioning key map is nullptr.");
return Status(error::INVALID_ARGUMENT,
"Pre-provisioning key map is nullptr.");
}
uint32_t system_id = GetSystemId(token);
@@ -143,7 +142,7 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
std::vector<PreprovKey> key_vector =
PreprovKeysMap::GetSingleton()->GetPreprovKeys(system_id);
util::Status status;
Status status;
// First pass through the matching system Ids is an attempt to find an
// alternate preprov key specific to this make/model.
const PreprovKey* preferred_ppk = NULL;
@@ -162,8 +161,8 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
ppk.key_bytes, token, device_key_out, insecure_out, &version);
if (version != 2) {
// Only version 2 keyboxes supported.
return util::Status(util::error::PERMISSION_DENIED,
absl::StrCat("invalid-keybox-version ", version));
return Status(error::PERMISSION_DENIED,
absl::StrCat("invalid-keybox-version ", version));
}
if (status.ok()) {
if (cipher_out) {
@@ -176,8 +175,8 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
// Return error from last attempt.
return status;
}
return util::Status(
util::error::NOT_FOUND,
return Status(
error::NOT_FOUND,
absl::StrCat("Unknown system id: ", system_id).c_str()); // NOLINT
}
@@ -185,12 +184,13 @@ util::Status WvmTokenHandler::DecryptDeviceKey(absl::string_view token,
// decrypted device key to encrypt the given asset key. Returns the encrypted
// asset key in |result|.
// On failure, returns an error from the Widevine Server SDK error space.
util::Status WvmTokenHandler::GetEncryptedAssetKey(
absl::string_view token, absl::string_view raw_asset_key,
const std::string& make_model, std::string* result) {
Status WvmTokenHandler::GetEncryptedAssetKey(absl::string_view token,
absl::string_view raw_asset_key,
const std::string& make_model,
std::string* result) {
std::string device_key;
Cipher cipher = AES;
util::Status status =
Status status =
DecryptDeviceKey(token, make_model, &device_key, &cipher, nullptr);
if (!status.ok()) {
return status;
@@ -215,20 +215,19 @@ std::string WvmTokenHandler::GetEncryptedUniqueId(absl::string_view token) {
return encrypted_unique_id;
}
util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
absl::string_view preprov_key, absl::string_view token,
std::string* device_key_out) {
return DecryptDeviceKeyWithPreprovKey(preprov_key, token, device_key_out,
nullptr, nullptr);
}
util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
absl::string_view preprov_key, absl::string_view token,
std::string* device_key_out, bool* insecure_out, uint32_t* version) {
CHECK(device_key_out);
if (token.size() < kKeyboxSizeBytes) {
return util::Status(util::error::INVALID_ARGUMENT,
"Keybox token is too short.");
return Status(error::INVALID_ARGUMENT, "Keybox token is too short.");
}
if (version) {
*version = BigEndian::Load32(token.data());
@@ -243,7 +242,7 @@ util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
if (unique_id.size() != 16) {
// Decrypting 16 bytes should result in 16 bytes.
LOG(WARNING) << "Internal error decrypting unique id from token.";
return util::Status(util::error::INTERNAL, "Wrong size after decrypt/16.");
return Status(error::INTERNAL, "Wrong size after decrypt/16.");
}
absl::string_view encrypted_bits = token.substr(24, 48);
@@ -252,7 +251,7 @@ util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
if (decrypted_bits.size() != 48) {
// Decrypting 48 bytes should result in 48 bytes.
LOG(WARNING) << "Internal error decrypting device key from token.";
return util::Status(util::error::INTERNAL, "Wrong size after decrypt/48.");
return Status(error::INTERNAL, "Wrong size after decrypt/48.");
}
uint8_t keybox_flags = decrypted_bits[36];
absl::string_view device_key =
@@ -269,48 +268,43 @@ util::Status WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
keybox_flags = 0;
}
if (expected_hash != actual_hash) {
return util::Status(util::error::PERMISSION_DENIED,
"Keybox validation failed.");
return Status(error::PERMISSION_DENIED, "Keybox validation failed.");
}
*device_key_out = std::string(device_key);
if (insecure_out) {
*insecure_out = (keybox_flags & kKeyboxFlagInsecure) != 0;
}
return util::OkStatus();
return OkStatus();
}
util::Status WvmTokenHandler::EncryptAssetKey(absl::string_view device_key,
absl::string_view raw_asset_key,
Cipher cipher, std::string* result) {
Status WvmTokenHandler::EncryptAssetKey(absl::string_view device_key,
absl::string_view raw_asset_key,
Cipher cipher, std::string* result) {
CHECK(result);
if (device_key.size() != 16) {
return util::Status(util::error::INVALID_ARGUMENT,
"Invalid device key: size != 16");
return Status(error::INVALID_ARGUMENT, "Invalid device key: size != 16");
}
if (raw_asset_key.size() < 16) {
return util::Status(util::error::INVALID_ARGUMENT,
"Invalid asset key: size < 16");
return Status(error::INVALID_ARGUMENT, "Invalid asset key: size < 16");
}
// Truncate extra characters in the key; wvm always uses 16.
absl::string_view asset_key = raw_asset_key.substr(0, 16);
switch (cipher) {
case DES3:
if (!crypto_util::Encrypt3DesEcb(device_key, asset_key, result)) {
return util::Status(util::error::INTERNAL,
"Error encrypting asset key with 3DES.");
return Status(error::INTERNAL, "Error encrypting asset key with 3DES.");
}
return util::OkStatus();
return OkStatus();
case AES:
if (!crypto_util::EncryptAesEcb(device_key, asset_key, result)) {
return util::Status(util::error::INTERNAL,
"Error encrypting asset key with AES.");
return Status(error::INTERNAL, "Error encrypting asset key with AES.");
}
return util::OkStatus();
return OkStatus();
case PASS_THRU:
result->assign(raw_asset_key.data(), raw_asset_key.size());
return util::OkStatus();
return OkStatus();
default:
return util::Status(util::error::INVALID_ARGUMENT, "Unknown cipher type");
return Status(error::INVALID_ARGUMENT, "Unknown cipher type");
}
}

View File

@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "absl/strings/string_view.h"
#include "util/status.h"
#include "common/status.h"
namespace widevine {
@@ -70,24 +70,23 @@ class WvmTokenHandler {
// to use with the device key.
// insecure_out may be null; if not, *insecure_out will be set to the
// decrypted value of the 'insecure keybox' flag.
static util::Status DecryptDeviceKey(absl::string_view token,
std::string* device_key_out,
Cipher* cipher_out, bool* insecure_out);
static Status DecryptDeviceKey(absl::string_view token,
std::string* device_key_out, Cipher* cipher_out,
bool* insecure_out);
// Same as above, except takes in the make/model from the license request.
// For legacy WVM license, we have some special cases where we need to inspect
// the make/model as we apply alternate keys.
static util::Status DecryptDeviceKey(absl::string_view token,
const std::string& make_model,
std::string* device_key_out,
Cipher* cipher_out, bool* insecure_out);
static Status DecryptDeviceKey(absl::string_view token,
const std::string& make_model,
std::string* device_key_out, Cipher* cipher_out,
bool* insecure_out);
// Decrypt a token using the preprov key for its system ID, and use the
// decrypted device key to encrypt the given asset key. Returns the encrypted
// asset key in result.
static util::Status GetEncryptedAssetKey(absl::string_view token,
absl::string_view raw_asset_key,
const std::string& make_model,
std::string* result);
static Status GetEncryptedAssetKey(absl::string_view token,
absl::string_view raw_asset_key,
const std::string& make_model, std::string* result);
// Extract the system ID component of a token (bytes 4-8).
static uint32_t GetSystemId(absl::string_view token);
@@ -101,21 +100,21 @@ class WvmTokenHandler {
// Note that the if the input std::string lengths are correct (16 and 72 bytes),
// the only possible cause of failure is the decrypted device key hash
// being incorrect.
static util::Status DecryptDeviceKeyWithPreprovKey(
static Status DecryptDeviceKeyWithPreprovKey(
absl::string_view preprov_key_bytes, absl::string_view token,
std::string* device_key_out);
// Same as above, but allows extracting the 'insecure keybox' flag and keybox
// version.
static util::Status DecryptDeviceKeyWithPreprovKey(
static Status DecryptDeviceKeyWithPreprovKey(
absl::string_view preprov_key_bytes, absl::string_view token,
std::string* device_key_out, bool* insecure_out, uint32_t* version);
// Given a decrypted device key as returned by DecryptToken(), use it to
// encrypt an asset key with the given cipher.
static util::Status EncryptAssetKey(absl::string_view device_key,
absl::string_view raw_asset_key,
Cipher cipher, std::string* result);
static Status EncryptAssetKey(absl::string_view device_key,
absl::string_view raw_asset_key, Cipher cipher,
std::string* result);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(WvmTokenHandler);

View File

@@ -29,12 +29,6 @@ namespace widevine {
using absl::BytesToHexString;
using absl::HexStringToBytes;
// TODO(user): Add EXPECT_OK macro to testing/gmock.h.
// (b/37545268).
#define EXPECT_OK(expression) \
EXPECT_EQ(util::error::OK, expression.error_code())
TEST(WvmTokenHandlerTest, GetSystemId) {
EXPECT_EQ(kTestSystemId,
WvmTokenHandler::GetSystemId(HexStringToBytes(kTestToken1Hex)));
@@ -52,7 +46,7 @@ TEST(WvmTokenHandlerTest, GetEncryptedUniqueId) {
}
TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) {
util::Status status;
Status status;
std::string device_key;
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
@@ -76,7 +70,7 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) {
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
HexStringToBytes(kTestPreprovKeyHex), token, &device_key);
EXPECT_FALSE(status.ok());
EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code());
EXPECT_EQ(error::PERMISSION_DENIED, status.error_code());
EXPECT_TRUE(device_key.empty());
}
@@ -86,18 +80,18 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKeyWithPreprovKey) {
TEST(WvmTokenHandlerTest, DecryptDeviceKey_PreprovKeysNullPtr) {
// Not calling WvmTokenHandler::SetPreprovKeys()
// So preprov_keys_ would be nullptr.
util::Status status;
Status status;
std::string device_key;
status = WvmTokenHandler::DecryptDeviceKey(HexStringToBytes(kTestToken1Hex),
&device_key, nullptr, nullptr);
EXPECT_FALSE(status.ok());
EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code());
EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code());
}
// Same tests as DecryptDeviceKeyWithPreprovKey(), but we use the handler's
// table of preprov keys instead of providing our own.
TEST(WvmTokenHandlerTest, DecryptDeviceKey) {
util::Status status;
Status status;
std::string device_key;
WvmTokenHandler::SetPreprovKeys(GetPreprovKeyVector());
@@ -120,7 +114,7 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKey) {
status =
WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr);
EXPECT_FALSE(status.ok());
EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code());
EXPECT_EQ(error::PERMISSION_DENIED, status.error_code());
EXPECT_TRUE(device_key.empty());
// Test with nonexistent system id. Should produce NOT_FOUND.
@@ -132,7 +126,7 @@ TEST(WvmTokenHandlerTest, DecryptDeviceKey) {
status =
WvmTokenHandler::DecryptDeviceKey(token, &device_key, nullptr, nullptr);
EXPECT_FALSE(status.ok());
EXPECT_EQ(util::error::NOT_FOUND, status.error_code());
EXPECT_EQ(error::NOT_FOUND, status.error_code());
EXPECT_TRUE(device_key.empty());
}
@@ -142,7 +136,7 @@ TEST(WvmTokenHandlerTest, GetEncryptedAssetKey) {
std::string raw_asset_key = "asset-key-000000";
std::string asset_key;
std::string make_model;
util::Status status = WvmTokenHandler::GetEncryptedAssetKey(
Status status = WvmTokenHandler::GetEncryptedAssetKey(
HexStringToBytes(kTestToken1Hex), raw_asset_key, make_model, &asset_key);
EXPECT_OK(status);
EXPECT_EQ("305d5f979074b1c4f932be70d3cc850c", BytesToHexString(asset_key));
@@ -194,7 +188,7 @@ TEST(WvmTokenHandlerTest, FilterOnMakeModel) {
std::string raw_asset_key = "asset-key-000000";
std::string asset_key;
// Check 3DES encryption of asset keys
util::Status status = WvmTokenHandler::EncryptAssetKey(
Status status = WvmTokenHandler::EncryptAssetKey(
HexStringToBytes(kTestDeviceKey3DesHex), raw_asset_key,
WvmTokenHandler::DES3, &asset_key);
EXPECT_OK(status);
@@ -220,7 +214,7 @@ TEST(WvmTokenHandlerTest, FilterOnMakeModel) {
}
TEST(WvmTokenHandlerTest, AncientKeybox) {
util::Status status;
Status status;
std::string device_key;
std::string v1_token(
@@ -228,7 +222,7 @@ TEST(WvmTokenHandlerTest, AncientKeybox) {
status = WvmTokenHandler::DecryptDeviceKeyWithPreprovKey(
HexStringToBytes(v1_token), HexStringToBytes(kTestToken1Hex),
&device_key);
EXPECT_EQ(util::error::PERMISSION_DENIED, status.error_code());
EXPECT_EQ(error::PERMISSION_DENIED, status.error_code());
EXPECT_TRUE(device_key.empty());
}

View File

@@ -67,22 +67,20 @@ X509Cert::~X509Cert() {
X509Cert::X509Cert(X509* openssl_cert) : openssl_cert_(openssl_cert) {}
util::Status X509Cert::LoadPem(const std::string& pem_cert) {
Status X509Cert::LoadPem(const std::string& pem_cert) {
if (pem_cert.empty()) {
return util::Status(util::error::INVALID_ARGUMENT, "Empty PEM certificate");
return Status(error::INVALID_ARGUMENT, "Empty PEM certificate");
}
BIO* bio(NULL);
X509* new_cert(NULL);
bio = BIO_new_mem_buf(const_cast<char*>(pem_cert.data()), pem_cert.size());
if (bio == NULL) {
return util::Status(util::error::INTERNAL, "BIO allocation failed");
return Status(error::INTERNAL, "BIO allocation failed");
}
util::Status status;
Status status;
new_cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
if (new_cert == NULL) {
status = util::Status(util::Status::canonical_space(),
util::error::INVALID_ARGUMENT,
"PEM certificate load failed");
status = Status(error::INVALID_ARGUMENT, "PEM certificate load failed");
goto cleanup;
}
if (openssl_cert_ != NULL) {
@@ -97,22 +95,21 @@ cleanup:
return status;
}
util::Status X509Cert::LoadDer(const std::string& der_cert) {
Status X509Cert::LoadDer(const std::string& der_cert) {
if (der_cert.empty()) {
return util::Status(util::error::INVALID_ARGUMENT, "Empty DER certificate");
return Status(error::INVALID_ARGUMENT, "Empty DER certificate");
}
const unsigned char* cert_data =
reinterpret_cast<const unsigned char*>(der_cert.data());
X509* new_cert = d2i_X509(NULL, &cert_data, der_cert.size());
if (new_cert == NULL) {
return util::Status(util::error::INVALID_ARGUMENT,
"DER certificate load failed");
return Status(error::INVALID_ARGUMENT, "DER certificate load failed");
}
if (openssl_cert_ != NULL) {
X509_free(openssl_cert_);
}
openssl_cert_ = new_cert;
return util::OkStatus();
return OkStatus();
}
std::string X509Cert::GetPem() const {
@@ -184,6 +181,24 @@ std::string X509Cert::GetSerialNumber() const {
return result;
}
bool X509Cert::GetNotBeforeSeconds(int64_t* valid_start_seconds) const {
if (openssl_cert_ == nullptr) {
return false;
}
return Asn1TimeToEpochSeconds(X509_get0_notBefore(openssl_cert_),
valid_start_seconds)
.ok();
}
bool X509Cert::GetNotAfterSeconds(int64_t* valid_end_seconds) const {
if (openssl_cert_ == nullptr) {
return false;
}
return Asn1TimeToEpochSeconds(X509_get0_notAfter(openssl_cert_),
valid_end_seconds)
.ok();
}
bool X509Cert::IsCaCertificate() const {
return X509_check_ca(openssl_cert_) != 0;
}
@@ -204,6 +219,38 @@ bool X509Cert::GetV3BooleanExtension(const std::string& oid, bool* value) const
return true;
}
Status X509Cert::Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time,
int64_t* epoch_seconds) const {
if (asn1_time == nullptr) {
// This code is exported to shared source. The exported code does not yet
// support MakeStatus.
// NOLINTNEXTLINE
return Status(error::INVALID_ARGUMENT, "asn1_time cannot be null.");
}
if (epoch_seconds == nullptr) {
// NOLINTNEXTLINE
return Status(error::INVALID_ARGUMENT, "epoch_seconds cannot be null.");
}
ScopedAsn1Time epoch_time(ASN1_TIME_new());
if (!ASN1_TIME_set(epoch_time.get(), 0)) {
// NOLINTNEXTLINE
return Status(error::INTERNAL, "Failed to set epoch time.");
}
int day = 0;
int seconds = 0;
if (!ASN1_TIME_diff(&day, &seconds, epoch_time.get(), asn1_time)) {
// NOLINTNEXTLINE
return Status(error::INTERNAL,
"Failed to convert asn1 time to epoch time.");
}
*epoch_seconds = 24L * 3600L * day + seconds;
return OkStatus();
}
X509CertChain::~X509CertChain() { Reset(); }
void X509CertChain::Reset() {
@@ -213,7 +260,7 @@ void X509CertChain::Reset() {
cert_chain_.clear();
}
util::Status X509CertChain::LoadPem(const std::string& pem_cert_chain) {
Status X509CertChain::LoadPem(const std::string& pem_cert_chain) {
static const char kBeginCertificate[] = "-----BEGIN CERTIFICATE-----";
static const char kEndCertificate[] = "-----END CERTIFICATE-----";
@@ -225,7 +272,7 @@ util::Status X509CertChain::LoadPem(const std::string& pem_cert_chain) {
if (end_pos != std::string::npos) {
end_pos += sizeof(kEndCertificate) - 1;
std::unique_ptr<X509Cert> new_cert(new X509Cert);
util::Status status = new_cert->LoadPem(
Status status = new_cert->LoadPem(
pem_cert_chain.substr(begin_pos, end_pos - begin_pos));
if (!status.ok()) {
return status;
@@ -234,17 +281,17 @@ util::Status X509CertChain::LoadPem(const std::string& pem_cert_chain) {
begin_pos = pem_cert_chain.find(kBeginCertificate, end_pos);
}
}
return util::OkStatus();
return OkStatus();
}
util::Status X509CertChain::LoadPkcs7(const std::string& pk7_cert_chain) {
Status X509CertChain::LoadPkcs7(const std::string& pk7_cert_chain) {
ScopedX509Stack cert_stack(sk_X509_new_null());
CBS cbs;
CBS_init(&cbs, reinterpret_cast<const uint8_t*>(pk7_cert_chain.data()),
pk7_cert_chain.size());
if (!PKCS7_get_certificates(cert_stack.get(), &cbs)) {
return util::Status(util::error::INVALID_ARGUMENT,
"Unable to load PKCS#7 certificate chain");
return Status(error::INVALID_ARGUMENT,
"Unable to load PKCS#7 certificate chain");
}
while (sk_X509_num(cert_stack.get()) > 0) {
@@ -252,7 +299,7 @@ util::Status X509CertChain::LoadPkcs7(const std::string& pk7_cert_chain) {
new X509Cert(sk_X509_pop(cert_stack.get())));
}
return util::OkStatus();
return OkStatus();
}
std::string X509CertChain::GetPkcs7() {
@@ -305,44 +352,42 @@ X509CA::~X509CA() {
}
}
util::Status X509CA::InitializeStore() {
Status X509CA::InitializeStore() {
absl::WriterMutexLock lock(&openssl_store_mutex_);
if (openssl_store_ == NULL) {
if (ca_cert_ == NULL) {
return util::Status(util::error::INTERNAL, "CA X.509Cert is NULL");
return Status(error::INTERNAL, "CA X.509Cert is NULL");
}
openssl_store_ = X509_STORE_new();
if (openssl_store_ == NULL) {
return util::Status(util::error::INTERNAL,
"Failed to allocate X.509 store");
return Status(error::INTERNAL, "Failed to allocate X.509 store");
}
if (X509_STORE_add_cert(openssl_store_,
const_cast<X509*>(ca_cert_->openssl_cert())) == 0) {
X509_STORE_free(openssl_store_);
openssl_store_ = NULL;
return util::Status(util::error::INTERNAL,
"Failed to add X.509 CA certificate to store");
return Status(error::INTERNAL,
"Failed to add X.509 CA certificate to store");
}
}
return util::OkStatus();
return OkStatus();
}
util::Status X509CA::VerifyCert(const X509Cert& cert) {
Status X509CA::VerifyCert(const X509Cert& cert) {
return OpenSslX509Verify(cert.openssl_cert(), nullptr);
}
util::Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) {
Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) {
if (cert_chain.GetNumCerts() < 1) {
return util::Status(util::error::INVALID_ARGUMENT,
"Cannot verify empty certificate chain");
return Status(error::INVALID_ARGUMENT,
"Cannot verify empty certificate chain");
}
ScopedX509StackOnly intermediates(sk_X509_new_null());
if (!intermediates) {
return util::Status(
util::Status::canonical_space(), util::error::INTERNAL,
"Failed to allocate X.509 intermediate certificate stack");
return Status(error::INTERNAL,
"Failed to allocate X.509 intermediate certificate stack");
}
const X509Cert* leaf_cert(nullptr);
for (size_t idx = 0; idx < cert_chain.GetNumCerts(); ++idx) {
@@ -354,23 +399,21 @@ util::Status X509CA::VerifyCertChain(const X509CertChain& cert_chain) {
}
}
if (!leaf_cert) {
return util::Status(util::Status::canonical_space(),
util::error::INVALID_ARGUMENT,
"X.509 certificate chain without leaf certificate.");
return Status(error::INVALID_ARGUMENT,
"X.509 certificate chain without leaf certificate.");
}
return OpenSslX509Verify(leaf_cert->openssl_cert(), intermediates.get());
}
util::Status X509CA::VerifyCertWithChain(const X509Cert& cert,
const X509CertChain& cert_chain) {
Status X509CA::VerifyCertWithChain(const X509Cert& cert,
const X509CertChain& cert_chain) {
ScopedX509StackOnly intermediates(sk_X509_new_null());
if (!intermediates) {
// MakeStatus is now preferred. But we don't support it in the exported
// version, yet. So, ignore lint here.
// NOLINTNEXTLINE
return util::Status(
util::Status::canonical_space(), util::error::INTERNAL,
"Failed to allocate X.509 intermediate certificate stack");
return Status(error::INTERNAL,
"Failed to allocate X.509 intermediate certificate stack");
}
for (size_t idx = 0; idx < cert_chain.GetNumCerts(); ++idx) {
sk_X509_push(intermediates.get(),
@@ -380,14 +423,14 @@ util::Status X509CA::VerifyCertWithChain(const X509Cert& cert,
return OpenSslX509Verify(cert.openssl_cert(), intermediates.get());
}
util::Status X509CA::OpenSslX509Verify(const X509* cert,
STACK_OF(X509) * intermediates) {
Status X509CA::OpenSslX509Verify(const X509* cert,
STACK_OF(X509) * intermediates) {
DCHECK(cert);
absl::ReaderMutexLock lock(&openssl_store_mutex_);
if (openssl_store_ == NULL) {
openssl_store_mutex_.ReaderUnlock();
util::Status status = InitializeStore();
Status status = InitializeStore();
if (!status.ok()) {
return status;
}
@@ -395,23 +438,21 @@ util::Status X509CA::OpenSslX509Verify(const X509* cert,
}
ScopedX509StoreCtx store_ctx(X509_STORE_CTX_new());
if (!store_ctx) {
return util::Status(util::Status::canonical_space(), util::error::INTERNAL,
"Failed to allocate X.509 store context");
return Status(error::INTERNAL, "Failed to allocate X.509 store context");
}
if (X509_STORE_CTX_init(store_ctx.get(), openssl_store_,
const_cast<X509*>(cert), intermediates) == 0) {
return util::Status(util::Status::canonical_space(), util::error::INTERNAL,
"Failed to initialize X.509 store context");
return Status(error::INTERNAL, "Failed to initialize X.509 store context");
}
int x509_status = X509_verify_cert(store_ctx.get());
if (x509_status != 1) {
return util::Status(util::Status::canonical_space(), util::error::INTERNAL,
std::string("X.509 certificate chain validation failed: ") +
X509_verify_cert_error_string(
X509_STORE_CTX_get_error(store_ctx.get())));
return Status(error::INTERNAL,
std::string("X.509 certificate chain validation failed: ") +
X509_verify_cert_error_string(
X509_STORE_CTX_get_error(store_ctx.get())));
}
return util::OkStatus();
return OkStatus();
}
} // namespace widevine

View File

@@ -24,13 +24,13 @@
#include "openssl/pem.h"
#include "openssl/x509.h"
#include "openssl/x509v3.h"
#include "util/status.h"
#include "common/openssl_util.h"
#include "common/rsa_key.h"
#include "common/status.h"
namespace widevine {
// NOTE: All util::Status codes are in the canonical error space.
// NOTE: All Status codes are in the canonical error space.
// Class which holds a single X.509 certificates.
class X509Cert {
@@ -43,11 +43,11 @@ class X509Cert {
// Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is
// a PEM-encoded certificate.
util::Status LoadPem(const std::string& pem_cert);
Status LoadPem(const std::string& pem_cert);
// Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is
// a DER-encoded certificate.
util::Status LoadDer(const std::string& der_cert);
Status LoadDer(const std::string& der_cert);
// Return a std::string containing the PEM-encoded certificate.
std::string GetPem() const;
@@ -70,6 +70,16 @@ class X509Cert {
// if an error occurs.
std::string GetSerialNumber() const;
// Gets the start of the validity period for the certificate in seconds
// since the epoch. |valid_start_seconds| must not be null. Returns true on
// success, false otherwise.
bool GetNotBeforeSeconds(int64_t* valid_start_seconds) const;
// Gets the end of the validity period for the certificate in seconds
// since the epoch. |valid_end_seconds| must not be null. Returns true on
// success, false otherwise.
bool GetNotAfterSeconds(int64_t* valid_end_seconds) const;
// Returns true if the certificate is a CA (root or intermediate) certificate.
bool IsCaCertificate() const;
@@ -81,6 +91,8 @@ class X509Cert {
private:
explicit X509Cert(X509* openssl_cert);
Status Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time,
int64_t* epoch_seconds) const;
X509* openssl_cert_;
std::string subject_name_;
@@ -100,12 +112,12 @@ class X509CertChain {
// |pem_cert_chain|, which is the concatenation of a number of PEM X.509
// certificates, beginning with the leaf certificate, and ending with the
// certificate signed by the root CA.
util::Status LoadPem(const std::string& pem_cert_chain);
Status LoadPem(const std::string& pem_cert_chain);
// Loads a chain of DER-encoded PKCS#7 certificates. Takes a single parameter,
// |pk7_cert_chain|, which is a DER-encoded PKCS#7 X.509 certificate
// container.
util::Status LoadPkcs7(const std::string& pk7_cert_chain);
Status LoadPkcs7(const std::string& pk7_cert_chain);
// Writes the |cert_chain_| to a DER-encoded PKCS#7 X.509 cryptographic
// message. The final message does not include signed data.
@@ -136,21 +148,21 @@ class X509CA {
// Does X.509 PKI validation of |cert| against the root CA certificate
// used when constructing X509CA. This method is thread-safe.
util::Status VerifyCert(const X509Cert& cert);
Status VerifyCert(const X509Cert& cert);
// Does X.509 PKI validation of |cert_chain| against the root CA certificate
// used when constructing X509CA. This method is thread-safe.
util::Status VerifyCertChain(const X509CertChain& cert_chain);
Status VerifyCertChain(const X509CertChain& cert_chain);
// Does X.509 PKI validation of |cert| using the |cert_chain|
// certificates. This method allows |cert| to be an ICA. This method is
// thread-safe.
util::Status VerifyCertWithChain(const X509Cert& cert,
const X509CertChain& cert_chain);
Status VerifyCertWithChain(const X509Cert& cert,
const X509CertChain& cert_chain);
private:
util::Status InitializeStore();
util::Status OpenSslX509Verify(const X509* cert, STACK_OF(X509) * stack);
Status InitializeStore();
Status OpenSslX509Verify(const X509* cert, STACK_OF(X509) * intermediates);
std::unique_ptr<X509Cert> ca_cert_;
absl::Mutex openssl_store_mutex_;

View File

@@ -107,6 +107,9 @@ const char kTestPemCertSubjectField_CN[] =
"stable id/emailAddress=tinskip@google.com";
const char kTestPemCertSerialNumber[] = "\002";
const int64_t kTestPemCertNotBeforeSeconds = 1376689440;
const int64_t kTestPemCertNotAfterSeconds = 2007755040;
const char kTestPemCertChain[] =
"-----BEGIN CERTIFICATE-----\n"
"MIIDwzCCAqsCAQIwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYD\n"
@@ -352,23 +355,23 @@ const bool kTestDevCodeSigningCertFlagValue = true;
TEST(X509CertTest, LoadCert) {
X509Cert test_cert;
EXPECT_EQ(util::OkStatus(),
EXPECT_EQ(OkStatus(),
test_cert.LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
EXPECT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
EXPECT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
// TODO(user): Add more specific status checks to failure tests.
EXPECT_NE(util::OkStatus(), test_cert.LoadDer("bad cert"));
EXPECT_NE(util::OkStatus(), test_cert.LoadPem("bad cert"));
EXPECT_NE(util::OkStatus(), test_cert.LoadDer(""));
EXPECT_NE(util::OkStatus(), test_cert.LoadPem(""));
EXPECT_NE(OkStatus(), test_cert.LoadDer("bad cert"));
EXPECT_NE(OkStatus(), test_cert.LoadPem("bad cert"));
EXPECT_NE(OkStatus(), test_cert.LoadDer(""));
EXPECT_NE(OkStatus(), test_cert.LoadPem(""));
}
TEST(X509CertTest, VerifySignature) {
X509Cert test_cert;
ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
std::string message(absl::HexStringToBytes(kTestMessage));
std::string signature;
ASSERT_EQ(util::OkStatus(), GenerateRsaSignatureSha256Pkcs1(
kTestCertPrivateKey, message, &signature));
ASSERT_EQ(OkStatus(), GenerateRsaSignatureSha256Pkcs1(kTestCertPrivateKey,
message, &signature));
std::unique_ptr<RsaPublicKey> pub_key(test_cert.GetRsaPublicKey());
ASSERT_TRUE(pub_key);
EXPECT_TRUE(pub_key->VerifySignatureSha256Pkcs7(message, signature));
@@ -381,7 +384,7 @@ TEST(X509CertTest, VerifySignature) {
TEST(X509CertTest, GetSubjectNameField) {
X509Cert test_cert;
ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
EXPECT_EQ(kTestPemCertSubjectField_C, test_cert.GetSubjectNameField("C"));
EXPECT_EQ(kTestPemCertSubjectField_CN, test_cert.GetSubjectNameField("CN"));
EXPECT_EQ("", test_cert.GetSubjectNameField("invalid_field"));
@@ -389,13 +392,29 @@ TEST(X509CertTest, GetSubjectNameField) {
TEST(X509CertTest, GetSerialNumber) {
X509Cert test_cert;
ASSERT_EQ(util::OkStatus(), test_cert.LoadPem(kTestPemCert));
ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
EXPECT_EQ(kTestPemCertSerialNumber, test_cert.GetSerialNumber());
}
TEST(X509CertTest, GetNotBeforeSeconds) {
X509Cert test_cert;
ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
int64_t not_before_seconds = 0;
ASSERT_TRUE(test_cert.GetNotBeforeSeconds(&not_before_seconds));
EXPECT_EQ(kTestPemCertNotBeforeSeconds, not_before_seconds);
}
TEST(X509CertTest, GetNotAfterSeconds) {
X509Cert test_cert;
ASSERT_EQ(OkStatus(), test_cert.LoadPem(kTestPemCert));
int64_t not_after_seconds = 0;
ASSERT_TRUE(test_cert.GetNotAfterSeconds(&not_after_seconds));
EXPECT_EQ(kTestPemCertNotAfterSeconds, not_after_seconds);
}
TEST(X509CertTest, CertChain) {
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
ASSERT_EQ(2, test_chain.GetNumCerts());
EXPECT_FALSE(test_chain.GetCert(0) == NULL);
EXPECT_FALSE(test_chain.GetCert(1) == NULL);
@@ -404,7 +423,7 @@ TEST(X509CertTest, CertChain) {
TEST(X509CertTest, IsCaCertificate) {
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
ASSERT_EQ(2, test_chain.GetNumCerts());
EXPECT_FALSE(test_chain.GetCert(0)->IsCaCertificate());
EXPECT_TRUE(test_chain.GetCert(1)->IsCaCertificate());
@@ -412,84 +431,84 @@ TEST(X509CertTest, IsCaCertificate) {
TEST(X509CertTest, ChainVerificationPem) {
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
ASSERT_EQ(util::OkStatus(),
ASSERT_EQ(OkStatus(),
ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
X509CA ca(ca_cert.release());
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCert));
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCert));
ASSERT_EQ(1, test_chain.GetNumCerts());
EXPECT_NE(util::OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
EXPECT_NE(OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain));
}
TEST(X509CertTest, ChainVerificationPkcs7) {
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
ASSERT_EQ(util::OkStatus(),
ASSERT_EQ(OkStatus(),
ca_cert->LoadDer(absl::HexStringToBytes(kTestRootCaDerCert)));
X509CA ca(ca_cert.release());
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(),
ASSERT_EQ(OkStatus(),
test_chain.LoadPkcs7(absl::HexStringToBytes(kTestPk7CertChain)));
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCert));
EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCert));
ASSERT_EQ(1, test_chain.GetNumCerts());
EXPECT_NE(util::OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
EXPECT_EQ(util::OkStatus(), ca.VerifyCertChain(test_chain));
EXPECT_NE(OkStatus(), ca.VerifyCertChain(test_chain));
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
EXPECT_EQ(OkStatus(), ca.VerifyCertChain(test_chain));
}
TEST(X509CertTest, VerifyCertWithChainIca) {
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
ASSERT_EQ(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
ASSERT_EQ(OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
X509CA ca(ca_cert.release());
// Verify the ICA with the root succeeds.
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestRootCaPemCert));
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestRootCaPemCert));
ASSERT_EQ(1, test_chain.GetNumCerts());
X509Cert ica_cert;
ASSERT_EQ(util::OkStatus(), ica_cert.LoadPem(kTestPemIca));
EXPECT_EQ(util::OkStatus(), ca.VerifyCertWithChain(ica_cert, test_chain));
ASSERT_EQ(OkStatus(), ica_cert.LoadPem(kTestPemIca));
EXPECT_EQ(OkStatus(), ca.VerifyCertWithChain(ica_cert, test_chain));
}
TEST(X509CertTest, VerifyCertWithChainLeaf) {
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
ASSERT_EQ(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
ASSERT_EQ(OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
X509CA ca(ca_cert.release());
// Verify the leaf with the root and ICA succeeds.
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemIca));
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemIca));
ASSERT_EQ(1, test_chain.GetNumCerts());
X509Cert leaf_cert;
ASSERT_EQ(util::OkStatus(), leaf_cert.LoadPem(kTestPemCert));
EXPECT_EQ(util::OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain));
ASSERT_EQ(OkStatus(), leaf_cert.LoadPem(kTestPemCert));
EXPECT_EQ(OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain));
}
TEST(X509CertTest, VerifyCertWithChainLeafMissincIca) {
std::unique_ptr<X509Cert> ca_cert(new X509Cert);
ASSERT_EQ(util::OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
ASSERT_EQ(OkStatus(), ca_cert->LoadPem(kTestRootCaPemCert));
X509CA ca(ca_cert.release());
// Verify the leaf with only the root fails (ICA missing).
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestRootCaPemCert));
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestRootCaPemCert));
ASSERT_EQ(1, test_chain.GetNumCerts());
X509Cert leaf_cert;
ASSERT_EQ(util::OkStatus(), leaf_cert.LoadPem(kTestPemCert));
EXPECT_NE(util::OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain));
ASSERT_EQ(OkStatus(), leaf_cert.LoadPem(kTestPemCert));
EXPECT_NE(OkStatus(), ca.VerifyCertWithChain(leaf_cert, test_chain));
}
TEST(X509CertTest, GetPkcs7) {
X509CertChain test_chain;
ASSERT_EQ(util::OkStatus(), test_chain.LoadPem(kTestPemCertChain));
ASSERT_EQ(OkStatus(), test_chain.LoadPem(kTestPemCertChain));
std::string pkcs7_certificate = test_chain.GetPkcs7();
ASSERT_NE(pkcs7_certificate.size(), 0);
X509CertChain new_test_chain;
ASSERT_EQ(util::OkStatus(), new_test_chain.LoadPkcs7(pkcs7_certificate));
ASSERT_EQ(OkStatus(), new_test_chain.LoadPkcs7(pkcs7_certificate));
ASSERT_EQ(test_chain.GetNumCerts(), new_test_chain.GetNumCerts());
for (int i = 0; i < test_chain.GetNumCerts(); i++) {
ASSERT_EQ(test_chain.GetCert(i)->GetPem(),
@@ -499,12 +518,12 @@ TEST(X509CertTest, GetPkcs7) {
TEST(X509CertTest, BooleanExtension) {
std::unique_ptr<X509Cert> cert1(new X509Cert);
ASSERT_EQ(util::OkStatus(), cert1->LoadPem(kTestPemCert));
ASSERT_EQ(OkStatus(), cert1->LoadPem(kTestPemCert));
bool extension_value;
EXPECT_FALSE(cert1->GetV3BooleanExtension(kDevCertFlagOid, &extension_value));
std::unique_ptr<X509Cert> cert2(new X509Cert);
ASSERT_EQ(util::OkStatus(), cert2->LoadPem(kTestDevCodeSigningCert));
ASSERT_EQ(OkStatus(), cert2->LoadPem(kTestDevCodeSigningCert));
ASSERT_TRUE(cert2->GetV3BooleanExtension(kDevCertFlagOid, &extension_value));
EXPECT_EQ(kTestDevCodeSigningCertFlagValue, extension_value);
}