// 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
//
//     http://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 "tink/signature/rsa_ssa_pkcs1_private_key.h"

#include <memory>
#include <string>
#include <utility>

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/log/absl_check.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/escaping.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "tink/restricted_big_integer.h"
#include "tink/restricted_data.h"
#ifdef OPENSSL_IS_BORINGSSL
#include "openssl/base.h"
#endif
#include "openssl/bn.h"
#include "openssl/rsa.h"
#include "tink/big_integer.h"
#include "tink/insecure_secret_key_access.h"
#include "tink/internal/bn_util.h"
#include "tink/internal/ssl_unique_ptr.h"
#include "tink/key.h"
#include "tink/partial_key_access.h"
#include "tink/signature/rsa_ssa_pkcs1_parameters.h"
#include "tink/signature/rsa_ssa_pkcs1_public_key.h"
#include "tink/util/test_matchers.h"

namespace crypto {
namespace tink {
namespace {

using ::crypto::tink::test::IsOk;
using ::crypto::tink::test::StatusIs;
using ::testing::Eq;
using ::testing::HasSubstr;
using ::testing::NotNull;
using ::testing::TestWithParam;
using ::testing::Values;

struct TestCase {
  RsaSsaPkcs1Parameters::HashType hash_type;
  RsaSsaPkcs1Parameters::Variant variant;
  absl::optional<int> id_requirement;
  std::string output_prefix;
};

struct PrivateValues {
  RestrictedData p;
  RestrictedData q;
  RestrictedData dp;
  RestrictedData dq;
  RestrictedData d;
  RestrictedData q_inv;
};

constexpr int kModulusSizeInBits = 2048;

// Test vector from
// https://github.com/C2SP/wycheproof/blob/main/testvectors_v1/rsa_pkcs1_2048_test.json
constexpr absl::string_view k2048BitRsaModulus =
    "s1EKK81M5kTFtZSuUFnhKy8FS2WNXaWVmi_fGHG4CLw98-"
    "Yo0nkuUarVwSS0O9pFPcpc3kvPKOe9Tv-6DLS3Qru21aATy2PRqjqJ4CYn71OYtSwM_"
    "ZfSCKvrjXybzgu-sBmobdtYm-sppbdL-GEHXGd8gdQw8DDCZSR6-dPJFAzLZTCdB-Ctwe_"
    "RXPF-ewVdfaOGjkZIzDoYDw7n-OHnsYCYozkbTOcWHpjVevipR-IBpGPi1rvKgFnlcG6d_"
    "tj0hWRl_6cS7RqhjoiNEtxqoJzpXs_"
    "Kg8xbCxXbCchkf11STA8udiCjQWuWI8rcDwl69XMmHJjIQAqhKvOOQ8rYTQ";

constexpr absl::string_view kD2048Bit =
    "GlAtDupse2niHVg5EB9wVFbtDvhS-0f-"
    "IQcfVMXzPIzrBmxi1yfjLSbFgTcyn4nTGVMlt5UmTBldhUcvdQfb0JYdKVH5NaJrNPCsJNFUkO"
    "ESiptxOJFbx9v6j-OWNXExxUOunJhQc2jZzrCMHGGYo-"
    "2nrqGFoOl2zULCLQDwA9nxnZbqTJr8v-"
    "FEHMyALPsGifWdgExqTk9ATBUXR0XtbLi8iO8LM7oNKoDjXkO8kPNQBS5yAW51sA01ejgcnA1G"
    "cGnKZgiHyYd2Y0n8xDRgtKpRa84Hnt2HuhZDB7dSwnftlSitO6C_"
    "GHc0ntO3lmpsJAEQQJv00PreDGj9rdhH_Q";

constexpr absl::string_view kP2048Bit =
    "7BJc834xCi_0YmO5suBinWOQAF7IiRPU-3G9TdhWEkSYquupg9e6K9lC5k0iP-t6I69NYF7-"
    "6mvXDTmv6Z01o6oV50oXaHeAk74O3UqNCbLe9tybZ_-FdkYlwuGSNttMQBzjCiVy0-y0-"
    "Wm3rRnFIsAtd0RlZ24aN3bFTWJINIs";

constexpr absl::string_view kQ2048Bit =
    "wnQqvNmJe9SwtnH5c_yCqPhKv1cF_4jdQZSGI6_p3KYNxlQzkHZ_"
    "6uvrU5V27ov6YbX8vKlKfO91oJFQxUD6lpTdgAStI3GMiJBJIZNpyZ9EWNSvwUj28H34cySpbZ"
    "z3s4XdhiJBShgy-fKURvBQwtWmQHZJ3EGrcOI7PcwiyYc";

constexpr absl::string_view kDp2048Bit =
    "lql5jSUCY0ALtidzQogWJ-B87N-RGHsBuJ_0cxQYinwg-ySAAVbSyF1WZujfbO_5-YBN362A_"
    "1dn3lbswCnHK_bHF9-fZNqvwprPnceQj5oK1n4g6JSZNsy6GNAhosT-"
    "uwQ0misgR8SQE4W25dDGkdEYsz-BgCsyrCcu8J5C-tU";

constexpr absl::string_view kDq2048Bit =
    "BVT0GwuH9opFcis74M9KseFlA0wakQAquPKenvni2rb-57JFW6-0IDfp0vflM_"
    "NIoUdBL9cggL58JjP12ALJHDnmvOzj5nXlmZUDPFVzcCDa2eizDQS4KK37kwStVKEaNaT1BwmH"
    "asWxGCNrp2pNfJopHdlgexad4dGCOFaRmZ8";

constexpr absl::string_view kQInv2048Bit =
    "HGQBidm_6MYjgzIQp2xCDG9E5ddg4lmRbOwq4rFWRWlg_ZXidHZgw4lWIlDwVQSc-"
    "rflwwOVSThKeiquscgk069wlIKoz5tYcCKgCx8HIttQ8zyybcIN0iRdUmXfYe4pg8k4whZ9zuE"
    "h_EtEecI35yjPYzq2CowOzQT85-O6pVk";

// Test vector from
// https://github.com/C2SP/wycheproof/blob/main/testvectors_v1/rsa_pkcs1_3072_test.json
constexpr absl::string_view k3072BitRsaModulus =
    "2R8NAPGqtYDirA6DdjjecAT8loviExWh7yojSWkEXdS8GUXrU5gu6z_pfOhKJsfUZHhP9-"
    "VhzuVw4m1BReFP_M5wQw7zL6zRnoDMzoqbZgQGX_HlCn-o_"
    "dQyyk57K4WMiKlmJuOhCoMVlvkcLyLIPhoCZ_x98SHTM387D6aoxgbtkDHB-"
    "DuSE96oMtxdyunAO0eAmVPXXZZvNbyxD__"
    "SM0Wm7icUw4iXKYCTitYSPZyXkWkguUEu4ahOHTRbg4ZuKzsCEnOEaBrKA4QBo5urXkZy1kk81"
    "KKTuTMlLj_AbY5DSPDha5muWPeXK0O7anoEKV0RLuUJ-vquOd5tBk9iLD88i0_"
    "ObYNnMMEoXZDFSNtit5WWR5Tq8UOtQnNgoug_Wx-KILCNGM29R08hwb9C5vHhN4kN-"
    "SiI2DzEBZdVlyCbegn03Jmfq4LU69d-DWa9idg_pWSgPjVgl3-"
    "04PunoDOfkiHcDJlAJYHLlUcqbBG26A6RBZ-8FEcLemjY5Q5T";

constexpr absl::string_view kD3072Bit =
    "AquVF1vhg5XwM7mB-GQ-qBYHnTpfL2jmsvBLus1l1lmVbqIjgMWwXghNMNISh2ORwyKPqTbS-"
    "x5rQv2g_eEFgNBxJQH8D6wKb-"
    "6ZljiyLJEEGw34iSaEx4pijYZlkWV1EwEyVmwaQOzXySGLLTE6UTk0ql66lcqatFluOoUMMlNH"
    "fKx__DOPWls0qlt3c9VoHdKFTF1xmp8NAxYs_"
    "0tgJG1I3kjwwm7dnQ8NwXlchBF287zdQCoDD5doToekUHvIvUY-"
    "q0mUXKjM3ryitMXIsV20D8sSU0zv12wTDpXFgGoco_"
    "tDWUd3gPQ3h3gT7J8fJBXxayJoFVo5khMlLQuIN7d15KIiMBKyDHZ8eUpBBEEWhFkK579-"
    "QieUnVnZTL-"
    "FdG0vppCDmGWR6bCvUQgKt8H0vvDZb6u3MY5koDqTrmL1L8lBujoesry87t5ZPc1sSvBFn7d6u"
    "Q926tcNv7ckmxfWK3QOKqQ28pn9uUBxqhUY6XymugDwFIr88xbd1QfR";

constexpr absl::string_view kP3072Bit =
    "8mG_"
    "wJd4bhw00SPBnNDQtsxlvvUnIMigA4krDnRhGIgJmrlsAyoHi3fgAL6Q1bmPuOQIPNkyatrQUO"
    "xsuS9Vtb-AZrEGXj-_0TPuzay3XM66ZnPSGEupoKlYM_t-DCfGB3d5R-rP5wLdzu3xamX-"
    "l4q1NVIHgI-ipZDxczuZ2RZJYu1c-YtHjNAoj_FhlDrRo_3RNTXHUvYiz44MXDukOru6-"
    "QHcRX-vEeCSIkc671PRdgYfo6cHQbq41UCpWeHH";

constexpr absl::string_view kQ3072Bit =
    "5VH4x-83GMB6qfUSej_oQ55w-6dDUkJnNV-Ala9k_"
    "XwLR1bMQ1VbthV6SIBG8cyZiOcWlBZBFrJQKD3VC3iUpFaRjWz46Dv-CFq-"
    "Zbvv55HP4XhlSJGrgtZvcMhadXVzoFEDlgU2PDirnasxEQqTxz-gm29xBoYz7Y_Qd-"
    "6AXALVWQkONGoo1xhqa19oBLZfZVs0oqbEa4FQGytHFUzu_mtsIP5zzfdk_HaPck-"
    "vKUiycOa1JRhxBGR21DkLXi8V";

constexpr absl::string_view kDp3072Bit =
    "dcWRSp9O4RHLiCN7nBrKj0fZ2GN-U6uoNI-"
    "d4DQkSaswH4IhPZhaeiYRLctqzK6RayFB728J1Gnl9qwqWADsAJfAaCV0Fq-bIKe_TSizH-"
    "FDKSz11OBO18XxGbEFmhppWo9u2sb5piH6bOWo_C36-t9nFTV6d7lTKme3Kmq3Yog1uF_"
    "lYUuPxJgQXYDIDSJXYvudf-FVrLX0TC2VS-ue7Pry6rNAuHRGOMWJvCYoOMndaR-ol_"
    "g8ym9UCCqXHxlZ";

constexpr absl::string_view kDq3072Bit =
    "EZ1MSL89Mi-GvItQkgdapecDsrDUYPssxlLBo73HOhlPHHm0Uu-"
    "5jbD0paEE0gnvOS7W8yUKdt3Xfl_Rf4IRmNX1dDGMpPoGt0mRGmtnMBhpKV6AGSTnUbN69-"
    "TL3f3ZldTjO6DG27VWqVO-_xoa49ElWwsiWWfxkSvczXmKbobhMGebqbcF0A_"
    "WDM1VRhdkGHr6_gtlRwS1zIB0g1RXfz9tHNOuvYFlRmcs-ZDZWYh1_GocO-82rymwXvjKwL9J";

constexpr absl::string_view kQInv3072Bit =
    "mZ_WBLgVj7lBYYkXJAVGwypzTKi0h32c75dDiHzTSh2Imgvv-K4bwwQGHrOdVpr1_"
    "gsmRrbRrX2sejeexpWo6cy0TOTxwReM8qvXQa_Pusny-"
    "LdJOCBnc0e98IwWtIH7FNKjV4I7tvrys3MoMP8nvn6-yOajJczx6MJKUpu1dJgh_e2oslUo_"
    "aDkc_"
    "vFFht2S4SBNZicK9SZFLttJEhMgYIbwwqhxKcCsi8UTLL3w1nBpo11WcAPgFoXzuI9KD0Z";

const BigInteger& kF4 = *new BigInteger(std::string("\x1\0\x1", 3));  // 65537

std::string Base64WebSafeDecode(absl::string_view base64_string) {
  std::string dest;
  ABSL_CHECK(absl::WebSafeBase64Unescape(base64_string, &dest))
      << "Failed to base64 decode.";

  return dest;
}

PrivateValues GetValid2048BitPrivateValues() {
  return PrivateValues{/*p=*/RestrictedData(Base64WebSafeDecode(kP2048Bit),
                                            InsecureSecretKeyAccess::Get()),
                       /*q=*/
                       RestrictedData(Base64WebSafeDecode(kQ2048Bit),
                                      InsecureSecretKeyAccess::Get()),
                       /*dp=*/
                       RestrictedData(Base64WebSafeDecode(kDp2048Bit),
                                      InsecureSecretKeyAccess::Get()),
                       /*dq=*/
                       RestrictedData(Base64WebSafeDecode(kDq2048Bit),
                                      InsecureSecretKeyAccess::Get()),
                       /*d=*/
                       RestrictedData(Base64WebSafeDecode(kD2048Bit),
                                      InsecureSecretKeyAccess::Get()),
                       /*q_inv=*/
                       RestrictedData(Base64WebSafeDecode(kQInv2048Bit),
                                      InsecureSecretKeyAccess::Get())};
}

PrivateValues GetValid3072BitPrivateValues() {
  return PrivateValues{/*p=*/RestrictedData(Base64WebSafeDecode(kP3072Bit),
                                            InsecureSecretKeyAccess::Get()),
                       /*q=*/
                       RestrictedData(Base64WebSafeDecode(kQ3072Bit),
                                      InsecureSecretKeyAccess::Get()),
                       /*dp=*/
                       RestrictedData(Base64WebSafeDecode(kDp3072Bit),
                                      InsecureSecretKeyAccess::Get()),
                       /*dq=*/
                       RestrictedData(Base64WebSafeDecode(kDq3072Bit),
                                      InsecureSecretKeyAccess::Get()),
                       /*d=*/
                       RestrictedData(Base64WebSafeDecode(kD3072Bit),
                                      InsecureSecretKeyAccess::Get()),
                       /*q_inv=*/
                       RestrictedData(Base64WebSafeDecode(kQInv3072Bit),
                                      InsecureSecretKeyAccess::Get())};
}

absl::StatusOr<RsaSsaPkcs1PrivateKey> CreateValid2048BitPrivateKey(
    const RsaSsaPkcs1Parameters& parameters,
    absl::optional<int> id_requirement) {
  BigInteger modulus(Base64WebSafeDecode(k2048BitRsaModulus));
  absl::StatusOr<RsaSsaPkcs1PublicKey> public_key =
      RsaSsaPkcs1PublicKey::Create(parameters, modulus, id_requirement,
                                   GetPartialKeyAccess());
  if (!public_key.ok()) {
    return public_key.status();
  }

  PrivateValues private_values = GetValid2048BitPrivateValues();
  return RsaSsaPkcs1PrivateKey::Builder()
      .SetPublicKey(*public_key)
      .SetPrimeP(private_values.p)
      .SetPrimeQ(private_values.q)
      .SetPrimeExponentP(private_values.dp)
      .SetPrimeExponentQ(private_values.dq)
      .SetPrivateExponent(private_values.d)
      .SetCrtCoefficient(private_values.q_inv)
      .Build(GetPartialKeyAccess());
}

absl::StatusOr<RsaSsaPkcs1PrivateKey> CreateValid3072BitPrivateKey(
    const RsaSsaPkcs1Parameters& parameters,
    absl::optional<int> id_requirement) {
  BigInteger modulus(Base64WebSafeDecode(k3072BitRsaModulus));
  absl::StatusOr<RsaSsaPkcs1PublicKey> public_key =
      RsaSsaPkcs1PublicKey::Create(parameters, modulus, id_requirement,
                                   GetPartialKeyAccess());
  if (!public_key.ok()) {
    return public_key.status();
  }

  PrivateValues private_values = GetValid3072BitPrivateValues();
  return RsaSsaPkcs1PrivateKey::Builder()
      .SetPublicKey(*public_key)
      .SetPrimeP(private_values.p)
      .SetPrimeQ(private_values.q)
      .SetPrimeExponentP(private_values.dp)
      .SetPrimeExponentQ(private_values.dq)
      .SetPrivateExponent(private_values.d)
      .SetCrtCoefficient(private_values.q_inv)
      .Build(GetPartialKeyAccess());
}

RsaSsaPkcs1PublicKey GetValidPublicKey() {
  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(kModulusSizeInBits)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kNoPrefix)
          .Build();
  ABSL_CHECK_OK(parameters.status()) << "Failed to create parameters.";

