From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
To: grub-devel@gnu.org
Cc: dja@axtens.net, jan.setjeeilers@oracle.com,
julian.klode@canonical.com, mate.kukri@canonical.com,
pjones@redhat.com, msuchanek@suse.com, mlewando@redhat.com,
stefanb@linux.ibm.com, avnish@linux.ibm.com, nayna@linux.ibm.com,
ssrish@linux.ibm.com, Sudhakar Kuppusamy <sudhakar@linux.ibm.com>,
sridharm@linux.ibm.com, Daniel Kiper <daniel.kiper@oracle.com>
Subject: [PATCH v18 15/20] appended signatures: GRUB commands to manage the certificates
Date: Mon, 6 Oct 2025 12:55:00 +0530 [thread overview]
Message-ID: <20251006072508.19088-16-sudhakar@linux.ibm.com> (raw)
In-Reply-To: <20251006072508.19088-1-sudhakar@linux.ibm.com>
Introducing the following GRUB commands to manage the certificates.
1. append_list_db:
Show the list of trusted certificates from the db list
2. append_add_db_cert:
Add the trusted certificate to the db list
3. append_add_dbx_cert:
Add the distrusted certificate to the dbx list
4. append_verify:
Verify the signed file using db list
Note that if signature verification (check_appended_signatures) is set to yes,
the append_add_db_cert and append_add_dbx_cert commands only accept the file
‘X509_certificate’ that is signed with an appended signature.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Tested-by: Sridhar Markonda <sridharm@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/appendedsig/appendedsig.c | 316 +++++++++++++++++++
1 file changed, 316 insertions(+)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 9cfa1bebb..614ebeec0 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -123,6 +123,9 @@ static bool append_key_mgmt = false;
/* Platform KeyStore db and dbx. */
static grub_pks_t *pks_keystore;
+/* Appended signature size. */
+static grub_size_t append_sig_len = 0;
+
static grub_ssize_t
pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
{
@@ -136,6 +139,65 @@ static struct grub_fs pseudo_fs = {
.fs_read = pseudo_read
};
+/*
+ * We cannot use hexdump() to display hash data because it is typically displayed
+ * in hexadecimal format, along with an ASCII representation of the same data.
+ *
+ * Example: sha256 hash data
+ * 00000000 52 b5 90 49 64 de 22 d7 4e 5f 4f b4 1b 51 9c 34 |R..Id.".N_O..Q.4|
+ * 00000010 b1 96 21 7c 91 78 a5 0d 20 8c e9 5c 22 54 53 f7 |..!|.x.. ..\"TS.|
+ *
+ * An appended signature only required to display the hexadecimal of the hash data
+ * by separating each byte with ":". So, we introduced a new method hexdump_colon
+ * to display it.
+ *
+ * Example: Sha256 hash data
+ * 52:b5:90:49:64:de:22:d7:4e:5f:4f:b4:1b:51:9c:34:
+ * b1:96:21:7c:91:78:a5:0d:20:8c:e9:5c:22:54:53:f7
+ */
+static void
+hexdump_colon (const grub_uint8_t *data, const grub_size_t length)
+{
+ grub_size_t i, count = 0;
+
+ for (i = 0; i < length - 1; i++)
+ {
+ grub_printf ("%02x:", data[i]);
+ count++;
+ if (count == 16)
+ {
+ grub_printf ("\n ");
+ count = 0;
+ }
+ }
+
+ grub_printf ("%02x\n", data[i]);
+}
+
+static void
+print_certificate (const grub_x509_cert_t *cert, const grub_uint32_t cert_num)
+{
+ grub_uint32_t i;
+
+ grub_printf ("\nCertificate: %u\n", cert_num);
+ grub_printf (" Data:\n");
+ grub_printf (" Version: %u (0x%u)\n", cert->version + 1, cert->version);
+ grub_printf (" Serial Number:\n ");
+
+ for (i = 0; i < cert->serial_len - 1; i++)
+ grub_printf ("%02x:", cert->serial[i]);
+
+ grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
+ grub_printf (" Issuer: %s\n", cert->issuer);
+ grub_printf (" Subject: %s\n", cert->subject);
+ grub_printf (" Subject Public Key Info:\n");
+ grub_printf (" Public Key Algorithm: rsaEncryption\n");
+ grub_printf (" RSA Public-Key: (%d bit)\n", cert->modulus_size);
+ grub_printf (" Fingerprint: sha256\n ");
+ hexdump_colon (&cert->fingerprint[GRUB_FINGERPRINT_SHA256][0],
+ grub_strlen ((char *) cert->fingerprint[GRUB_FINGERPRINT_SHA256]));
+}
+
/*
* GUID can be used to determine the hashing function and generate the hash using
* determined hashing function.
@@ -429,6 +491,61 @@ add_certificate (const grub_uint8_t *data, const grub_size_t data_size,
return rc;
}
+static void
+_remove_cert_from_db (const grub_x509_cert_t *cert)
+{
+ grub_uint32_t i = 1;
+ grub_x509_cert_t *curr_cert, *prev_cert;
+
+ for (curr_cert = prev_cert = db.certs; curr_cert != NULL; curr_cert = curr_cert->next, i++)
+ {
+ if (is_cert_match (curr_cert, cert) == true)
+ {
+ if (i == 1) /* Match with first certificate in the db list. */
+ db.certs = curr_cert->next;
+ else
+ prev_cert->next = curr_cert->next;
+
+ grub_dprintf ("appendedsig",
+ "removed distrusted certificate with CN: %s from the db list\n",
+ curr_cert->subject);
+ curr_cert->next = NULL;
+ grub_x509_cert_release (curr_cert);
+ grub_free (curr_cert);
+ break;
+ }
+ else
+ prev_cert = curr_cert;
+ }
+}
+
+static grub_err_t
+remove_cert_from_db (const grub_uint8_t *data, const grub_size_t data_size)
+{
+ grub_err_t rc;
+ grub_x509_cert_t *cert;
+
+ if (data == NULL || data_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate data or size is not available");
+
+ cert = grub_zalloc (sizeof (grub_x509_cert_t));
+ if (cert == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ rc = grub_x509_cert_parse (data, data_size, cert);
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_dprintf ("appendedsig", "cannot remove an invalid certificate from the db list\n");
+ grub_free (cert);
+ return rc;
+ }
+
+ /* Remove certificate from the db list. */
+ _remove_cert_from_db (cert);
+
+ return rc;
+}
+
static grub_err_t
file_read_whole (grub_file_t file, grub_uint8_t **buf, grub_size_t *len)
{
@@ -649,6 +766,7 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
if (err != GRUB_ERR_NONE)
return err;
+ append_sig_len = sig.signature_len;
datasize = bufsize - sig.signature_len;
/*
@@ -709,6 +827,189 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
return err;
}
+static grub_err_t
+grub_cmd_verify_signature (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+{
+ grub_file_t signed_file;
+ grub_err_t err;
+ grub_uint8_t *signed_data = NULL;
+ grub_size_t signed_data_size = 0;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "a signed file is expected\nExample:\n\tappend_verify <SIGNED FILE>\n");
+
+ if (!grub_strlen (args[0]))
+ return grub_error (GRUB_ERR_BAD_FILENAME, "missing signed file");
+
+ grub_dprintf ("appendedsig", "verifying %s\n", args[0]);
+
+ signed_file = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
+ if (signed_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "could not open %s file", args[0]);
+
+ err = file_read_whole (signed_file, &signed_data, &signed_data_size);
+ if (err == GRUB_ERR_NONE)
+ {
+ err = grub_verify_appended_signature (signed_data, signed_data_size);
+ grub_free (signed_data);
+ }
+
+ grub_file_close (signed_file);
+
+ return err;
+}
+
+/*
+ * Checks the trusted certificate against dbx list if dynamic key management is
+ * enabled. And add it to the db list if it is not already present.
+ *
+ * Note: When signature verification is enabled, this command only accepts the
+ * trusted certificate that is signed with an appended signature.
+ * The signature is verified by the appendedsig module. If verification succeeds,
+ * the certificate is added to the db list. Otherwise, an error is posted and
+ * the certificate is not added.
+ * When signature verification is disabled, it accepts the trusted certificate
+ * without an appended signature and add it to the db list.
+ *
+ * Also, note that the adding of the trusted certificate using this command does
+ * not persist across reboots.
+ */
+static grub_err_t
+grub_cmd_db_cert (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+{
+ grub_err_t err;
+ grub_file_t cert_file;
+ grub_uint8_t *cert_data = NULL;
+ grub_size_t cert_data_size = 0;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "a trusted X.509 certificate file is expected in DER format\n"
+ "Example:\n\tappend_add_db_cert <X509_CERTIFICATE>\n");
+
+ if (!grub_strlen (args[0]))
+ return grub_error (GRUB_ERR_BAD_FILENAME, "missing trusted X.509 certificate file");
+
+ cert_file = grub_file_open (args[0],
+ GRUB_FILE_TYPE_CERTIFICATE_TRUST | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (cert_file == NULL)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "could not open %s file", args[0]);
+
+ err = file_read_whole (cert_file, &cert_data, &cert_data_size);
+ grub_file_close (cert_file);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ /*
+ * If signature verification is enabled (check_sigs is set to true), obtain
+ * the actual certificate size by subtracting the appended signature size from
+ * the certificate size because the certificate has an appended signature, and
+ * this actual certificate size is used to get the X.509 certificate.
+ */
+ if (check_sigs == true)
+ cert_data_size -= append_sig_len;
+
+ err = add_certificate (cert_data, cert_data_size, &db);
+ grub_free (cert_data);
+
+ return err;
+}
+
+/*
+ * Remove the distrusted certificate from the db list if it is already present.
+ * And add it to the dbx list if not present when dynamic key management is
+ * enabled.
+ *
+ * Note: When signature verification is enabled, this command only accepts the
+ * distrusted certificate that is signed with an appended signature.
+ * The signature is verified by the appended sig module. If verification
+ * succeeds, the certificate is removed from the db list. Otherwise, an error
+ * is posted and the certificate is not removed.
+ * When signature verification is disabled, it accepts the distrusted certificate
+ * without an appended signature and removes it from the db list.
+ *
+ * Also, note that the removal of the distrusted certificate using this command
+ * does not persist across reboots.
+ */
+static grub_err_t
+grub_cmd_dbx_cert (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+{
+ grub_err_t err;
+ grub_file_t cert_file;
+ grub_uint8_t *cert_data = NULL;
+ grub_size_t cert_data_size = 0;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "a distrusted X.509 certificate file is expected in DER format\n"
+ "Example:\n\tappend_add_dbx_cert <X509_CERTIFICATE>\n");
+
+ if (!grub_strlen (args[0]))
+ return grub_error (GRUB_ERR_BAD_FILENAME, "missing distrusted X.509 certificate file");
+
+ cert_file = grub_file_open (args[0],
+ GRUB_FILE_TYPE_CERTIFICATE_TRUST | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (cert_file == NULL)
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "could not open %s file", args[0]);
+
+ err = file_read_whole (cert_file, &cert_data, &cert_data_size);
+ grub_file_close (cert_file);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ /*
+ * If signature verification is enabled (check_sigs is set to true), obtain
+ * the actual certificate size by subtracting the appended signature size from
+ * the certificate size because the certificate has an appended signature, and
+ * this actual certificate size is used to get the X.509 certificate.
+ */
+ if (check_sigs == true)
+ cert_data_size -= append_sig_len;
+
+ /* Remove distrusted certificate from the db list if present. */
+ err = remove_cert_from_db (cert_data, cert_data_size);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_free (cert_data);
+ return err;
+ }
+
+ /* Only add the certificate to the dbx list if dynamic key management is enabled. */
+ if (append_key_mgmt == true)
+ err = add_certificate (cert_data, cert_data_size, &dbx);
+
+ grub_free (cert_data);
+
+ return err;
+}
+
+static grub_err_t
+grub_cmd_list_db (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct x509_certificate *cert;
+ grub_uint32_t i, cert_num = 1;
+
+ for (cert = db.certs; cert != NULL; cert = cert->next, cert_num++)
+ print_certificate (cert, cert_num);
+
+ if (append_key_mgmt == false)
+ return GRUB_ERR_NONE;
+
+ for (i = 0; i < db.hash_entries; i++)
+ {
+ if (db.hashes[i] != NULL)
+ {
+ grub_printf ("\nBinary hash: %u\n", i + 1);
+ grub_printf (" Hash: sha%" PRIuGRUB_SIZE "\n ", db.hash_sizes[i] * 8);
+ hexdump_colon (db.hashes[i], db.hash_sizes[i]);
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
/* Add the X.509 certificates/binary hash to the db list from PKS. */
static grub_err_t
load_pks2db (void)
@@ -1031,6 +1332,8 @@ struct grub_file_verifier grub_appendedsig_verifier = {
.write = appendedsig_write,
};
+static grub_command_t cmd_verify, cmd_list_db, cmd_dbx_cert, cmd_db_cert;
+
GRUB_MOD_INIT (appendedsig)
{
grub_int32_t rc;
@@ -1100,6 +1403,15 @@ GRUB_MOD_INIT (appendedsig)
db.cert_entries);
}
+ cmd_verify = grub_register_command ("append_verify", grub_cmd_verify_signature, N_("<SIGNED_FILE>"),
+ N_("Verify SIGNED_FILE against the trusted X.509 certificates in the db list"));
+ cmd_list_db = grub_register_command ("append_list_db", grub_cmd_list_db, 0,
+ N_("Show the list of trusted X.509 certificates from the db list"));
+ cmd_db_cert = grub_register_command ("append_add_db_cert", grub_cmd_db_cert, N_("<X509_CERTIFICATE>"),
+ N_("Add trusted X509_CERTIFICATE to the db list"));
+ cmd_dbx_cert = grub_register_command ("append_add_dbx_cert", grub_cmd_dbx_cert, N_("<X509_CERTIFICATE>"),
+ N_("Add distrusted X509_CERTIFICATE to the dbx list"));
+
grub_verifier_register (&grub_appendedsig_verifier);
grub_dl_set_persistent (mod);
}
@@ -1118,4 +1430,8 @@ GRUB_MOD_FINI (appendedsig)
grub_register_variable_hook ("appendedsig_key_mgmt", NULL, NULL);
grub_env_unset ("appendedsig_key_mgmt");
grub_verifier_unregister (&grub_appendedsig_verifier);
+ grub_unregister_command (cmd_verify);
+ grub_unregister_command (cmd_list_db);
+ grub_unregister_command (cmd_db_cert);
+ grub_unregister_command (cmd_dbx_cert);
}
--
2.50.1 (Apple Git-155)
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
next prev parent reply other threads:[~2025-10-06 7:28 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-06 7:24 [PATCH v18 00/20] Appended Signature Secure Boot Support for PowerPC Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 01/20] powerpc-ieee1275: Add support for signing GRUB with an appended signature Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 02/20] crypto: Move storage for grub_crypto_pk_* to crypto.c Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 03/20] pgp: Rename OBJ_TYPE_PUBKEY to OBJ_TYPE_GPG_PUBKEY Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 04/20] grub-install: Support embedding x509 certificates Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 05/20] appended signatures: Import GNUTLS's ASN.1 description files Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 06/20] appended signatures: Parse ASN1 node Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 07/20] appended signatures: Parse PKCS#7 signed data Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 08/20] appended signatures: Parse X.509 certificates Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 09/20] powerpc_ieee1275: Enter lockdown based on /ibm, secure-boot Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 10/20] appended signatures: Support verifying appended signatures Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 11/20] powerpc_ieee1275: Read the db and dbx secure boot variables Sudhakar Kuppusamy
2026-02-24 18:47 ` John Paul Adrian Glaubitz
2026-02-27 13:52 ` Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 12/20] appended signatures: Introducing key management environment variable Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 13/20] appended signatures: Create db and dbx lists Sudhakar Kuppusamy
2025-10-06 7:24 ` [PATCH v18 14/20] appended signatures: Using db and dbx lists for signature verification Sudhakar Kuppusamy
2025-10-06 7:25 ` Sudhakar Kuppusamy [this message]
2025-10-06 7:25 ` [PATCH v18 16/20] appended signatures: GRUB commands to manage the hashes Sudhakar Kuppusamy
2025-10-06 7:25 ` [PATCH v18 17/20] appended signatures: Verification tests Sudhakar Kuppusamy
2025-10-06 7:25 ` [PATCH v18 18/20] docs/grub: Document signing GRUB under UEFI Sudhakar Kuppusamy
2025-10-06 7:25 ` [PATCH v18 19/20] docs/grub: Document signing GRUB with an appended signature Sudhakar Kuppusamy
2025-10-06 7:25 ` [PATCH v18 20/20] docs/grub: Document " Sudhakar Kuppusamy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251006072508.19088-16-sudhakar@linux.ibm.com \
--to=sudhakar@linux.ibm.com \
--cc=avnish@linux.ibm.com \
--cc=daniel.kiper@oracle.com \
--cc=dja@axtens.net \
--cc=grub-devel@gnu.org \
--cc=jan.setjeeilers@oracle.com \
--cc=julian.klode@canonical.com \
--cc=mate.kukri@canonical.com \
--cc=mlewando@redhat.com \
--cc=msuchanek@suse.com \
--cc=nayna@linux.ibm.com \
--cc=pjones@redhat.com \
--cc=sridharm@linux.ibm.com \
--cc=ssrish@linux.ibm.com \
--cc=stefanb@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.