| // Copyright 2018 Google Inc. |
| // |
| // 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/signature_pem_keyset_reader.h" |
| |
| #include <cstddef> |
| #include <memory> |
| #include <random> |
| |
| #include "absl/memory/memory.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/string_view.h" |
| #include "tink/keyset_reader.h" |
| #include "tink/signature/rsa_ssa_pkcs1_sign_key_manager.h" |
| #include "tink/signature/rsa_ssa_pkcs1_verify_key_manager.h" |
| #include "tink/signature/rsa_ssa_pss_sign_key_manager.h" |
| #include "tink/signature/rsa_ssa_pss_verify_key_manager.h" |
| #include "tink/subtle/pem_parser_boringssl.h" |
| #include "tink/subtle/subtle_util_boringssl.h" |
| #include "tink/util/enums.h" |
| #include "tink/util/keyset_util.h" |
| #include "tink/util/secret_data.h" |
| #include "tink/util/status.h" |
| #include "tink/util/statusor.h" |
| #include "proto/common.pb.h" |
| #include "proto/rsa_ssa_pkcs1.pb.h" |
| #include "proto/rsa_ssa_pss.pb.h" |
| #include "proto/tink.pb.h" |
| |
| namespace crypto { |
| namespace tink { |
| |
| using ::google::crypto::tink::EncryptedKeyset; |
| using ::google::crypto::tink::KeyData; |
| using ::google::crypto::tink::Keyset; |
| using ::google::crypto::tink::KeyStatusType; |
| using ::google::crypto::tink::OutputPrefixType; |
| using ::google::crypto::tink::RsaSsaPkcs1PrivateKey; |
| using ::google::crypto::tink::RsaSsaPkcs1PublicKey; |
| using ::google::crypto::tink::RsaSsaPssParams; |
| using ::google::crypto::tink::RsaSsaPssPrivateKey; |
| using ::google::crypto::tink::RsaSsaPssPublicKey; |
| |
| namespace { |
| |
| // Sets the parameters for an RSASSA-PSS key `parameters` given the PEM |
| // parameters `pem_parameters`. |
| util::Status SetRsaSsaPssParameters(const PemKeyParams& pem_parameters, |
| RsaSsaPssParams* parameters) { |
| if (parameters == nullptr) { |
| return util::Status(util::error::INVALID_ARGUMENT, |
| "Null parameters provided"); |
| } |
| parameters->set_mgf1_hash(pem_parameters.hash_type); |
| parameters->set_sig_hash(pem_parameters.hash_type); |
| auto salt_len_or = util::Enums::HashLength(pem_parameters.hash_type); |
| if (!salt_len_or.ok()) return salt_len_or.status(); |
| parameters->set_salt_length(salt_len_or.ValueOrDie()); |
| |
| return util::OkStatus(); |
| } |
| |
| // Creates a new Keyset::Key with ID `key_id`. The key has key data |
| // `key_data`, key type `key_type`, and key material type |
| // `key_material_type`. |
| Keyset::Key NewKeysetKey(uint32_t key_id, absl::string_view key_type, |
| const KeyData::KeyMaterialType& key_material_type, |
| absl::string_view key_data) { |
| Keyset::Key key; |
| // Populate KeyData for the new key. |
| key.set_key_id(key_id); |
| key.set_status(KeyStatusType::ENABLED); |
| // PEM keys don't add any prefix to signatures |
| key.set_output_prefix_type(OutputPrefixType::RAW); |
| KeyData* key_data_proto = key.mutable_key_data(); |
| key_data_proto->set_type_url(key_type.data(), key_type.size()); |
| key_data_proto->set_value(key_data.data(), key_data.size()); |
| key_data_proto->set_key_material_type(key_material_type); |
| return key; |
| } |
| |
| // Construct a new RSASSA-PSS key proto from a subtle RSA private key |
| // `private_key_subtle`; the key is assigned version `key_version` and |
| // key paramters `parameters`. |
| util::StatusOr<RsaSsaPssPrivateKey> NewRsaSsaPrivateKey( |
| const subtle::SubtleUtilBoringSSL::RsaPrivateKey& private_key_subtle, |
| uint32_t key_version, const PemKeyParams& parameters) { |
| RsaSsaPssPrivateKey private_key_proto; |
| |
| // RSA Private key parameters. |
| private_key_proto.set_version(key_version); |
| private_key_proto.set_d( |
| std::string(util::SecretDataAsStringView(private_key_subtle.d))); |
| private_key_proto.set_p( |
| std::string(util::SecretDataAsStringView(private_key_subtle.p))); |
| private_key_proto.set_q( |
| std::string(util::SecretDataAsStringView(private_key_subtle.q))); |
| private_key_proto.set_dp( |
| std::string(util::SecretDataAsStringView(private_key_subtle.dp))); |
| private_key_proto.set_dq( |
| std::string(util::SecretDataAsStringView(private_key_subtle.dq))); |
| private_key_proto.set_crt( |
| std::string(util::SecretDataAsStringView(private_key_subtle.crt))); |
| |
| // Inner RSA public key. |
| RsaSsaPssPublicKey* public_key_proto = private_key_proto.mutable_public_key(); |
| public_key_proto->set_version(key_version); |
| public_key_proto->set_n(private_key_subtle.n); |
| public_key_proto->set_e(private_key_subtle.e); |
| |
| // RSASSA-PSS public key parameters. |
| auto set_parameter_status = |
| SetRsaSsaPssParameters(parameters, public_key_proto->mutable_params()); |
| if (!set_parameter_status.ok()) { |
| return set_parameter_status; |
| } |
| |
| return private_key_proto; |
| } |
| |
| // Construct a new RSASSA-PKCS1 key proto from a subtle RSA private key |
| // `private_key_subtle`; the key is assigned version `key_version` and |
| // key paramters `parameters`. |
| RsaSsaPkcs1PrivateKey NewRsaSsaPkcs1PrivateKey( |
| const subtle::SubtleUtilBoringSSL::RsaPrivateKey& private_key_subtle, |
| uint32_t key_version, const PemKeyParams& parameters) { |
| RsaSsaPkcs1PrivateKey private_key_proto; |
| |
| // RSA Private key parameters. |
| private_key_proto.set_version(key_version); |
| private_key_proto.set_d( |
| std::string(util::SecretDataAsStringView(private_key_subtle.d))); |
| private_key_proto.set_p( |
| std::string(util::SecretDataAsStringView(private_key_subtle.p))); |
| private_key_proto.set_q( |
| std::string(util::SecretDataAsStringView(private_key_subtle.q))); |
| private_key_proto.set_dp( |
| std::string(util::SecretDataAsStringView(private_key_subtle.dp))); |
| private_key_proto.set_dq( |
| std::string(util::SecretDataAsStringView(private_key_subtle.dq))); |
| private_key_proto.set_crt( |
| std::string(util::SecretDataAsStringView(private_key_subtle.crt))); |
| |
| // Inner RSA Public key parameters. |
| RsaSsaPkcs1PublicKey* public_key_proto = |
| private_key_proto.mutable_public_key(); |
| public_key_proto->set_version(key_version); |
| public_key_proto->set_n(private_key_subtle.n); |
| public_key_proto->set_e(private_key_subtle.e); |
| |
| // RSASSA-PKCS1 Public key parameters. |
| public_key_proto->mutable_params()->set_hash_type(parameters.hash_type); |
| |
| return private_key_proto; |
| } |
| |
| // Adds the PEM-encoded private key `pem_key` to `keyset`. |
| util::Status AddRsaSsaPrivateKey(const PemKey& pem_key, Keyset* keyset) { |
| // Try to parse the PEM RSA private key. |
| auto private_key_subtle_or = |
| subtle::PemParser::ParseRsaPrivateKey(pem_key.serialized_key); |
| if (!private_key_subtle_or.ok()) return private_key_subtle_or.status(); |
| |
| std::unique_ptr<subtle::SubtleUtilBoringSSL::RsaPrivateKey> |
| private_key_subtle = std::move(private_key_subtle_or).ValueOrDie(); |
| |
| size_t modulus_size = private_key_subtle->n.length() * 8; |
| if (pem_key.parameters.key_size_in_bits != modulus_size) { |
| return util::Status( |
| util::error::INVALID_ARGUMENT, |
| absl::StrCat("Invalid RSA Key modulus size; found: ", modulus_size, |
| ", expected: ", pem_key.parameters.key_size_in_bits)); |
| } |
| |
| switch (pem_key.parameters.algorithm) { |
| case PemAlgorithm::RSASSA_PSS: { |
| RsaSsaPssSignKeyManager key_manager; |
| auto private_key_proto_or = NewRsaSsaPrivateKey( |
| *private_key_subtle, key_manager.get_version(), pem_key.parameters); |
| if (!private_key_proto_or.ok()) return private_key_proto_or.status(); |
| RsaSsaPssPrivateKey private_key_proto = private_key_proto_or.ValueOrDie(); |
| |
| // Validate the key. |
| auto key_validation_status = key_manager.ValidateKey(private_key_proto); |
| if (!key_validation_status.ok()) return key_validation_status; |
| |
| *keyset->add_key() = |
| NewKeysetKey(GenerateUnusedKeyId(*keyset), key_manager.get_key_type(), |
| key_manager.key_material_type(), |
| private_key_proto.SerializeAsString()); |
| break; |
| } |
| case PemAlgorithm::RSASSA_PKCS1: { |
| RsaSsaPkcs1SignKeyManager key_manager; |
| RsaSsaPkcs1PrivateKey private_key_proto = NewRsaSsaPkcs1PrivateKey( |
| *private_key_subtle, key_manager.get_version(), pem_key.parameters); |
| |
| // Validate the key. |
| auto key_validation_status = key_manager.ValidateKey(private_key_proto); |
| if (!key_validation_status.ok()) return key_validation_status; |
| |
| *keyset->add_key() = |
| NewKeysetKey(GenerateUnusedKeyId(*keyset), key_manager.get_key_type(), |
| key_manager.key_material_type(), |
| private_key_proto.SerializeAsString()); |
| |
| break; |
| } |
| default: |
| return util::Status( |
| util::error::INVALID_ARGUMENT, |
| absl::StrCat("Invalid RSA algorithm ", pem_key.parameters.algorithm)); |
| } |
| |
| return util::OkStatus(); |
| } |
| |
| // Parses a given PEM-encoded RSA public key `pem_key`, and adds it to the |
| // keyset `keyset`. |
| util::Status AddRsaSsaPublicKey(const PemKey& pem_key, Keyset* keyset) { |
| // Parse the PEM string into a RSA public key. |
| auto public_key_subtle_or = |
| subtle::PemParser::ParseRsaPublicKey(pem_key.serialized_key); |
| if (!public_key_subtle_or.ok()) return public_key_subtle_or.status(); |
| |
| std::unique_ptr<subtle::SubtleUtilBoringSSL::RsaPublicKey> public_key_subtle = |
| std::move(public_key_subtle_or).ValueOrDie(); |
| |
| // Check key length is as expected. |
| size_t modulus_size = public_key_subtle->n.length() * 8; |
| if (pem_key.parameters.key_size_in_bits != modulus_size) { |
| return util::Status( |
| util::error::INVALID_ARGUMENT, |
| absl::StrCat("Invalid RSA Key modulus size; found ", modulus_size, |
| ", expected ", pem_key.parameters.key_size_in_bits)); |
| } |
| |
| switch (pem_key.parameters.algorithm) { |
| case PemAlgorithm::RSASSA_PSS: { |
| RsaSsaPssPublicKey public_key_proto; |
| RsaSsaPssVerifyKeyManager key_manager; |
| |
| // RSA Public key paramters. |
| public_key_proto.set_e(public_key_subtle->e); |
| public_key_proto.set_n(public_key_subtle->n); |
| |
| // RSASSA-PSS Public key parameters. |
| auto set_parameter_status = SetRsaSsaPssParameters( |
| pem_key.parameters, public_key_proto.mutable_params()); |
| if (!set_parameter_status.ok()) return set_parameter_status; |
| public_key_proto.set_version(key_manager.get_version()); |
| |
| // Validate the key. |
| auto key_validation_status = key_manager.ValidateKey(public_key_proto); |
| if (!key_validation_status.ok()) return key_validation_status; |
| |
| *keyset->add_key() = |
| NewKeysetKey(GenerateUnusedKeyId(*keyset), key_manager.get_key_type(), |
| key_manager.key_material_type(), |
| public_key_proto.SerializeAsString()); |
| |
| break; |
| } |
| case PemAlgorithm::RSASSA_PKCS1: { |
| RsaSsaPkcs1PublicKey public_key_proto; |
| RsaSsaPkcs1VerifyKeyManager key_manager; |
| |
| // RSA Public key paramters. |
| public_key_proto.set_e(public_key_subtle->e); |
| public_key_proto.set_n(public_key_subtle->n); |
| |
| // RSASSA-PKCS1 Public key parameters. |
| public_key_proto.mutable_params()->set_hash_type( |
| pem_key.parameters.hash_type); |
| public_key_proto.set_version(key_manager.get_version()); |
| |
| // Validate the key. |
| auto key_validation_status = key_manager.ValidateKey(public_key_proto); |
| if (!key_validation_status.ok()) return key_validation_status; |
| |
| *keyset->add_key() = |
| NewKeysetKey(GenerateUnusedKeyId(*keyset), key_manager.get_key_type(), |
| key_manager.key_material_type(), |
| public_key_proto.SerializeAsString()); |
| break; |
| } |
| default: |
| return util::Status( |
| util::error::INVALID_ARGUMENT, |
| absl::StrCat("Invalid RSA algorithm ", pem_key.parameters.algorithm)); |
| } |
| return util::OkStatus(); |
| } |
| |
| } // namespace |
| |
| void SignaturePemKeysetReaderBuilder::Add(const PemKey& pem_serialized_key) { |
| pem_serialized_keys_.push_back(pem_serialized_key); |
| } |
| |
| util::StatusOr<std::unique_ptr<KeysetReader>> |
| SignaturePemKeysetReaderBuilder::Build() { |
| if (pem_serialized_keys_.empty()) { |
| return util::Status(util::error::INVALID_ARGUMENT, |
| "Empty array of PEM-encoded keys"); |
| } |
| |
| switch (pem_reader_type_) { |
| case PUBLIC_KEY_SIGN: { |
| return absl::WrapUnique<KeysetReader>( |
| new PublicKeySignPemKeysetReader(pem_serialized_keys_)); |
| } |
| case PUBLIC_KEY_VERIFY: { |
| return absl::WrapUnique<KeysetReader>( |
| new PublicKeyVerifyPemKeysetReader(pem_serialized_keys_)); |
| } |
| } |
| return util::Status(util::error::INVALID_ARGUMENT, |
| "Unknown pem_reader_type_"); |
| } |
| |
| util::StatusOr<std::unique_ptr<Keyset>> PublicKeySignPemKeysetReader::Read() { |
| if (pem_serialized_keys_.empty()) { |
| return util::Status(util::error::INVALID_ARGUMENT, |
| "Empty array of PEM-encoded keys"); |
| } |
| |
| auto keyset = absl::make_unique<Keyset>(); |
| for (const PemKey& pem_key : pem_serialized_keys_) { |
| // Parse and add the new key to the keyset. |
| switch (pem_key.parameters.key_type) { |
| case PemKeyType::PEM_RSA: { |
| auto add_rsassa_pss_status = AddRsaSsaPrivateKey(pem_key, keyset.get()); |
| if (!add_rsassa_pss_status.ok()) return add_rsassa_pss_status; |
| break; |
| } |
| default: |
| return util::Status(util::error::UNIMPLEMENTED, |
| "EC Keys Parsing unimplemented"); |
| } |
| } |
| |
| // Set the 1st key as primary. |
| keyset->set_primary_key_id(keyset->key(0).key_id()); |
| |
| return keyset; |
| } |
| |
| util::StatusOr<std::unique_ptr<Keyset>> PublicKeyVerifyPemKeysetReader::Read() { |
| if (pem_serialized_keys_.empty()) { |
| return util::Status(util::error::INVALID_ARGUMENT, |
| "Empty array of PEM-encoded keys"); |
| } |
| |
| auto keyset = absl::make_unique<Keyset>(); |
| for (const PemKey& pem_key : pem_serialized_keys_) { |
| // Parse and add the new key to the keyset. |
| switch (pem_key.parameters.key_type) { |
| case PemKeyType::PEM_RSA: { |
| auto add_rsassa_pss_status = AddRsaSsaPublicKey(pem_key, keyset.get()); |
| if (!add_rsassa_pss_status.ok()) return add_rsassa_pss_status; |
| break; |
| } |
| default: |
| return util::Status(util::error::UNIMPLEMENTED, |
| "EC Keys Parsing unimplemented"); |
| } |
| } |
| |
| // Set the 1st key as primary. |
| keyset->set_primary_key_id(keyset->key(0).key_id()); |
| |
| return keyset; |
| } |
| |
| util::StatusOr<std::unique_ptr<EncryptedKeyset>> |
| SignaturePemKeysetReader::ReadEncrypted() { |
| return util::Status(util::error::UNIMPLEMENTED, |
| "Reading Encrypted PEM is not supported"); |
| } |
| |
| } // namespace tink |
| } // namespace crypto |