blob: 60ff06e2719d8506afd681ae86dcd7e7febfaebb [file] [log] [blame]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ANONYMOUS_TOKENS_CPP_PRIVACY_PASS_TOKEN_ENCODINGS_H_
#define ANONYMOUS_TOKENS_CPP_PRIVACY_PASS_TOKEN_ENCODINGS_H_
#include <stdint.h>
#include <string>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "absl/types/span.h"
namespace anonymous_tokens {
// blinded_token_request will be encoded in 256 bytes for token type DA7A.
constexpr int kDA7ABlindedTokenRequestSizeInBytes = 256;
// TokenRequest struct will be encoded in 259 bytes for token type DA7A.
constexpr int kDA7AMarshaledTokenRequestSizeInBytes = 259;
// Timestamp precision must be at least 15 minutes.
constexpr int kFifteenMinutesInSeconds = 900;
// Timestamp must expire within the next week.
constexpr int kOneWeekToHours = 168;
constexpr int kAlpha2CountryCodeLength = 2;
// TokenRequest contains the blinded_token_request along with the token type
// represented using two bytes and the truncated_token_key_id which is the last
// byte of the the key identifier computed as SHA256(encoded_key), where
// encoded_key is a DER-encoded object carrying the public key as described
// here:
// https://smhendrickson.github.io/draft-hendrickson-privacypass-public-metadata-issuance/draft-hendrickson-privacypass-public-metadata.html#section-6.5
//
// The token_type is initialized to a default value of 0xDA7A which represents
// RSA Blind Signatures with Public Metadata.
struct TokenRequest {
uint16_t token_type{0XDA7A};
uint8_t truncated_token_key_id;
std::string blinded_token_request;
};
// Extension id a type-value structure whose semantics are determined by the
// type. The extension_type as well as length (size in bytes) of an
// extension_value must be a 2-octet integer.
struct Extension {
uint16_t extension_type{0X0001};
std::string extension_value;
};
// Represents the extension defined in Privacy Pass Token Expiration Extension
// See
// https://chris-wood.github.io/draft-hendrickson-privacypass-expiration-extension/draft-hendrickson-privacypass-expiration-extension.html
// for the editors copy.
struct ExpirationTimestamp {
uint64_t timestamp_precision;
uint64_t timestamp;
absl::StatusOr<Extension> AsExtension() const;
static absl::StatusOr<ExpirationTimestamp> FromExtension(
const Extension& ext);
};
// Represents the extension defined in Privacy Pass Geolocation Hint Extension
// See
// https://chris-wood.github.io/draft-hendrickson-privacypass-geolocation-extension/draft-hendrickson-privacypass-geolocation-extension.txt
// for the editors copy.
struct GeoHint {
std::string geo_hint;
// Derived in FromExtension from geo_hint.
std::string country_code;
std::string region;
std::string city;
absl::StatusOr<Extension> AsExtension() const;
static absl::StatusOr<GeoHint> FromExtension(const Extension& ext);
};
// ServiceType allows verifiers to differentiate and apply service specific
// policies at verification time. Only a single ID representing the Chrome
// IP Protection project is supported at this time.
// This struct and its implementation should be considered the registry of
// service type identifier mappings.
// Represents a private extension using id 0xF001.
struct ServiceType {
typedef uint8_t ServiceTypeId;
static constexpr ServiceTypeId kChromeIpBlinding = 0x01;
ServiceTypeId service_type_id;
// Derived in FromExtension from service_type_id.
std::string service_type;
absl::StatusOr<Extension> AsExtension() const;
static absl::StatusOr<ServiceType> FromExtension(const Extension& ext);
};
// DebugMode allows verifiers to apply service specific policies at verification
// time. The mode field is a boolean.
// - 0x00 is production.
// - 0x01 is debug.
// - Any other mode value is invalid.
// Production clients MUST never set 0x01, and attesters should refuse to grant
// 0x01 to production clients.
// Represents a private extension using id 0xF002.
struct DebugMode {
// Mode values
// We don't use an enum here because SWIG doesn't support c++11 typed enums,
// and we need enum to be exactly uint8
typedef uint8_t Mode;
static constexpr Mode kProd = 0x00;
static constexpr Mode kDebug = 0x01;
Mode mode;
absl::StatusOr<Extension> AsExtension() const;
static absl::StatusOr<DebugMode> FromExtension(const Extension& ext);
};
// ProxyLayer allows verifiers corresponding to a particular layer to check that
// the request is intended for them.
// - 0x00 is proxy A.
// - 0x01 is proxy B.
// - Any other mode value is invalid.
// Represents a private extension using id 0xF003.
struct ProxyLayer {
// Layer values
// We don't use an enum here because SWIG doesn't support c++11 typed enums,
// and we need enum to be exactly uint8
typedef uint8_t Layer;
static constexpr Layer kProxyA = 0x00;
static constexpr Layer kProxyB = 0x01;
Layer layer;
absl::StatusOr<Extension> AsExtension() const;
static absl::StatusOr<ProxyLayer> FromExtension(const Extension& ext);
};
// The contents of Extensions is a list of Extension values. The length (size in
// bytes) of this list should be a 2-octet integer.
struct Extensions {
std::vector<Extension> extensions;
};
// ExtendedTokenRequest is simply a TokenRequest-Extensions structure. Public
// Metadata will be encoded as Extensions.
struct ExtendedTokenRequest {
TokenRequest request;
Extensions extensions;
};
// Token is a structure that contains the actual signature / token i.e. the
// authenticator along with the token_type represented using two bytes, the
// token_key_id which the key identifier computed as SHA256(encoded_key) where
// encoded_key is a DER-encoded object carrying the public key, the nonce which
// is a random 32 byte value, and the context which is a SHA256 digest of an
// input challenge. All of these are described here:
// https://smhendrickson.github.io/draft-hendrickson-privacypass-public-metadata-issuance/draft-hendrickson-privacypass-public-metadata.html#section-6.5
//
// The token_type is initialized to a default value of 0xDA7A which represents
// RSA Blind Signatures with Public Metadata.
struct Token {
uint16_t token_type{0XDA7A};
std::string token_key_id;
std::string nonce;
std::string context;
std::string authenticator;
};
// TokenChallenge is a structure that is sent from origins to the client. It
// contains information used to generate the token.
// Fields are described here:
// https://datatracker.ietf.org/doc/html/draft-ietf-privacypass-auth-scheme-14#challenge
// However, we will not use the redemption_context and origin_info fields.
// Our scheme combines the origin and issuer so they are superfluous.
//
// The token_type is initialized to a default value of 0xDA7A which represents
// RSA Blind Signatures with Public Metadata.
struct TokenChallenge {
uint16_t token_type{0XDA7A};
std::string issuer_name;
};
// This methods takes in a Token and outputs the authenticator input /
// token_input, defined in the specification:
// https://smhendrickson.github.io/draft-hendrickson-privacypass-public-metadata-issuance/draft-hendrickson-privacypass-public-metadata.html
// This will be used to create the token request as well as to verify the final
// signature.
//
// It does not require the authenticator field to be populated.
absl::StatusOr<std::string> AuthenticatorInput(
const Token& token);
// This methods takes in a Token structure and encodes it into a string.
absl::StatusOr<std::string> MarshalToken(
const Token& token);
// This methods takes in an encoded Token and decodes it into a Token struct.
absl::StatusOr<Token> UnmarshalToken(std::string token);
// This methods takes in an Extension struct and encodes it into a string.
absl::StatusOr<std::string> EncodeExtension(
const Extension& extension);
// This methods takes in an Extensions struct and encodes it into a string.
absl::StatusOr<std::string> EncodeExtensions(
const Extensions& extensions);
// This methods takes a string of encoded extensions and decodes it to an
// Extensions struct.
absl::StatusOr<Extensions> DecodeExtensions(
absl::string_view encoded_extensions);
// This method takes in a TokenChallenge structure and encodes it into a string.
absl::StatusOr<std::string> MarshalTokenChallenge(
const TokenChallenge& token_challenge);
// This method takes in a TokenRequest structure and encodes it into a string.
absl::StatusOr<std::string> MarshalTokenRequest(
const TokenRequest& token_request);
// This methods takes in an encoded TokenRequest and decodes it into a
// TokenRequest struct.
absl::StatusOr<TokenRequest> UnmarshalTokenRequest(
absl::string_view token_request);
// This method takes in an ExtendedTokenRequest structure and encodes it into a
// string.
absl::StatusOr<std::string> MarshalExtendedTokenRequest(
const ExtendedTokenRequest& extended_token_request);
// This methods takes in an encoded ExtendedTokenRequest and decodes it into a
// ExtendedTokenRequest struct.
absl::StatusOr<ExtendedTokenRequest>
UnmarshalExtendedTokenRequest(absl::string_view extended_token_request);
// This method takes in an Extensions struct, checks that the ordering matches
// the given ordering in expected_types, and validates extension values.
absl::Status ValidateExtensionsOrderAndValues(
const Extensions& extensions, absl::Span<uint16_t> expected_types,
absl::Time now);
// This method takes in an Extensions struct and validates extension values by
// converting them to structs.
absl::Status ValidateExtensionsValues(const Extensions& extensions,
absl::Time now);
} // namespace anonymous_tokens
#endif // ANONYMOUS_TOKENS_CPP_PRIVACY_PASS_TOKEN_ENCODINGS_H_