Thank you Daniel.

> On 11 Aug 2025, at 10:51 PM, Daniel Kiper <dki...@net-space.pl> wrote:
> 
> On Tue, Jul 29, 2025 at 08:21:48PM +0530, Sudhakar Kuppusamy wrote:
>> If secure boot is enabled with static key management mode, the trusted
>> certificates will be extracted from the GRUB ELF Note and added to db list.
>> This is introduced by a subsequent patch.
>> 
>> If secure boot is enabled with dynamic key management mode, the trusted
>> certificates and certificate/binary hash will be extracted from the PKS
>> and added to db list. The distrusted certificates, certificate/binary hash
>> from the PKS and added to dbx list. Both dbx and db lists are introduced by
>> a subsequent patch.
>> 
>> Note:-
>> 
>> If the certificate or the certificate hash exists in the dbx list, then
>> do not add that certificate/certificate hash to the db list.
>> 
>> Signed-off-by: Sudhakar Kuppusamy <sudha...@linux.ibm.com>
>> Reviewed-by: Stefan Berger <stef...@linux.ibm.com>
>> Reviewed-by: Avnish Chouhan <avn...@linux.ibm.com>
> 
> [...]
> 
>> +/* Add the certificate into the db/dbx list */
>> +static grub_err_t
>> +add_certificate (const grub_uint8_t *data, const grub_size_t data_size,
>> +                 struct grub_database *database, const bool is_db)
>> +{
>> +  struct x509_certificate *cert;
>> +  grub_err_t rc;
>> +  grub_size_t cert_entries = database->cert_entries;
>> +
>> +  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 (struct x509_certificate));
>> +  if (cert == NULL)
>> +    return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
>> +
>> +  rc = parse_x509_certificate (data, data_size, cert);
>> +  if (rc != GRUB_ERR_NONE)
>> +    {
>> +      grub_dprintf ("appendedsig", "skipped %s certificate (%d)\n",
>> +                    ((is_db == true) ? "trusted" : "distrusted"), (int) rc);
> 
> The rc value is meaningless for user because it may change from one GRUB
> version to another. Just add an error message which makes sense here...

Sure. Will do it.
> 
>> +      grub_free (cert);
>> +      return rc;
>> +    }
>> +
>> +  if (is_db == true)
>> +    {
>> +      rc = is_dbx_cert (cert);
>> +      if (rc != GRUB_ERR_NONE)
>> +        {
>> +          certificate_release (cert);
>> +          grub_free (cert);
>> +          return rc;
>> +        }
>> +    }
>> +
>> +  grub_dprintf ("appendedsig", "add a %s certificate CN='%s'\n",
>> +                ((is_db == true) ? "trusted" : "distrusted"), 
>> cert->subject);
> 
> grub_dprintf ("add a certificate CN='%s' to %s", ((is_db == true) ? "db" : 
> "dbx"), cert->subject);
> 
> I think the error message above should be changed in similar way, e.g.,
> "cannot add a certificate CN='%s' to %s due to an error"...