  BigInteger modulus(Base64WebSafeDecode(k2048BitRsaModulus));
  absl::StatusOr<RsaSsaPkcs1PublicKey> public_key =
      RsaSsaPkcs1PublicKey::Create(*parameters, modulus,
                                   /*id_requirement=*/absl::nullopt,
                                   GetPartialKeyAccess());
  ABSL_CHECK_OK(public_key.status()) << "Failed to create public key.";
  return *public_key;
}

std::string FlipFirstByte(absl::string_view str) {
  std::string res(str);
  res[0] = ~res[0];
  return res;
}

using RsaSsaPkcs1PrivateKeyTest = TestWithParam<TestCase>;

INSTANTIATE_TEST_SUITE_P(
    RsaSsaPkcs1PrivateKeyTestSuite, RsaSsaPkcs1PrivateKeyTest,
    Values(TestCase{RsaSsaPkcs1Parameters::HashType::kSha256,
                    RsaSsaPkcs1Parameters::Variant::kTink,
                    /*id_requirement=*/0x02030400,
                    /*output_prefix=*/std::string("\x01\x02\x03\x04\x00", 5)},
           TestCase{RsaSsaPkcs1Parameters::HashType::kSha256,
                    RsaSsaPkcs1Parameters::Variant::kCrunchy,
                    /*id_requirement=*/0x01030005,
                    /*output_prefix=*/std::string("\x00\x01\x03\x00\x05", 5)},
           TestCase{RsaSsaPkcs1Parameters::HashType::kSha384,
                    RsaSsaPkcs1Parameters::Variant::kLegacy,
                    /*id_requirement=*/0x07080910,
                    /*output_prefix=*/std::string("\x00\x07\x08\x09\x10", 5)},
           TestCase{RsaSsaPkcs1Parameters::HashType::kSha512,
                    RsaSsaPkcs1Parameters::Variant::kNoPrefix,
                    /*id_requirement=*/absl::nullopt,
                    /*output_prefix=*/""}));

TEST_P(RsaSsaPkcs1PrivateKeyTest, BuildPrivateKeySucceeds) {
  TestCase test_case = GetParam();

  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(kModulusSizeInBits)
          .SetPublicExponent(kF4)
          .SetHashType(test_case.hash_type)
          .SetVariant(test_case.variant)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  BigInteger modulus(Base64WebSafeDecode(k2048BitRsaModulus));
  absl::StatusOr<RsaSsaPkcs1PublicKey> public_key =
      RsaSsaPkcs1PublicKey::Create(*parameters, modulus,
                                   test_case.id_requirement,
                                   GetPartialKeyAccess());
  ASSERT_THAT(public_key, IsOk());

  PrivateValues private_values = GetValid2048BitPrivateValues();
  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(*public_key)
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());
  ASSERT_THAT(private_key, IsOk());

