blob: a1ff55e6fd49d0bc2c6ff838233f5672f893f6f8 [file] [log] [blame]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// To run this binary from this directory use:
// bazel run -c opt :rsa_bssa_public_metadata_privacy_pass_client_demo
// --cxxopt='-std=c++17'
#include <cstdint>
#include <iostream>
#include <memory>
#include <ostream>
#include <random>
#include <string>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/escaping.h"
#include "anonymous_tokens/cpp/crypto/crypto_utils.h"
#include "anonymous_tokens/cpp/privacy_pass/rsa_bssa_public_metadata_client.h"
#include "anonymous_tokens/cpp/privacy_pass/token_encodings.h"
#include "anonymous_tokens/cpp/testing/utils.h"
#include <openssl/base.h>
#include <openssl/digest.h>
// Generates a random string of size string_length.
std::string GetRandomString(int string_length) {
std::mt19937_64 generator;
std::uniform_int_distribution<int> distr_u8 =
std::uniform_int_distribution<int>{0, 255};
std::string rand(string_length, 0);
for (int i = 0; i < string_length; ++i) {
rand[i] = static_cast<uint8_t>((distr_u8)(generator));
}
return rand;
}
absl::Status RunDemo() {
// Construct RSA public key with a strong rsa modulus.
auto [test_rsa_public_key, _] =
anonymous_tokens::GetStrongTestRsaKeyPair2048();
absl::StatusOr<bssl::UniquePtr<RSA>> rsa_public_key =
anonymous_tokens::CreatePublicKeyRSA(
test_rsa_public_key.n, test_rsa_public_key.e);
if (!rsa_public_key.ok()) {
return rsa_public_key.status();
}
// Compute RSA BSSA Public Key Token ID.
absl::StatusOr<std::string> public_key_der =
anonymous_tokens::RsaSsaPssPublicKeyToDerEncoding(
rsa_public_key.value().get());
if (!public_key_der.ok()) {
return public_key_der.status();
}
const EVP_MD* sha256 = EVP_sha256();
absl::StatusOr<std::string> token_key_id =
anonymous_tokens::ComputeHash(public_key_der.value(),
*sha256);
if (!token_key_id.ok()) {
return token_key_id.status();
}
// Create the privacy pass client.
static absl::StatusOr<
std::unique_ptr<anonymous_tokens::
PrivacyPassRsaBssaPublicMetadataClient>>
pp_client = anonymous_tokens::
PrivacyPassRsaBssaPublicMetadataClient::Create(
*rsa_public_key.value());
if (!pp_client.ok()) {
return pp_client.status();
}
// Create token challenge.
anonymous_tokens::TokenChallenge challenge;
challenge.issuer_name = "issuer.dummy.com";
absl::StatusOr<std::string> token_challenge =
anonymous_tokens::MarshalTokenChallenge(challenge);
if (!token_challenge.ok()) {
return token_challenge.status();
}
// Nonce is a random string of 32 bytes.
std::string nonce = GetRandomString(/*string_length=*/32);
// Public metadata for the purposes of this demo.
anonymous_tokens::Extensions extensions;
anonymous_tokens::GeoHint geo_hint;
geo_hint.country_code = "US";
absl::StatusOr<anonymous_tokens::Extension>
geo_hint_extension = geo_hint.AsExtension();
if (!geo_hint_extension.ok()) {
return geo_hint_extension.status();
}
extensions.extensions.push_back(*geo_hint_extension);
anonymous_tokens::ServiceType service_type;
service_type.service_type_id =
anonymous_tokens::ServiceType::kChromeIpBlinding;
absl::StatusOr<anonymous_tokens::Extension>
service_type_extension = service_type.AsExtension();
if (!service_type_extension.ok()) {
return service_type_extension.status();
}
extensions.extensions.push_back(*service_type_extension);
absl::StatusOr<std::string> encoded_extensions =
anonymous_tokens::EncodeExtensions(extensions);
if (!encoded_extensions.ok()) {
return encoded_extensions.status();
}
// Create token request.
absl::StatusOr<anonymous_tokens::ExtendedTokenRequest>
extended_token_request = pp_client.value()->CreateTokenRequest(
token_challenge.value(), nonce, token_key_id.value(), extensions);
if (!extended_token_request.ok()) {
return extended_token_request.status();
}
absl::StatusOr<std::string> marshaled_extended_token_request =
anonymous_tokens::MarshalExtendedTokenRequest(
extended_token_request.value());
if (!marshaled_extended_token_request.ok()) {
return marshaled_extended_token_request.status();
}
// Output token request and wait for response.
std::cout << "Token Type DA7A, Extended Token Request (in hexadecimal string "
"format):\n"
<< absl::BytesToHexString(marshaled_extended_token_request.value())
<< std::endl;
std::cout << "Please enter the token response (in hexadecimal string format):"
<< std::endl;
std::string token_response;
std::string token_response_hex_str;
std::cin >> token_response_hex_str;
token_response = absl::HexStringToBytes(token_response_hex_str);
// Finalize the token.
absl::StatusOr<anonymous_tokens::Token> final_token =
pp_client.value()->FinalizeToken(token_response);
if (!final_token.ok()) {
return final_token.status();
}
// Run public key verification successfully.
absl::Status is_verified = anonymous_tokens::
PrivacyPassRsaBssaPublicMetadataClient::Verify(final_token.value(),
encoded_extensions.value(),
*rsa_public_key.value());
if (!is_verified.ok()) {
return is_verified;
}
std::cout << "Token successfully finalized and verified." << std::endl;
return absl::OkStatus();
}
int main(int argc, char** argv) {
absl::Status status = RunDemo();
if (!status.ok()) {
std::cout << status << std::endl;
return -1;
} else {
std::cout << "Client demo ran successfully!" << std::endl;
}
return 0;
}