platform/x86: think-lmi: Multi-certificate support
Lenovo are adding support for both Admin and System certificates to the certificate based authentication feature This commit adds the support for this. Signed-off-by: Mark Pearson <mpearson-lenovo@squebb.ca> Link: https://lore.kernel.org/r/20241024195536.6992-4-mpearson-lenovo@squebb.ca [ij: Added #include <linux/array_size.h> + comment grammar fix] Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
This commit is contained in:
1 parent
7c0bbf1ae6
commit
5dcb5ef125
3 files changed
+95
-26
No files matched your search
@@ -303,6 +303,7 @@ Description:
|
||||
being configured allowing anyone to make changes.
|
||||
After any of these operations the system must reboot for the changes to
|
||||
take effect.
|
||||
Admin and System certificates are supported from 2025 systems onward.
|
||||
|
||||
certificate_thumbprint:
|
||||
Read only attribute used to display the MD5, SHA1 and SHA256 thumbprints
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/array_size.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mutex.h>
|
||||
@@ -169,11 +170,12 @@ MODULE_PARM_DESC(debug_support, "Enable debug command support");
|
||||
*/
|
||||
#define LENOVO_CERT_THUMBPRINT_GUID "C59119ED-1C0D-4806-A8E9-59AA318176C4"
|
||||
|
||||
#define TLMI_POP_PWD BIT(0) /* Supervisor */
|
||||
#define TLMI_PAP_PWD BIT(1) /* Power-on */
|
||||
#define TLMI_HDD_PWD BIT(2) /* HDD/NVME */
|
||||
#define TLMI_SMP_PWD BIT(6) /* System Management */
|
||||
#define TLMI_CERT BIT(7) /* Certificate Based */
|
||||
#define TLMI_POP_PWD BIT(0) /* Supervisor */
|
||||
#define TLMI_PAP_PWD BIT(1) /* Power-on */
|
||||
#define TLMI_HDD_PWD BIT(2) /* HDD/NVME */
|
||||
#define TLMI_SMP_PWD BIT(6) /* System Management */
|
||||
#define TLMI_CERT_SVC BIT(7) /* Admin Certificate Based */
|
||||
#define TLMI_CERT_SMC BIT(8) /* System Certificate Based */
|
||||
|
||||
static const struct tlmi_err_codes tlmi_errs[] = {
|
||||
{"Success", 0},
|
||||
@@ -653,6 +655,17 @@ static ssize_t level_store(struct kobject *kobj,
|
||||
|
||||
static struct kobj_attribute auth_level = __ATTR_RW(level);
|
||||
|
||||
static char *cert_command(struct tlmi_pwd_setting *setting, const char *arg1, const char *arg2)
|
||||
{
|
||||
/* Prepend with SVC or SMC if multicert supported */
|
||||
if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT)
|
||||
return kasprintf(GFP_KERNEL, "%s,%s,%s",
|
||||
setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
|
||||
arg1, arg2);
|
||||
else
|
||||
return kasprintf(GFP_KERNEL, "%s,%s", arg1, arg2);
|
||||
}
|
||||
|
||||
static ssize_t cert_thumbprint(char *buf, const char *arg, int count)
|
||||
{
|
||||
const struct acpi_buffer input = { strlen(arg), (char *)arg };
|
||||
@@ -678,18 +691,35 @@ static ssize_t cert_thumbprint(char *buf, const char *arg, int count)
|
||||
return count;
|
||||
}
|
||||
|
||||
static char *thumbtypes[] = {"Md5", "Sha1", "Sha256"};
|
||||
|
||||
static ssize_t certificate_thumbprint_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
|
||||
unsigned int i;
|
||||
int count = 0;
|
||||
char *wmistr;
|
||||
|
||||
if (!tlmi_priv.certificate_support || !setting->cert_installed)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
count += cert_thumbprint(buf, "Md5", count);
|
||||
count += cert_thumbprint(buf, "Sha1", count);
|
||||
count += cert_thumbprint(buf, "Sha256", count);
|
||||
for (i = 0; i < ARRAY_SIZE(thumbtypes); i++) {
|
||||
if (tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) {
|
||||
/* Format: 'SVC | SMC, Thumbtype' */
|
||||
wmistr = kasprintf(GFP_KERNEL, "%s,%s",
|
||||
setting == tlmi_priv.pwd_admin ? "SVC" : "SMC",
|
||||
thumbtypes[i]);
|
||||
} else {
|
||||
/* Format: 'Thumbtype' */
|
||||
wmistr = kasprintf(GFP_KERNEL, "%s", thumbtypes[i]);
|
||||
}
|
||||
if (!wmistr)
|
||||
return -ENOMEM;
|
||||
count += cert_thumbprint(buf, wmistr, count);
|
||||
kfree(wmistr);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -721,7 +751,7 @@ static ssize_t cert_to_password_store(struct kobject *kobj,
|
||||
return -ENOMEM;
|
||||
|
||||
/* Format: 'Password,Signature' */
|
||||
auth_str = kasprintf(GFP_KERNEL, "%s,%s", passwd, setting->signature);
|
||||
auth_str = cert_command(setting, passwd, setting->signature);
|
||||
if (!auth_str) {
|
||||
kfree_sensitive(passwd);
|
||||
return -ENOMEM;
|
||||
@@ -735,12 +765,19 @@ static ssize_t cert_to_password_store(struct kobject *kobj,
|
||||
|
||||
static struct kobj_attribute auth_cert_to_password = __ATTR_WO(cert_to_password);
|
||||
|
||||
enum cert_install_mode {
|
||||
TLMI_CERT_INSTALL,
|
||||
TLMI_CERT_UPDATE,
|
||||
};
|
||||
|
||||
static ssize_t certificate_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct tlmi_pwd_setting *setting = to_tlmi_pwd_setting(kobj);
|
||||
enum cert_install_mode install_mode = TLMI_CERT_INSTALL;
|
||||
char *auth_str, *new_cert;
|
||||
char *signature;
|
||||
char *guid;
|
||||
int ret;
|
||||
|
||||
@@ -757,9 +794,9 @@ static ssize_t certificate_store(struct kobject *kobj,
|
||||
return -EACCES;
|
||||
|
||||
/* Format: 'serial#, signature' */
|
||||
auth_str = kasprintf(GFP_KERNEL, "%s,%s",
|
||||
dmi_get_system_info(DMI_PRODUCT_SERIAL),
|
||||
setting->signature);
|
||||
auth_str = cert_command(setting,
|
||||
dmi_get_system_info(DMI_PRODUCT_SERIAL),
|
||||
setting->signature);
|
||||
if (!auth_str)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -776,24 +813,44 @@ static ssize_t certificate_store(struct kobject *kobj,
|
||||
|
||||
if (setting->cert_installed) {
|
||||
/* Certificate is installed so this is an update */
|
||||
if (!setting->signature || !setting->signature[0]) {
|
||||
install_mode = TLMI_CERT_UPDATE;
|
||||
/* If admin account enabled - need to use its signature */
|
||||
if (tlmi_priv.pwd_admin->pwd_enabled)
|
||||
signature = tlmi_priv.pwd_admin->signature;
|
||||
else
|
||||
signature = setting->signature;
|
||||
} else { /* Cert install */
|
||||
/* Check if SMC and SVC already installed */
|
||||
if ((setting == tlmi_priv.pwd_system) && tlmi_priv.pwd_admin->cert_installed) {
|
||||
/* This gets treated as a cert update */
|
||||
install_mode = TLMI_CERT_UPDATE;
|
||||
signature = tlmi_priv.pwd_admin->signature;
|
||||
} else { /* Regular cert install */
|
||||
install_mode = TLMI_CERT_INSTALL;
|
||||
signature = setting->signature;
|
||||
}
|
||||
}
|
||||
|
||||
if (install_mode == TLMI_CERT_UPDATE) {
|
||||
/* This is a certificate update */
|
||||
if (!signature || !signature[0]) {
|
||||
kfree(new_cert);
|
||||
return -EACCES;
|
||||
}
|
||||
guid = LENOVO_UPDATE_BIOS_CERT_GUID;
|
||||
/* Format: 'Certificate,Signature' */
|
||||
auth_str = kasprintf(GFP_KERNEL, "%s,%s",
|
||||
new_cert, setting->signature);
|
||||
auth_str = cert_command(setting, new_cert, signature);
|
||||
} else {
|
||||
/* This is a fresh install */
|
||||
if (!setting->pwd_enabled || !setting->password[0]) {
|
||||
/* To set admin cert, a password must be enabled */
|
||||
if ((setting == tlmi_priv.pwd_admin) &&
|
||||
(!setting->pwd_enabled || !setting->password[0])) {
|
||||
kfree(new_cert);
|
||||
return -EACCES;
|
||||
}
|
||||
guid = LENOVO_SET_BIOS_CERT_GUID;
|
||||
/* Format: 'Certificate,Admin-password' */
|
||||
auth_str = kasprintf(GFP_KERNEL, "%s,%s",
|
||||
new_cert, setting->password);
|
||||
/* Format: 'Certificate, password' */
|
||||
auth_str = cert_command(setting, new_cert, setting->password);
|
||||
}
|
||||
kfree(new_cert);
|
||||
if (!auth_str)
|
||||
@@ -873,14 +930,19 @@ static umode_t auth_attr_is_visible(struct kobject *kobj,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We only display certificates on Admin account, if supported */
|
||||
/* We only display certificates, if supported */
|
||||
if (attr == &auth_certificate.attr ||
|
||||
attr == &auth_signature.attr ||
|
||||
attr == &auth_save_signature.attr ||
|
||||
attr == &auth_cert_thumb.attr ||
|
||||
attr == &auth_cert_to_password.attr) {
|
||||
if ((setting == tlmi_priv.pwd_admin) && tlmi_priv.certificate_support)
|
||||
return attr->mode;
|
||||
if (tlmi_priv.certificate_support) {
|
||||
if (setting == tlmi_priv.pwd_admin)
|
||||
return attr->mode;
|
||||
if ((tlmi_priv.pwdcfg.core.password_mode >= TLMI_PWDCFG_MODE_MULTICERT) &&
|
||||
(setting == tlmi_priv.pwd_system))
|
||||
return attr->mode;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1700,10 +1762,12 @@ static int tlmi_analyze(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (tlmi_priv.certificate_support &&
|
||||
(tlmi_priv.pwdcfg.core.password_state & TLMI_CERT))
|
||||
tlmi_priv.pwd_admin->cert_installed = true;
|
||||
|
||||
if (tlmi_priv.certificate_support) {
|
||||
tlmi_priv.pwd_admin->cert_installed =
|
||||
tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SVC;
|
||||
tlmi_priv.pwd_system->cert_installed =
|
||||
tlmi_priv.pwdcfg.core.password_state & TLMI_CERT_SMC;
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail_clear_attr:
|
||||
|
||||
@@ -41,6 +41,10 @@ enum save_mode {
|
||||
};
|
||||
|
||||
/* password configuration details */
|
||||
#define TLMI_PWDCFG_MODE_LEGACY 0
|
||||
#define TLMI_PWDCFG_MODE_PASSWORD 1
|
||||
#define TLMI_PWDCFG_MODE_MULTICERT 3
|
||||
|
||||
struct tlmi_pwdcfg_core {
|
||||
uint32_t password_mode;
|
||||
uint32_t password_state;
|
||||
|
||||
Reference in new issue
Block a user