Commit 71358f6e authored by jdoerrie's avatar jdoerrie Committed by Commit Bot

[fido] Introduce SplitSpan()

This change introduces SplitSpan() to u2f_parsing_utils. This method
takes a span and chunks it into smaller parts.

Bug: 763303
Change-Id: I13deb5efca224ae00c8dc5ac8ee2df7fc418ccfd
Reviewed-on: https://chromium-review.googlesource.com/1005183
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#550153}
parent dbc5d3bb
......@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "device/fido/fido_constants.h"
#include "device/fido/u2f_parsing_utils.h"
namespace device {
......@@ -70,15 +71,11 @@ FidoBleFrame::ToFragments(size_t max_fragment_size) const {
base::queue<FidoBleFrameContinuationFragment> other_fragments;
data_view = data_view.subspan(init_fragment_size);
while (!data_view.empty()) {
// Subtract 1 to account for SEQ byte.
const size_t cont_fragment_size =
std::min(max_fragment_size - 1, data_view.size());
// Subtract 1 to account for SEQ byte.
for (auto cont_data :
u2f_parsing_utils::SplitSpan(data_view, max_fragment_size - 1)) {
// High bit must stay cleared.
other_fragments.emplace(data_view.first(cont_fragment_size),
other_fragments.size() & 0x7F);
data_view = data_view.subspan(cont_fragment_size);
other_fragments.emplace(cont_data, other_fragments.size() & 0x7F);
}
return {initial_fragment, std::move(other_fragments)};
......
......@@ -10,6 +10,7 @@
#include "base/memory/ptr_util.h"
#include "base/numerics/safe_conversions.h"
#include "device/fido/u2f_parsing_utils.h"
namespace device {
......@@ -135,13 +136,10 @@ FidoHidMessage::FidoHidMessage(uint32_t channel_id,
std::vector<uint8_t>(init_data.begin(), init_data.end()), data.size()));
data = data.subspan(init_data.size());
while (!data.empty()) {
auto cont_data =
data.first(std::min(kHidContinuationPacketDataSize, data.size()));
for (auto cont_data :
u2f_parsing_utils::SplitSpan(data, kHidContinuationPacketDataSize)) {
packets_.push_back(std::make_unique<FidoHidContinuationPacket>(
channel_id, sequence++,
std::vector<uint8_t>(cont_data.begin(), cont_data.end())));
data = data.subspan(cont_data.size());
channel_id, sequence++, u2f_parsing_utils::Materialize(cont_data)));
}
}
......
......@@ -64,5 +64,20 @@ base::span<const uint8_t> ExtractSuffixSpan(base::span<const uint8_t> span,
return span.subspan(pos);
}
std::vector<base::span<const uint8_t>> SplitSpan(base::span<const uint8_t> span,
size_t max_chunk_size) {
DCHECK_NE(0u, max_chunk_size);
std::vector<base::span<const uint8_t>> chunks;
const size_t num_chunks = (span.size() + max_chunk_size - 1) / max_chunk_size;
chunks.reserve(num_chunks);
while (!span.empty()) {
const size_t chunk_size = std::min(span.size(), max_chunk_size);
chunks.emplace_back(span.subspan(0, chunk_size));
span = span.subspan(chunk_size);
}
return chunks;
}
} // namespace u2f_parsing_utils
} // namespace device
......@@ -73,6 +73,14 @@ bool ExtractArray(base::span<const uint8_t> span,
return true;
}
// Partitions |span| into N = ⌈span.size() / max_chunk_size⌉ consecutive chunks.
// The first N-1 chunks are of size |max_chunk_size|, and the Nth chunk is of
// size span.size() % max_chunk_size. |max_chunk_size| must be greater than 0.
// Returns an empty vector in case |span| is empty.
COMPONENT_EXPORT(DEVICE_FIDO)
std::vector<base::span<const uint8_t>> SplitSpan(base::span<const uint8_t> span,
size_t max_chunk_size);
} // namespace u2f_parsing_utils
} // namespace device
......
......@@ -12,6 +12,8 @@ namespace u2f_parsing_utils {
namespace {
constexpr uint8_t kOne[] = {0x01};
constexpr uint8_t kOneTwo[] = {0x01, 0x02};
constexpr uint8_t kTwo[] = {0x02};
constexpr uint8_t kTwoThree[] = {0x02, 0x03};
constexpr uint8_t kThree[] = {0x03};
constexpr uint8_t kOneTwoThree[] = {0x01, 0x02, 0x03};
......@@ -144,5 +146,47 @@ TEST(U2fParsingUtils, ExtractArray) {
EXPECT_THAT(array_three, ::testing::ElementsAreArray(kThree));
}
TEST(U2fParsingUtils, SplitSpan) {
std::vector<uint8_t> empty;
EXPECT_THAT(SplitSpan(empty, 1), ::testing::IsEmpty());
EXPECT_THAT(SplitSpan(empty, 2), ::testing::IsEmpty());
EXPECT_THAT(SplitSpan(empty, 3), ::testing::IsEmpty());
EXPECT_THAT(SplitSpan(kOne, 1),
::testing::ElementsAre(::testing::ElementsAreArray(kOne)));
EXPECT_THAT(SplitSpan(kOne, 2),
::testing::ElementsAre(::testing::ElementsAreArray(kOne)));
EXPECT_THAT(SplitSpan(kOne, 3),
::testing::ElementsAre(::testing::ElementsAreArray(kOne)));
EXPECT_THAT(SplitSpan(kOneTwo, 1),
::testing::ElementsAre(::testing::ElementsAreArray(kOne),
::testing::ElementsAreArray(kTwo)));
EXPECT_THAT(SplitSpan(kOneTwo, 2),
::testing::ElementsAre(::testing::ElementsAreArray(kOneTwo)));
EXPECT_THAT(SplitSpan(kOneTwo, 3),
::testing::ElementsAre(::testing::ElementsAreArray(kOneTwo)));
EXPECT_THAT(SplitSpan(kOneTwoThree, 1),
::testing::ElementsAre(::testing::ElementsAreArray(kOne),
::testing::ElementsAreArray(kTwo),
::testing::ElementsAreArray(kThree)));
EXPECT_THAT(SplitSpan(kOneTwoThree, 2),
::testing::ElementsAre(::testing::ElementsAreArray(kOneTwo),
::testing::ElementsAreArray(kThree)));
EXPECT_THAT(
SplitSpan(kOneTwoThree, 3),
::testing::ElementsAre(::testing::ElementsAreArray(kOneTwoThree)));
EXPECT_THAT(
SplitSpan(kOneTwoThree, 4),
::testing::ElementsAre(::testing::ElementsAreArray(kOneTwoThree)));
EXPECT_THAT(
SplitSpan(kOneTwoThree, 5),
::testing::ElementsAre(::testing::ElementsAreArray(kOneTwoThree)));
EXPECT_THAT(
SplitSpan(kOneTwoThree, 6),
::testing::ElementsAre(::testing::ElementsAreArray(kOneTwoThree)));
}
} // namespace u2f_parsing_utils
} // namespace device
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