Commit 46e7c41b authored by Leonid Baraz's avatar Leonid Baraz Committed by Chromium LUCI CQ

Add Ed25519 signature verifier.

Key pair is generated by the test; production server will retrieve
private key from KeyStore, and client will use a hardcoded public key
that matches the Keystore key.

Bug: b:170054326
Change-Id: I676dc48871af75e6a1733ee1d345460e6708d38d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2611901
Commit-Queue: Leonid Baraz <lbaraz@chromium.org>
Reviewed-by: default avatarZach Trudo <zatrudo@google.com>
Cr-Commit-Position: refs/heads/master@{#840709}
parent 2496ea90
......@@ -1221,6 +1221,8 @@ static_library("browser") {
"policy/messaging_layer/encryption/encryption.h",
"policy/messaging_layer/encryption/encryption_module.cc",
"policy/messaging_layer/encryption/encryption_module.h",
"policy/messaging_layer/encryption/verification.cc",
"policy/messaging_layer/encryption/verification.h",
"policy/messaging_layer/public/report_client.cc",
"policy/messaging_layer/public/report_client.h",
"policy/messaging_layer/public/report_queue.cc",
......
// 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/encryption/verification.h"
#include "chrome/browser/policy/messaging_layer/util/status.h"
#include "third_party/boringssl/src/include/openssl/curve25519.h"
namespace reporting {
SignatureVerifier::SignatureVerifier(base::StringPiece verification_public_key)
: verification_public_key_(verification_public_key) {}
Status SignatureVerifier::Verify(base::StringPiece message,
base::StringPiece signature) {
if (signature.size() != ED25519_SIGNATURE_LEN) {
return Status{error::FAILED_PRECONDITION, "Wrong signature size"};
}
if (verification_public_key_.size() != ED25519_PUBLIC_KEY_LEN) {
return Status{error::FAILED_PRECONDITION, "Wrong public key size"};
}
const int result = ED25519_verify(
reinterpret_cast<const uint8_t*>(message.data()), message.size(),
reinterpret_cast<const uint8_t*>(signature.data()),
reinterpret_cast<const uint8_t*>(verification_public_key_.data()));
if (result != 1) {
return Status{error::INVALID_ARGUMENT, "Verification failed"};
}
return Status::StatusOK();
}
} // namespace reporting
// 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.
#ifndef CHROME_BROWSER_POLICY_MESSAGING_LAYER_ENCRYPTION_VERIFICATION_H_
#define CHROME_BROWSER_POLICY_MESSAGING_LAYER_ENCRYPTION_VERIFICATION_H_
#include <string>
#include "base/strings/string_piece.h"
#include "chrome/browser/policy/messaging_layer/util/status.h"
namespace reporting {
// Helper class that verifies an Ed25519 signed message received from
// the server. It uses boringssl implementation available on the client.
class SignatureVerifier {
public:
// Ed25519 |verification_public_key| must consist of ED25519_PUBLIC_KEY_LEN
// bytes.
explicit SignatureVerifier(base::StringPiece verification_public_key);
// Actual verification - returns error status if provided |signature| does not
// match |message|. Signature must be ED25519_SIGNATURE_LEN bytes.
Status Verify(base::StringPiece message, base::StringPiece signature);
private:
std::string verification_public_key_;
};
} // namespace reporting
#endif // CHROME_BROWSER_POLICY_MESSAGING_LAYER_ENCRYPTION_VERIFICATION_H_
// 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/encryption/verification.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/boringssl/src/include/openssl/curve25519.h"
using ::testing::Eq;
using ::testing::HasSubstr;
namespace reporting {
namespace {
class VerificationTest : public ::testing::Test {
protected:
VerificationTest() = default;
void SetUp() override {
// Generate key pair
ED25519_keypair(public_key_, private_key_);
}
uint8_t public_key_[ED25519_PUBLIC_KEY_LEN];
uint8_t private_key_[ED25519_PRIVATE_KEY_LEN];
};
TEST_F(VerificationTest, SignAndVerify) {
static constexpr char message[] = "ABCDEF 012345";
// Sign a message.
uint8_t signature[ED25519_SIGNATURE_LEN];
ASSERT_THAT(ED25519_sign(signature, reinterpret_cast<const uint8_t*>(message),
strlen(message), private_key_),
Eq(1));
// Verify the signature.
SignatureVerifier verifier(std::string(
reinterpret_cast<const char*>(public_key_), ED25519_PUBLIC_KEY_LEN));
EXPECT_OK(
verifier.Verify(std::string(message, strlen(message)),
std::string(reinterpret_cast<const char*>(signature),
ED25519_SIGNATURE_LEN)));
}
TEST_F(VerificationTest, SignAndFailBadSignature) {
static constexpr char message[] = "ABCDEF 012345";
// Sign a message.
uint8_t signature[ED25519_SIGNATURE_LEN];
ASSERT_THAT(ED25519_sign(signature, reinterpret_cast<const uint8_t*>(message),
strlen(message), private_key_),
Eq(1));
// Verify the signature - wrong length.
SignatureVerifier verifier(std::string(
reinterpret_cast<const char*>(public_key_), ED25519_PUBLIC_KEY_LEN));
Status status =
verifier.Verify(std::string(message, strlen(message)),
std::string(reinterpret_cast<const char*>(signature),
ED25519_SIGNATURE_LEN - 1));
EXPECT_THAT(status.code(), Eq(error::FAILED_PRECONDITION));
EXPECT_THAT(status.message(), HasSubstr("Wrong signature size"));
// Verify the signature - mismatch.
signature[0] = ~signature[0];
status = verifier.Verify(std::string(message, strlen(message)),
std::string(reinterpret_cast<const char*>(signature),
ED25519_SIGNATURE_LEN));
EXPECT_THAT(status.code(), Eq(error::INVALID_ARGUMENT));
EXPECT_THAT(status.message(), HasSubstr("Verification failed"));
}
TEST_F(VerificationTest, SignAndFailBadPublicKey) {
static constexpr char message[] = "ABCDEF 012345";
// Sign a message.
uint8_t signature[ED25519_SIGNATURE_LEN];
ASSERT_THAT(ED25519_sign(signature, reinterpret_cast<const uint8_t*>(message),
strlen(message), private_key_),
Eq(1));
// Verify the public key - wrong length.
SignatureVerifier verifier(std::string(
reinterpret_cast<const char*>(public_key_), ED25519_PUBLIC_KEY_LEN - 1));
Status status =
verifier.Verify(std::string(message, strlen(message)),
std::string(reinterpret_cast<const char*>(signature),
ED25519_SIGNATURE_LEN));
EXPECT_THAT(status.code(), Eq(error::FAILED_PRECONDITION));
EXPECT_THAT(status.message(), HasSubstr("Wrong public key size"));
// Verify the public key - mismatch.
public_key_[0] = ~public_key_[0];
SignatureVerifier verifier2(std::string(
reinterpret_cast<const char*>(public_key_), ED25519_PUBLIC_KEY_LEN));
status =
verifier2.Verify(std::string(message, strlen(message)),
std::string(reinterpret_cast<const char*>(signature),
ED25519_SIGNATURE_LEN));
EXPECT_THAT(status.code(), Eq(error::INVALID_ARGUMENT));
EXPECT_THAT(status.message(), HasSubstr("Verification failed"));
}
} // namespace
} // namespace reporting
......@@ -3659,6 +3659,7 @@ test("unit_tests") {
"../browser/policy/messaging_layer/encryption/encryption_unittest.cc",
"../browser/policy/messaging_layer/encryption/test_encryption_module.cc",
"../browser/policy/messaging_layer/encryption/test_encryption_module.h",
"../browser/policy/messaging_layer/encryption/verification_unittest.cc",
"../browser/policy/messaging_layer/public/report_client_unittest.cc",
"../browser/policy/messaging_layer/public/report_queue_configuration_unittest.cc",
"../browser/policy/messaging_layer/public/report_queue_unittest.cc",
......
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