blob: 57bd04b40c8fefe28f737c6e791bd25b79bec285 [file] [log] [blame]
// Copyright 2022 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/internal/keyset_handle_builder_entry.h"
#include <memory>
#include <string>
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "tink/insecure_secret_key_access.h"
#include "tink/internal/key_status_util.h"
#include "tink/internal/legacy_proto_key.h"
#include "tink/internal/legacy_proto_parameters.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/key.h"
#include "tink/parameters.h"
#include "tink/registry.h"
#include "tink/restricted_data.h"
#include "tink/secret_key_access_token.h"
#include "tink/util/secret_proto.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "proto/tink.pb.h"
namespace crypto {
namespace tink {
namespace internal {
namespace {
using ::crypto::tink::util::SecretProto;
using ::google::crypto::tink::KeyData;
using ::google::crypto::tink::Keyset;
using ::google::crypto::tink::KeyStatusType;
SecretProto<Keyset::Key> ToKeysetKey(
int id, KeyStatusType status, const ProtoKeySerialization& serialization) {
SecretProto<Keyset::Key> key;
key->set_status(status);
key->set_key_id(id);
key->set_output_prefix_type(serialization.GetOutputPrefixType());
KeyData* key_data = key->mutable_key_data();
key_data->set_type_url(std::string(serialization.TypeUrl()));
key_data->set_value(serialization.SerializedKeyProto().GetSecret(
InsecureSecretKeyAccess::Get()));
key_data->set_key_material_type(serialization.KeyMaterialType());
return key;
}
util::StatusOr<ProtoParametersSerialization> SerializeParameters(
const Parameters& params) {
util::StatusOr<std::unique_ptr<Serialization>> serialization =
MutableSerializationRegistry::GlobalInstance()
.SerializeParameters<ProtoParametersSerialization>(params);
if (!serialization.ok()) return serialization.status();
const ProtoParametersSerialization* proto_serialization =
dynamic_cast<const ProtoParametersSerialization*>(serialization->get());
if (proto_serialization == nullptr) {
return util::Status(absl::StatusCode::kInternal,
"Failed to serialize proto parameters.");
}
return *proto_serialization;
}
util::StatusOr<ProtoParametersSerialization> SerializeLegacyParameters(
const Parameters* params) {
const LegacyProtoParameters* proto_params =
dynamic_cast<const LegacyProtoParameters*>(params);
if (proto_params == nullptr) {
return util::Status(absl::StatusCode::kInvalidArgument,
"Failed to serialize legacy proto parameters.");
}
return proto_params->Serialization();
}
util::StatusOr<ProtoKeySerialization> SerializeKey(const Key& key) {
util::StatusOr<std::unique_ptr<Serialization>> serialization =
MutableSerializationRegistry::GlobalInstance()
.SerializeKey<ProtoKeySerialization>(key,
InsecureSecretKeyAccess::Get());
if (!serialization.ok()) return serialization.status();
const ProtoKeySerialization* serialized_proto_key =
dynamic_cast<const ProtoKeySerialization*>(serialization->get());
if (serialized_proto_key == nullptr) {
return util::Status(absl::StatusCode::kInternal,
"Failed to serialize proto key.");
}
return *serialized_proto_key;
}
util::StatusOr<ProtoKeySerialization> SerializeLegacyKey(const Key* key) {
const LegacyProtoKey* proto_key = dynamic_cast<const LegacyProtoKey*>(key);
if (proto_key == nullptr) {
return util::Status(absl::StatusCode::kInvalidArgument,
"Failed to serialize legacy proto key.");
}
util::StatusOr<const ProtoKeySerialization*> serialized_key =
proto_key->Serialization(InsecureSecretKeyAccess::Get());
if (!serialized_key.ok()) return serialized_key.status();
return **serialized_key;
}
util::StatusOr<SecretProto<Keyset::Key>>
CreateKeysetKeyFromProtoParametersSerialization(
const ProtoParametersSerialization& serialization, int id,
KeyStatusType status) {
// TODO(tholenst): ensure this doesn't leak.
util::StatusOr<std::unique_ptr<KeyData>> key_data =
Registry::NewKeyData(serialization.GetKeyTemplate());
if (!key_data.ok()) return key_data.status();
SecretProto<Keyset::Key> key;
key->set_status(status);
key->set_key_id(id);
key->set_output_prefix_type(
serialization.GetKeyTemplate().output_prefix_type());
*key->mutable_key_data() = **key_data;
return key;
}
util::StatusOr<SecretProto<Keyset::Key>>
CreateKeysetKeyFromProtoKeySerialization(const ProtoKeySerialization& key,
int id, KeyStatusType status) {
absl::optional<int> id_requirement = key.IdRequirement();
if (id_requirement.has_value() && *id_requirement != id) {
return util::Status(absl::StatusCode::kInvalidArgument,
"Wrong ID set for key with ID requirement.");
}
return ToKeysetKey(id, status, key);
}
} // namespace
void KeysetHandleBuilderEntry::SetFixedId(int id) {
strategy_.strategy = KeyIdStrategyEnum::kFixedId;
strategy_.id_requirement = id;
}
void KeysetHandleBuilderEntry::SetRandomId() {
strategy_.strategy = KeyIdStrategyEnum::kRandomId;
strategy_.id_requirement = absl::nullopt;
}
util::StatusOr<SecretProto<Keyset::Key>> KeyEntry::CreateKeysetKey(int id) {
util::StatusOr<KeyStatusType> key_status = ToKeyStatusType(key_status_);
if (!key_status.ok()) return key_status.status();
if (GetKeyIdRequirement().has_value() && GetKeyIdRequirement() != id) {
return util::Status(absl::StatusCode::kInvalidArgument,
"Requested id does not match id requirement.");
}
util::StatusOr<ProtoKeySerialization> serialization = SerializeKey(*key_);
if (!serialization.ok() &&
serialization.status().code() != absl::StatusCode::kNotFound) {
return serialization.status();
}
if (serialization.status().code() == absl::StatusCode::kNotFound) {
// Fallback to legacy proto key.
serialization = SerializeLegacyKey(key_.get());
if (!serialization.ok()) return serialization.status();
}
return CreateKeysetKeyFromProtoKeySerialization(*serialization, id,
*key_status);
}
util::StatusOr<SecretProto<Keyset::Key>> ParametersEntry::CreateKeysetKey(
int id) {
util::StatusOr<KeyStatusType> key_status = ToKeyStatusType(key_status_);
if (!key_status.ok()) return key_status.status();
if (GetKeyIdRequirement().has_value() && GetKeyIdRequirement() != id) {
return util::Status(absl::StatusCode::kInvalidArgument,
"Requested id does not match id requirement.");
}
util::StatusOr<ProtoParametersSerialization> serialization =
SerializeParameters(*parameters_);
if (!serialization.ok() &&
serialization.status().code() != absl::StatusCode::kNotFound) {
return serialization.status();
}
if (serialization.status().code() == absl::StatusCode::kNotFound) {
// Fallback to legacy proto parameters.
serialization = SerializeLegacyParameters(parameters_.get());
if (!serialization.ok()) return serialization.status();
}
return CreateKeysetKeyFromProtoParametersSerialization(*serialization, id,
*key_status);
}
} // namespace internal
} // namespace tink
} // namespace crypto