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 #include "anonymous_tokens/cpp/privacy_pass/token_encodings.h"
16 
17 #include <sys/types.h>
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <optional>
22 #include <string>
23 
24 #include "absl/status/status.h"
25 #include "absl/status/statusor.h"
26 #include "absl/strings/ascii.h"
27 #include "absl/strings/str_cat.h"
28 #include "absl/strings/str_format.h"
29 #include "absl/strings/str_split.h"
30 #include "absl/time/time.h"
31 #include "absl/types/span.h"
32 #include "anonymous_tokens/cpp/shared/status_utils.h"
33 #include <openssl/base.h>
34 #include <openssl/bytestring.h>
35 #include <openssl/mem.h>
36 
37 namespace anonymous_tokens {
38 
39 namespace {
40 
EncodeTokenStructHelper(const uint16_t & token_type,const std::string & token_key_id,const std::string & nonce,const std::string & context,const std::optional<std::string> authenticator)41 absl::StatusOr<std::string> EncodeTokenStructHelper(
42     const uint16_t& token_type, const std::string& token_key_id,
43     const std::string& nonce, const std::string& context,
44     const std::optional<std::string> authenticator) {
45   // Main CryptoByteBuilder object cbb which will be passed to CBB_finish to
46   // finalize the output string.
47   bssl::ScopedCBB cbb;
48   // initial_capacity only serves as a hint.
49   if (!CBB_init(cbb.get(), /*initial_capacity=*/98)) {
50     return absl::InternalError("CBB_init() failed.");
51   }
52   // Add token_type to cbb.
53   if (!CBB_add_u16(cbb.get(), token_type) ||
54       // Add nonce to cbb.
55       !CBB_add_bytes(cbb.get(), reinterpret_cast<const uint8_t*>(nonce.data()),
56                      nonce.size()) ||
57       // Add context string to cbb.
58       !CBB_add_bytes(cbb.get(),
59                      reinterpret_cast<const uint8_t*>(context.data()),
60                      context.size()) ||
61       // Add token_key_id to cbb.
62       !CBB_add_bytes(cbb.get(),
63                      reinterpret_cast<const uint8_t*>(token_key_id.data()),
64                      token_key_id.size())) {
65     return absl::InvalidArgumentError(
66         "Could not construct cbb with given inputs.");
67   }
68   // Add authenticator to cbb.
69   if (authenticator.has_value() &&
70       !CBB_add_bytes(cbb.get(),
71                      reinterpret_cast<const uint8_t*>(authenticator->data()),
72                      authenticator->size())) {
73     return absl::InvalidArgumentError("Could not add authenticator to cbb.");
74   }
75   uint8_t* encoded_output;
76   size_t encoded_output_len;
77   if (!CBB_finish(cbb.get(), &encoded_output, &encoded_output_len)) {
78     return absl::InvalidArgumentError(
79         "Failed to generate token / token input encoding");
80   }
81   std::string encoded_output_str(reinterpret_cast<const char*>(encoded_output),
82                                  encoded_output_len);
83   // Free memory.
84   OPENSSL_free(encoded_output);
85   return encoded_output_str;
86 }
87 
88 // `extensions_cbs` may contain one or more encoded extensions in a row.
89 // This function only decodes the first extension from `extensions_cbs`. After
90 // this function is called `extensions_cbs` will point to the next extension
91 // after the one returned by decodeExtensions. If an error is returned,
92 // `extensions_cbs` may be in a partially read state - do not rely on it to
93 // parse more extensions.
decodeExtension(CBS * extensions_cbs)94 absl::StatusOr<Extension> decodeExtension(CBS* extensions_cbs) {
95   Extension ext;
96   if (!CBS_get_u16(extensions_cbs, &ext.extension_type)) {
97     return absl::InvalidArgumentError("failed to read next type.");
98   }
99   CBS extension_cbs;
100   if (!CBS_get_u16_length_prefixed(extensions_cbs, &extension_cbs)) {
101     return absl::InvalidArgumentError("failed to read extension value.");
102   }
103   ext.extension_value.resize(CBS_len(&extension_cbs));
104   if (!CBS_copy_bytes(&extension_cbs,
105                       reinterpret_cast<uint8_t*>(ext.extension_value.data()),
106                       CBS_len(&extension_cbs))) {
107     return absl::InvalidArgumentError("failed to read Extension value.");
108   }
109   return ext;
110 }
111 
112 }  // namespace
113 
AuthenticatorInput(const Token & token)114 absl::StatusOr<std::string> AuthenticatorInput(const Token& token) {
115   return EncodeTokenStructHelper(token.token_type, token.token_key_id,
116                                  token.nonce, token.context, std::nullopt);
117 }
118 
MarshalToken(const Token & token)119 absl::StatusOr<std::string> MarshalToken(const Token& token) {
120   return EncodeTokenStructHelper(token.token_type, token.token_key_id,
121                                  token.nonce, token.context,
122                                  token.authenticator);
123 }
124 
UnmarshalToken(std::string token)125 absl::StatusOr<Token> UnmarshalToken(std::string token) {
126   Token out;
127   out.nonce.resize(32);
128   out.context.resize(32);
129   out.token_key_id.resize(32);
130   out.authenticator.resize(256);
131   CBS cbs;
132   CBS_init(&cbs, reinterpret_cast<const uint8_t*>(token.data()), token.size());
133   if (!CBS_get_u16(&cbs, &out.token_type)) {
134     return absl::InvalidArgumentError("failed to read token type");
135   }
136   if (out.token_type != 0xDA7A) {
137     return absl::InvalidArgumentError("unsupported token type");
138   }
139   if (!CBS_copy_bytes(&cbs, reinterpret_cast<uint8_t*>(out.nonce.data()),
140                       out.nonce.size())) {
141     return absl::InvalidArgumentError("failed to read nonce");
142   }
143   if (!CBS_copy_bytes(&cbs, reinterpret_cast<uint8_t*>(out.context.data()),
144                       out.context.size())) {
145     return absl::InvalidArgumentError("failed to read context");
146   }
147   if (!CBS_copy_bytes(&cbs, reinterpret_cast<uint8_t*>(out.token_key_id.data()),
148                       out.token_key_id.size())) {
149     return absl::InvalidArgumentError("failed to read token_key_id");
150   }
151   if (!CBS_copy_bytes(&cbs,
152                       reinterpret_cast<uint8_t*>(out.authenticator.data()),
153                       out.authenticator.size())) {
154     return absl::InvalidArgumentError("failed to read authenticator");
155   }
156   if (CBS_len(&cbs) != 0) {
157     return absl::InvalidArgumentError("token had extra bytes");
158   }
159   return out;
160 }
161 
EncodeExtension(const Extension & extension)162 absl::StatusOr<std::string> EncodeExtension(const Extension& extension) {
163   // Main CryptoByteBuilder object cbb which will be passed to CBB_finish to
164   // finalize the output string.
165   bssl::ScopedCBB cbb;
166   // Temporary cbb struct object to fill with value bytes.
167   CBB extension_value;
168   // initial_capacity only serves as a hint.
169   if (!CBB_init(cbb.get(), /*initial_capacity=*/4)) {
170     return absl::InternalError("CBB_init() failed.");
171   }
172   // Add extension type using only 2 bytes.
173   if (!CBB_add_u16(cbb.get(), extension.extension_type) ||
174       // Add extension value but prefix it with its length which should fit in 2
175       // bytes.
176       !CBB_add_u16_length_prefixed(cbb.get(), &extension_value) ||
177       !CBB_add_bytes(
178           &extension_value,
179           reinterpret_cast<const uint8_t*>(extension.extension_value.data()),
180           extension.extension_value.size())) {
181     return absl::InvalidArgumentError("Failed to populate cbb.");
182   }
183 
184   uint8_t* encoded_ext;
185   size_t encoded_ext_len;
186   if (!CBB_finish(cbb.get(), &encoded_ext, &encoded_ext_len)) {
187     return absl::InvalidArgumentError("Failed to generate extension encoding");
188   }
189   std::string encoded_ext_str(reinterpret_cast<const char*>(encoded_ext),
190                               encoded_ext_len);
191   // Free memory.
192   OPENSSL_free(encoded_ext);
193   return encoded_ext_str;
194 }
195 
EncodeExtensions(const Extensions & extensions)196 absl::StatusOr<std::string> EncodeExtensions(const Extensions& extensions) {
197   // Main CryptoByteBuilder object cbb which will be passed to CBB_finish to
198   // finalize the output string.
199   bssl::ScopedCBB cbb;
200   // Temporary cbb struct object to fill with encoded extensions bytes.
201   CBB extensions_list;
202   // initial_capacity only serves as a hint.
203   if (!CBB_init(cbb.get(), /*initial_capacity=*/6)) {
204     return absl::InternalError("CBB_init() failed.");
205   }
206   // Size in bytes for the extensions list must fit in 2 bytes.
207   if (!CBB_add_u16_length_prefixed(cbb.get(), &extensions_list)) {
208     return absl::InvalidArgumentError(
209         "Call to CBB_add_u16_length_prefixed erred.");
210   }
211   // Add all encoded extensions to the temporary cbb.
212   for (const Extension& ext : extensions.extensions) {
213     ANON_TOKENS_ASSIGN_OR_RETURN(std::string encoded_ext, EncodeExtension(ext));
214     if (!CBB_add_bytes(&extensions_list,
215                        reinterpret_cast<const uint8_t*>(encoded_ext.data()),
216                        encoded_ext.size())) {
217       return absl::InvalidArgumentError(
218           "Could not add encoded extension to cbb.");
219     }
220   }
221 
222   uint8_t* encoded_extensions;
223   size_t encoded_extensions_len;
224   if (!CBB_finish(cbb.get(), &encoded_extensions, &encoded_extensions_len)) {
225     return absl::InvalidArgumentError(
226         "Failed to generate encoded extensions list.");
227   }
228   std::string encoded_extensions_str(
229       reinterpret_cast<const char*>(encoded_extensions),
230       encoded_extensions_len);
231   // Free memory.
232   OPENSSL_free(encoded_extensions);
233   return encoded_extensions_str;
234 }
235 
FromExtension(const Extension & ext)236 absl::StatusOr<ExpirationTimestamp> ExpirationTimestamp::FromExtension(
237     const Extension& ext) {
238   if (ext.extension_type != 0x0001) {
239     return absl::InvalidArgumentError(
240         absl::StrCat("Extension of wrong type: ", ext.extension_type));
241   }
242   ExpirationTimestamp ts;
243   CBS cbs;
244   CBS_init(&cbs, reinterpret_cast<const uint8_t*>(ext.extension_value.data()),
245            ext.extension_value.size());
246   if (!CBS_get_u64(&cbs, &ts.timestamp_precision)) {
247     return absl::InvalidArgumentError("failed to read timestamp_precision");
248   }
249   if (!CBS_get_u64(&cbs, &ts.timestamp)) {
250     return absl::InvalidArgumentError("failed to read timestamp");
251   }
252   return ts;
253 }
254 
AsExtension() const255 absl::StatusOr<Extension> ExpirationTimestamp::AsExtension() const {
256   bssl::ScopedCBB cbb;
257   if (!CBB_init(cbb.get(), sizeof(ExpirationTimestamp))) {
258     return absl::InternalError("CBB_init() failed.");
259   }
260   if (!CBB_add_u64(cbb.get(), timestamp_precision)) {
261     return absl::InternalError("Failed to add timestamp_precision to cbb.");
262   }
263   if (!CBB_add_u64(cbb.get(), timestamp)) {
264     return absl::InternalError("Failed to add timestamp to cbb.");
265   }
266   uint8_t* wire_format;
267   size_t wire_format_len;
268   if (!CBB_finish(cbb.get(), &wire_format, &wire_format_len)) {
269     return absl::InternalError("Failed to generate wire format.");
270   }
271   std::string wire_format_str(reinterpret_cast<const char*>(wire_format),
272                               wire_format_len);
273   OPENSSL_free(wire_format);
274   return Extension{
275       .extension_type = 0x0001,
276       .extension_value = wire_format_str,
277   };
278 }
279 
AsExtension() const280 absl::StatusOr<Extension> GeoHint::AsExtension() const {
281   bssl::ScopedCBB cbb;
282   if (!CBB_init(cbb.get(), sizeof(uint16_t) + geo_hint.size())) {
283     return absl::InternalError("CBB_init() failed.");
284   }
285   // Temporary cbb struct object to fill with geo_hint bytes.
286   CBB geo_hint_cbb;
287   if (!CBB_add_u16_length_prefixed(cbb.get(), &geo_hint_cbb) ||
288       !CBB_add_bytes(&geo_hint_cbb,
289                      reinterpret_cast<const uint8_t*>(geo_hint.data()),
290                      geo_hint.size())) {
291     return absl::InternalError("Failed to add geohint to cbb.");
292   }
293   uint8_t* wire_format;
294   size_t wire_format_len;
295   if (!CBB_finish(cbb.get(), &wire_format, &wire_format_len)) {
296     return absl::InternalError("Failed to generate wire format.");
297   }
298   std::string wire_format_str(reinterpret_cast<const char*>(wire_format),
299                               wire_format_len);
300   OPENSSL_free(wire_format);
301   return Extension{
302       .extension_type = 0x0002,
303       .extension_value = wire_format_str,
304   };
305 }
306 
FromExtension(const Extension & ext)307 absl::StatusOr<GeoHint> GeoHint::FromExtension(const Extension& ext) {
308   if (ext.extension_type != 0x0002) {
309     return absl::InvalidArgumentError(absl::StrCat(
310         "[GeoHint] Extension of wrong type: ", ext.extension_type));
311   }
312   GeoHint gh;
313   CBS cbs;
314   CBS_init(&cbs, reinterpret_cast<const uint8_t*>(ext.extension_value.data()),
315            ext.extension_value.size());
316   CBS geohint_cbs;
317   if (!CBS_get_u16_length_prefixed(&cbs, &geohint_cbs)) {
318     return absl::InvalidArgumentError(
319         "[GeoHint] failed to read geohint length");
320   }
321   gh.geo_hint.resize(CBS_len(&geohint_cbs));
322   if (!CBS_copy_bytes(&geohint_cbs,
323                       reinterpret_cast<uint8_t*>(gh.geo_hint.data()),
324                       gh.geo_hint.size())) {
325     return absl::InvalidArgumentError("[GeoHint] failed to read geohint data");
326   }
327 
328   const std::vector<std::string_view> split = absl::StrSplit(gh.geo_hint, ',');
329   if (split.size() != 3) {
330     return absl::InvalidArgumentError(
331         "[GeoHint] geo_hint must be exactly 3 parts.");
332   }
333   for (const std::string_view part : split) {
334     if (absl::AsciiStrToUpper(part) != part) {
335       return absl::InvalidArgumentError(
336           "[GeoHint] all geo_hint parts must be UPPERCASE.");
337     }
338   }
339   gh.country_code = split[0];
340   gh.region = split[1];
341   gh.city = split[2];
342   return gh;
343 }
344 
AsExtension() const345 absl::StatusOr<Extension> ServiceType::AsExtension() const {
346   bssl::ScopedCBB cbb;
347   if (!CBB_init(cbb.get(), sizeof(uint8_t))) {
348     return absl::InternalError("CBB_init() failed.");
349   }
350   if (!CBB_add_u8(cbb.get(), service_type_id)) {
351     return absl::InternalError("Failed to add service_type_id to cbb.");
352   }
353   uint8_t* wire_format;
354   size_t wire_format_len;
355   if (!CBB_finish(cbb.get(), &wire_format, &wire_format_len)) {
356     return absl::InternalError("Failed to generate wire format.");
357   }
358   std::string wire_format_str(reinterpret_cast<const char*>(wire_format),
359                               wire_format_len);
360   OPENSSL_free(wire_format);
361   return Extension{.extension_type = 0xF001,
362                    .extension_value = wire_format_str};
363 }
364 
FromExtension(const Extension & ext)365 absl::StatusOr<ServiceType> ServiceType::FromExtension(const Extension& ext) {
366   if (ext.extension_type != 0xF001) {
367     return absl::InvalidArgumentError(absl::StrCat(
368         "[ServiceType] extension of wrong type: ", ext.extension_type));
369   }
370   ServiceType st;
371   CBS cbs;
372   CBS_init(&cbs, reinterpret_cast<const uint8_t*>(ext.extension_value.data()),
373            ext.extension_value.size());
374   if (!CBS_get_u8(&cbs, &st.service_type_id)) {
375     return absl::InvalidArgumentError(
376         "[ServiceType] failed to read len from extension");
377   }
378   switch (st.service_type_id) {
379     case kChromeIpBlinding:
380       st.service_type = "chromeipblinding";
381       break;
382     default:
383       return absl::InvalidArgumentError(
384           "[ServiceType] unknown service_type_id");
385   }
386   return st;
387 }
388 
AsExtension() const389 absl::StatusOr<Extension> DebugMode::AsExtension() const {
390   bssl::ScopedCBB cbb;
391   if (!CBB_init(cbb.get(), sizeof(uint8_t))) {
392     return absl::InternalError("CBB_init() failed.");
393   }
394   if (!CBB_add_u8(cbb.get(), mode)) {
395     return absl::InternalError("Failed to add mode to cbb.");
396   }
397   uint8_t* wire_format;
398   size_t wire_format_len;
399   if (!CBB_finish(cbb.get(), &wire_format, &wire_format_len)) {
400     return absl::InternalError("Failed to generate wire format.");
401   }
402   std::string wire_format_str(reinterpret_cast<const char*>(wire_format),
403                               wire_format_len);
404   OPENSSL_free(wire_format);
405   return Extension{.extension_type = 0xF002,
406                    .extension_value = wire_format_str};
407 }
408 
FromExtension(const Extension & ext)409 absl::StatusOr<DebugMode> DebugMode::FromExtension(const Extension& ext) {
410   if (ext.extension_type != 0xF002) {
411     return absl::InvalidArgumentError(absl::StrCat(
412         "[DebugMode] extension of wrong type: ", ext.extension_type));
413   }
414   DebugMode dm;
415   CBS cbs;
416   CBS_init(&cbs, reinterpret_cast<const uint8_t*>(ext.extension_value.data()),
417            ext.extension_value.size());
418   if (!CBS_get_u8(&cbs, &dm.mode)) {
419     return absl::InvalidArgumentError(
420         "[DebugMode] failed to read len from extension");
421   }
422   if (dm.mode != kProd && dm.mode != kDebug) {
423     return absl::InvalidArgumentError(
424         absl::StrCat("[DebugMode] invalid mode: ", dm.mode));
425   }
426   return dm;
427 }
428 
AsExtension() const429 absl::StatusOr<Extension> ProxyLayer::AsExtension() const {
430   bssl::ScopedCBB cbb;
431   if (!CBB_init(cbb.get(), sizeof(uint8_t))) {
432     return absl::InternalError("CBB_init() failed.");
433   }
434   if (!CBB_add_u8(cbb.get(), layer)) {
435     return absl::InternalError("Failed to add layer to cbb.");
436   }
437   uint8_t* wire_format;
438   size_t wire_format_len;
439   if (!CBB_finish(cbb.get(), &wire_format, &wire_format_len)) {
440     return absl::InternalError("Failed to generate wire format.");
441   }
442   std::string wire_format_str(reinterpret_cast<const char*>(wire_format),
443                               wire_format_len);
444   OPENSSL_free(wire_format);
445   return Extension{.extension_type = 0xF003,
446                    .extension_value = wire_format_str};
447 }
448 
FromExtension(const Extension & ext)449 absl::StatusOr<ProxyLayer> ProxyLayer::FromExtension(const Extension& ext) {
450   if (ext.extension_type != 0xF003) {
451     return absl::InvalidArgumentError(absl::StrCat(
452         "[ProxyLayer] extension of wrong type: ", ext.extension_type));
453   }
454   ProxyLayer pl;
455   CBS cbs;
456   CBS_init(&cbs, reinterpret_cast<const uint8_t*>(ext.extension_value.data()),
457            ext.extension_value.size());
458   if (!CBS_get_u8(&cbs, &pl.layer)) {
459     return absl::InvalidArgumentError(
460         "[ProxyLayer] failed to read len from extension");
461   }
462   if (pl.layer != kProxyA && pl.layer != kProxyB) {
463     return absl::InvalidArgumentError(
464         absl::StrCat("[ProxyLayer] invalid layer: ", pl.layer));
465   }
466   return pl;
467 }
468 
DecodeExtensions(absl::string_view encoded_extensions)469 absl::StatusOr<Extensions> DecodeExtensions(
470     absl::string_view encoded_extensions) {
471   CBS cbs;
472   CBS_init(&cbs, reinterpret_cast<const uint8_t*>(encoded_extensions.data()),
473            encoded_extensions.size());
474   CBS extensions_cbs;
475   if (!CBS_get_u16_length_prefixed(&cbs, &extensions_cbs)) {
476     return absl::InvalidArgumentError("failed to read extensions.");
477   }
478   if (CBS_len(&extensions_cbs) == 0) {
479     return absl::InvalidArgumentError("At least one extension is required.");
480   }
481   if (CBS_len(&cbs) != 0) {
482     return absl::InvalidArgumentError("no data after extensions is allowed.");
483   }
484   Extensions extensions;
485   while (CBS_len(&extensions_cbs) > 0) {
486     ANON_TOKENS_ASSIGN_OR_RETURN(const Extension ext,
487                                  decodeExtension(&extensions_cbs));
488     extensions.extensions.push_back(ext);
489   }
490   return extensions;
491 }
492 
MarshalTokenChallenge(const TokenChallenge & token_challenge)493 absl::StatusOr<std::string> MarshalTokenChallenge(
494     const TokenChallenge& token_challenge) {
495   // Main CryptoByteBuilder object cbb which will be passed to CBB_finish to
496   // finalize the output string.
497   bssl::ScopedCBB cbb;
498   // initial_capacity only serves as a hint.
499   if (!CBB_init(cbb.get(), /*initial_capacity=*/98)) {
500     return absl::InternalError("CBB_init() failed.");
501   }
502   // Add token_type to cbb.
503   if (!CBB_add_u16(cbb.get(), token_challenge.token_type)) {
504     return absl::InvalidArgumentError("Could not add token_type to cbb.");
505   }
506   // Add issuer_name to cbb using temporary cbb struct object issuer_name_cbb.
507   CBB issuer_name_cbb;
508   if (!CBB_add_u16_length_prefixed(cbb.get(), &issuer_name_cbb) ||
509       !CBB_add_bytes(
510           &issuer_name_cbb,
511           reinterpret_cast<const uint8_t*>(token_challenge.issuer_name.data()),
512           token_challenge.issuer_name.size())) {
513     return absl::InvalidArgumentError("Could not add issuer_name to cbb.");
514   }
515   uint8_t* marshaled_challenge;
516   size_t marshaled_challenge_len;
517   if (!CBB_finish(cbb.get(), &marshaled_challenge, &marshaled_challenge_len)) {
518     return absl::InvalidArgumentError("Failed to marshal token challenge");
519   }
520   std::string marshaled_challenge_str(
521       reinterpret_cast<const char*>(marshaled_challenge),
522       marshaled_challenge_len);
523   // Free memory.
524   OPENSSL_free(marshaled_challenge);
525   return marshaled_challenge_str;
526 }
527 
MarshalTokenRequest(const TokenRequest & token_request)528 absl::StatusOr<std::string> MarshalTokenRequest(
529     const TokenRequest& token_request) {
530   // Main CryptoByteBuilder object cbb which will be passed to CBB_finish to
531   // finalize the output string.
532   bssl::ScopedCBB cbb;
533   // initial_capacity only serves as a hint.
534   if (!CBB_init(cbb.get(),
535                 /*initial_capacity=*/kDA7AMarshaledTokenRequestSizeInBytes)) {
536     return absl::InternalError("CBB_init() failed.");
537   }
538   // Add token_type to cbb.
539   if (!CBB_add_u16(cbb.get(), token_request.token_type) ||
540       // Add truncated_token_key_id to cbb.
541       !CBB_add_u8(cbb.get(), token_request.truncated_token_key_id) ||
542       // Add blinded_token_request string to cbb.
543       !CBB_add_bytes(cbb.get(),
544                      reinterpret_cast<const uint8_t*>(
545                          token_request.blinded_token_request.data()),
546                      token_request.blinded_token_request.size())) {
547     return absl::InvalidArgumentError(
548         "Could not construct cbb with given inputs.");
549   }
550 
551   uint8_t* encoded_output;
552   size_t encoded_output_len;
553   if (!CBB_finish(cbb.get(), &encoded_output, &encoded_output_len)) {
554     return absl::InvalidArgumentError(
555         "Failed to generate token request encoding");
556   }
557   std::string encoded_output_str(reinterpret_cast<const char*>(encoded_output),
558                                  encoded_output_len);
559   // Free memory.
560   OPENSSL_free(encoded_output);
561   return encoded_output_str;
562 }
563 
UnmarshalTokenRequest(absl::string_view token_request)564 absl::StatusOr<TokenRequest> UnmarshalTokenRequest(
565     absl::string_view token_request) {
566   TokenRequest out;
567   out.blinded_token_request.resize(kDA7ABlindedTokenRequestSizeInBytes);
568   CBS cbs;
569   CBS_init(&cbs, reinterpret_cast<const uint8_t*>(token_request.data()),
570            token_request.size());
571   if (!CBS_get_u16(&cbs, &out.token_type)) {
572     return absl::InvalidArgumentError("failed to read token type");
573   }
574   if (out.token_type != 0xDA7A) {
575     return absl::InvalidArgumentError("unsupported token type");
576   }
577   if (!CBS_get_u8(&cbs, &out.truncated_token_key_id)) {
578     return absl::InvalidArgumentError("failed to read truncated_token_key_id");
579   }
580   if (!CBS_copy_bytes(
581           &cbs, reinterpret_cast<uint8_t*>(out.blinded_token_request.data()),
582           out.blinded_token_request.size())) {
583     return absl::InvalidArgumentError("failed to read blinded_token_request");
584   }
585   if (CBS_len(&cbs) != 0) {
586     return absl::InvalidArgumentError("token request had extra bytes");
587   }
588   return out;
589 }
590 
MarshalExtendedTokenRequest(const ExtendedTokenRequest & extended_token_request)591 absl::StatusOr<std::string> MarshalExtendedTokenRequest(
592     const ExtendedTokenRequest& extended_token_request) {
593   // Main CryptoByteBuilder object cbb which will be passed to CBB_finish to
594   // finalize the output string.
595   bssl::ScopedCBB cbb;
596   // Initial_capacity only serves as a hint. Note that
597   // extended_token_request.request would occupy 259 bytes as the token type is
598   // DA7A and we will add some additional bytes as  buffer for the extensions.
599   if (!CBB_init(
600           cbb.get(),
601           /*initial_capacity=*/kDA7AMarshaledTokenRequestSizeInBytes + 41)) {
602     return absl::InternalError("CBB_init() failed.");
603   }
604   // Marshal TokenRequest structure.
605   ANON_TOKENS_ASSIGN_OR_RETURN(
606       std::string encoded_request,
607       MarshalTokenRequest(extended_token_request.request));
608   // Marshal Extensions structure.
609   ANON_TOKENS_ASSIGN_OR_RETURN(
610       std::string encoded_extensions,
611       EncodeExtensions(extended_token_request.extensions));
612 
613   // Add encoded_request to cbb.
614   if (!CBB_add_bytes(cbb.get(),
615                      reinterpret_cast<const uint8_t*>(encoded_request.data()),
616                      encoded_request.size()) ||
617       // Add encoded_extensions to cbb.
618       !CBB_add_bytes(
619           cbb.get(),
620           reinterpret_cast<const uint8_t*>(encoded_extensions.data()),
621           encoded_extensions.size())) {
622     return absl::InvalidArgumentError(
623         "Could not construct cbb with given inputs.");
624   }
625 
626   uint8_t* encoded_output;
627   size_t encoded_output_len;
628   if (!CBB_finish(cbb.get(), &encoded_output, &encoded_output_len)) {
629     return absl::InvalidArgumentError(
630         "Failed to generate token request encoding");
631   }
632   std::string encoded_output_str(reinterpret_cast<const char*>(encoded_output),
633                                  encoded_output_len);
634   // Free memory.
635   OPENSSL_free(encoded_output);
636   return encoded_output_str;
637 }
638 
UnmarshalExtendedTokenRequest(absl::string_view extended_token_request)639 absl::StatusOr<ExtendedTokenRequest> UnmarshalExtendedTokenRequest(
640     absl::string_view extended_token_request) {
641   CBS cbs;
642   CBS_init(&cbs,
643            reinterpret_cast<const uint8_t*>(extended_token_request.data()),
644            extended_token_request.size());
645 
646   std::string encoded_token_request;
647   encoded_token_request.resize(kDA7AMarshaledTokenRequestSizeInBytes);
648   if (!CBS_copy_bytes(&cbs,
649                       reinterpret_cast<uint8_t*>(encoded_token_request.data()),
650                       encoded_token_request.size())) {
651     return absl::InvalidArgumentError("failed to read encoded_token_request");
652   }
653 
654   std::string encoded_extensions;
655   encoded_extensions.resize(CBS_len(&cbs));
656   if (!CBS_copy_bytes(&cbs,
657                       reinterpret_cast<uint8_t*>(encoded_extensions.data()),
658                       encoded_extensions.size())) {
659     return absl::InvalidArgumentError("failed to read encoded_extensions");
660   }
661 
662   ExtendedTokenRequest out;
663   ANON_TOKENS_ASSIGN_OR_RETURN(out.request,
664                                UnmarshalTokenRequest(encoded_token_request));
665   ANON_TOKENS_ASSIGN_OR_RETURN(out.extensions,
666                                DecodeExtensions(encoded_extensions));
667   return out;
668 }
669 
ValidateExtensionsOrderAndValues(const Extensions & extensions,absl::Span<uint16_t> expected_types,absl::Time now)670 absl::Status ValidateExtensionsOrderAndValues(
671     const Extensions& extensions, absl::Span<uint16_t> expected_types,
672     absl::Time now) {
673   if (expected_types.size() != extensions.extensions.size()) {
674     return absl::InvalidArgumentError(
675         absl::StrFormat("Expected %d type, got %d", expected_types.size(),
676                         extensions.extensions.size()));
677   }
678   for (size_t i = 0; i < expected_types.size(); i++) {
679     if (expected_types[i] != extensions.extensions[i].extension_type) {
680       return absl::InvalidArgumentError(absl::StrFormat(
681           "Expected %x type at index %d, got %x", expected_types[i], i,
682           extensions.extensions[i].extension_type));
683     }
684   }
685   return ValidateExtensionsValues(extensions, now);
686 }
687 
ValidateExtensionsValues(const Extensions & extensions,absl::Time now)688 absl::Status ValidateExtensionsValues(const Extensions& extensions,
689                                       absl::Time now) {
690   for (const Extension& ext : extensions.extensions) {
691     switch (ext.extension_type) {
692       case 0x0001: {
693         absl::StatusOr<ExpirationTimestamp> expiration_timestamp =
694             ExpirationTimestamp::FromExtension(ext);
695         if (!expiration_timestamp.ok()) {
696           return expiration_timestamp.status();
697         }
698         if (expiration_timestamp->timestamp % kFifteenMinutesInSeconds != 0) {
699           return absl::InvalidArgumentError(
700               "Expiration timestamp is not rounded");
701         }
702         absl::Time timestamp =
703             absl::FromUnixSeconds(expiration_timestamp->timestamp);
704         if (timestamp < now || timestamp > now + absl::Hours(kOneWeekToHours)) {
705           return absl::InvalidArgumentError(
706               "Expiration timestamp is out of range");
707         }
708         break;
709       }
710       case 0x0002: {
711         absl::StatusOr<GeoHint> geo_hint = GeoHint::FromExtension(ext);
712         if (!geo_hint.ok()) {
713           return geo_hint.status();
714         }
715         if (geo_hint->country_code.length() != kAlpha2CountryCodeLength) {
716           return absl::InvalidArgumentError("Country code is not 2 characters");
717         }
718         for (const char& c : geo_hint->country_code) {
719           if (!absl::ascii_isupper(c)) {
720             return absl::InvalidArgumentError("Country code is not uppercase");
721           }
722         }
723         for (const char& c : geo_hint->region) {
724           if (!absl::ascii_isupper(c) && !absl::ascii_ispunct(c)) {
725             return absl::InvalidArgumentError("Region is not uppercase");
726           }
727         }
728         break;
729       }
730       case 0xF001: {
731         absl::StatusOr<ServiceType> service_type =
732             ServiceType::FromExtension(ext);
733         if (!service_type.ok()) {
734           return service_type.status();
735         }
736         break;
737       }
738       case 0xF002: {
739         absl::StatusOr<DebugMode> debug_mode = DebugMode::FromExtension(ext);
740         if (!debug_mode.ok()) {
741           return debug_mode.status();
742         }
743         break;
744       }
745       case 0xF003: {
746         absl::StatusOr<ProxyLayer> proxy_layer = ProxyLayer::FromExtension(ext);
747         if (!proxy_layer.ok()) {
748           return proxy_layer.status();
749         }
750         break;
751       }
752       default: {
753         return absl::InvalidArgumentError("Unsupported extension type");
754       }
755     }
756   }
757   return absl::OkStatus();
758 }
759 
760 }  // namespace anonymous_tokens
761