| // 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_ |