blob: 4dea5ac81fda9663d737ec0e14a399d06dcd543d [file]
// 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