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