  EXPECT_THAT(private_key->GetParameters(), Eq(*parameters));
  EXPECT_THAT(private_key->GetIdRequirement(), Eq(test_case.id_requirement));
  EXPECT_THAT(private_key->GetPublicKey(), Eq(*public_key));
  EXPECT_THAT(private_key->GetOutputPrefix(), Eq(test_case.output_prefix));
  EXPECT_THAT(private_key->GetPrimePData(GetPartialKeyAccess()),
              Eq(private_values.p));
  EXPECT_THAT(private_key->GetPrimeQData(GetPartialKeyAccess()),
              Eq(private_values.q));
  EXPECT_THAT(private_key->GetPrimeExponentPData(), Eq(private_values.dp));
  EXPECT_THAT(private_key->GetPrimeExponentQData(), Eq(private_values.dq));
  EXPECT_THAT(private_key->GetCrtCoefficientData(), Eq(private_values.q_inv));
  EXPECT_THAT(private_key->GetPrivateExponentData(), Eq(private_values.d));
  EXPECT_THAT(private_key->GetPrimeP(GetPartialKeyAccess()),
              Eq(RestrictedBigInteger(
                  private_values.p.Get(InsecureSecretKeyAccess::Get()),
                  InsecureSecretKeyAccess::Get())));
  EXPECT_THAT(private_key->GetPrimeQ(GetPartialKeyAccess()),
              Eq(RestrictedBigInteger(
                  private_values.q.Get(InsecureSecretKeyAccess::Get()),
                  InsecureSecretKeyAccess::Get())));
  EXPECT_THAT(private_key->GetPrimeExponentP(),
              Eq(RestrictedBigInteger(
                  private_values.dp.Get(InsecureSecretKeyAccess::Get()),
                  InsecureSecretKeyAccess::Get())));
  EXPECT_THAT(private_key->GetPrimeExponentQ(),
              Eq(RestrictedBigInteger(
                  private_values.dq.Get(InsecureSecretKeyAccess::Get()),
                  InsecureSecretKeyAccess::Get())));
  EXPECT_THAT(private_key->GetCrtCoefficient(),
              Eq(RestrictedBigInteger(
                  private_values.q_inv.Get(InsecureSecretKeyAccess::Get()),
                  InsecureSecretKeyAccess::Get())));
  EXPECT_THAT(private_key->GetPrivateExponent(),
              Eq(RestrictedBigInteger(
                  private_values.d.Get(InsecureSecretKeyAccess::Get()),
                  InsecureSecretKeyAccess::Get())));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrivateKeyFromBoringSsl) {
  internal::SslUniquePtr<RSA> rsa(RSA_new());
  ASSERT_THAT(rsa, NotNull());

  // Set public exponent to 65537.
  internal::SslUniquePtr<BIGNUM> e(BN_new());
  BN_set_word(e.get(), 65537);

  // Generate an RSA key pair and get the values.
  ASSERT_THAT(RSA_generate_key_ex(rsa.get(), 2048, e.get(), /*cb=*/nullptr),
              Eq(1));

  const BIGNUM *n_bn, *e_bn, *d_bn, *p_bn, *q_bn, *dp_bn, *dq_bn, *q_inv_bn;
  RSA_get0_key(rsa.get(), &n_bn, &e_bn, &d_bn);
  RSA_get0_factors(rsa.get(), &p_bn, &q_bn);
  RSA_get0_crt_params(rsa.get(), &dp_bn, &dq_bn, &q_inv_bn);

  absl::StatusOr<std::string> n_str =
      internal::BignumToString(n_bn, BN_num_bytes(n_bn));
  ASSERT_THAT(n_str, IsOk());
  absl::StatusOr<std::string> e_str =
      internal::BignumToString(e_bn, BN_num_bytes(e_bn));
  ASSERT_THAT(e_str, IsOk());
  absl::StatusOr<std::string> d_str = internal::BignumToString(d_bn, 256);
  ASSERT_THAT(d_str, IsOk());
  absl::StatusOr<std::string> p_str =
      internal::BignumToString(p_bn, BN_num_bytes(p_bn));
  ASSERT_THAT(p_str, IsOk());
  absl::StatusOr<std::string> q_str =
      internal::BignumToString(q_bn, BN_num_bytes(q_bn));
  ASSERT_THAT(q_str, IsOk());
  absl::StatusOr<std::string> dp_str =
      internal::BignumToString(dp_bn, BN_num_bytes(p_bn));
  ASSERT_THAT(dp_str, IsOk());
  absl::StatusOr<std::string> dq_str =
      internal::BignumToString(dq_bn, BN_num_bytes(q_bn));
  ASSERT_THAT(dq_str, IsOk());
  absl::StatusOr<std::string> q_inv_str =
      internal::BignumToString(q_inv_bn, BN_num_bytes(p_bn));
  ASSERT_THAT(q_inv_str, IsOk());

  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(2048)
          .SetPublicExponent(BigInteger(*e_str))
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kNoPrefix)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PublicKey> public_key =
      RsaSsaPkcs1PublicKey::Create(*parameters, /*modulus=*/BigInteger(*n_str),
                                   /*id_requirement=*/absl::nullopt,
                                   GetPartialKeyAccess());
  ASSERT_THAT(public_key, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(*public_key)
          .SetPrimeP(RestrictedData(*p_str, InsecureSecretKeyAccess::Get()))
          .SetPrimeQ(RestrictedData(*q_str, InsecureSecretKeyAccess::Get()))
          .SetPrimeExponentP(
              RestrictedData(*dp_str, InsecureSecretKeyAccess::Get()))
          .SetPrimeExponentQ(
              RestrictedData(*dq_str, InsecureSecretKeyAccess::Get()))
          .SetPrivateExponent(
              RestrictedData(*d_str, InsecureSecretKeyAccess::Get()))
          .SetCrtCoefficient(
              RestrictedData(*q_inv_str, InsecureSecretKeyAccess::Get()))
          .Build(GetPartialKeyAccess());
  ASSERT_THAT(private_key, IsOk());

  EXPECT_THAT(private_key->GetParameters(), Eq(*parameters));
  EXPECT_THAT(private_key->GetPublicKey(), Eq(*public_key));
  EXPECT_THAT(private_key->GetPrimePData(GetPartialKeyAccess())
                  .GetSecret(InsecureSecretKeyAccess::Get()),
              Eq(*p_str));
  EXPECT_THAT(private_key->GetPrimeQData(GetPartialKeyAccess())
                  .GetSecret(InsecureSecretKeyAccess::Get()),
              Eq(*q_str));
  EXPECT_THAT(private_key->GetPrimeExponentPData().GetSecret(
                  InsecureSecretKeyAccess::Get()),
              Eq(*dp_str));
  EXPECT_THAT(private_key->GetPrimeExponentQData().GetSecret(
                  InsecureSecretKeyAccess::Get()),
              Eq(*dq_str));
  EXPECT_THAT(private_key->GetCrtCoefficientData().GetSecret(
                  InsecureSecretKeyAccess::Get()),
              Eq(*q_inv_str));
  EXPECT_THAT(private_key->GetPrivateExponentData().GetSecret(
                  InsecureSecretKeyAccess::Get()),
              Eq(*d_str));
  EXPECT_THAT(private_key->GetIdRequirement(), Eq(absl::nullopt));
  EXPECT_THAT(private_key->GetOutputPrefix(), Eq(""));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrivateKeyValidatesModulus) {
  RsaSsaPkcs1PublicKey public_key = GetValidPublicKey();
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PublicKey> public_key_modified_modulus =
      RsaSsaPkcs1PublicKey::Create(
          public_key.GetParameters(),
          BigInteger(FlipFirstByte(Base64WebSafeDecode(k2048BitRsaModulus))),
          /*id_requirement=*/absl::nullopt, GetPartialKeyAccess());
  ASSERT_THAT(public_key_modified_modulus, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_modified_modulus =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(*public_key_modified_modulus)
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_modified_modulus.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrivateKeyValidatesPrimeP) {
  RsaSsaPkcs1PublicKey public_key = GetValidPublicKey();
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_modified_prime_p =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(public_key)
          .SetPrimeP(
              RestrictedData(FlipFirstByte(Base64WebSafeDecode(kP2048Bit)),
                             InsecureSecretKeyAccess::Get()))
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_modified_prime_p.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrivateKeyValidatesPrimeQ) {
  RsaSsaPkcs1PublicKey public_key = GetValidPublicKey();
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_modified_prime_q =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(public_key)
          .SetPrimeP(private_values.p)
          .SetPrimeQ(
              RestrictedData(FlipFirstByte(Base64WebSafeDecode(kQ2048Bit)),
                             InsecureSecretKeyAccess::Get()))
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_modified_prime_q.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrivateKeyValidatesPrimeExponentP) {
  RsaSsaPkcs1PublicKey public_key = GetValidPublicKey();
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_modified_prime_exponent_p =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(public_key)
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(
              RestrictedData(FlipFirstByte(Base64WebSafeDecode(kDp2048Bit)),
                             InsecureSecretKeyAccess::Get()))
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_modified_prime_exponent_p.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrivateKeyValidatesPrimeExponentQ) {
  RsaSsaPkcs1PublicKey public_key = GetValidPublicKey();
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_modified_prime_exponent_q =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(public_key)
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(
              RestrictedData(FlipFirstByte(Base64WebSafeDecode(kDq2048Bit)),
                             InsecureSecretKeyAccess::Get()))
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_modified_prime_exponent_q.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrivateKeyValidatesPrivateExponent) {
  RsaSsaPkcs1PublicKey public_key = GetValidPublicKey();
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_modified_private_exponent =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(public_key)
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(
              RestrictedData(FlipFirstByte(Base64WebSafeDecode(kD2048Bit)),
                             InsecureSecretKeyAccess::Get()))
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_modified_private_exponent.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrivateKeyValidatesCrtCoefficient) {
  RsaSsaPkcs1PublicKey public_key = GetValidPublicKey();
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_modified_crt_coefficient =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(public_key)
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(
              RestrictedData(FlipFirstByte(Base64WebSafeDecode(kQInv2048Bit)),
                             InsecureSecretKeyAccess::Get()))
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_modified_crt_coefficient.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPublicKeyNotSetFails) {
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_no_public_key_set =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_no_public_key_set.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrimePNotSetFails) {
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_no_prime_p_set =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(GetValidPublicKey())
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_no_prime_p_set.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrimeQNotSetFails) {
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_no_prime_q_set =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(GetValidPublicKey())
          .SetPrimeP(private_values.p)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_no_prime_q_set.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrimeExponentPNotSetFails) {
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_no_prime_exponent_p_set =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(GetValidPublicKey())
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_no_prime_exponent_p_set.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrimeExponentQNotSetFails) {
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_no_prime_exponent_q_set =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(GetValidPublicKey())
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_no_prime_exponent_q_set.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildPrivateExponentNotSetFails) {
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_no_private_exponent_set =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(GetValidPublicKey())
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_no_private_exponent_set.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, BuildCrtCoefficientNotSetFails) {
  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key_no_crt_coefficient_set =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(GetValidPublicKey())
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key_no_crt_coefficient_set.status(),
              StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST(RsaSsaPkcs1PrivateKeyTest, CreateMismatchedKeyPairFails) {
  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(2048)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kTink)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  // Test value from
  // https://github.com/google/wycheproof/blob/master/testvectors/rsa_pkcs1_2048_test.json
  BigInteger mismatched_modulus(Base64WebSafeDecode(
      "3ZBFkDl4CMQxQyliPZATRThDJRsTuLPE_vVFmBEq8-sxxxEDxiWZUWdOU72Tp-NtGUcuR06-"
      "gChobZUpSE2Lr-pKBLoZVVZnYWyEeGcFlACcm8aj7-UidMumTHJHR9ftwZTk_"
      "t3jKjKJ2Uwxk25-"
      "ehXXVvVISS9bNFuSfoxhi91VCsshoXrhSDBDg9ubPHuqPkyL2OhEqITao-GNVpmMsy-"
      "brk1B1WoY3dQxPICJt16du5EoRwusmwh_thkoqw-"
      "MTIk2CwIImQCNCOi9MfkHqAfoBWrWgA3_357Z2WSpOefkgRS4SXhVGsuFyd-"
      "RlvPv9VKG1s1LOagiqKd2Ohggjw"));
  absl::StatusOr<RsaSsaPkcs1PublicKey> public_key =
      RsaSsaPkcs1PublicKey::Create(*parameters, mismatched_modulus,
                                   /*id_requirement=*/0x02030400,
                                   GetPartialKeyAccess());
  ASSERT_THAT(public_key, IsOk());

  PrivateValues private_values = GetValid2048BitPrivateValues();

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(*public_key)
          .SetPrimeP(private_values.p)
          .SetPrimeQ(private_values.q)
          .SetPrimeExponentP(private_values.dp)
          .SetPrimeExponentQ(private_values.dq)
          .SetPrivateExponent(private_values.d)
          .SetCrtCoefficient(private_values.q_inv)
          .Build(GetPartialKeyAccess());

  EXPECT_THAT(private_key.status(),
              StatusIs(absl::StatusCode ::kInvalidArgument));
}

TEST_P(RsaSsaPkcs1PrivateKeyTest, BuildWithRestrictedBigIntegerSucceeds) {
  TestCase test_case = GetParam();

  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(kModulusSizeInBits)
          .SetPublicExponent(kF4)
          .SetHashType(test_case.hash_type)
          .SetVariant(test_case.variant)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  BigInteger modulus(Base64WebSafeDecode(k2048BitRsaModulus));
  absl::StatusOr<RsaSsaPkcs1PublicKey> public_key =
      RsaSsaPkcs1PublicKey::Create(*parameters, modulus,
                                   test_case.id_requirement,
                                   GetPartialKeyAccess());
  ASSERT_THAT(public_key, IsOk());

  RestrictedBigInteger p_rb(Base64WebSafeDecode(kP2048Bit),
                            InsecureSecretKeyAccess::Get());
  RestrictedBigInteger q_rb(Base64WebSafeDecode(kQ2048Bit),
                            InsecureSecretKeyAccess::Get());
  RestrictedBigInteger dp_rb(Base64WebSafeDecode(kDp2048Bit),
                             InsecureSecretKeyAccess::Get());
  RestrictedBigInteger dq_rb(Base64WebSafeDecode(kDq2048Bit),
                             InsecureSecretKeyAccess::Get());
  RestrictedBigInteger d_rb(Base64WebSafeDecode(kD2048Bit),
                            InsecureSecretKeyAccess::Get());
  RestrictedBigInteger q_inv_rb(Base64WebSafeDecode(kQInv2048Bit),
                                InsecureSecretKeyAccess::Get());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      RsaSsaPkcs1PrivateKey::Builder()
          .SetPublicKey(*public_key)
          .SetPrimeP(p_rb)
          .SetPrimeQ(q_rb)
          .SetPrimeExponentP(dp_rb)
          .SetPrimeExponentQ(dq_rb)
          .SetPrivateExponent(d_rb)
          .SetCrtCoefficient(q_inv_rb)
          .Build(GetPartialKeyAccess());
  ASSERT_THAT(private_key, IsOk());

  PrivateValues private_values = GetValid2048BitPrivateValues();
  EXPECT_THAT(private_key->GetParameters(), Eq(*parameters));
  EXPECT_THAT(private_key->GetIdRequirement(), Eq(test_case.id_requirement));
  EXPECT_THAT(private_key->GetPublicKey(), Eq(*public_key));
  EXPECT_THAT(private_key->GetOutputPrefix(), Eq(test_case.output_prefix));
  EXPECT_THAT(private_key->GetPrimePData(GetPartialKeyAccess()),
              Eq(private_values.p));
  EXPECT_THAT(private_key->GetPrimeQData(GetPartialKeyAccess()),
              Eq(private_values.q));
  EXPECT_THAT(private_key->GetPrimeExponentPData(), Eq(private_values.dp));
  EXPECT_THAT(private_key->GetPrimeExponentQData(), Eq(private_values.dq));
  EXPECT_THAT(private_key->GetCrtCoefficientData(), Eq(private_values.q_inv));
  EXPECT_THAT(private_key->GetPrivateExponentData(), Eq(private_values.d));
}

TEST_P(RsaSsaPkcs1PrivateKeyTest,
       BuildWithRestrictedBigIntegerAndRestrictedDataFails) {
  TestCase test_case = GetParam();

  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(kModulusSizeInBits)
          .SetPublicExponent(kF4)
          .SetHashType(test_case.hash_type)
          .SetVariant(test_case.variant)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  BigInteger modulus(Base64WebSafeDecode(k2048BitRsaModulus));
  absl::StatusOr<RsaSsaPkcs1PublicKey> public_key =
      RsaSsaPkcs1PublicKey::Create(*parameters, modulus,
                                   test_case.id_requirement,
                                   GetPartialKeyAccess());
  ASSERT_THAT(public_key, IsOk());

  RestrictedBigInteger p_rb(Base64WebSafeDecode(kP2048Bit),
                            InsecureSecretKeyAccess::Get());
  RestrictedBigInteger dp_rb(Base64WebSafeDecode(kDp2048Bit),
                             InsecureSecretKeyAccess::Get());
  RestrictedBigInteger dq_rb(Base64WebSafeDecode(kDq2048Bit),
                             InsecureSecretKeyAccess::Get());
  RestrictedBigInteger d_rb(Base64WebSafeDecode(kD2048Bit),
                            InsecureSecretKeyAccess::Get());
  RestrictedBigInteger q_inv_rb(Base64WebSafeDecode(kQInv2048Bit),
                                InsecureSecretKeyAccess::Get());
  PrivateValues private_values = GetValid2048BitPrivateValues();

  EXPECT_THAT(RsaSsaPkcs1PrivateKey::Builder()
                  .SetPublicKey(*public_key)
                  .SetPrimeP(p_rb)
                  .SetPrimeQ(private_values.q)
                  .SetPrimeExponentP(dp_rb)
                  .SetPrimeExponentQ(dq_rb)
                  .SetPrivateExponent(d_rb)
                  .SetCrtCoefficient(q_inv_rb)
                  .Build(GetPartialKeyAccess()),
              StatusIs(absl::StatusCode::kInvalidArgument,
                       testing::AllOf(HasSubstr("RestrictedData"),
                                      HasSubstr("RestrictedBigInteger"))));
}

TEST_P(RsaSsaPkcs1PrivateKeyTest, PrivateKeyEquals) {
  TestCase test_case = GetParam();
  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(kModulusSizeInBits)
          .SetPublicExponent(kF4)
          .SetHashType(test_case.hash_type)
          .SetVariant(test_case.variant)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      CreateValid2048BitPrivateKey(*parameters, test_case.id_requirement);
  ASSERT_THAT(private_key, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> same_private_key =
      CreateValid2048BitPrivateKey(*parameters, test_case.id_requirement);
  ASSERT_THAT(same_private_key, IsOk());

  EXPECT_TRUE(*private_key == *same_private_key);
  EXPECT_TRUE(*same_private_key == *private_key);
  EXPECT_FALSE(*private_key != *same_private_key);
  EXPECT_FALSE(*same_private_key != *private_key);
}

TEST(RsaSsaPkcs1PrivateKeyTest, DifferentPublicKeyNotEqual) {
  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(2048)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kTink)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  // Different id requirements result in different public keys.
  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key1 =
      CreateValid2048BitPrivateKey(*parameters, /*id_requirement=*/0x02030400);
  ASSERT_THAT(private_key1, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key2 =
      CreateValid2048BitPrivateKey(*parameters, /*id_requirement=*/0x01030005);
  ASSERT_THAT(private_key2, IsOk());

  EXPECT_TRUE(*private_key1 != *private_key2);
  EXPECT_TRUE(*private_key2 != *private_key1);
  EXPECT_FALSE(*private_key1 == *private_key2);
  EXPECT_FALSE(*private_key2 == *private_key1);
}

TEST(RsaSsaPkcs1PrivateKeyTest, DifferentKeyTypesNotEqual) {
  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(2048)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kNoPrefix)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PublicKey> public_key =
      RsaSsaPkcs1PublicKey::Create(
          *parameters, BigInteger(Base64WebSafeDecode(k2048BitRsaModulus)),
          /*id_requirement=*/absl::nullopt, GetPartialKeyAccess());
  ASSERT_THAT(public_key, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      CreateValid2048BitPrivateKey(*parameters,
                                   /*id_requirement=*/absl::nullopt);
  ASSERT_THAT(private_key, IsOk());

  EXPECT_TRUE(*private_key != *public_key);
  EXPECT_TRUE(*public_key != *private_key);
  EXPECT_FALSE(*private_key == *public_key);
  EXPECT_FALSE(*public_key == *private_key);
}

TEST(RsaSsaPkcs1PrivateKeyTest, Clone) {
  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(2048)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kNoPrefix)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      CreateValid2048BitPrivateKey(*parameters,
                                   /*id_requirement=*/absl::nullopt);
  ASSERT_THAT(private_key, IsOk());

  // Clone the key.
  std::unique_ptr<Key> cloned_key = private_key->Clone();

  ASSERT_THAT(*cloned_key, Eq(*private_key));
}

TEST(RsaSsaPkcs1PrivateKeyTest, CopyConstructor) {
  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(2048)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kNoPrefix)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      CreateValid2048BitPrivateKey(*parameters,
                                   /*id_requirement=*/absl::nullopt);
  ASSERT_THAT(private_key, IsOk());

  RsaSsaPkcs1PrivateKey copy(*private_key);

  EXPECT_THAT(copy, Eq(*private_key));
}

TEST(RsaSsaPkcs1PrivateKeyTest, CopyAssignment) {
  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(2048)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kNoPrefix)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      CreateValid2048BitPrivateKey(*parameters,
                                   /*id_requirement=*/absl::nullopt);
  ASSERT_THAT(private_key, IsOk());

