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