blob: 1d8822ff87832bebeb7309553f17f4bc6e84ea3b [file] [log] [blame] [edit]
// Copyright 2023 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libhwsec/backend/tpm2/static_utils.h"
#include <string>
#include <utility>
#include <base/hash/sha1.h>
#include <brillo/secure_blob.h>
#include <crypto/scoped_openssl_types.h>
#include <crypto/sha2.h>
#include <libhwsec-foundation/status/status_chain_macros.h>
#include <libhwsec-foundation/crypto/openssl.h>
#include <tpm_manager/proto_bindings/tpm_manager.pb.h>
#include <tpm_manager-client/tpm_manager/dbus-constants.h>
#include <tpm_manager-client/tpm_manager/dbus-proxies.h>
#include <trunks/tpm_generated.h>
#include "libhwsec/error/tpm2_error.h"
#include "libhwsec/error/tpm_manager_error.h"
#include "libhwsec/proxy/proxy.h"
#include "libhwsec/status.h"
using hwsec_foundation::status::MakeStatus;
namespace hwsec {
namespace {
constexpr uint32_t kMaxPasswordLength = sizeof(trunks::TPMU_HA);
StatusOr<crypto::ScopedBIGNUM> StringToBignum(const std::string& big_integer) {
if (big_integer.empty()) {
return MakeStatus<TPMError>("Input string is empty",
TPMRetryAction::kNoRetry);
}
crypto::ScopedBIGNUM bn(BN_new());
if (!bn) {
return MakeStatus<TPMError>("Failed to allocate BIGNUM",
TPMRetryAction::kNoRetry);
}
if (!BN_bin2bn(reinterpret_cast<const uint8_t*>(big_integer.data()),
big_integer.length(), bn.get())) {
return MakeStatus<TPMError>("Failed to convert string to BIGNUM",
TPMRetryAction::kNoRetry);
}
return bn;
}
StatusOr<crypto::ScopedECDSA_SIG> CreateEcdsaSigFromRS(const std::string& r,
const std::string& s) {
ASSIGN_OR_RETURN(crypto::ScopedBIGNUM r_bn, StringToBignum(r));
ASSIGN_OR_RETURN(crypto::ScopedBIGNUM s_bn, StringToBignum(s));
crypto::ScopedECDSA_SIG sig(ECDSA_SIG_new());
if (!sig) {
return MakeStatus<TPMError>("Failed to allocate ECDSA",
TPMRetryAction::kNoRetry);
}
if (!ECDSA_SIG_set0(sig.get(), r_bn.release(), s_bn.release())) {
return MakeStatus<TPMError>("Failed to set ECDSA SIG parameters",
TPMRetryAction::kNoRetry);
}
return sig;
}
} // namespace
StatusOr<std::string> SerializeFromTpmSignature(
const trunks::TPMT_SIGNATURE& signature) {
switch (signature.sig_alg) {
case trunks::TPM_ALG_RSASSA:
if (signature.signature.rsassa.sig.size >
sizeof(signature.signature.rsassa.sig.buffer)) {
return MakeStatus<TPMError>("RSASSA signature overflow",
TPMRetryAction::kNoRetry);
}
return StringFrom_TPM2B_PUBLIC_KEY_RSA(signature.signature.rsassa.sig);
case trunks::TPM_ALG_ECDSA: {
if (signature.signature.ecdsa.signature_r.size >
sizeof(signature.signature.ecdsa.signature_r.buffer) ||
signature.signature.ecdsa.signature_s.size >
sizeof(signature.signature.ecdsa.signature_s.buffer)) {
return MakeStatus<TPMError>("ECDSA signature overflow",
TPMRetryAction::kNoRetry);
}
ASSIGN_OR_RETURN(
crypto::ScopedECDSA_SIG sig,
CreateEcdsaSigFromRS(StringFrom_TPM2B_ECC_PARAMETER(
signature.signature.ecdsa.signature_r),
StringFrom_TPM2B_ECC_PARAMETER(
signature.signature.ecdsa.signature_s)),
_.WithStatus<TPMError>("Failed to create ECDSA SIG"));
std::string result = hwsec_foundation::ECDSASignatureToString(sig);
if (result.empty()) {
return MakeStatus<TPMError>("Failed to convert ECDSA signature",
TPMRetryAction::kNoRetry);
}
return result;
}
default:
return MakeStatus<TPMError>("Unkown TPM 2.0 signature type",
TPMRetryAction::kNoRetry);
}
}
std::string GetTpm2PCRValueForMode(
const DeviceConfigSettings::BootModeSetting::Mode& mode) {
char boot_modes[3] = {mode.developer_mode, mode.recovery_mode,
mode.verified_firmware};
std::string mode_str(std::begin(boot_modes), std::end(boot_modes));
std::string mode_digest = base::SHA1HashString(mode_str);
mode_digest.resize(SHA256_DIGEST_LENGTH);
const std::string pcr_initial_value(SHA256_DIGEST_LENGTH, 0);
return crypto::SHA256HashString(pcr_initial_value + mode_digest);
}
StatusOr<brillo::SecureBlob> GetEndorsementPassword(
org::chromium::TpmManagerProxyInterface& tpm_manager) {
tpm_manager::GetTpmStatusRequest status_request;
tpm_manager::GetTpmStatusReply status_reply;
if (brillo::ErrorPtr err; !tpm_manager.GetTpmStatus(
status_request, &status_reply, &err, Proxy::kDefaultDBusTimeoutMs)) {
return MakeStatus<TPMError>(TPMRetryAction::kCommunication)
.Wrap(std::move(err));
}
RETURN_IF_ERROR(MakeStatus<TPMManagerError>(status_reply.status()));
brillo::SecureBlob password(status_reply.local_data().endorsement_password());
if (password.empty()) {
return MakeStatus<TPMError>("Empty endorsement password",
TPMRetryAction::kLater);
}
if (password.size() > kMaxPasswordLength) {
return MakeStatus<TPMError>("Endorsement password too large",
TPMRetryAction::kLater);
}
return password;
}
} // namespace hwsec