  absl::StatusOr<RsaSsaPkcs1Parameters> other_parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(3072)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha512)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kTink)
          .Build();
  ASSERT_THAT(other_parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> copy = CreateValid3072BitPrivateKey(
      *other_parameters, /*id_requirement=*/0x01020304);
  ASSERT_THAT(copy, IsOk());

  *copy = *private_key;

  EXPECT_THAT(*copy, Eq(*private_key));
}

TEST(RsaSsaPkcs1PrivateKeyTest,
     CopyAssignmentWithRestrictedBigIntegerFieldsInitialized) {
  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(2048)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kNoPrefix)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      CreateValid2048BitPrivateKey(*parameters,
                                   /*id_requirement=*/absl::nullopt);
  ASSERT_THAT(private_key, IsOk());
  private_key->GetPrivateExponent();
  private_key->GetPrimeP(GetPartialKeyAccess());
  private_key->GetPrimeQ(GetPartialKeyAccess());
  private_key->GetPrimeExponentP();
  private_key->GetPrimeExponentQ();
  private_key->GetCrtCoefficient();

  absl::StatusOr<RsaSsaPkcs1Parameters> other_parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(3072)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha512)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kTink)
          .Build();
  ASSERT_THAT(other_parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> copy = CreateValid3072BitPrivateKey(
      *other_parameters, /*id_requirement=*/0x01020304);
  ASSERT_THAT(copy, IsOk());

  *copy = *private_key;

  EXPECT_THAT(*copy, Eq(*private_key));
}

