blob: f138eb41d471659c3b04cf0b5f814a6b34009ecc [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.
#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/rsa_blind_signer.h"
#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/constants.h"
#include "quiche/blind_sign_auth/anonymous_tokens/cpp/crypto/crypto_utils.h"
#include "quiche/blind_sign_auth/anonymous_tokens/cpp/shared/status_utils.h"
#include "quiche/blind_sign_auth/anonymous_tokens/proto/anonymous_tokens.pb.h"
#include "openssl/rsa.h"
namespace private_membership {
namespace anonymous_tokens {
RsaBlindSigner::RsaBlindSigner(std::optional<absl::string_view> public_metadata,
bssl::UniquePtr<BIGNUM> rsa_modulus,
bssl::UniquePtr<BIGNUM> rsa_p,
bssl::UniquePtr<BIGNUM> rsa_q,
bssl::UniquePtr<BIGNUM> augmented_rsa_e,
bssl::UniquePtr<BIGNUM> augmented_rsa_d,
bssl::UniquePtr<RSA> rsa_standard_key)
: public_metadata_(public_metadata),
rsa_modulus_(std::move(rsa_modulus)),
rsa_p_(std::move(rsa_p)),
rsa_q_(std::move(rsa_q)),
augmented_rsa_e_(std::move(augmented_rsa_e)),
augmented_rsa_d_(std::move(augmented_rsa_d)),
rsa_standard_key_(std::move(rsa_standard_key)) {}
absl::StatusOr<std::unique_ptr<RsaBlindSigner>> RsaBlindSigner::New(
const RSAPrivateKey& signing_key,
std::optional<absl::string_view> public_metadata) {
if (!public_metadata.has_value()) {
// The RSA modulus and exponent are checked as part of the conversion to
// bssl::UniquePtr<RSA>.
ANON_TOKENS_ASSIGN_OR_RETURN(
bssl::UniquePtr<RSA> rsa_standard_key,
AnonymousTokensRSAPrivateKeyToRSA(signing_key));
return absl::WrapUnique(
new RsaBlindSigner(public_metadata, nullptr, nullptr, nullptr, nullptr,
nullptr, std::move(rsa_standard_key)));
}
// Convert RSA modulus n (=p*q) to BIGNUM
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> rsa_modulus,
StringToBignum(signing_key.n()));
// Convert p & q to BIGNUM
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> rsa_p,
StringToBignum(signing_key.p()));
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> rsa_q,
StringToBignum(signing_key.q()));
// Convert public exponent e to BIGNUM
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> old_e,
StringToBignum(signing_key.e()));
// Convert public exponent e to BIGNUM
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> old_d,
StringToBignum(signing_key.d()));
// Compute new exponents based on public metadata.
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> augmented_rsa_e,
ComputeFinalExponentUnderPublicMetadata(
*rsa_modulus, *old_e, *public_metadata));
// Compute phi(p) = p-1 and phi(q) = q-1
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> phi_p, NewBigNum());
if (BN_sub(phi_p.get(), rsa_p.get(), BN_value_one()) != 1) {
return absl::InternalError(
absl::StrCat("Unable to compute phi(p): ", GetSslErrors()));
}
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> phi_q, NewBigNum());
if (BN_sub(phi_q.get(), rsa_q.get(), BN_value_one()) != 1) {
return absl::InternalError(
absl::StrCat("Unable to compute phi(q): ", GetSslErrors()));
}
bssl::UniquePtr<BN_CTX> bn_ctx(BN_CTX_new());
if (!bn_ctx) {
return absl::InternalError("BN_CTX_new failed.");
}
// Compute lcm(phi(p), phi(q)).
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> lcm,
ComputeCarmichaelLcm(*phi_p, *phi_q, *bn_ctx));
// Compute the new private exponent new_d
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> augmented_rsa_d,
NewBigNum());
if (!BN_mod_inverse(augmented_rsa_d.get(), augmented_rsa_e.get(), lcm.get(),
bn_ctx.get())) {
return absl::InternalError(
absl::StrCat("Could not compute private exponent d: ", GetSslErrors()));
}
return absl::WrapUnique(new RsaBlindSigner(
*public_metadata, std::move(rsa_modulus), std::move(rsa_p),
std::move(rsa_q), std::move(augmented_rsa_e),
std::move(augmented_rsa_d)));
}
// Helper Signature method that assumes RSA_NO_PADDING.
// TODO(b/271438729): Adding blinding of private operations in RSA Sign
// TODO(b/271438266): Implement RsaSign using the Chinese Remainder Theorem
absl::StatusOr<std::string> RsaBlindSigner::SignInternal(
absl::string_view input) const {
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> input_bn,
StringToBignum(input));
if (BN_ucmp(input_bn.get(), rsa_modulus_.get()) >= 0) {
return absl::InvalidArgumentError(
"RsaSign input size too large for modulus size");
}
ANON_TOKENS_ASSIGN_OR_RETURN(BnCtxPtr ctx, GetAndStartBigNumCtx());
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> result, NewBigNum());
// TODO(b/271438266): Replace with constant-time implementation.
if (!BN_mod_exp(result.get(), input_bn.get(), augmented_rsa_d_.get(),
rsa_modulus_.get(), ctx.get())) {
return absl::InternalError("BN_mod_exp_mont_consttime failed in RsaSign");
}
// Verify the result to protect against fault attacks as described in
// boringssl. Also serves as a check for correctness.
ANON_TOKENS_ASSIGN_OR_RETURN(bssl::UniquePtr<BIGNUM> vrfy, NewBigNum());
if (vrfy == nullptr ||
!BN_mod_exp(vrfy.get(), result.get(), augmented_rsa_e_.get(),
rsa_modulus_.get(), ctx.get()) ||
BN_cmp(vrfy.get(), input_bn.get()) != 0) {
return absl::InternalError("Signature verification failed in RsaSign");
}
return BignumToString(*result, BN_num_bytes(rsa_modulus_.get()));
}
absl::StatusOr<std::string> RsaBlindSigner::Sign(
const absl::string_view blinded_data) const {
if (blinded_data.empty() || blinded_data.data() == nullptr) {
return absl::InvalidArgumentError("blinded_data string is empty.");
}
int mod_size;
if (!public_metadata_.has_value()) {
mod_size = RSA_size(rsa_standard_key_.get());
} else {
mod_size = BN_num_bytes(rsa_modulus_.get());
}
if (blinded_data.size() != mod_size) {
return absl::InternalError(absl::StrCat(
"Expected blind data size = ", mod_size,
" actual blind data size = ", blinded_data.size(), " bytes."));
}
std::string signature(mod_size, 0);
if (!public_metadata_.has_value()) {
// Compute a raw RSA signature.
size_t out_len;
if (RSA_sign_raw(/*rsa=*/rsa_standard_key_.get(), /*out_len=*/&out_len,
/*out=*/reinterpret_cast<uint8_t*>(&signature[0]),
/*max_out=*/mod_size,
/*in=*/reinterpret_cast<const uint8_t*>(&blinded_data[0]),
/*in_len=*/mod_size,
/*padding=*/RSA_NO_PADDING) != kBsslSuccess) {
return absl::InternalError(
"RSA_sign_raw failed when called from RsaBlindSigner::Sign");
}
if (out_len != mod_size && out_len == signature.size()) {
return absl::InternalError(absl::StrCat(
"Expected value of out_len = ", mod_size,
" bytes, actual value of out_len and signature.size() = ", out_len,
" and ", signature.size(), " bytes."));
}
} else {
// As public metadata is not empty, we cannot use RSA_sign_raw as it might
// err on exponent size.
ANON_TOKENS_ASSIGN_OR_RETURN(signature, SignInternal(blinded_data));
if (signature.size() != mod_size) {
return absl::InternalError(absl::StrCat(
"Expected value of signature.size() = ", mod_size,
" bytes, actual value of signature.size() = ", signature.size(),
" bytes."));
}
}
return signature;
}
} // namespace anonymous_tokens
} // namespace private_membership