| // Copyright 2026 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 | |
| // | |
| // https://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 "testing/pem.h" | |
| #include <memory> | |
| #include <string> | |
| #include <variant> | |
| #include "absl/base/no_destructor.h" | |
| #include "absl/functional/overload.h" | |
| #include "absl/status/status.h" | |
| #include "absl/status/status_macros.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/string_view.h" | |
| #include "openssl/bio.h" | |
| #include "openssl/ec.h" | |
| #include "openssl/ec_key.h" | |
| #include "openssl/evp.h" | |
| #include "openssl/mem.h" | |
| #include "openssl/nid.h" | |
| #include "openssl/obj.h" | |
| #include "openssl/pem.h" | |
| #include "openssl/x509.h" | |
| #include "tink/insecure_secret_key_access.h" | |
| #include "tink/key_status.h" | |
| #include "tink/keyset_handle.h" | |
| #include "tink/partial_key_access.h" | |
| #include "tink/pem/signature_key_parser.h" | |
| #include "tink/public_key_sign.h" | |
| #include "tink/signature/config_v0.h" | |
| #include "tink/signature/ecdsa_parameters.h" | |
| #include "tink/signature/ecdsa_private_key.h" | |
| #include "tink/signature/ed25519_parameters.h" | |
| #include "tink/signature/ed25519_private_key.h" | |
| #include "tink/signature/rsa_ssa_pss_parameters.h" | |
| #include "tink/signature/rsa_ssa_pss_private_key.h" | |
| #include "tink/signature/signature_config.h" | |
| namespace credentio { | |
| using ::crypto::tink::EcdsaParameters; | |
| using ::crypto::tink::Ed25519Parameters; | |
| using ::crypto::tink::GetPartialKeyAccess; | |
| using ::crypto::tink::InsecureSecretKeyAccess; | |
| using ::crypto::tink::KeysetHandle; | |
| using ::crypto::tink::KeysetHandleBuilder; | |
| using ::crypto::tink::PublicKeySign; | |
| using ::crypto::tink::RsaSsaPssParameters; | |
| absl::StatusOr<std::unique_ptr<crypto::tink::PublicKeySign>> LoadTestKeyFromPem( | |
| absl::string_view pem, | |
| const std::variant<EcdsaParameters, Ed25519Parameters, RsaSsaPssParameters>& | |
| key_params) { | |
| static const absl::NoDestructor<absl::Status> registration_status( | |
| []() { return crypto::tink::SignatureConfig::Register(); }()); | |
| ABSL_RETURN_IF_ERROR(*registration_status); | |
| using TinkPrivateKey = std::variant<crypto::tink::EcdsaPrivateKey, | |
| crypto::tink::RsaSsaPssPrivateKey, | |
| crypto::tink::Ed25519PrivateKey>; | |
| absl::StatusOr<TinkPrivateKey> private_key = std::visit( | |
| absl::Overload( | |
| [&pem]( | |
| const EcdsaParameters& params) -> absl::StatusOr<TinkPrivateKey> { | |
| return tink_pem::PemToEcdsaPrivateKey( | |
| pem, params, InsecureSecretKeyAccess::Get(), | |
| GetPartialKeyAccess()); | |
| }, | |
| [&pem](const RsaSsaPssParameters& params) | |
| -> absl::StatusOr<TinkPrivateKey> { | |
| return tink_pem::PemToRsaSsaPssPrivateKey( | |
| pem, params, InsecureSecretKeyAccess::Get(), | |
| GetPartialKeyAccess()); | |
| }, | |
| [&pem](const Ed25519Parameters& params) | |
| -> absl::StatusOr<TinkPrivateKey> { | |
| return tink_pem::PemToEd25519PrivateKey( | |
| pem, params, InsecureSecretKeyAccess::Get(), | |
| GetPartialKeyAccess()); | |
| }), | |
| key_params); | |
| if (!private_key.ok()) { | |
| return private_key.status(); | |
| } | |
| KeysetHandleBuilder builder; | |
| std::visit( | |
| [&builder](const auto& key) { | |
| builder.AddEntry(KeysetHandleBuilder::Entry::CreateFromCopyableKey( | |
| key, crypto::tink::KeyStatus::kEnabled, /*is_primary=*/true)); | |
| }, | |
| *private_key); | |
| ABSL_ASSIGN_OR_RETURN(KeysetHandle handle, builder.Build()); | |
| return handle.GetPrimitive<crypto::tink::PublicKeySign>( | |
| crypto::tink::ConfigSignatureV0()); | |
| } | |
| absl::StatusOr<std::string> LoadOcspResponseFromPem(absl::string_view pem) { | |
| bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem.data(), pem.size())); | |
| if (bio == nullptr) { | |
| return absl::InternalError("Failed to create BIO."); | |
| } | |
| std::string response; | |
| bool found = false; | |
| while (true) { | |
| char* name = nullptr; | |
| char* header = nullptr; | |
| unsigned char* data = nullptr; | |
| long len = 0; // NOLINT: Can't use `int64_t` because on ARM that becomes | |
| // long long which is incompatible with `PEM_read_bio(...)`. | |
| if (!PEM_read_bio(bio.get(), &name, &header, &data, &len)) { | |
| break; | |
| } | |
| bssl::UniquePtr<char> name_ptr(name); | |
| bssl::UniquePtr<char> header_ptr(header); | |
| bssl::UniquePtr<unsigned char> data_ptr(data); | |
| if (absl::string_view(name) == "OCSP RESPONSE") { | |
| if (found) { | |
| return absl::InvalidArgumentError( | |
| "Multiple OCSP RESPONSE blocks found; expected only one."); | |
| } | |
| response = std::string(reinterpret_cast<char*>(data), len); | |
| found = true; | |
| } | |
| } | |
| if (!found) { | |
| return absl::InvalidArgumentError("No OCSP RESPONSE block found."); | |
| } | |
| return response; | |
| } | |
| } // namespace credentio |