TEST(RsaSsaPkcs1PrivateKeyTest, MoveConstructor) {
  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(2048)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kNoPrefix)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      CreateValid2048BitPrivateKey(*parameters,
                                   /*id_requirement=*/absl::nullopt);
  ASSERT_THAT(private_key, IsOk());

  RsaSsaPkcs1PrivateKey expected = *private_key;
  RsaSsaPkcs1PrivateKey moved(std::move(*private_key));

  EXPECT_THAT(moved, Eq(expected));
}

TEST(RsaSsaPkcs1PrivateKeyTest, MoveAssignment) {
  absl::StatusOr<RsaSsaPkcs1Parameters> parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(2048)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kNoPrefix)
          .Build();
  ASSERT_THAT(parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
      CreateValid2048BitPrivateKey(*parameters,
                                   /*id_requirement=*/absl::nullopt);
  ASSERT_THAT(private_key, IsOk());

  absl::StatusOr<RsaSsaPkcs1Parameters> other_parameters =
      RsaSsaPkcs1Parameters::Builder()
          .SetModulusSizeInBits(3072)
          .SetPublicExponent(kF4)
          .SetHashType(RsaSsaPkcs1Parameters::HashType::kSha512)
          .SetVariant(RsaSsaPkcs1Parameters::Variant::kTink)
          .Build();
  ASSERT_THAT(other_parameters, IsOk());

  absl::StatusOr<RsaSsaPkcs1PrivateKey> moved = CreateValid3072BitPrivateKey(
      *other_parameters, /*id_requirement=*/0x01020304);
  ASSERT_THAT(moved, IsOk());

  RsaSsaPkcs1PrivateKey expected = *private_key;
  *moved = std::move(*private_key);

  EXPECT_THAT(*moved, Eq(expected));
}

}  // namespace
}  // namespace tink
}  // namespace crypto
