blob: cb262d094fa867275f4410d27b1fdbc474f199c5 [file] [log] [blame] [edit]
// Copyright 2022 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/frontend/chaps/frontend_impl.h"
#include <string>
#include <utility>
#include <vector>
#include <base/functional/callback.h>
#include <base/time/time.h>
#include <brillo/secure_blob.h>
#include <libhwsec-foundation/status/status_chain_macros.h>
#include "libhwsec/backend/backend.h"
#include "libhwsec/middleware/middleware.h"
#include "libhwsec/status.h"
using hwsec_foundation::status::MakeStatus;
namespace {
constexpr base::TimeDelta kDefaultLazyExpirationTime = base::Seconds(10);
} // namespace
namespace hwsec {
StatusOr<uint32_t> ChapsFrontendImpl::GetFamily() const {
return middleware_.CallSync<&Backend::Vendor::GetFamily>();
}
StatusOr<bool> ChapsFrontendImpl::IsEnabled() const {
return middleware_.CallSync<&Backend::State::IsEnabled>();
}
StatusOr<bool> ChapsFrontendImpl::IsReady() const {
return middleware_.CallSync<&Backend::State::IsReady>();
}
StatusOr<brillo::Blob> ChapsFrontendImpl::GetRandomBlob(size_t size) const {
return middleware_.CallSync<&Backend::Random::RandomBlob>(size);
}
StatusOr<brillo::SecureBlob> ChapsFrontendImpl::GetRandomSecureBlob(
size_t size) const {
return middleware_.CallSync<&Backend::Random::RandomSecureBlob>(size);
}
Status ChapsFrontendImpl::IsRSAModulusSupported(uint32_t modulus_bits) const {
return middleware_.CallSync<&Backend::KeyManagement::IsSupported>(
KeyAlgoType::kRsa, Backend::KeyManagement::CreateKeyOptions{
.allow_software_gen = false,
.allow_decrypt = true,
.allow_sign = true,
.rsa_modulus_bits = modulus_bits,
});
}
Status ChapsFrontendImpl::IsECCurveSupported(int nid) const {
return middleware_.CallSync<&Backend::KeyManagement::IsSupported>(
KeyAlgoType::kEcc, Backend::KeyManagement::CreateKeyOptions{
.allow_software_gen = false,
.allow_decrypt = true,
.allow_sign = true,
.ecc_nid = nid,
});
}
StatusOr<ChapsFrontend::CreateKeyResult> ChapsFrontendImpl::GenerateRSAKey(
int modulus_bits,
const brillo::Blob& public_exponent,
const brillo::SecureBlob& auth_value,
AllowSoftwareGen allow_soft_gen,
AllowDecrypt allow_decrypt,
AllowSign allow_sign) const {
return middleware_.CallSync<&Backend::KeyManagement::CreateKey>(
OperationPolicySetting{
.permission =
Permission{
.auth_value = auth_value,
},
},
KeyAlgoType::kRsa,
KeyManagement::LoadKeyOptions{
.auto_reload = true,
.lazy_expiration_time = kDefaultLazyExpirationTime,
},
Backend::KeyManagement::CreateKeyOptions{
.allow_software_gen = (allow_soft_gen == AllowSoftwareGen::kAllow),
.allow_decrypt = (allow_decrypt == AllowDecrypt::kAllow),
.allow_sign = (allow_sign == AllowSign::kAllow),
.rsa_modulus_bits = modulus_bits,
.rsa_exponent = public_exponent,
});
}
StatusOr<RSAPublicInfo> ChapsFrontendImpl::GetRSAPublicKey(Key key) const {
return middleware_.CallSync<&Backend::KeyManagement::GetRSAPublicInfo>(key);
}
StatusOr<ChapsFrontend::CreateKeyResult> ChapsFrontendImpl::GenerateECCKey(
int nid,
const brillo::SecureBlob& auth_value,
AllowDecrypt allow_decrypt,
AllowSign allow_sign) const {
return middleware_.CallSync<&Backend::KeyManagement::CreateKey>(
OperationPolicySetting{
.permission =
Permission{
.auth_value = auth_value,
},
},
KeyAlgoType::kEcc,
KeyManagement::LoadKeyOptions{
.auto_reload = true,
.lazy_expiration_time = kDefaultLazyExpirationTime,
},
KeyManagement::CreateKeyOptions{
.allow_software_gen = false,
.allow_decrypt = (allow_decrypt == AllowDecrypt::kAllow),
.allow_sign = (allow_sign == AllowSign::kAllow),
.ecc_nid = nid,
});
}
StatusOr<ECCPublicInfo> ChapsFrontendImpl::GetECCPublicKey(Key key) const {
return middleware_.CallSync<&Backend::KeyManagement::GetECCPublicInfo>(key);
}
StatusOr<ChapsFrontend::CreateKeyResult> ChapsFrontendImpl::WrapRSAKey(
const brillo::Blob& exponent,
const brillo::Blob& modulus,
const brillo::SecureBlob& prime_factor,
const brillo::SecureBlob& auth_value,
AllowDecrypt allow_decrypt,
AllowSign allow_sign) const {
return middleware_.CallSync<&Backend::KeyManagement::WrapRSAKey>(
OperationPolicySetting{
.permission =
Permission{
.auth_value = auth_value,
},
},
modulus, prime_factor,
KeyManagement::LoadKeyOptions{
.auto_reload = true,
.lazy_expiration_time = kDefaultLazyExpirationTime,
},
KeyManagement::CreateKeyOptions{
.allow_software_gen = false,
.allow_decrypt = (allow_decrypt == AllowDecrypt::kAllow),
.allow_sign = (allow_sign == AllowSign::kAllow),
.rsa_modulus_bits = modulus.size() * 8,
.rsa_exponent = exponent,
});
}
StatusOr<ChapsFrontend::CreateKeyResult> ChapsFrontendImpl::WrapECCKey(
int curve_nid,
const brillo::Blob& public_point_x,
const brillo::Blob& public_point_y,
const brillo::SecureBlob& private_value,
const brillo::SecureBlob& auth_value,
AllowDecrypt allow_decrypt,
AllowSign allow_sign) const {
return middleware_.CallSync<&Backend::KeyManagement::WrapECCKey>(
OperationPolicySetting{
.permission =
Permission{
.auth_value = auth_value,
},
},
public_point_x, public_point_y, private_value,
KeyManagement::LoadKeyOptions{
.auto_reload = true,
.lazy_expiration_time = kDefaultLazyExpirationTime,
},
KeyManagement::CreateKeyOptions{
.allow_software_gen = false,
.allow_decrypt = (allow_decrypt == AllowDecrypt::kAllow),
.allow_sign = (allow_sign == AllowSign::kAllow),
.ecc_nid = curve_nid,
});
}
StatusOr<ScopedKey> ChapsFrontendImpl::LoadKey(
const brillo::Blob& key_blob, const brillo::SecureBlob& auth_value) const {
return middleware_.CallSync<&Backend::KeyManagement::LoadKey>(
OperationPolicy{
.permission =
Permission{
.auth_value = auth_value,
},
},
key_blob,
KeyManagement::LoadKeyOptions{
.auto_reload = true,
.lazy_expiration_time = kDefaultLazyExpirationTime,
});
}
StatusOr<brillo::SecureBlob> ChapsFrontendImpl::Decrypt(
Key key, const brillo::Blob& ciphertext) const {
return middleware_.CallSync<&Backend::Encryption::Decrypt>(
key, ciphertext,
Encryption::EncryptionOptions{
.schema = Encryption::EncryptionOptions::Schema::kOaepSha1,
});
}
StatusOr<brillo::SecureBlob> ChapsFrontendImpl::Unbind(
Key key, const brillo::Blob& ciphertext) const {
return middleware_.CallSync<&Backend::Encryption::Decrypt>(
key, ciphertext,
Encryption::EncryptionOptions{
.schema = Encryption::EncryptionOptions::Schema::kRsaesSha1,
});
}
StatusOr<brillo::Blob> ChapsFrontendImpl::Sign(
Key key, const brillo::Blob& data, const SigningOptions& options) const {
return middleware_.CallSync<&Backend::Signing::RawSign>(key, data, options);
}
StatusOr<ChapsSealedData> ChapsFrontendImpl::SealData(
const brillo::SecureBlob& unsealed_data,
const brillo::SecureBlob& auth_value) const {
ASSIGN_OR_RETURN(brillo::Blob sealed_data,
middleware_.CallSync<&Backend::Sealing::Seal>(
OperationPolicySetting{
.permission =
Permission{
.auth_value = auth_value,
},
},
unsealed_data));
return ChapsSealedData{
.key_blob = std::move(sealed_data),
};
}
StatusOr<brillo::SecureBlob> ChapsFrontendImpl::UnsealData(
const ChapsSealedData& sealed_data,
const brillo::SecureBlob& auth_value) const {
// Backward compatible check.
if (!sealed_data.encrypted_data.empty()) {
ASSIGN_OR_RETURN(ScopedKey key,
middleware_.CallSync<&Backend::KeyManagement::LoadKey>(
OperationPolicy{
.permission =
Permission{
.auth_value = auth_value,
},
},
sealed_data.key_blob,
KeyManagement::LoadKeyOptions{
.auto_reload = true,
.lazy_expiration_time = kDefaultLazyExpirationTime,
}));
return middleware_.CallSync<&Backend::Encryption::Decrypt>(
key.GetKey(), sealed_data.encrypted_data,
Encryption::EncryptionOptions{
.schema = Encryption::EncryptionOptions::Schema::kRsaesSha1,
});
}
return middleware_.CallSync<&Backend::Sealing::Unseal>(
OperationPolicy{
.permission =
Permission{
.auth_value = auth_value,
},
},
sealed_data.key_blob, Sealing::UnsealOptions{});
}
void ChapsFrontendImpl::GetRandomSecureBlobAsync(
size_t size, GetRandomSecureBlobCallback callback) const {
middleware_.CallAsync<&Backend::Random::RandomSecureBlob>(std::move(callback),
size);
}
void ChapsFrontendImpl::SealDataAsync(const brillo::SecureBlob& unsealed_data,
const brillo::SecureBlob& auth_value,
SealDataCallback callback) const {
base::OnceCallback<void(StatusOr<brillo::Blob>)> on_seal_done =
base::BindOnce(
[](SealDataCallback callback, StatusOr<brillo::Blob> sealed_data) {
if (!sealed_data.ok()) {
std::move(callback).Run(std::move(sealed_data).err_status());
return;
}
std::move(callback).Run(ChapsSealedData{
.key_blob = std::move(sealed_data).value(),
});
},
std::move(callback));
middleware_.CallAsync<&Backend::Sealing::Seal>(
std::move(on_seal_done),
OperationPolicySetting{
.permission =
Permission{
.auth_value = auth_value,
},
},
unsealed_data);
}
void ChapsFrontendImpl::UnsealDataAsync(const ChapsSealedData& sealed_data,
const brillo::SecureBlob& auth_value,
UnsealDataCallback callback) const {
// Backward compatible check.
if (!sealed_data.encrypted_data.empty()) {
base::OnceCallback<void(StatusOr<ScopedKey>)> on_load_done = base::BindOnce(
[](UnsealDataCallback callback, MiddlewareDerivative derivative,
brillo::Blob encrypted_data, StatusOr<ScopedKey> key) {
if (!key.ok()) {
std::move(callback).Run(std::move(key).err_status());
return;
}
Middleware(derivative)
.CallAsync<&Backend::Encryption::Decrypt>(
std::move(callback), key->GetKey(), encrypted_data,
Encryption::EncryptionOptions{
.schema =
Encryption::EncryptionOptions::Schema::kRsaesSha1,
});
},
std::move(callback), middleware_.Derive(), sealed_data.encrypted_data);
middleware_.CallAsync<&Backend::KeyManagement::LoadKey>(
std::move(on_load_done),
OperationPolicy{
.permission =
Permission{
.auth_value = auth_value,
},
},
sealed_data.key_blob,
KeyManagement::LoadKeyOptions{
.auto_reload = true,
.lazy_expiration_time = kDefaultLazyExpirationTime,
});
return;
}
return middleware_.CallAsync<&Backend::Sealing::Unseal>(
std::move(callback),
OperationPolicy{
.permission =
Permission{
.auth_value = auth_value,
},
},
sealed_data.key_blob, Sealing::UnsealOptions{});
}
} // namespace hwsec