Sure. Will do it.
> 
>> +  cert_entries++;
>> +  cert->next = database->certs;
>> +  database->certs = cert;
>> +  database->cert_entries = cert_entries;
>> +
>> +  return rc;
>> +}
>> +
>> static grub_err_t
>> file_read_whole (grub_file_t file, grub_uint8_t **buf, grub_size_t *len)
>> {
>> @@ -272,7 +472,7 @@ grub_verify_appended_signature (const grub_uint8_t *buf, 
>> grub_size_t bufsize)
>>   struct pkcs7_signerInfo *si;
>>   int i;
>> 
>> -  if (db == NULL)
>> +  if (!db.cert_entries)
>>     return grub_error (GRUB_ERR_BAD_SIGNATURE, "no trusted keys to verify 
>> against");
>> 
>>   err = extract_appended_signature (buf, bufsize, &sig);
>> @@ -303,7 +503,7 @@ grub_verify_appended_signature (const grub_uint8_t *buf, 
>> grub_size_t bufsize)
>>       grub_dprintf ("appendedsig", "data size %" PRIuGRUB_SIZE ", signer %d 
>> hash %02x%02x%02x%02x...\n",
>>                     datasize, i, hash[0], hash[1], hash[2], hash[3]);
>> 
>> -      for (pk = db; pk != NULL; pk = pk->next)
>> +      for (pk = db.certs; pk != NULL; pk = pk->next)
>>         {
>>           err = verify_signature (pk->mpis, si->sig_mpi, si->hash, hash);
>>           if (err == GRUB_ERR_NONE)
>> @@ -359,7 +559,7 @@ is_cert_present_in_db (const struct x509_certificate 
>> *cert_in)
>> {
>>   struct x509_certificate *cert;
>> 
>> -  for (cert = db; cert; cert = cert->next)
>> +  for (cert = db.certs; cert; cert = cert->next)
> 
> ...; cert != NULL;...??? If yes then it should be changed in patch which
> introduces the file_read_whole() function...

Sure. Will do it.
> 
>>     {
>>       if (is_cert_match (cert, cert_in) == true)
>>         return true;
>> @@ -374,12 +574,12 @@ is_cert_removed_from_db (const struct x509_certificate 
>> *cert)
>>   int i = 1;
>>   struct x509_certificate *curr_cert, *prev_cert;
>> 
>> -  for (curr_cert = prev_cert = db; curr_cert != NULL; curr_cert = 
>> curr_cert->next)
>> +  for (curr_cert = prev_cert = db.certs; curr_cert != NULL; curr_cert = 
>> curr_cert->next)
>>     {
>>       if (is_cert_match (curr_cert, cert) == true)
>>         {
>>           if (i == 1) /* Match with first certificate in the db list. */
>> -            db = curr_cert->next;
>> +            db.certs = curr_cert->next;
>>           else
>>             prev_cert->next = curr_cert->next;
>> 
>> @@ -468,8 +668,9 @@ grub_cmd_db_cert (grub_command_t cmd __attribute__ 
>> ((unused)), int argc, char **
>> 
>>   grub_dprintf ("appendedsig", "added certificate with CN: %s\n", 
>> cert->subject);
>> 
>> -  cert->next = db;
>> -  db = cert;
>> +  cert->next = db.certs;
>> +  db.certs = cert;
>> +  db.cert_entries++;
>> 
>>   return GRUB_ERR_NONE;
>> }
>> @@ -517,7 +718,7 @@ grub_cmd_list_db (grub_command_t cmd __attribute__ 
>> ((unused)), int argc __attrib
>>   int cert_num = 1;
>>   grub_size_t i;
>> 
>> -  for (cert = db; cert != NULL; cert = cert->next)
>> +  for (cert = db.certs; cert != NULL; cert = cert->next)
> 
> ... like here…
Will do it.
> 
>>     {
>>       grub_printf ("Certificate %d:\n", cert_num);
>>       grub_printf ("\tSerial: ");
>> @@ -609,6 +810,238 @@ static struct grub_fs pseudo_fs = {
>> 
>> static grub_command_t cmd_verify, cmd_list_db, cmd_dbx_cert, cmd_db_cert;
>> 
>> +/* Check the certificate hash presence in the PKS dbx list. */
>> +static bool
>> +is_dbx_cert_hash (const grub_uint8_t *data, const grub_size_t data_size)
>> +{
>> +  grub_err_t rc;
>> +  grub_size_t i, cert_hash_size = 0;
>> +  grub_uint8_t cert_hash[GRUB_MAX_HASH_SIZE] = { 0 };
>> +
>> +  for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
>> +    {
>> +      if (grub_pks_keystore.dbx[i].data == NULL ||
>> +          grub_pks_keystore.dbx[i].data_size == 0)
>> +        continue;
>> +
>> +      rc = get_hash (&grub_pks_keystore.dbx[i].guid, data, data_size,
>> +                     cert_hash, &cert_hash_size);
>> +      if (rc != GRUB_ERR_NONE)
>> +        continue;
>> +
>> +      if (cert_hash_size == grub_pks_keystore.dbx[i].data_size &&
>> +          grub_memcmp (grub_pks_keystore.dbx[i].data, cert_hash, 
>> cert_hash_size) == 0)
>> +        {
>> +          grub_dprintf ("appendedsig", "a trusted certificate 
>> (%02x%02x%02x%02x) is ignored "
> 
> s/trusted//
Will do it.
> 
>> +                        "because this certificate hash is on the dbx 
>> list\n",
>> +                        cert_hash[0], cert_hash[1], cert_hash[2], 
>> cert_hash[3]);
>> +          return true;
>> +        }
>> +    }
>> +
>> +  return false;
>> +}
>> +
>> +/* Check the binary hash presence in the PKS dbx list. */
>> +static bool
>> +is_dbx_binary_hash (const grub_uint8_t *binary_hash, const grub_size_t 
>> binary_hash_size)
>> +{
>> +  grub_size_t i;
>> +
>> +  for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
>> +    {
>> +      if (grub_pks_keystore.dbx[i].data == NULL ||
>> +          grub_pks_keystore.dbx[i].data_size == 0)
>> +        continue;
>> +
>> +      if (binary_hash_size == grub_pks_keystore.dbx[i].data_size &&
>> +          grub_memcmp (grub_pks_keystore.dbx[i].data, binary_hash, 
>> binary_hash_size) == 0)
>> +        {
>> +          grub_dprintf ("appendedsig", "a trusted binary hash 
>> (%02x%02x%02x%02x) is ignored"
> 
> s/trusted//
Will do it.
> 
>> +                        " because it is on the dbx list\n", binary_hash[0], 
>> binary_hash[1],
>> +                        binary_hash[2], binary_hash[3]);
>> +          return true;
>> +        }
>> +    }
>> +
>> +  return false;
>> +}
> 
> [...]
> 
>> GRUB_MOD_INIT (appendedsig)
>> {
>>   int rc;
>> @@ -621,7 +1054,6 @@ GRUB_MOD_INIT (appendedsig)
>>   if (grub_ieee1275_is_secure_boot () == GRUB_SB_ENFORCED)
>>     check_sigs = true;
>> 
>> -  db = NULL;
>>   grub_register_variable_hook ("check_appended_signatures", 
>> grub_env_read_sec, grub_env_write_sec);
>>   grub_env_export ("check_appended_signatures");
>> 
>> @@ -630,38 +1062,54 @@ GRUB_MOD_INIT (appendedsig)
>>     grub_fatal ("error initing ASN.1 data structures: %d: %s\n", rc, 
>> asn1_strerror (rc));
>> 
>>   /*
>> -   * If signature verification is enabled,
>> -   * extract trusted keys from ELF Note and store them in the db.
>> +   * If signature verification is enabled with static key management mode,
>> +   * extract trusted keys from ELF Note and store them in the db list.
>>    */
>> -  if (check_sigs == true)
>> +  if (grub_pks_use_keystore == false && check_sigs == true)
>>     {
>>       FOR_MODULES (header)
>> -      {
>> -        struct grub_file pseudo_file;
>> -        struct x509_certificate *pk = NULL;
>> -        grub_err_t err;
>> -
>> -        /* Not an X.509 certificate, skip. */
>> -        if (header->type != OBJ_TYPE_X509_PUBKEY)
>> -          continue;
>> -
>> -        grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
>> -        pseudo_file.fs = &pseudo_fs;
>> -        pseudo_file.size = header->size - sizeof (struct 
>> grub_module_header);
>> -        pseudo_file.data = (char *) header + sizeof (struct 
>> grub_module_header);
>> -
>> -        grub_dprintf ("appendedsig", "found an x509 key, size=%" 
>> PRIuGRUB_UINT64_T "\n",
>> -                      pseudo_file.size);
>> -
>> -        err = read_cert_from_file (&pseudo_file, &pk);
>> -        if (err != GRUB_ERR_NONE)
>> -          grub_fatal ("error loading initial key: %s", grub_errmsg);
>> -
>> -        grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", 
>> pk->subject);
>> -
>> -        pk->next = db;
>> -        db = pk;
>> -      }
>> +        {
>> +          /* Not an ELF module, skip.  */
>> +          if (header->type != OBJ_TYPE_X509_PUBKEY)
>> +            continue;
>> +          rc = build_static_db_list (header);
>> +          if (rc != GRUB_ERR_NONE)
>> +            {
>> +              free_db_list ();
>> +              grub_error (rc, "static db list creation failed");
>> +            }
>> +          else
>> +            grub_dprintf ("appendedsig", "the db list now has %" 
>> PRIuGRUB_SIZE " static keys\n",
>> +                          db.cert_entries);
>> +        }
>> +    }
>> +  /*
>> +   * If signature verification is enabled with dynamic key management mode,
>> +   * extract trusted and distrusted keys from PKS and store them in the db 
>> and dbx list.
>> +   */
>> +  else if (grub_pks_use_keystore == true && check_sigs == true)
>> +    {
>> +      rc = create_db_list ();
>> +      if (rc != GRUB_ERR_NONE)
>> +        {
>> +          free_db_list ();
> 
> I would not call free_db_list() here because even partially populated
> list can be useful. Though we should be sure partial or even empty list
> does not lead to crashes.

Sure. Do I need to use partial or empty list even out of memory case?

> 
>> +          grub_error (rc, "db list creation failed");
>> +        }
>> +      else
>> +        {
>> +          rc = create_dbx_list ();
> 
> The dbx should be populated regardless of create_db_list() failure.
> 
>> +          if (rc != GRUB_ERR_NONE)
>> +            {
>> +              free_db_list ();
>> +              free_dbx_list ();
> 
> Again, do not free lists in case of errors.
> 
>> +              grub_error (rc, "dbx list creation failed");
>> +            }
>> +          else
>> +            grub_dprintf ("appendedsig", "the db list now has %" 
>> PRIuGRUB_SIZE " keys\n"
>> +                          "the dbx list now has %" PRIuGRUB_SIZE " keys\n",
>> +                          db.signature_entries + db.cert_entries, 
>> dbx.signature_entries);
>> +        }
>> +      grub_pks_free_keystore ();
>>     }
>> 
>>   cmd_db_cert = grub_register_command ("append_add_db_cert", 
>> grub_cmd_db_cert, N_("X509_CERTIFICATE"),
> 
> Daniel


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

Reply via email to