Commit 2debb4df authored by Leonid Baraz's avatar Leonid Baraz Committed by Chromium LUCI CQ

Activate signature verification.

Signature is now mandatory in storage, when encryption is enabled.

Bug: b:170054326
Change-Id: If0720332dfa84b296b49ee75dc95e14c557b0684
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2615099
Commit-Queue: Leonid Baraz <lbaraz@chromium.org>
Reviewed-by: default avatarZach Trudo <zatrudo@google.com>
Cr-Commit-Position: refs/heads/master@{#841359}
parent ab3c35d1
...@@ -1228,6 +1228,7 @@ static_library("browser") { ...@@ -1228,6 +1228,7 @@ static_library("browser") {
"policy/messaging_layer/storage/resources/resource_interface.h", "policy/messaging_layer/storage/resources/resource_interface.h",
"policy/messaging_layer/storage/storage.cc", "policy/messaging_layer/storage/storage.cc",
"policy/messaging_layer/storage/storage.h", "policy/messaging_layer/storage/storage.h",
"policy/messaging_layer/storage/storage_configuration.cc",
"policy/messaging_layer/storage/storage_configuration.h", "policy/messaging_layer/storage/storage_configuration.h",
"policy/messaging_layer/storage/storage_module.cc", "policy/messaging_layer/storage/storage_module.cc",
"policy/messaging_layer/storage/storage_module.h", "policy/messaging_layer/storage/storage_module.h",
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "chrome/browser/policy/messaging_layer/storage/storage.h" #include "chrome/browser/policy/messaging_layer/storage/storage.h"
#include <cstdint>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -22,6 +23,7 @@ ...@@ -22,6 +23,7 @@
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/policy/messaging_layer/encryption/encryption_module.h" #include "chrome/browser/policy/messaging_layer/encryption/encryption_module.h"
#include "chrome/browser/policy/messaging_layer/encryption/verification.h"
#include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h" #include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h"
#include "chrome/browser/policy/messaging_layer/storage/storage_queue.h" #include "chrome/browser/policy/messaging_layer/storage/storage_queue.h"
#include "chrome/browser/policy/messaging_layer/util/status.h" #include "chrome/browser/policy/messaging_layer/util/status.h"
...@@ -29,6 +31,7 @@ ...@@ -29,6 +31,7 @@
#include "chrome/browser/policy/messaging_layer/util/statusor.h" #include "chrome/browser/policy/messaging_layer/util/statusor.h"
#include "chrome/browser/policy/messaging_layer/util/task_runner_context.h" #include "chrome/browser/policy/messaging_layer/util/task_runner_context.h"
#include "components/policy/proto/record.pb.h" #include "components/policy/proto/record.pb.h"
#include "third_party/boringssl/src/include/openssl/curve25519.h"
#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl.h" #include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl.h"
namespace reporting { namespace reporting {
...@@ -157,8 +160,9 @@ class Storage::QueueUploaderInterface : public StorageQueue::UploaderInterface { ...@@ -157,8 +160,9 @@ class Storage::QueueUploaderInterface : public StorageQueue::UploaderInterface {
class Storage::KeyInStorage { class Storage::KeyInStorage {
public: public:
explicit KeyInStorage(const base::FilePath& directory) explicit KeyInStorage(base::StringPiece signature_verification_public_key,
: directory_(directory) {} const base::FilePath& directory)
: verifier_(signature_verification_public_key), directory_(directory) {}
~KeyInStorage() = default; ~KeyInStorage() = default;
// Uploads signed encryption key to a file with an |index| >= // Uploads signed encryption key to a file with an |index| >=
...@@ -219,6 +223,24 @@ class Storage::KeyInStorage { ...@@ -219,6 +223,24 @@ class Storage::KeyInStorage {
signed_encryption_key_result.value().second.public_key_id()); signed_encryption_key_result.value().second.public_key_id());
} }
Status VerifySignature(const SignedEncryptionInfo& signed_encryption_key) {
if (signed_encryption_key.public_asymmetric_key().size() !=
X25519_PUBLIC_VALUE_LEN) {
return Status{error::FAILED_PRECONDITION, "Key size mismatch"};
}
char value_to_verify[sizeof(Encryptor::PublicKeyId) +
X25519_PUBLIC_VALUE_LEN];
const Encryptor::PublicKeyId public_key_id =
signed_encryption_key.public_key_id();
memcpy(value_to_verify, &public_key_id, sizeof(Encryptor::PublicKeyId));
memcpy(value_to_verify + sizeof(Encryptor::PublicKeyId),
signed_encryption_key.public_asymmetric_key().data(),
X25519_PUBLIC_VALUE_LEN);
return verifier_.Verify(
std::string(value_to_verify, sizeof(value_to_verify)),
signed_encryption_key.signature());
}
private: private:
// Writes key into file. Called during key upload. // Writes key into file. Called during key upload.
Status WriteKeyInfoFile(uint64_t new_file_index, Status WriteKeyInfoFile(uint64_t new_file_index,
...@@ -375,8 +397,16 @@ class Storage::KeyInStorage { ...@@ -375,8 +397,16 @@ class Storage::KeyInStorage {
} }
} }
// Parsed successfully. // Parsed successfully. Verify signature of the whole "id"+"key" string.
// TODO(b/170054326): Validate signature. const auto signature_verification_status =
VerifySignature(signed_encryption_key);
if (!signature_verification_status.ok()) {
LOG(WARNING) << "Loaded key failed verification, status="
<< signature_verification_status << ", full_name='"
<< key_file_it->second.MaybeAsASCII() << "'";
continue;
}
// Validated successfully. Return file name and signed key proto. // Validated successfully. Return file name and signed key proto.
return std::make_pair(key_file_it->second, signed_encryption_key); return std::make_pair(key_file_it->second, signed_encryption_key);
} }
...@@ -392,6 +422,8 @@ class Storage::KeyInStorage { ...@@ -392,6 +422,8 @@ class Storage::KeyInStorage {
// to successfully encrypt records and for the server to then decrypt them. // to successfully encrypt records and for the server to then decrypt them.
std::atomic<uint64_t> next_key_file_index_{0}; std::atomic<uint64_t> next_key_file_index_{0};
SignatureVerifier verifier_;
const base::FilePath directory_; const base::FilePath directory_;
}; };
...@@ -537,7 +569,9 @@ Storage::Storage(const StorageOptions& options, ...@@ -537,7 +569,9 @@ Storage::Storage(const StorageOptions& options,
StartUploadCb start_upload_cb) StartUploadCb start_upload_cb)
: options_(options), : options_(options),
encryption_module_(encryption_module), encryption_module_(encryption_module),
key_in_storage_(std::make_unique<KeyInStorage>(options.directory())), key_in_storage_(std::make_unique<KeyInStorage>(
options.signature_verification_public_key(),
options.directory())),
start_upload_cb_(std::move(start_upload_cb)) {} start_upload_cb_(std::move(start_upload_cb)) {}
Storage::~Storage() = default; Storage::~Storage() = default;
...@@ -571,7 +605,14 @@ Status Storage::Flush(Priority priority) { ...@@ -571,7 +605,14 @@ Status Storage::Flush(Priority priority) {
} }
void Storage::UpdateEncryptionKey(SignedEncryptionInfo signed_encryption_key) { void Storage::UpdateEncryptionKey(SignedEncryptionInfo signed_encryption_key) {
// TODO(b/170054326): Verify received key signature. Bail out if failed. // Verify received key signature. Bail out if failed.
const auto signature_verification_status =
key_in_storage_->VerifySignature(signed_encryption_key);
if (!signature_verification_status.ok()) {
LOG(WARNING) << "Key failed verification, status="
<< signature_verification_status;
return;
}
// Assign the received key to encryption module. // Assign the received key to encryption module.
encryption_module_->UpdateAsymmetricKey( encryption_module_->UpdateAsymmetricKey(
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/policy/messaging_layer/storage/storage_configuration.h"
namespace reporting {
StorageOptions::StorageOptions() = default;
StorageOptions::StorageOptions(const StorageOptions& options) = default;
StorageOptions& StorageOptions::operator=(const StorageOptions& options) =
default;
StorageOptions::~StorageOptions() = default;
} // namespace reporting
...@@ -5,6 +5,12 @@ ...@@ -5,6 +5,12 @@
#ifndef CHROME_BROWSER_POLICY_MESSAGING_LAYER_STORAGE_STORAGE_CONFIGURATION_H_ #ifndef CHROME_BROWSER_POLICY_MESSAGING_LAYER_STORAGE_STORAGE_CONFIGURATION_H_
#define CHROME_BROWSER_POLICY_MESSAGING_LAYER_STORAGE_STORAGE_CONFIGURATION_H_ #define CHROME_BROWSER_POLICY_MESSAGING_LAYER_STORAGE_STORAGE_CONFIGURATION_H_
#include <string>
#include "base/files/file_path.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
namespace reporting { namespace reporting {
// Storage options class allowing to set parameters individually, e.g.: // Storage options class allowing to set parameters individually, e.g.:
...@@ -16,13 +22,20 @@ namespace reporting { ...@@ -16,13 +22,20 @@ namespace reporting {
// callback); // callback);
class StorageOptions { class StorageOptions {
public: public:
StorageOptions() = default; StorageOptions();
StorageOptions(const StorageOptions& options) = default; StorageOptions(const StorageOptions& options);
StorageOptions& operator=(const StorageOptions& options) = default; StorageOptions& operator=(const StorageOptions& options);
~StorageOptions();
StorageOptions& set_directory(const base::FilePath& directory) { StorageOptions& set_directory(const base::FilePath& directory) {
directory_ = directory; directory_ = directory;
return *this; return *this;
} }
StorageOptions& set_signature_verification_public_key(
base::StringPiece signature_verification_public_key) {
signature_verification_public_key_ =
std::string(signature_verification_public_key);
return *this;
}
StorageOptions& set_max_record_size(size_t max_record_size) { StorageOptions& set_max_record_size(size_t max_record_size) {
max_record_size_ = max_record_size; max_record_size_ = max_record_size;
return *this; return *this;
...@@ -40,6 +53,9 @@ class StorageOptions { ...@@ -40,6 +53,9 @@ class StorageOptions {
return *this; return *this;
} }
const base::FilePath& directory() const { return directory_; } const base::FilePath& directory() const { return directory_; }
base::StringPiece signature_verification_public_key() const {
return signature_verification_public_key_;
}
size_t max_record_size() const { return max_record_size_; } size_t max_record_size() const { return max_record_size_; }
uint64_t max_total_files_size() const { return max_total_files_size_; } uint64_t max_total_files_size() const { return max_total_files_size_; }
uint64_t max_total_memory_size() const { return max_total_memory_size_; } uint64_t max_total_memory_size() const { return max_total_memory_size_; }
...@@ -49,6 +65,10 @@ class StorageOptions { ...@@ -49,6 +65,10 @@ class StorageOptions {
// Subdirectory of the location assigned for this Storage. // Subdirectory of the location assigned for this Storage.
base::FilePath directory_; base::FilePath directory_;
// Public key for signature verification when encryption key
// is delivered to Storage.
std::string signature_verification_public_key_;
// Maximum record size. // Maximum record size.
size_t max_record_size_ = 1 * 1024LL * 1024LL; // 1 MiB size_t max_record_size_ = 1 * 1024LL * 1024LL; // 1 MiB
......
...@@ -438,6 +438,8 @@ class StorageTest ...@@ -438,6 +438,8 @@ class StorageTest
// Enable encryption. // Enable encryption.
scoped_feature_list_.InitFromCommandLine( scoped_feature_list_.InitFromCommandLine(
{EncryptionModule::kEncryptedReporting}, {}); {EncryptionModule::kEncryptedReporting}, {});
// Generate signing key pair.
ED25519_keypair(signature_verification_public_key_, signing_private_key_);
// Create decryption module. // Create decryption module.
auto decryptor_result = Decryptor::Create(); auto decryptor_result = Decryptor::Create();
ASSERT_OK(decryptor_result.status()) << decryptor_result.status(); ASSERT_OK(decryptor_result.status()) << decryptor_result.status();
...@@ -495,9 +497,16 @@ class StorageTest ...@@ -495,9 +497,16 @@ class StorageTest
} }
StorageOptions BuildTestStorageOptions() const { StorageOptions BuildTestStorageOptions() const {
return StorageOptions() auto options = StorageOptions()
.set_directory(base::FilePath(location_.GetPath())) .set_directory(base::FilePath(location_.GetPath()))
.set_single_file_size(::testing::get<1>(GetParam())); .set_single_file_size(::testing::get<1>(GetParam()));
if (::testing::get<0>(GetParam())) {
// Encryption enabled.
options.set_signature_verification_public_key(std::string(
reinterpret_cast<const char*>(signature_verification_public_key_),
ED25519_PUBLIC_KEY_LEN));
}
return options;
} }
StatusOr<std::unique_ptr<Storage::UploaderInterface>> BuildMockUploader( StatusOr<std::unique_ptr<Storage::UploaderInterface>> BuildMockUploader(
...@@ -534,8 +543,9 @@ class StorageTest ...@@ -534,8 +543,9 @@ class StorageTest
void GenerateAndDeliverKey(Storage* storage) { void GenerateAndDeliverKey(Storage* storage) {
ASSERT_TRUE(decryptor_) << "Decryptor not created"; ASSERT_TRUE(decryptor_) << "Decryptor not created";
// Generate new pair of private key and public value. // Generate new pair of private key and public value.
uint8_t public_value[X25519_PUBLIC_VALUE_LEN];
uint8_t private_key[X25519_PRIVATE_KEY_LEN]; uint8_t private_key[X25519_PRIVATE_KEY_LEN];
Encryptor::PublicKeyId public_key_id;
uint8_t public_value[X25519_PUBLIC_VALUE_LEN];
X25519_keypair(public_value, private_key); X25519_keypair(public_value, private_key);
TestEvent<StatusOr<Encryptor::PublicKeyId>> prepare_key_pair; TestEvent<StatusOr<Encryptor::PublicKeyId>> prepare_key_pair;
decryptor_->RecordKeyPair( decryptor_->RecordKeyPair(
...@@ -546,13 +556,28 @@ class StorageTest ...@@ -546,13 +556,28 @@ class StorageTest
prepare_key_pair.cb()); prepare_key_pair.cb());
auto prepare_key_result = prepare_key_pair.result(); auto prepare_key_result = prepare_key_pair.result();
ASSERT_OK(prepare_key_result.status()); ASSERT_OK(prepare_key_result.status());
Encryptor::PublicKeyId new_public_key_id = prepare_key_result.ValueOrDie(); public_key_id = prepare_key_result.ValueOrDie();
// Deliver public key to storage. // Deliver public key to storage.
SignedEncryptionInfo signed_encryption_key; SignedEncryptionInfo signed_encryption_key;
signed_encryption_key.set_public_asymmetric_key(std::string( signed_encryption_key.set_public_asymmetric_key(std::string(
reinterpret_cast<const char*>(public_value), X25519_PUBLIC_VALUE_LEN)); reinterpret_cast<const char*>(public_value), X25519_PUBLIC_VALUE_LEN));
signed_encryption_key.set_public_key_id(new_public_key_id); signed_encryption_key.set_public_key_id(public_key_id);
// TODO(b/170054326): Add key signature. // Sign public key.
uint8_t
value_to_sign[sizeof(Encryptor::PublicKeyId) + X25519_PUBLIC_VALUE_LEN];
memcpy(value_to_sign, &public_key_id, sizeof(Encryptor::PublicKeyId));
memcpy(value_to_sign + sizeof(Encryptor::PublicKeyId), public_value,
X25519_PUBLIC_VALUE_LEN);
uint8_t signature[ED25519_SIGNATURE_LEN];
ASSERT_THAT(ED25519_sign(signature, value_to_sign, sizeof(value_to_sign),
signing_private_key_),
Eq(1));
signed_encryption_key.set_signature(std::string(
reinterpret_cast<const char*>(signature), ED25519_SIGNATURE_LEN));
// Double check signature.
ASSERT_THAT(ED25519_verify(value_to_sign, sizeof(value_to_sign), signature,
signature_verification_public_key_),
Eq(1));
storage->UpdateEncryptionKey(signed_encryption_key); storage->UpdateEncryptionKey(signed_encryption_key);
} }
...@@ -561,6 +586,9 @@ class StorageTest ...@@ -561,6 +586,9 @@ class StorageTest
base::test::ScopedFeatureList scoped_feature_list_; base::test::ScopedFeatureList scoped_feature_list_;
uint8_t signature_verification_public_key_[ED25519_PUBLIC_KEY_LEN];
uint8_t signing_private_key_[ED25519_PRIVATE_KEY_LEN];
base::ScopedTempDir location_; base::ScopedTempDir location_;
scoped_refptr<Decryptor> decryptor_; scoped_refptr<Decryptor> decryptor_;
scoped_refptr<Storage> storage_; scoped_refptr<Storage> storage_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment