On Mon, Aug 25, 2025 at 04:38:32PM +0530, Sudhakar Kuppusamy wrote:
> Building on the parsers and the ability to embed X.509 certificates, as
> well as the existing gcrypt functionality, add a module for verifying
> appended signatures.
>
> This includes a signature verifier that requires that the Linux kernel and
> GRUB modules have appended signatures for verification.
>
> Signature verification must be enabled by setting check_appended_signatures.
> If secure boot is enabled with enforced mode when the appendedsig
> module is loaded, signature verification will be enabled, and trusted
> keys will be extracted from the GRUB ELF Note and stored in the db and
> locked automatically.
>
> Signed-off-by: Daniel Axtens <d...@axtens.net>
> Signed-off-by: Sudhakar Kuppusamy <sudha...@linux.ibm.com>

Except two nits below Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com>...

[...]

> diff --git a/grub-core/commands/appendedsig/appendedsig.c 
> b/grub-core/commands/appendedsig/appendedsig.c
> new file mode 100644
> index 000000000..5eb7b768a
> --- /dev/null
> +++ b/grub-core/commands/appendedsig/appendedsig.c
> @@ -0,0 +1,597 @@
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 2020, 2021, 2022 Free Software Foundation, Inc.
> + *  Copyright (C) 2020, 2021, 2022, 2025 IBM Corporation
> + *
> + *  GRUB is free software: you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation, either version 3 of the License, or
> + *  (at your option) any later version.
> + *
> + *  GRUB is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/types.h>
> +#include <grub/misc.h>
> +#include <grub/mm.h>
> +#include <grub/err.h>
> +#include <grub/dl.h>
> +#include <grub/file.h>
> +#include <grub/command.h>
> +#include <grub/crypto.h>
> +#include <grub/i18n.h>
> +#include <grub/gcrypt/gcrypt.h>
> +#include <grub/kernel.h>
> +#include <grub/extcmd.h>
> +#include <grub/verify.h>
> +#include <libtasn1.h>
> +#include <grub/env.h>
> +#include <grub/lockdown.h>
> +
> +#include "appendedsig.h"
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +/* Max size of hash data. */
> +#define MAX_HASH_SIZE      64
> +
> +/* Public key type. */
> +#define PKEY_ID_PKCS7      2
> +
> +/* Appended signature magic string and size. */
> +#define SIG_MAGIC          "~Module signature appended~\n"
> +#define SIG_MAGIC_SIZE     ((sizeof(SIG_MAGIC) - 1))
> +
> +/*
> + * This structure is extracted from scripts/sign-file.c in the linux kernel
> + * source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible.
> + */
> +struct module_signature
> +{
> +  grub_uint8_t algo;       /* Public-key crypto algorithm [0]. */
> +  grub_uint8_t hash;       /* Digest algorithm [0]. */
> +  grub_uint8_t id_type;    /* Key identifier type [GRUB_PKEY_ID_PKCS7]. */
> +  grub_uint8_t signer_len; /* Length of signer's name [0]. */
> +  grub_uint8_t key_id_len; /* Length of key identifier [0]. */
> +  grub_uint8_t __pad[3];
> +  grub_uint32_t sig_len;   /* Length of signature data. */
> +} GRUB_PACKED;
> +
> +#define SIG_METADATA_SIZE  (sizeof (struct module_signature))
> +#define APPENDED_SIG_SIZE(pkcs7_data_size) \
> +                           (pkcs7_data_size + SIG_MAGIC_SIZE + 
> SIG_METADATA_SIZE)
> +
> +/* This represents an entire, parsed, appended signature. */
> +struct grub_appended_signature
> +{
> +  grub_size_t signature_len;            /* Length of PKCS#7 data + metadata 
> + magic. */
> +  struct module_signature sig_metadata; /* Module signature metadata. */
> +  struct pkcs7_signedData pkcs7;        /* Parsed PKCS#7 data. */
> +};
> +
> +/* This represents a trusted certificates. */
> +struct grub_database
> +{
> +  struct x509_certificate *certs; /* Certificates. */
> +  grub_uint32_t cert_entries;     /* Number of certificates. */
> +};
> +
> +/* The db list is used to validate appended signatures. */
> +struct grub_database db = {.certs = NULL, .cert_entries = 0};
> +
> +/*
> + * Signature verification flag (check_sigs).
> + * check_sigs: false
> + *  - No signature verification. This is the default.
> + * check_sigs: true
> + *  - Enforce signature verification, and if signature verification fails,
> + *    post the errors and stop the boot.
> + */
> +static bool check_sigs = false;
> +
> +static grub_ssize_t
> +pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
> +{
> +  grub_memcpy (buf, (grub_uint8_t *) file->data + file->offset, len);
> +  return len;
> +}
> +
> +/* Filesystem descriptor. */
> +static struct grub_fs pseudo_fs = {
> +  .name = "pseudo",
> +  .fs_read = pseudo_read
> +};
> +
> +static void
> +add_cert_fingerprint (const grub_uint8_t *data, const grub_size_t data_size,
> +                      struct x509_certificate *const cert)
> +{
> +  gcry_md_spec_t *hash_func = NULL;
> +
> +  /* Add SHA256 hash of certificate. */
> +  hash_func = &_gcry_digest_spec_sha256;
> +  grub_memset (&cert->fingerprint[0], 0, MAX_HASH_SIZE);
> +  grub_crypto_hash (hash_func, &cert->fingerprint[0], data, data_size);

grub_crypto_hash ((gcry_md_spec_t *) &_gcry_digest_spec_sha256, ...

And you can drop hash_func vaiable then...

> +}

[...]

> +static char *
> +grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)), const 
> char *val)
> +{
> +  char *ret;
> +
> +  /*
> +   * Do not allow the value to be changed If signature verification is

s/If/if/

> +   * (check_sigs is set to enforce) enabled and GRUB is locked down.
> +   */
> +  if (check_sigs == true && grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED)
> +    {
> +      ret = grub_strdup ("enforce");
> +      if (ret == NULL)
> +        grub_error (GRUB_ERR_OUT_OF_MEMORY, "could not duplicate a string 
> enforce");
> +
> +      return ret;
> +    }
> +
> +  if ((*val == '1') || (*val == 'e'))
> +    check_sigs = true;
> +  else if ((*val == '0') || (*val == 'n'))
> +    check_sigs = false;
> +
> +  ret = grub_strdup (grub_env_read_sec (NULL, NULL));
> +  if (ret == NULL)
> +    grub_error (GRUB_ERR_OUT_OF_MEMORY, "could not duplicate a string %s",
> +                grub_env_read_sec (NULL, NULL));
> +
> +  return ret;
> +}

Daniel

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to