blob: f2e12fb029439c34c1b3fa917b636a4da55215cc [file] [log] [blame]
// 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 "services/network/trust_tokens/signed_redemption_record_serialization.h"
#include <string>
#include "base/containers/span.h"
#include "base/strings/string_piece.h"
#include "base/traits_bag.h"
#include "net/http/structured_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace network {
namespace {
enum class WithBody { kValid, kInvalid, kAbsent };
enum class WithSignature { kValid, kInvalid, kAbsent };
enum class WithAdditionalMember { kYes, kNo };
// Returns a minimal signed redemption record-like Structured Headers dictionary
// to help with error handling in the SRR deserialization code.
//
// |with_body| specifies whether to include a valid "body" field, a type-unsafe
// one, or none at all; |with_signature| does the same for the "signature"
// field.
//
// If |with_additional_member| is kYes, the dictionary will contain an
// additional member beyond whichever of the body and signature are included.
std::string CreateSerializedDictionary(
WithBody with_body,
WithSignature with_signature,
WithAdditionalMember with_additional_member) {
net::structured_headers::Dictionary dict;
switch (with_signature) {
case WithSignature::kValid:
dict["signature"] = net::structured_headers::ParameterizedMember(
net::structured_headers::Item(
"example signature",
net::structured_headers::Item::kByteSequenceType),
{});
break;
case WithSignature::kInvalid:
// This isn't a byte sequence, so it's not a valid value corresponding to
// the "signature" key.
dict["signature"] = net::structured_headers::ParameterizedMember(
net::structured_headers::Item(int64_t{5}), {});
break;
case WithSignature::kAbsent:
break;
}
switch (with_body) {
case WithBody::kValid:
dict["body"] = net::structured_headers::ParameterizedMember(
net::structured_headers::Item(
"example body", net::structured_headers::Item::kByteSequenceType),
{});
break;
case WithBody::kInvalid:
// This isn't a byte sequence, so it's not a valid value corresponding to
// the "body" key.
dict["body"] = net::structured_headers::ParameterizedMember(
net::structured_headers::Item(int64_t{5}), {});
break;
case WithBody::kAbsent:
break;
}
if (with_additional_member == WithAdditionalMember::kYes) {
dict["additional"] = net::structured_headers::ParameterizedMember(
net::structured_headers::Item(int64_t{5}), {});
}
return *net::structured_headers::SerializeDictionary(dict);
}
} // namespace
TEST(SignedRedemptionRecordSerialization, SerializeAndParse) {
std::string body = "body";
std::string signature = "example signature";
base::Optional<std::string> maybe_serialized =
ConstructSignedRedemptionRecord(
base::as_bytes(base::make_span(body)),
base::as_bytes(base::make_span(signature)));
ASSERT_TRUE(maybe_serialized);
std::string obtained_body;
std::string obtained_signature;
EXPECT_TRUE(ParseTrustTokenSignedRedemptionRecord(
*maybe_serialized, &obtained_body, &obtained_signature));
EXPECT_EQ(obtained_body, body);
EXPECT_EQ(obtained_signature, signature);
}
TEST(SignedRedemptionRecordSerialization, SerializeAndParseNullptrParams) {
// Make sure ParseTrustTokenSignedRedemptionRecord doesn't blow up (i.e.,
// dereference a null pointer) when its optional params aren't provided.
std::string body = "example body";
std::string signature = "example signature";
base::Optional<std::string> maybe_serialized =
ConstructSignedRedemptionRecord(
base::as_bytes(base::make_span(body)),
base::as_bytes(base::make_span(signature)));
ASSERT_TRUE(maybe_serialized);
EXPECT_TRUE(ParseTrustTokenSignedRedemptionRecord(*maybe_serialized, nullptr,
nullptr));
}
TEST(SignedRedemptionRecordSerialization, ParseNotDictionary) {
// Parse should reject objects that aren't Structured Headers dictionaries.
EXPECT_FALSE(ParseTrustTokenSignedRedemptionRecord(
"Not a Structured Headers dictionary", nullptr, nullptr));
}
TEST(SignedRedemptionRecordSerialization, ParseTooSmallDictionary) {
// Parse should reject Structured Headers dictionaries that aren't size 2.
EXPECT_FALSE(ParseTrustTokenSignedRedemptionRecord(
CreateSerializedDictionary(WithBody::kAbsent, WithSignature::kAbsent,
WithAdditionalMember::kNo),
nullptr, nullptr));
}
TEST(SignedRedemptionRecordSerialization,
ParseDictionaryWithTypeUnsafeSignature) {
// Parse should reject size 2 structured headers dictionaries with members of
// the wrong type.
EXPECT_FALSE(ParseTrustTokenSignedRedemptionRecord(
CreateSerializedDictionary(WithBody::kValid, WithSignature::kInvalid,
WithAdditionalMember::kNo),
nullptr, nullptr));
}
TEST(SignedRedemptionRecordSerialization, ParseDictionaryWithTypeUnsafeBody) {
// Parse should reject size 2 structured headers dictionaries with members of
// the wrong type.
EXPECT_FALSE(ParseTrustTokenSignedRedemptionRecord(
CreateSerializedDictionary(WithBody::kInvalid, WithSignature::kValid,
WithAdditionalMember::kNo),
nullptr, nullptr));
}
TEST(SignedRedemptionRecordSerialization, ParseDictionaryWithExtraMembers) {
// Parse should reject size >2 structured headers dictionaries.
EXPECT_FALSE(ParseTrustTokenSignedRedemptionRecord(
CreateSerializedDictionary(WithBody::kValid, WithSignature::kValid,
WithAdditionalMember::kYes),
nullptr, nullptr));
}
} // namespace network