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