blob: d23e0e1ad9bbcd07de93d61838f6823c3c776a98 [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
//
// 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_proto_serialization.h"
#include <memory>
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/log/check.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.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/mutable_serialization_registry.h"
#include "tink/internal/proto_key_serialization.h"
#include "tink/internal/proto_parameters_serialization.h"
#include "tink/internal/serialization.h"
#include "tink/internal/ssl_unique_ptr.h"
#include "tink/key.h"
#include "tink/parameters.h"
#include "tink/partial_key_access.h"
#include "tink/restricted_big_integer.h"
#include "tink/restricted_data.h"
#include "tink/signature/rsa_ssa_pkcs1_parameters.h"
#include "tink/signature/rsa_ssa_pkcs1_private_key.h"
#include "tink/signature/rsa_ssa_pkcs1_public_key.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"
#include "proto/common.pb.h"
#include "proto/rsa_ssa_pkcs1.pb.h"
#include "proto/tink.pb.h"
namespace crypto {
namespace tink {
namespace {
using ::crypto::tink::test::IsOk;
using ::crypto::tink::test::StatusIs;
using ::google::crypto::tink::HashType;
using ::google::crypto::tink::KeyData;
using ::google::crypto::tink::OutputPrefixType;
using ::google::crypto::tink::RsaSsaPkcs1KeyFormat;
using ::google::crypto::tink::RsaSsaPkcs1Params;
using ::testing::Eq;
using ::testing::IsTrue;
using ::testing::NotNull;
using ::testing::TestWithParam;
using ::testing::Values;
struct TestCase {
RsaSsaPkcs1Parameters::Variant variant;
OutputPrefixType output_prefix_type;
RsaSsaPkcs1Parameters::HashType hash_type;
HashType proto_hash_type;
int modulus_size_in_bits;
absl::optional<int> id;
std::string output_prefix;
};
const std::string& kF4Str = *new std::string("\x1\0\x1", 3); // 65537
const absl::string_view kPrivateTypeUrl =
"type.googleapis.com/google.crypto.tink.RsaSsaPkcs1PrivateKey";
const absl::string_view kPublicTypeUrl =
"type.googleapis.com/google.crypto.tink.RsaSsaPkcs1PublicKey";
class RsaSsaPkcs1ProtoSerializationTest : public TestWithParam<TestCase> {
protected:
void SetUp() override {
internal::MutableSerializationRegistry::GlobalInstance().Reset();
}
};
TEST_F(RsaSsaPkcs1ProtoSerializationTest, RegisterTwiceSucceeds) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
}
INSTANTIATE_TEST_SUITE_P(
RsaSsaPkcs1ProtoSerializationTestSuite, RsaSsaPkcs1ProtoSerializationTest,
Values(TestCase{RsaSsaPkcs1Parameters::Variant::kTink,
OutputPrefixType::TINK,
RsaSsaPkcs1Parameters::HashType::kSha256, HashType::SHA256,
/*modulus_size=*/2048, /*id=*/0x02030400,
/*output_prefix=*/std::string("\x01\x02\x03\x04\x00", 5)},
TestCase{RsaSsaPkcs1Parameters::Variant::kCrunchy,
OutputPrefixType::CRUNCHY,
RsaSsaPkcs1Parameters::HashType::kSha256, HashType::SHA256,
/*modulus_size=*/2048, /*id=*/0x01030005,
/*output_prefix=*/std::string("\x00\x01\x03\x00\x05", 5)},
TestCase{RsaSsaPkcs1Parameters::Variant::kLegacy,
OutputPrefixType::LEGACY,
RsaSsaPkcs1Parameters::HashType::kSha384, HashType::SHA384,
/*modulus_size=*/3072, /*id=*/0x07080910,
/*output_prefix=*/std::string("\x00\x07\x08\x09\x10", 5)},
TestCase{RsaSsaPkcs1Parameters::Variant::kNoPrefix,
OutputPrefixType::RAW,
RsaSsaPkcs1Parameters::HashType::kSha512, HashType::SHA512,
/*modulus_size=*/3072, /*id=*/absl::nullopt,
/*output_prefix=*/""}));
TEST_P(RsaSsaPkcs1ProtoSerializationTest, ParseParametersSucceeds) {
TestCase test_case = GetParam();
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
RsaSsaPkcs1KeyFormat key_format_proto;
key_format_proto.set_modulus_size_in_bits(test_case.modulus_size_in_bits);
key_format_proto.set_public_exponent(kF4Str);
key_format_proto.mutable_params()->set_hash_type(test_case.proto_hash_type);
util::StatusOr<internal::ProtoParametersSerialization> serialization =
internal::ProtoParametersSerialization::Create(
kPrivateTypeUrl, test_case.output_prefix_type,
key_format_proto.SerializeAsString());
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Parameters>> parameters =
internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
*serialization);
ASSERT_THAT(parameters, IsOk());
EXPECT_THAT((*parameters)->HasIdRequirement(), test_case.id.has_value());
const RsaSsaPkcs1Parameters* rsa_ssa_pkcs1_parameters =
dynamic_cast<const RsaSsaPkcs1Parameters*>(parameters->get());
ASSERT_THAT(rsa_ssa_pkcs1_parameters, NotNull());
EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetVariant(), Eq(test_case.variant));
EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetModulusSizeInBits(),
Eq(test_case.modulus_size_in_bits));
EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetHashType(), Eq(test_case.hash_type));
EXPECT_THAT(rsa_ssa_pkcs1_parameters->GetPublicExponent(),
Eq(BigInteger(kF4Str)));
}
TEST_F(RsaSsaPkcs1ProtoSerializationTest,
ParseParametersWithInvalidSerializationFails) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
util::StatusOr<internal::ProtoParametersSerialization> serialization =
internal::ProtoParametersSerialization::Create(
kPrivateTypeUrl, OutputPrefixType::RAW, "invalid_serialization");
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Parameters>> parameters =
internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
*serialization);
ASSERT_THAT(parameters.status(),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST_F(RsaSsaPkcs1ProtoSerializationTest,
ParseParametersKeyFormatWithoutParamsFails) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
RsaSsaPkcs1KeyFormat key_format_proto;
key_format_proto.set_modulus_size_in_bits(2048);
key_format_proto.set_public_exponent(kF4Str);
util::StatusOr<internal::ProtoParametersSerialization> serialization =
internal::ProtoParametersSerialization::Create(
kPrivateTypeUrl, OutputPrefixType::RAW,
key_format_proto.SerializeAsString());
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Parameters>> parameters =
internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
*serialization);
ASSERT_THAT(parameters.status(),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST_F(RsaSsaPkcs1ProtoSerializationTest,
ParseParametersWithUnkownOutputPrefixFails) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
RsaSsaPkcs1KeyFormat key_format_proto;
key_format_proto.set_modulus_size_in_bits(2048);
key_format_proto.set_public_exponent(kF4Str);
key_format_proto.mutable_params()->set_hash_type(HashType::SHA256);
util::StatusOr<internal::ProtoParametersSerialization> serialization =
internal::ProtoParametersSerialization::Create(
kPrivateTypeUrl, OutputPrefixType::UNKNOWN_PREFIX,
key_format_proto.SerializeAsString());
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Parameters>> parameters =
internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
*serialization);
ASSERT_THAT(parameters.status(),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST_F(RsaSsaPkcs1ProtoSerializationTest, ParseParametersWithUnkownHashFails) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
RsaSsaPkcs1KeyFormat key_format_proto;
key_format_proto.set_modulus_size_in_bits(2048);
key_format_proto.set_public_exponent(kF4Str);
key_format_proto.mutable_params()->set_hash_type(HashType::UNKNOWN_HASH);
util::StatusOr<internal::ProtoParametersSerialization> serialization =
internal::ProtoParametersSerialization::Create(
kPrivateTypeUrl, OutputPrefixType::TINK,
key_format_proto.SerializeAsString());
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Parameters>> parameters =
internal::MutableSerializationRegistry::GlobalInstance().ParseParameters(
*serialization);
ASSERT_THAT(parameters.status(),
StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST_P(RsaSsaPkcs1ProtoSerializationTest, SerializeParametersSucceeds) {
TestCase test_case = GetParam();
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
util::StatusOr<RsaSsaPkcs1Parameters> parameters =
RsaSsaPkcs1Parameters::Builder()
.SetVariant(test_case.variant)
.SetHashType(test_case.hash_type)
.SetModulusSizeInBits(test_case.modulus_size_in_bits)
.SetPublicExponent(BigInteger(kF4Str))
.Build();
ASSERT_THAT(parameters, IsOk());
util::StatusOr<std::unique_ptr<Serialization>> serialization =
internal::MutableSerializationRegistry::GlobalInstance()
.SerializeParameters<internal::ProtoParametersSerialization>(
*parameters);
ASSERT_THAT(serialization, IsOk());
EXPECT_THAT((*serialization)->ObjectIdentifier(), Eq(kPrivateTypeUrl));
const internal::ProtoParametersSerialization* proto_serialization =
dynamic_cast<const internal::ProtoParametersSerialization*>(
serialization->get());
ASSERT_THAT(proto_serialization, NotNull());
EXPECT_THAT(proto_serialization->GetKeyTemplate().type_url(),
Eq(kPrivateTypeUrl));
EXPECT_THAT(proto_serialization->GetKeyTemplate().output_prefix_type(),
Eq(test_case.output_prefix_type));
RsaSsaPkcs1KeyFormat key_format;
ASSERT_THAT(
key_format.ParseFromString(proto_serialization->GetKeyTemplate().value()),
IsTrue());
ASSERT_THAT(key_format.has_params(), IsTrue());
EXPECT_THAT(key_format.params().hash_type(), Eq(test_case.proto_hash_type));
EXPECT_THAT(key_format.modulus_size_in_bits(),
Eq(test_case.modulus_size_in_bits));
EXPECT_THAT(key_format.public_exponent(), Eq(kF4Str));
}
struct KeyValues {
std::string n;
std::string e;
std::string p;
std::string q;
std::string dp;
std::string dq;
std::string d;
std::string q_inv;
};
KeyValues GenerateKeyValues(int modulus_size_in_bits) {
internal::SslUniquePtr<RSA> rsa(RSA_new());
CHECK_NE(rsa.get(), nullptr);
// Set public exponent to 65537.
internal::SslUniquePtr<BIGNUM> e(BN_new());
CHECK_NE(e.get(), nullptr);
BN_set_word(e.get(), 65537);
// Generate an RSA key pair and get the values.
CHECK(RSA_generate_key_ex(rsa.get(), modulus_size_in_bits, e.get(),
/*cb=*/nullptr));
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);
util::StatusOr<std::string> n_str =
internal::BignumToString(n_bn, BN_num_bytes(n_bn));
CHECK_OK(n_str);
util::StatusOr<std::string> e_str =
internal::BignumToString(e_bn, BN_num_bytes(e_bn));
CHECK_OK(e_str);
util::StatusOr<std::string> d_str =
internal::BignumToString(d_bn, BN_num_bytes(d_bn));
CHECK_OK(d_str);
RSA_get0_factors(rsa.get(), &p_bn, &q_bn);
util::StatusOr<std::string> p_str =
internal::BignumToString(p_bn, BN_num_bytes(p_bn));
CHECK_OK(p_str);
util::StatusOr<std::string> q_str =
internal::BignumToString(q_bn, BN_num_bytes(q_bn));
CHECK_OK(q_str);
RSA_get0_crt_params(rsa.get(), &dp_bn, &dq_bn, &q_inv_bn);
util::StatusOr<std::string> dp_str =
internal::BignumToString(dp_bn, BN_num_bytes(dp_bn));
CHECK_OK(dp_str);
util::StatusOr<std::string> dq_str =
internal::BignumToString(dq_bn, BN_num_bytes(dq_bn));
CHECK_OK(dq_str);
util::StatusOr<std::string> q_inv_str =
internal::BignumToString(q_inv_bn, BN_num_bytes(q_inv_bn));
CHECK_OK(q_inv_str);
return KeyValues{*n_str, *e_str, *p_str, *q_str,
*dp_str, *dq_str, *d_str, *q_inv_str};
}
TEST_P(RsaSsaPkcs1ProtoSerializationTest, ParsePublicKeySucceeds) {
TestCase test_case = GetParam();
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
RsaSsaPkcs1Params params;
params.set_hash_type(test_case.proto_hash_type);
KeyValues key_values = GenerateKeyValues(test_case.modulus_size_in_bits);
google::crypto::tink::RsaSsaPkcs1PublicKey key_proto;
key_proto.set_version(0);
key_proto.set_n(key_values.n);
key_proto.set_e(key_values.e);
*key_proto.mutable_params() = params;
RestrictedData serialized_key = RestrictedData(
key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
util::StatusOr<internal::ProtoKeySerialization> serialization =
internal::ProtoKeySerialization::Create(
kPublicTypeUrl, serialized_key, KeyData::ASYMMETRIC_PUBLIC,
test_case.output_prefix_type, test_case.id);
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Key>> key =
internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
*serialization, /*token=*/absl::nullopt);
ASSERT_THAT(key, IsOk());
EXPECT_THAT((*key)->GetIdRequirement(), Eq(test_case.id));
EXPECT_THAT((*key)->GetParameters().HasIdRequirement(),
test_case.id.has_value());
util::StatusOr<RsaSsaPkcs1Parameters> expected_parameters =
RsaSsaPkcs1Parameters::Builder()
.SetVariant(test_case.variant)
.SetHashType(test_case.hash_type)
.SetModulusSizeInBits(test_case.modulus_size_in_bits)
.SetPublicExponent(BigInteger(key_values.e))
.Build();
ASSERT_THAT(expected_parameters, IsOk());
util::StatusOr<RsaSsaPkcs1PublicKey> expected_key =
RsaSsaPkcs1PublicKey::Create(*expected_parameters,
BigInteger(key_values.n), test_case.id,
GetPartialKeyAccess());
ASSERT_THAT(expected_key, IsOk());
EXPECT_THAT(**key, Eq(*expected_key));
}
TEST_F(RsaSsaPkcs1ProtoSerializationTest,
ParsePublicKeyWithInvalidSerializationFails) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
RestrictedData serialized_key =
RestrictedData("invalid_serialization", InsecureSecretKeyAccess::Get());
util::StatusOr<internal::ProtoKeySerialization> serialization =
internal::ProtoKeySerialization::Create(kPublicTypeUrl, serialized_key,
KeyData::ASYMMETRIC_PUBLIC,
OutputPrefixType::TINK,
/*id_requirement=*/0x23456789);
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Key>> key =
internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
*serialization, InsecureSecretKeyAccess::Get());
EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST_F(RsaSsaPkcs1ProtoSerializationTest,
ParsePublicKeyWithInvalidVersionFails) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
RsaSsaPkcs1Params params;
params.set_hash_type(HashType::SHA256);
KeyValues key_values = GenerateKeyValues(2048);
google::crypto::tink::RsaSsaPkcs1PublicKey key_proto;
key_proto.set_version(1);
key_proto.set_n(key_values.n);
key_proto.set_e(key_values.e);
*key_proto.mutable_params() = params;
RestrictedData serialized_key = RestrictedData(
key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
util::StatusOr<internal::ProtoKeySerialization> serialization =
internal::ProtoKeySerialization::Create(kPublicTypeUrl, serialized_key,
KeyData::ASYMMETRIC_PUBLIC,
OutputPrefixType::TINK,
/*id_requirement=*/0x23456789);
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Key>> key =
internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
*serialization, /*token=*/absl::nullopt);
EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST_P(RsaSsaPkcs1ProtoSerializationTest, SerializePublicKeySucceeds) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
TestCase test_case = GetParam();
KeyValues key_values = GenerateKeyValues(test_case.modulus_size_in_bits);
util::StatusOr<RsaSsaPkcs1Parameters> parameters =
RsaSsaPkcs1Parameters::Builder()
.SetVariant(test_case.variant)
.SetHashType(test_case.hash_type)
.SetModulusSizeInBits(test_case.modulus_size_in_bits)
.SetPublicExponent(BigInteger(key_values.e))
.Build();
ASSERT_THAT(parameters, IsOk());
util::StatusOr<RsaSsaPkcs1PublicKey> key =
RsaSsaPkcs1PublicKey::Create(*parameters, BigInteger(key_values.n),
test_case.id, GetPartialKeyAccess());
ASSERT_THAT(key, IsOk());
util::StatusOr<std::unique_ptr<Serialization>> serialization =
internal::MutableSerializationRegistry::GlobalInstance()
.SerializeKey<internal::ProtoKeySerialization>(
*key, /*token=*/absl::nullopt);
ASSERT_THAT(serialization, IsOk());
EXPECT_THAT((*serialization)->ObjectIdentifier(), Eq(kPublicTypeUrl));
const internal::ProtoKeySerialization* proto_serialization =
dynamic_cast<const internal::ProtoKeySerialization*>(
serialization->get());
ASSERT_THAT(proto_serialization, NotNull());
EXPECT_THAT(proto_serialization->TypeUrl(), Eq(kPublicTypeUrl));
EXPECT_THAT(proto_serialization->KeyMaterialType(),
Eq(KeyData::ASYMMETRIC_PUBLIC));
EXPECT_THAT(proto_serialization->GetOutputPrefixType(),
Eq(test_case.output_prefix_type));
EXPECT_THAT(proto_serialization->IdRequirement(), Eq(test_case.id));
google::crypto::tink::RsaSsaPkcs1PublicKey proto_key;
ASSERT_THAT(proto_key.ParseFromString(
proto_serialization->SerializedKeyProto().GetSecret(
InsecureSecretKeyAccess::Get())),
IsTrue());
EXPECT_THAT(proto_key.version(), Eq(0));
EXPECT_THAT(proto_key.n(), Eq(key_values.n));
EXPECT_THAT(proto_key.e(), Eq(key_values.e));
EXPECT_THAT(proto_key.has_params(), IsTrue());
EXPECT_THAT(proto_key.params().hash_type(), Eq(test_case.proto_hash_type));
}
TEST_P(RsaSsaPkcs1ProtoSerializationTest, ParsePrivateKeySucceeds) {
TestCase test_case = GetParam();
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
RsaSsaPkcs1Params params;
params.set_hash_type(test_case.proto_hash_type);
KeyValues key_values = GenerateKeyValues(test_case.modulus_size_in_bits);
google::crypto::tink::RsaSsaPkcs1PublicKey public_key_proto;
public_key_proto.set_version(0);
public_key_proto.set_n(key_values.n);
public_key_proto.set_e(key_values.e);
*public_key_proto.mutable_params() = params;
google::crypto::tink::RsaSsaPkcs1PrivateKey private_key_proto;
private_key_proto.set_version(0);
*private_key_proto.mutable_public_key() = public_key_proto;
private_key_proto.set_p(key_values.p);
private_key_proto.set_q(key_values.q);
private_key_proto.set_dp(key_values.dp);
private_key_proto.set_dq(key_values.dq);
private_key_proto.set_d(key_values.d);
private_key_proto.set_crt(key_values.q_inv);
RestrictedData serialized_key = RestrictedData(
private_key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
util::StatusOr<internal::ProtoKeySerialization> serialization =
internal::ProtoKeySerialization::Create(
kPrivateTypeUrl, serialized_key, KeyData::ASYMMETRIC_PRIVATE,
test_case.output_prefix_type, test_case.id);
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Key>> key =
internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
*serialization, InsecureSecretKeyAccess::Get());
ASSERT_THAT(key, IsOk());
EXPECT_THAT((*key)->GetIdRequirement(), Eq(test_case.id));
EXPECT_THAT((*key)->GetParameters().HasIdRequirement(),
test_case.id.has_value());
util::StatusOr<RsaSsaPkcs1Parameters> expected_parameters =
RsaSsaPkcs1Parameters::Builder()
.SetVariant(test_case.variant)
.SetHashType(test_case.hash_type)
.SetModulusSizeInBits(test_case.modulus_size_in_bits)
.SetPublicExponent(BigInteger(key_values.e))
.Build();
ASSERT_THAT(expected_parameters, IsOk());
util::StatusOr<RsaSsaPkcs1PublicKey> expected_public_key =
RsaSsaPkcs1PublicKey::Create(*expected_parameters,
BigInteger(key_values.n), test_case.id,
GetPartialKeyAccess());
ASSERT_THAT(expected_public_key, IsOk());
util::StatusOr<RsaSsaPkcs1PrivateKey> expected_private_key =
RsaSsaPkcs1PrivateKey::Builder()
.SetPublicKey(*expected_public_key)
.SetPrimeP(RestrictedBigInteger(key_values.p,
InsecureSecretKeyAccess::Get()))
.SetPrimeQ(RestrictedBigInteger(key_values.q,
InsecureSecretKeyAccess::Get()))
.SetPrimeExponentP(RestrictedBigInteger(
key_values.dp, InsecureSecretKeyAccess::Get()))
.SetPrimeExponentQ(RestrictedBigInteger(
key_values.dq, InsecureSecretKeyAccess::Get()))
.SetPrivateExponent(RestrictedBigInteger(
key_values.d, InsecureSecretKeyAccess::Get()))
.SetCrtCoefficient(RestrictedBigInteger(
key_values.q_inv, InsecureSecretKeyAccess::Get()))
.Build(GetPartialKeyAccess());
EXPECT_THAT(**key, Eq(*expected_private_key));
}
TEST_F(RsaSsaPkcs1ProtoSerializationTest,
ParsePrivateKeyWithInvalidSerializationFails) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
RestrictedData serialized_key =
RestrictedData("invalid_serialization", InsecureSecretKeyAccess::Get());
util::StatusOr<internal::ProtoKeySerialization> serialization =
internal::ProtoKeySerialization::Create(kPrivateTypeUrl, serialized_key,
KeyData::ASYMMETRIC_PRIVATE,
OutputPrefixType::TINK,
/*id_requirement=*/0x23456789);
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Key>> key =
internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
*serialization, InsecureSecretKeyAccess::Get());
EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST_F(RsaSsaPkcs1ProtoSerializationTest,
ParsePrivateKeyWithInvalidVersionFails) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
RsaSsaPkcs1Params params;
params.set_hash_type(HashType::SHA256);
KeyValues key_values = GenerateKeyValues(2048);
google::crypto::tink::RsaSsaPkcs1PublicKey public_key_proto;
public_key_proto.set_version(0);
public_key_proto.set_n(key_values.n);
public_key_proto.set_e(key_values.e);
*public_key_proto.mutable_params() = params;
google::crypto::tink::RsaSsaPkcs1PrivateKey private_key_proto;
private_key_proto.set_version(1);
*private_key_proto.mutable_public_key() = public_key_proto;
private_key_proto.set_p(key_values.p);
private_key_proto.set_q(key_values.q);
private_key_proto.set_dp(key_values.dp);
private_key_proto.set_dq(key_values.dq);
private_key_proto.set_d(key_values.d);
private_key_proto.set_crt(key_values.q_inv);
RestrictedData serialized_key = RestrictedData(
private_key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
util::StatusOr<internal::ProtoKeySerialization> serialization =
internal::ProtoKeySerialization::Create(kPrivateTypeUrl, serialized_key,
KeyData::ASYMMETRIC_PRIVATE,
OutputPrefixType::TINK,
/*id_requirement=*/0x23456789);
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Key>> key =
internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
*serialization, InsecureSecretKeyAccess::Get());
EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kInvalidArgument));
}
TEST_F(RsaSsaPkcs1ProtoSerializationTest,
ParsePrivateKeyNoSecretKeyAccessFails) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
RsaSsaPkcs1Params params;
params.set_hash_type(HashType::SHA256);
KeyValues key_values = GenerateKeyValues(2048);
google::crypto::tink::RsaSsaPkcs1PublicKey public_key_proto;
public_key_proto.set_version(0);
public_key_proto.set_n(key_values.n);
public_key_proto.set_e(key_values.e);
*public_key_proto.mutable_params() = params;
google::crypto::tink::RsaSsaPkcs1PrivateKey private_key_proto;
private_key_proto.set_version(0);
*private_key_proto.mutable_public_key() = public_key_proto;
private_key_proto.set_p(key_values.p);
private_key_proto.set_q(key_values.q);
private_key_proto.set_dp(key_values.dp);
private_key_proto.set_dq(key_values.dq);
private_key_proto.set_d(key_values.d);
private_key_proto.set_crt(key_values.q_inv);
RestrictedData serialized_key = RestrictedData(
private_key_proto.SerializeAsString(), InsecureSecretKeyAccess::Get());
util::StatusOr<internal::ProtoKeySerialization> serialization =
internal::ProtoKeySerialization::Create(kPrivateTypeUrl, serialized_key,
KeyData::ASYMMETRIC_PRIVATE,
OutputPrefixType::TINK,
/*id_requirement=*/0x23456789);
ASSERT_THAT(serialization, IsOk());
util::StatusOr<std::unique_ptr<Key>> key =
internal::MutableSerializationRegistry::GlobalInstance().ParseKey(
*serialization, /*token=*/absl::nullopt);
EXPECT_THAT(key.status(), StatusIs(absl::StatusCode::kPermissionDenied));
}
TEST_P(RsaSsaPkcs1ProtoSerializationTest, SerializePrivateKeySucceeds) {
TestCase test_case = GetParam();
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
KeyValues key_values = GenerateKeyValues(test_case.modulus_size_in_bits);
util::StatusOr<RsaSsaPkcs1Parameters> parameters =
RsaSsaPkcs1Parameters::Builder()
.SetVariant(test_case.variant)
.SetHashType(test_case.hash_type)
.SetModulusSizeInBits(test_case.modulus_size_in_bits)
.SetPublicExponent(BigInteger(key_values.e))
.Build();
ASSERT_THAT(parameters, IsOk());
util::StatusOr<RsaSsaPkcs1PublicKey> public_key =
RsaSsaPkcs1PublicKey::Create(*parameters, BigInteger(key_values.n),
test_case.id, GetPartialKeyAccess());
ASSERT_THAT(public_key, IsOk());
util::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
RsaSsaPkcs1PrivateKey::Builder()
.SetPublicKey(*public_key)
.SetPrimeP(RestrictedBigInteger(key_values.p,
InsecureSecretKeyAccess::Get()))
.SetPrimeQ(RestrictedBigInteger(key_values.q,
InsecureSecretKeyAccess::Get()))
.SetPrimeExponentP(RestrictedBigInteger(
key_values.dp, InsecureSecretKeyAccess::Get()))
.SetPrimeExponentQ(RestrictedBigInteger(
key_values.dq, InsecureSecretKeyAccess::Get()))
.SetPrivateExponent(RestrictedBigInteger(
key_values.d, InsecureSecretKeyAccess::Get()))
.SetCrtCoefficient(RestrictedBigInteger(
key_values.q_inv, InsecureSecretKeyAccess::Get()))
.Build(GetPartialKeyAccess());
ASSERT_THAT(private_key, IsOk());
util::StatusOr<std::unique_ptr<Serialization>> serialization =
internal::MutableSerializationRegistry::GlobalInstance()
.SerializeKey<internal::ProtoKeySerialization>(
*private_key, InsecureSecretKeyAccess::Get());
ASSERT_THAT(serialization, IsOk());
EXPECT_THAT((*serialization)->ObjectIdentifier(), Eq(kPrivateTypeUrl));
const internal::ProtoKeySerialization* proto_serialization =
dynamic_cast<const internal::ProtoKeySerialization*>(
serialization->get());
ASSERT_THAT(proto_serialization, NotNull());
EXPECT_THAT(proto_serialization->TypeUrl(), Eq(kPrivateTypeUrl));
EXPECT_THAT(proto_serialization->KeyMaterialType(),
Eq(KeyData::ASYMMETRIC_PRIVATE));
EXPECT_THAT(proto_serialization->GetOutputPrefixType(),
Eq(test_case.output_prefix_type));
EXPECT_THAT(proto_serialization->IdRequirement(), Eq(test_case.id));
google::crypto::tink::RsaSsaPkcs1PrivateKey proto_key;
ASSERT_THAT(proto_key.ParseFromString(
proto_serialization->SerializedKeyProto().GetSecret(
InsecureSecretKeyAccess::Get())),
IsTrue());
EXPECT_THAT(proto_key.version(), Eq(0));
EXPECT_THAT(proto_key.p(), Eq(key_values.p));
EXPECT_THAT(proto_key.q(), Eq(key_values.q));
EXPECT_THAT(proto_key.dp(), Eq(key_values.dp));
EXPECT_THAT(proto_key.dq(), Eq(key_values.dq));
EXPECT_THAT(proto_key.d(), Eq(key_values.d));
EXPECT_THAT(proto_key.crt(), Eq(key_values.q_inv));
EXPECT_THAT(proto_key.has_public_key(), IsTrue());
EXPECT_THAT(proto_key.public_key().version(), Eq(0));
EXPECT_THAT(proto_key.public_key().n(), Eq(key_values.n));
EXPECT_THAT(proto_key.public_key().e(), Eq(key_values.e));
EXPECT_THAT(proto_key.public_key().has_params(), IsTrue());
EXPECT_THAT(proto_key.public_key().params().hash_type(),
Eq(test_case.proto_hash_type));
}
TEST_F(RsaSsaPkcs1ProtoSerializationTest,
SerializePrivateKeyNoSecretKeyAccessFails) {
ASSERT_THAT(RegisterRsaSsaPkcs1ProtoSerialization(), IsOk());
KeyValues key_values = GenerateKeyValues(2048);
util::StatusOr<RsaSsaPkcs1Parameters> parameters =
RsaSsaPkcs1Parameters::Builder()
.SetVariant(RsaSsaPkcs1Parameters::Variant::kTink)
.SetHashType(RsaSsaPkcs1Parameters::HashType::kSha256)
.SetModulusSizeInBits(2048)
.SetPublicExponent(BigInteger(kF4Str))
.Build();
ASSERT_THAT(parameters, IsOk());
util::StatusOr<RsaSsaPkcs1PublicKey> public_key =
RsaSsaPkcs1PublicKey::Create(*parameters, BigInteger(key_values.n),
/*id_requirement=*/0x23456789,
GetPartialKeyAccess());
ASSERT_THAT(public_key, IsOk());
util::StatusOr<RsaSsaPkcs1PrivateKey> private_key =
RsaSsaPkcs1PrivateKey::Builder()
.SetPublicKey(*public_key)
.SetPrimeP(RestrictedBigInteger(key_values.p,
InsecureSecretKeyAccess::Get()))
.SetPrimeQ(RestrictedBigInteger(key_values.q,
InsecureSecretKeyAccess::Get()))
.SetPrimeExponentP(RestrictedBigInteger(
key_values.dp, InsecureSecretKeyAccess::Get()))
.SetPrimeExponentQ(RestrictedBigInteger(
key_values.dq, InsecureSecretKeyAccess::Get()))
.SetPrivateExponent(RestrictedBigInteger(
key_values.d, InsecureSecretKeyAccess::Get()))
.SetCrtCoefficient(RestrictedBigInteger(
key_values.q_inv, InsecureSecretKeyAccess::Get()))
.Build(GetPartialKeyAccess());
ASSERT_THAT(private_key, IsOk());
util::StatusOr<std::unique_ptr<Serialization>> serialization =
internal::MutableSerializationRegistry::GlobalInstance()
.SerializeKey<internal::ProtoKeySerialization>(
*private_key, /*token=*/absl::nullopt);
ASSERT_THAT(serialization.status(),
StatusIs(absl::StatusCode::kPermissionDenied));
}
} // namespace
} // namespace tink
} // namespace crypto