// Copyright 2020 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. // /////////////////////////////////////////////////////////////////////////////// // Implementation of a Keyset Service. #include "keyset_impl.h" #include #include #include #include #include #include "tink/aead/aead_key_templates.h" #include "tink/binary_keyset_reader.h" #include "tink/binary_keyset_writer.h" #include "tink/cleartext_keyset_handle.h" #include "tink/daead/deterministic_aead_key_templates.h" #include "tink/hybrid/hybrid_key_templates.h" #include "tink/json_keyset_reader.h" #include "tink/json_keyset_writer.h" #include "tink/jwt/jwt_key_templates.h" #include "tink/keyset_handle.h" #include "tink/mac/mac_key_templates.h" #include "tink/prf/prf_key_templates.h" #include "tink/signature/signature_key_templates.h" #include "tink/streamingaead/streaming_aead_key_templates.h" #include "proto/tink.pb.h" namespace tink_testing_api { using ::crypto::tink::BinaryKeysetReader; using ::crypto::tink::BinaryKeysetWriter; using ::crypto::tink::CleartextKeysetHandle; using ::crypto::tink::JsonKeysetReader; using ::crypto::tink::JsonKeysetWriter; using ::crypto::tink::KeysetHandle; using ::crypto::tink::KeysetReader; using ::crypto::tink::KeysetWriter; using ::crypto::tink::util::StatusOr; using ::google::crypto::tink::KeyTemplate; KeysetImpl::KeysetImpl() { key_templates_["AES128_EAX"] = crypto::tink::AeadKeyTemplates::Aes128Eax(); key_templates_["AES256_EAX"] = crypto::tink::AeadKeyTemplates::Aes256Eax(); key_templates_["AES128_GCM"] = crypto::tink::AeadKeyTemplates::Aes128Gcm(); key_templates_["AES128_GCM_RAW"] = crypto::tink::AeadKeyTemplates::Aes128GcmNoPrefix(); key_templates_["AES256_GCM"] = crypto::tink::AeadKeyTemplates::Aes256Gcm(); key_templates_["AES256_GCM_RAW"] = crypto::tink::AeadKeyTemplates::Aes256GcmNoPrefix(); key_templates_["AES128_GCM_SIV"] = crypto::tink::AeadKeyTemplates::Aes128GcmSiv(); key_templates_["AES256_GCM_SIV"] = crypto::tink::AeadKeyTemplates::Aes256GcmSiv(); key_templates_["AES128_CTR_HMAC_SHA256"] = crypto::tink::AeadKeyTemplates::Aes128CtrHmacSha256(); key_templates_["AES256_CTR_HMAC_SHA256"] = crypto::tink::AeadKeyTemplates::Aes256CtrHmacSha256(); key_templates_["CHACHA20_POLY1305"] = crypto::tink::AeadKeyTemplates::XChaCha20Poly1305(); key_templates_["XCHACHA20_POLY1305"] = crypto::tink::AeadKeyTemplates::XChaCha20Poly1305(); key_templates_["AES256_SIV"] = crypto::tink::DeterministicAeadKeyTemplates::Aes256Siv(); key_templates_["AES128_CTR_HMAC_SHA256_4KB"] = crypto::tink::StreamingAeadKeyTemplates::Aes128CtrHmacSha256Segment4KB(); key_templates_["AES128_CTR_HMAC_SHA256_1MB"] = crypto::tink::StreamingAeadKeyTemplates::Aes128CtrHmacSha256Segment1MB(); key_templates_["AES256_CTR_HMAC_SHA256_4KB"] = crypto::tink::StreamingAeadKeyTemplates::Aes256CtrHmacSha256Segment4KB(); key_templates_["AES256_CTR_HMAC_SHA256_1MB"] = crypto::tink::StreamingAeadKeyTemplates::Aes256CtrHmacSha256Segment1MB(); key_templates_["AES128_GCM_HKDF_4KB"] = crypto::tink::StreamingAeadKeyTemplates::Aes128GcmHkdf4KB(); key_templates_["AES256_GCM_HKDF_4KB"] = crypto::tink::StreamingAeadKeyTemplates::Aes256GcmHkdf4KB(); key_templates_["AES256_GCM_HKDF_1MB"] = crypto::tink::StreamingAeadKeyTemplates::Aes256GcmHkdf1MB(); key_templates_["ECIES_P256_HKDF_HMAC_SHA256_AES128_GCM"] = crypto::tink::HybridKeyTemplates::EciesP256HkdfHmacSha256Aes128Gcm(); key_templates_["ECIES_P256_COMPRESSED_HKDF_HMAC_SHA256_AES128_GCM"] = crypto:: tink::HybridKeyTemplates::EciesP256CompressedHkdfHmacSha256Aes128Gcm(); key_templates_["ECIES_P256_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256"] = crypto::tink::HybridKeyTemplates:: EciesP256HkdfHmacSha256Aes128CtrHmacSha256(); key_templates_ ["ECIES_P256_COMPRESSED_HKDF_HMAC_SHA256_AES128_CTR_HMAC_SHA256"] = crypto::tink::HybridKeyTemplates:: EciesP256CompressedHkdfHmacSha256Aes128CtrHmacSha256(); key_templates_["DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM"] = crypto::tink::HybridKeyTemplates::HpkeX25519HkdfSha256Aes128Gcm(); key_templates_["DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_128_GCM_RAW"] = crypto::tink::HybridKeyTemplates::HpkeX25519HkdfSha256Aes128GcmRaw(); key_templates_["DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM"] = crypto::tink::HybridKeyTemplates::HpkeX25519HkdfSha256Aes256Gcm(); key_templates_["DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_AES_256_GCM_RAW"] = crypto::tink::HybridKeyTemplates::HpkeX25519HkdfSha256Aes256GcmRaw(); key_templates_["DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305"] = crypto::tink::HybridKeyTemplates::HpkeX25519HkdfSha256ChaCha20Poly1305(); key_templates_["DHKEM_X25519_HKDF_SHA256_HKDF_SHA256_CHACHA20_POLY1305_RAW"] = crypto::tink::HybridKeyTemplates:: HpkeX25519HkdfSha256ChaCha20Poly1305Raw(); key_templates_["AES_CMAC"] = crypto::tink::MacKeyTemplates::AesCmac(); key_templates_["HMAC_SHA256_128BITTAG"] = crypto::tink::MacKeyTemplates::HmacSha256HalfSizeTag(); key_templates_["HMAC_SHA256_256BITTAG"] = crypto::tink::MacKeyTemplates::HmacSha256(); key_templates_["HMAC_SHA512_256BITTAG"] = crypto::tink::MacKeyTemplates::HmacSha512HalfSizeTag(); key_templates_["HMAC_SHA512_512BITTAG"] = crypto::tink::MacKeyTemplates::HmacSha512(); key_templates_["ECDSA_P256"] = crypto::tink::SignatureKeyTemplates::EcdsaP256(); key_templates_["ECDSA_P256_RAW"] = crypto::tink::SignatureKeyTemplates::EcdsaP256Raw(); key_templates_["ECDSA_P384"] = crypto::tink::SignatureKeyTemplates::EcdsaP384(); key_templates_["ECDSA_P384_SHA384"] = crypto::tink::SignatureKeyTemplates::EcdsaP384Sha384(); key_templates_["ECDSA_P384_SHA512"] = crypto::tink::SignatureKeyTemplates::EcdsaP384Sha512(); key_templates_["ECDSA_P521"] = crypto::tink::SignatureKeyTemplates::EcdsaP521(); key_templates_["ECDSA_P256_IEEE_P1363"] = crypto::tink::SignatureKeyTemplates::EcdsaP256Ieee(); key_templates_["ECDSA_P384_IEEE_P1363"] = crypto::tink::SignatureKeyTemplates::EcdsaP384Ieee(); key_templates_["ECDSA_P521_IEEE_P1363"] = crypto::tink::SignatureKeyTemplates::EcdsaP521Ieee(); key_templates_["ED25519"] = crypto::tink::SignatureKeyTemplates::Ed25519(); key_templates_["RSA_SSA_PKCS1_3072_SHA256_F4"] = crypto::tink::SignatureKeyTemplates::RsaSsaPkcs13072Sha256F4(); key_templates_["RSA_SSA_PKCS1_4096_SHA512_F4"] = crypto::tink::SignatureKeyTemplates::RsaSsaPkcs14096Sha512F4(); key_templates_["RSA_SSA_PSS_3072_SHA256_SHA256_32_F4"] = crypto::tink::SignatureKeyTemplates::RsaSsaPss3072Sha256Sha256F4(); key_templates_["RSA_SSA_PSS_4096_SHA512_SHA512_64_F4"] = crypto::tink::SignatureKeyTemplates::RsaSsaPss4096Sha512Sha512F4(); key_templates_["AES_CMAC_PRF"] = crypto::tink::PrfKeyTemplates::AesCmac(); key_templates_["HMAC_SHA256_PRF"] = crypto::tink::PrfKeyTemplates::HmacSha256(); key_templates_["HMAC_SHA512_PRF"] = crypto::tink::PrfKeyTemplates::HmacSha512(); key_templates_["HKDF_SHA256"] = crypto::tink::PrfKeyTemplates::HkdfSha256(); key_templates_["JWT_HS256"] = crypto::tink::JwtHs256Template(); key_templates_["JWT_HS256_RAW"] = crypto::tink::RawJwtHs256Template(); key_templates_["JWT_HS384"] = crypto::tink::JwtHs384Template(); key_templates_["JWT_HS384_RAW"] = crypto::tink::RawJwtHs384Template(); key_templates_["JWT_HS512"] = crypto::tink::JwtHs512Template(); key_templates_["JWT_HS512_RAW"] = crypto::tink::RawJwtHs512Template(); key_templates_["JWT_ES256"] = crypto::tink::JwtEs256Template(); key_templates_["JWT_ES256_RAW"] = crypto::tink::RawJwtEs256Template(); key_templates_["JWT_ES384"] = crypto::tink::JwtEs384Template(); key_templates_["JWT_ES384_RAW"] = crypto::tink::RawJwtEs384Template(); key_templates_["JWT_ES512"] = crypto::tink::JwtEs512Template(); key_templates_["JWT_ES512_RAW"] = crypto::tink::RawJwtEs512Template(); key_templates_["JWT_RS256_2048_F4"] = crypto::tink::JwtRs256_2048_F4_Template(); key_templates_["JWT_RS256_2048_F4_RAW"] = crypto::tink::RawJwtRs256_2048_F4_Template(); key_templates_["JWT_RS256_3072_F4"] = crypto::tink::JwtRs256_3072_F4_Template(); key_templates_["JWT_RS256_3072_F4_RAW"] = crypto::tink::RawJwtRs256_3072_F4_Template(); key_templates_["JWT_RS384_3072_F4"] = crypto::tink::JwtRs384_3072_F4_Template(); key_templates_["JWT_RS384_3072_F4_RAW"] = crypto::tink::RawJwtRs384_3072_F4_Template(); key_templates_["JWT_RS512_4096_F4"] = crypto::tink::JwtRs512_4096_F4_Template(); key_templates_["JWT_RS512_4096_F4_RAW"] = crypto::tink::RawJwtRs512_4096_F4_Template(); key_templates_["JWT_PS256_2048_F4"] = crypto::tink::JwtPs256_2048_F4_Template(); key_templates_["JWT_PS256_2048_F4_RAW"] = crypto::tink::RawJwtPs256_2048_F4_Template(); key_templates_["JWT_PS256_3072_F4"] = crypto::tink::JwtPs256_3072_F4_Template(); key_templates_["JWT_PS256_3072_F4_RAW"] = crypto::tink::RawJwtPs256_3072_F4_Template(); key_templates_["JWT_PS384_3072_F4"] = crypto::tink::JwtPs384_3072_F4_Template(); key_templates_["JWT_PS384_3072_F4_RAW"] = crypto::tink::RawJwtPs384_3072_F4_Template(); key_templates_["JWT_PS512_4096_F4"] = crypto::tink::JwtPs512_4096_F4_Template(); key_templates_["JWT_PS512_4096_F4_RAW"] = crypto::tink::RawJwtPs512_4096_F4_Template(); } // Returns the key template for the given template name. grpc::Status KeysetImpl::GetTemplate(grpc::ServerContext* context, const KeysetTemplateRequest* request, KeysetTemplateResponse* response) { auto it = key_templates_.find(request->template_name()); if (it == key_templates_.end()) { response->set_err( absl::StrCat("key template not found: ", request->template_name())); return grpc::Status::OK; } std::string templ; if (!it->second.SerializeToString(&templ)) { response->set_err("Failed to serialize template."); return grpc::Status::OK; } response->set_key_template(templ); return grpc::Status::OK; } // Generates a new keyset with one key from a template. grpc::Status KeysetImpl::Generate(grpc::ServerContext* context, const KeysetGenerateRequest* request, KeysetGenerateResponse* response) { KeyTemplate key_template; if (!key_template.ParseFromString(request->template_())) { response->set_err("Could not parse the key template"); return grpc::Status::OK; } auto handle_result = ::crypto::tink::KeysetHandle::GenerateNew(key_template); if (!handle_result.ok()) { response->set_err(std::string(handle_result.status().message())); return grpc::Status::OK; } std::stringbuf keyset; auto writer_result = BinaryKeysetWriter::New(absl::make_unique(&keyset)); if (!writer_result.ok()) { response->set_err(std::string(writer_result.status().message())); return grpc::Status::OK; } auto status = CleartextKeysetHandle::Write(writer_result.value().get(), *handle_result.value()); if (!status.ok()) { response->set_err(std::string(status.message())); return grpc::Status::OK; } response->set_keyset(keyset.str()); return grpc::Status::OK; } // Returns a public keyset for a given private keyset. grpc::Status KeysetImpl::Public(grpc::ServerContext* context, const KeysetPublicRequest* request, KeysetPublicResponse* response) { auto reader_result = BinaryKeysetReader::New(request->private_keyset()); if (!reader_result.ok()) { response->set_err(std::string(reader_result.status().message())); return grpc::Status::OK; } auto private_handle_result = CleartextKeysetHandle::Read(std::move(reader_result.value())); if (!private_handle_result.ok()) { response->set_err(std::string(private_handle_result.status().message())); return grpc::Status::OK; } auto public_handle_result = private_handle_result.value()->GetPublicKeysetHandle(); if (!public_handle_result.ok()) { response->set_err(std::string(public_handle_result.status().message())); return grpc::Status::OK; } std::stringbuf public_keyset; auto writer_result = BinaryKeysetWriter::New(absl::make_unique(&public_keyset)); if (!writer_result.ok()) { response->set_err(std::string(writer_result.status().message())); return grpc::Status::OK; } auto status = CleartextKeysetHandle::Write(writer_result.value().get(), *public_handle_result.value()); if (!status.ok()) { response->set_err(std::string(status.message())); return grpc::Status::OK; } response->set_public_keyset(public_keyset.str()); return grpc::Status::OK; } // Converts a keyset from binary to JSON format. grpc::Status KeysetImpl::ToJson(grpc::ServerContext* context, const KeysetToJsonRequest* request, KeysetToJsonResponse* response) { auto reader_result = BinaryKeysetReader::New(request->keyset()); if (!reader_result.ok()) { response->set_err(std::string(reader_result.status().message())); return grpc::Status::OK; } auto handle_result = CleartextKeysetHandle::Read(std::move(reader_result.value())); if (!handle_result.ok()) { response->set_err(std::string(handle_result.status().message())); return grpc::Status::OK; } std::stringbuf json_keyset; auto writer_result = JsonKeysetWriter::New(absl::make_unique(&json_keyset)); if (!writer_result.ok()) { response->set_err(std::string(writer_result.status().message())); return grpc::Status::OK; } auto status = CleartextKeysetHandle::Write(writer_result.value().get(), *handle_result.value()); if (!status.ok()) { response->set_err(std::string(status.message())); return grpc::Status::OK; } response->set_json_keyset(json_keyset.str()); return grpc::Status::OK; } // Converts a keyset from JSON to binary format. grpc::Status KeysetImpl::FromJson(grpc::ServerContext* context, const KeysetFromJsonRequest* request, KeysetFromJsonResponse* response) { auto reader_result = JsonKeysetReader::New(request->json_keyset()); if (!reader_result.ok()) { response->set_err(std::string(reader_result.status().message())); return grpc::Status::OK; } auto handle_result = CleartextKeysetHandle::Read(std::move(reader_result.value())); if (!handle_result.ok()) { response->set_err(std::string(handle_result.status().message())); return grpc::Status::OK; } std::stringbuf keyset; auto writer_result = BinaryKeysetWriter::New(absl::make_unique(&keyset)); if (!writer_result.ok()) { response->set_err(std::string(writer_result.status().message())); return grpc::Status::OK; } auto status = CleartextKeysetHandle::Write(writer_result.value().get(), *handle_result.value()); if (!status.ok()) { response->set_err(std::string(status.message())); return grpc::Status::OK; } response->set_keyset(keyset.str()); return grpc::Status::OK; } grpc::Status KeysetImpl::WriteEncrypted( grpc::ServerContext* context, const KeysetWriteEncryptedRequest* request, KeysetWriteEncryptedResponse* response) { StatusOr> master_keyset_reader = BinaryKeysetReader::New(request->master_keyset()); if (!master_keyset_reader.ok()) { response->set_err(std::string(master_keyset_reader.status().message())); return grpc::Status::OK; } StatusOr> master_keyset_handle = CleartextKeysetHandle::Read(*std::move(master_keyset_reader)); if (!master_keyset_handle.ok()) { response->set_err(std::string(master_keyset_handle.status().message())); return grpc::Status::OK; } StatusOr> master_aead = (*master_keyset_handle)->GetPrimitive(); if (!master_aead.ok()) { response->set_err(std::string(master_aead.status().message())); return grpc::Status::OK; } StatusOr> keyset_reader = BinaryKeysetReader::New(request->keyset()); if (!keyset_reader.ok()) { response->set_err(std::string(keyset_reader.status().message())); return grpc::Status::OK; } StatusOr> keyset_handle = CleartextKeysetHandle::Read(*std::move(keyset_reader)); if (!keyset_handle.ok()) { response->set_err(std::string(keyset_handle.status().message())); return grpc::Status::OK; } std::stringbuf encrypted_keyset; std::unique_ptr keyset_writer; if (request->keyset_writer_type() == KEYSET_WRITER_BINARY) { StatusOr> binary_keyset_writer = BinaryKeysetWriter::New( absl::make_unique(&encrypted_keyset)); if (!binary_keyset_writer.ok()) { response->set_err(std::string(binary_keyset_writer.status().message())); return grpc::Status::OK; } keyset_writer = *std::move(binary_keyset_writer); } else if (request->keyset_writer_type() == KEYSET_WRITER_JSON) { StatusOr> json_keyset_writer = JsonKeysetWriter::New( absl::make_unique(&encrypted_keyset)); if (!json_keyset_writer.ok()) { response->set_err(std::string(json_keyset_writer.status().message())); return grpc::Status::OK; } keyset_writer = *std::move(json_keyset_writer); } else { return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "unknown keyset_writer_type"); } if (request->has_associated_data()) { crypto::tink::util::Status status = (*keyset_handle) ->WriteWithAssociatedData(keyset_writer.get(), **master_aead, request->associated_data().value()); if (!status.ok()) { response->set_err(std::string(status.message())); return grpc::Status::OK; } } else { crypto::tink::util::Status status = (*keyset_handle)->Write(keyset_writer.get(), **master_aead); if (!status.ok()) { response->set_err(std::string(status.message())); return grpc::Status::OK; } } response->set_encrypted_keyset(encrypted_keyset.str()); return grpc::Status::OK; } grpc::Status KeysetImpl::ReadEncrypted( grpc::ServerContext* context, const KeysetReadEncryptedRequest* request, KeysetReadEncryptedResponse* response) { StatusOr> master_keyset_reader = BinaryKeysetReader::New(request->master_keyset()); if (!master_keyset_reader.ok()) { response->set_err(std::string(master_keyset_reader.status().message())); return grpc::Status::OK; } StatusOr> master_keyset_handle = CleartextKeysetHandle::Read(*std::move(master_keyset_reader)); if (!master_keyset_handle.ok()) { response->set_err(std::string(master_keyset_handle.status().message())); return grpc::Status::OK; } StatusOr> master_aead = (*master_keyset_handle)->GetPrimitive(); if (!master_aead.ok()) { response->set_err(std::string(master_aead.status().message())); return grpc::Status::OK; } std::unique_ptr keyset_reader; if (request->keyset_reader_type() == KEYSET_READER_BINARY) { StatusOr> binary_keyset_reader = BinaryKeysetReader::New(request->encrypted_keyset()); if (!binary_keyset_reader.ok()) { response->set_err(std::string(binary_keyset_reader.status().message())); return grpc::Status::OK; } keyset_reader = *std::move(binary_keyset_reader); } else if (request->keyset_reader_type() == KEYSET_READER_JSON) { StatusOr> json_keyset_reader = JsonKeysetReader::New(request->encrypted_keyset()); if (!json_keyset_reader.ok()) { response->set_err(std::string(json_keyset_reader.status().message())); return grpc::Status::OK; } keyset_reader = *std::move(json_keyset_reader); } else { return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "unknown keyset_writer_type"); } std::unique_ptr keyset_handle; if (request->has_associated_data()) { StatusOr> read_result = ::crypto::tink::KeysetHandle::ReadWithAssociatedData( std::move(keyset_reader), **master_aead, request->associated_data().value()); if (!read_result.ok()) { response->set_err(std::string(read_result.status().message())); return grpc::Status::OK; } keyset_handle = *std::move(read_result); } else { StatusOr> read_result = ::crypto::tink::KeysetHandle::Read(std::move(keyset_reader), **master_aead); if (!read_result.ok()) { response->set_err(std::string(read_result.status().message())); return grpc::Status::OK; } keyset_handle = *std::move(read_result); } std::stringbuf keyset; StatusOr> keyset_writer = BinaryKeysetWriter::New(absl::make_unique(&keyset)); if (!keyset_writer.ok()) { response->set_err(std::string(keyset_writer.status().message())); return grpc::Status::OK; } crypto::tink::util::Status status = CleartextKeysetHandle::Write(keyset_writer->get(), *keyset_handle); if (!status.ok()) { response->set_err(std::string(status.message())); return grpc::Status::OK; } response->set_keyset(keyset.str()); return grpc::Status::OK; } } // namespace tink_testing_api