1 // Copyright 2023 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ANONYMOUS_TOKENS_CPP_PRIVACY_PASS_TOKEN_ENCODINGS_H_ 16 #define ANONYMOUS_TOKENS_CPP_PRIVACY_PASS_TOKEN_ENCODINGS_H_ 17 18 #include <stdint.h> 19 20 #include <string> 21 22 #include "absl/status/status.h" 23 #include "absl/status/statusor.h" 24 #include "absl/strings/string_view.h" 25 #include "absl/time/time.h" 26 #include "absl/types/span.h" 27 28 namespace anonymous_tokens { 29 30 // blinded_token_request will be encoded in 256 bytes for token type DA7A. 31 constexpr int kDA7ABlindedTokenRequestSizeInBytes = 256; 32 33 // TokenRequest struct will be encoded in 259 bytes for token type DA7A. 34 constexpr int kDA7AMarshaledTokenRequestSizeInBytes = 259; 35 36 // Timestamp precision must be at least 15 minutes. 37 constexpr int kFifteenMinutesInSeconds = 900; 38 39 // Timestamp must expire within the next week. 40 constexpr int kOneWeekToHours = 168; 41 42 constexpr int kAlpha2CountryCodeLength = 2; 43 44 // TokenRequest contains the blinded_token_request along with the token type 45 // represented using two bytes and the truncated_token_key_id which is the last 46 // byte of the the key identifier computed as SHA256(encoded_key), where 47 // encoded_key is a DER-encoded object carrying the public key as described 48 // here: 49 // https://smhendrickson.github.io/draft-hendrickson-privacypass-public-metadata-issuance/draft-hendrickson-privacypass-public-metadata.html#section-6.5 50 // 51 // The token_type is initialized to a default value of 0xDA7A which represents 52 // RSA Blind Signatures with Public Metadata. 53 struct TokenRequest { 54 uint16_t token_type{0XDA7A}; 55 uint8_t truncated_token_key_id; 56 std::string blinded_token_request; 57 }; 58 59 // Extension id a type-value structure whose semantics are determined by the 60 // type. The extension_type as well as length (size in bytes) of an 61 // extension_value must be a 2-octet integer. 62 struct Extension { 63 uint16_t extension_type{0X0001}; 64 std::string extension_value; 65 }; 66 67 // Represents the extension defined in Privacy Pass Token Expiration Extension 68 // See 69 // https://chris-wood.github.io/draft-hendrickson-privacypass-expiration-extension/draft-hendrickson-privacypass-expiration-extension.html 70 // for the editors copy. 71 struct ExpirationTimestamp { 72 uint64_t timestamp_precision; 73 uint64_t timestamp; 74 75 absl::StatusOr<Extension> AsExtension() const; 76 77 static absl::StatusOr<ExpirationTimestamp> FromExtension( 78 const Extension& ext); 79 }; 80 81 // Represents the extension defined in Privacy Pass Geolocation Hint Extension 82 // See 83 // https://chris-wood.github.io/draft-hendrickson-privacypass-geolocation-extension/draft-hendrickson-privacypass-geolocation-extension.txt 84 // for the editors copy. 85 struct GeoHint { 86 std::string geo_hint; 87 88 // Derived in FromExtension from geo_hint. 89 std::string country_code; 90 std::string region; 91 std::string city; 92 93 absl::StatusOr<Extension> AsExtension() const; 94 95 static absl::StatusOr<GeoHint> FromExtension(const Extension& ext); 96 }; 97 98 // ServiceType allows verifiers to differentiate and apply service specific 99 // policies at verification time. Only a single ID representing the Chrome 100 // IP Protection project is supported at this time. 101 // This struct and its implementation should be considered the registry of 102 // service type identifier mappings. 103 // Represents a private extension using id 0xF001. 104 struct ServiceType { 105 typedef uint8_t ServiceTypeId; 106 static constexpr ServiceTypeId kChromeIpBlinding = 0x01; 107 ServiceTypeId service_type_id; 108 109 // Derived in FromExtension from service_type_id. 110 std::string service_type; 111 112 absl::StatusOr<Extension> AsExtension() const; 113 114 static absl::StatusOr<ServiceType> FromExtension(const Extension& ext); 115 }; 116 117 // DebugMode allows verifiers to apply service specific policies at verification 118 // time. The mode field is a boolean. 119 // - 0x00 is production. 120 // - 0x01 is debug. 121 // - Any other mode value is invalid. 122 // Production clients MUST never set 0x01, and attesters should refuse to grant 123 // 0x01 to production clients. 124 // Represents a private extension using id 0xF002. 125 struct DebugMode { 126 // Mode values 127 // We don't use an enum here because SWIG doesn't support c++11 typed enums, 128 // and we need enum to be exactly uint8 129 typedef uint8_t Mode; 130 static constexpr Mode kProd = 0x00; 131 static constexpr Mode kDebug = 0x01; 132 Mode mode; 133 134 absl::StatusOr<Extension> AsExtension() const; 135 136 static absl::StatusOr<DebugMode> FromExtension(const Extension& ext); 137 }; 138 139 // ProxyLayer allows verifiers corresponding to a particular layer to check that 140 // the request is intended for them. 141 // - 0x00 is proxy A. 142 // - 0x01 is proxy B. 143 // - Any other mode value is invalid. 144 // Represents a private extension using id 0xF003. 145 struct ProxyLayer { 146 // Layer values 147 // We don't use an enum here because SWIG doesn't support c++11 typed enums, 148 // and we need enum to be exactly uint8 149 typedef uint8_t Layer; 150 static constexpr Layer kProxyA = 0x00; 151 static constexpr Layer kProxyB = 0x01; 152 Layer layer; 153 154 absl::StatusOr<Extension> AsExtension() const; 155 156 static absl::StatusOr<ProxyLayer> FromExtension(const Extension& ext); 157 }; 158 159 // The contents of Extensions is a list of Extension values. The length (size in 160 // bytes) of this list should be a 2-octet integer. 161 struct Extensions { 162 std::vector<Extension> extensions; 163 }; 164 165 // ExtendedTokenRequest is simply a TokenRequest-Extensions structure. Public 166 // Metadata will be encoded as Extensions. 167 struct ExtendedTokenRequest { 168 TokenRequest request; 169 Extensions extensions; 170 }; 171 172 // Token is a structure that contains the actual signature / token i.e. the 173 // authenticator along with the token_type represented using two bytes, the 174 // token_key_id which the key identifier computed as SHA256(encoded_key) where 175 // encoded_key is a DER-encoded object carrying the public key, the nonce which 176 // is a random 32 byte value, and the context which is a SHA256 digest of an 177 // input challenge. All of these are described here: 178 // https://smhendrickson.github.io/draft-hendrickson-privacypass-public-metadata-issuance/draft-hendrickson-privacypass-public-metadata.html#section-6.5 179 // 180 // The token_type is initialized to a default value of 0xDA7A which represents 181 // RSA Blind Signatures with Public Metadata. 182 struct Token { 183 uint16_t token_type{0XDA7A}; 184 std::string token_key_id; 185 std::string nonce; 186 std::string context; 187 std::string authenticator; 188 }; 189 190 // TokenChallenge is a structure that is sent from origins to the client. It 191 // contains information used to generate the token. 192 // Fields are described here: 193 // https://datatracker.ietf.org/doc/html/draft-ietf-privacypass-auth-scheme-14#challenge 194 // However, we will not use the redemption_context and origin_info fields. 195 // Our scheme combines the origin and issuer so they are superfluous. 196 // 197 // The token_type is initialized to a default value of 0xDA7A which represents 198 // RSA Blind Signatures with Public Metadata. 199 struct TokenChallenge { 200 uint16_t token_type{0XDA7A}; 201 std::string issuer_name; 202 }; 203 204 // This methods takes in a Token and outputs the authenticator input / 205 // token_input, defined in the specification: 206 // https://smhendrickson.github.io/draft-hendrickson-privacypass-public-metadata-issuance/draft-hendrickson-privacypass-public-metadata.html 207 // This will be used to create the token request as well as to verify the final 208 // signature. 209 // 210 // It does not require the authenticator field to be populated. 211 absl::StatusOr<std::string> AuthenticatorInput( 212 const Token& token); 213 214 // This methods takes in a Token structure and encodes it into a string. 215 absl::StatusOr<std::string> MarshalToken( 216 const Token& token); 217 218 // This methods takes in an encoded Token and decodes it into a Token struct. 219 absl::StatusOr<Token> UnmarshalToken(std::string token); 220 221 // This methods takes in an Extension struct and encodes it into a string. 222 absl::StatusOr<std::string> EncodeExtension( 223 const Extension& extension); 224 225 // This methods takes in an Extensions struct and encodes it into a string. 226 absl::StatusOr<std::string> EncodeExtensions( 227 const Extensions& extensions); 228 229 // This methods takes a string of encoded extensions and decodes it to an 230 // Extensions struct. 231 absl::StatusOr<Extensions> DecodeExtensions( 232 absl::string_view encoded_extensions); 233 234 // This method takes in a TokenChallenge structure and encodes it into a string. 235 absl::StatusOr<std::string> MarshalTokenChallenge( 236 const TokenChallenge& token_challenge); 237 238 // This method takes in a TokenRequest structure and encodes it into a string. 239 absl::StatusOr<std::string> MarshalTokenRequest( 240 const TokenRequest& token_request); 241 242 // This methods takes in an encoded TokenRequest and decodes it into a 243 // TokenRequest struct. 244 absl::StatusOr<TokenRequest> UnmarshalTokenRequest( 245 absl::string_view token_request); 246 247 // This method takes in an ExtendedTokenRequest structure and encodes it into a 248 // string. 249 absl::StatusOr<std::string> MarshalExtendedTokenRequest( 250 const ExtendedTokenRequest& extended_token_request); 251 252 // This methods takes in an encoded ExtendedTokenRequest and decodes it into a 253 // ExtendedTokenRequest struct. 254 absl::StatusOr<ExtendedTokenRequest> 255 UnmarshalExtendedTokenRequest(absl::string_view extended_token_request); 256 257 // This method takes in an Extensions struct, checks that the ordering matches 258 // the given ordering in expected_types, and validates extension values. 259 absl::Status ValidateExtensionsOrderAndValues( 260 const Extensions& extensions, absl::Span<uint16_t> expected_types, 261 absl::Time now); 262 263 // This method takes in an Extensions struct and validates extension values by 264 // converting them to structs. 265 absl::Status ValidateExtensionsValues(const Extensions& extensions, 266 absl::Time now); 267 268 } // namespace anonymous_tokens 269 270 #endif // ANONYMOUS_TOKENS_CPP_PRIVACY_PASS_TOKEN_ENCODINGS_H_ 271