blob: 8f40f0345dcc52f448fd3e04e2d197acb7ae980a [file] [log] [blame]
// Copyright 2020 The Fuchsia 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 "blob-verifier.h"
#include <zircon/status.h>
#include <digest/digest.h>
#include <digest/merkle-tree.h>
#include <fs/trace.h>
namespace blobfs {
BlobVerifier::BlobVerifier(BlobfsMetrics* metrics) : metrics_(metrics) {}
zx_status_t BlobVerifier::Create(digest::Digest digest, BlobfsMetrics* metrics, const void* merkle,
size_t merkle_size, size_t data_size,
std::unique_ptr<BlobVerifier>* out) {
std::unique_ptr<BlobVerifier> verifier(new BlobVerifier(metrics));
verifier->digest_ = std::move(digest);
zx_status_t status = verifier->tree_verifier_.SetDataLength(data_size);
if (status != ZX_OK) {
FS_TRACE_ERROR("blobfs: Failed to set merkle data length: %s\n", zx_status_get_string(status));
return status;
}
size_t actual_merkle_length = verifier->tree_verifier_.GetTreeLength();
if (actual_merkle_length > merkle_size) {
FS_TRACE_ERROR("blobfs: merkle too small for data\n");
return ZX_ERR_BUFFER_TOO_SMALL;
}
if ((status = verifier->tree_verifier_.SetTree(
merkle, actual_merkle_length, verifier->digest_.get(), verifier->digest_.len())) !=
ZX_OK) {
FS_TRACE_ERROR("blobfs: Failed to create merkle verifier: %s\n", zx_status_get_string(status));
return status;
}
*out = std::move(verifier);
return ZX_OK;
}
zx_status_t BlobVerifier::CreateWithoutTree(digest::Digest digest, BlobfsMetrics* metrics,
size_t data_size, std::unique_ptr<BlobVerifier>* out) {
std::unique_ptr<BlobVerifier> verifier(new BlobVerifier(metrics));
verifier->digest_ = std::move(digest);
zx_status_t status = verifier->tree_verifier_.SetDataLength(data_size);
if (status != ZX_OK) {
FS_TRACE_ERROR("blobfs: Failed to set merkle data length: %s\n", zx_status_get_string(status));
return status;
} else if (verifier->tree_verifier_.GetTreeLength() > 0) {
FS_TRACE_ERROR("blobfs: Failed to create merkle verifier -- data too big for empty tree");
return ZX_ERR_INVALID_ARGS;
}
if ((status = verifier->tree_verifier_.SetTree(nullptr, 0, verifier->digest_.get(),
verifier->digest_.len())) != ZX_OK) {
FS_TRACE_ERROR("blobfs: Failed to create merkle verifier: %s\n", zx_status_get_string(status));
return status;
}
*out = std::move(verifier);
return ZX_OK;
}
zx_status_t BlobVerifier::Verify(const void* data, size_t data_size) {
TRACE_DURATION("blobfs", "BlobVerifier::Verify", "data_size", data_size);
fs::Ticker ticker(metrics_->Collecting());
zx_status_t status = tree_verifier_.Verify(data, data_size, 0);
if (status != ZX_OK) {
FS_TRACE_ERROR("blobfs: Verify(%s, %lu) failed: %s\n", digest_.ToString().c_str(), data_size,
zx_status_get_string(status));
}
metrics_->UpdateMerkleVerify(data_size, tree_verifier_.GetTreeLength(), ticker.End());
return status;
}
zx_status_t BlobVerifier::VerifyPartial(const void* data, size_t length, size_t data_offset) {
TRACE_DURATION("blobfs", "BlobVerifier::VerifyPartial", "length", length, "offset", data_offset);
fs::Ticker ticker(metrics_->Collecting());
zx_status_t status = tree_verifier_.Verify(data, length, data_offset);
if (status != ZX_OK) {
FS_TRACE_ERROR("blobfs: Verify(%s, %lu, %lu) failed: %s\n", digest_.ToString().c_str(),
data_offset, length, zx_status_get_string(status));
}
metrics_->UpdateMerkleVerify(length, tree_verifier_.GetTreeLength(), ticker.End());
return status;
}
} // namespace blobfs