These tests are run through all_functional_test and test a range of commands and behaviours. Signed-off-by: Daniel Axtens <dja@axtens.net> Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com> Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
349 lines
13 KiB
C
349 lines
13 KiB
C
/*
|
|
* GRUB -- GRand Unified Bootloader
|
|
* Copyright (C) 2020, 2022 Free Software Foundation, Inc.
|
|
* Copyright (C) 2020, 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/time.h>
|
|
#include <grub/misc.h>
|
|
#include <grub/dl.h>
|
|
#include <grub/command.h>
|
|
#include <grub/env.h>
|
|
#include <grub/test.h>
|
|
#include <grub/mm.h>
|
|
#include <grub/procfs.h>
|
|
#include <grub/file.h>
|
|
|
|
#include "appended_signatures.h"
|
|
|
|
GRUB_MOD_LICENSE ("GPLv3+");
|
|
|
|
#define PROC_FILE(identifier, file_name) \
|
|
static char *get_##identifier (grub_size_t *sz) \
|
|
{ \
|
|
char *ret; \
|
|
\
|
|
*sz = identifier##_len; \
|
|
ret = grub_malloc (*sz); \
|
|
if (ret != NULL) \
|
|
grub_memcpy (ret, identifier, *sz); \
|
|
return ret; \
|
|
} \
|
|
\
|
|
static struct grub_procfs_entry identifier##_entry = { .name = file_name, \
|
|
.get_contents = get_##identifier };
|
|
|
|
#define DEFINE_TEST_CASE(case_name) PROC_FILE (case_name, #case_name)
|
|
|
|
#define DO_TEST(case_name, is_valid) \
|
|
{ \
|
|
grub_procfs_register (#case_name, &case_name##_entry); \
|
|
do_verify ("(proc)/" #case_name, is_valid); \
|
|
grub_procfs_unregister (&case_name##_entry); \
|
|
}
|
|
|
|
DEFINE_TEST_CASE (hi_signed);
|
|
DEFINE_TEST_CASE (hi_signed_sha256);
|
|
DEFINE_TEST_CASE (hj_signed);
|
|
DEFINE_TEST_CASE (short_msg);
|
|
DEFINE_TEST_CASE (unsigned_msg);
|
|
DEFINE_TEST_CASE (hi_signed_2nd);
|
|
DEFINE_TEST_CASE (hi_double);
|
|
DEFINE_TEST_CASE (hi_double_extended);
|
|
|
|
PROC_FILE (certificate_der, "certificate.der")
|
|
PROC_FILE (certificate2_der, "certificate2.der")
|
|
PROC_FILE (certificate_printable_der, "certificate_printable.der")
|
|
PROC_FILE (certificate_eku_der, "certificate_eku.der")
|
|
|
|
static void
|
|
do_verify (const char *f, int is_valid)
|
|
{
|
|
grub_command_t cmd;
|
|
char *args[] = { (char *) f, NULL };
|
|
grub_err_t err;
|
|
|
|
cmd = grub_command_find ("append_verify");
|
|
if (cmd == NULL)
|
|
{
|
|
grub_test_assert (0, "can't find command `%s'", "append_verify");
|
|
return;
|
|
}
|
|
|
|
err = (cmd->func) (cmd, 1, args);
|
|
if (is_valid)
|
|
{
|
|
grub_test_assert (err == GRUB_ERR_NONE, "verification of %s failed: %d: %s",
|
|
f, grub_errno, grub_errmsg);
|
|
}
|
|
else
|
|
{
|
|
grub_test_assert (err != GRUB_ERR_NONE,
|
|
"verification of %s unexpectedly succeeded", f);
|
|
}
|
|
}
|
|
|
|
static void
|
|
appended_signature_test (void)
|
|
{
|
|
grub_command_t cmd_trust, cmd_distrust;
|
|
char *trust_args[] = { (char *) "(proc)/certificate.der", NULL };
|
|
char *trust_args2[] = { (char *) "(proc)/certificate2.der", NULL };
|
|
char *trust_args_printable[] = { (char *) "(proc)/certificate_printable.der", NULL };
|
|
char *trust_args_eku[] = { (char *) "(proc)/certificate_eku.der", NULL };
|
|
const char *key_mgmt;
|
|
grub_err_t err;
|
|
|
|
grub_procfs_register ("certificate.der", &certificate_der_entry);
|
|
grub_procfs_register ("certificate2.der", &certificate2_der_entry);
|
|
grub_procfs_register ("certificate_printable.der", &certificate_printable_der_entry);
|
|
grub_procfs_register ("certificate_eku.der", &certificate_eku_der_entry);
|
|
|
|
/* Set appended signature key managment to static. */
|
|
err = grub_env_set ("appendedsig_key_mgmt", "static");
|
|
grub_test_assert (err == GRUB_ERR_NONE, "set of key management is failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
|
|
/* Get appended signatures key management. */
|
|
key_mgmt = grub_env_get ("appendedsig_key_mgmt");
|
|
grub_test_assert (grub_strncmp (key_mgmt, "static", grub_strlen(key_mgmt)) == 0,
|
|
"getting unexpected key management: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
|
|
cmd_trust = grub_command_find ("append_add_db_cert");
|
|
if (cmd_trust == NULL)
|
|
{
|
|
grub_test_assert (0, "can't find command `%s'", "append_add_db_cert");
|
|
return;
|
|
}
|
|
|
|
grub_errno = GRUB_ERR_NONE;
|
|
err = (cmd_trust->func) (cmd_trust, 1, trust_args);
|
|
grub_test_assert (err == GRUB_ERR_NONE, "loading certificate failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
/* If we have no certificate the remainder of the tests are meaningless. */
|
|
if (err != GRUB_ERR_NONE)
|
|
return;
|
|
|
|
/*
|
|
* Reload the command: this works around some 'interesting' behaviour in the
|
|
* dynamic command dispatcher. The first time you call cmd->func you get a
|
|
* dispatcher that loads the module, finds the real cmd, calls it, and then
|
|
* releases some internal storage. This means it's not safe to call a second
|
|
* time and we need to reload it.
|
|
*/
|
|
cmd_trust = grub_command_find ("append_add_db_cert");
|
|
|
|
/* The hi, signed with key 1, SHA-512. */
|
|
DO_TEST (hi_signed, 1);
|
|
|
|
/* The hi, signed with key 1, SHA-256. */
|
|
DO_TEST (hi_signed_sha256, 1);
|
|
|
|
/* The hi, key 1, SHA-512, second byte corrupted. */
|
|
DO_TEST (hj_signed, 0);
|
|
|
|
/* Message too short for a signature. */
|
|
DO_TEST (short_msg, 0);
|
|
|
|
/* Lorem ipsum. */
|
|
DO_TEST (unsigned_msg, 0);
|
|
|
|
/* The hi, signed with both keys, SHA-512. */
|
|
DO_TEST (hi_double, 1);
|
|
|
|
/*
|
|
* The hi, signed with both keys and with empty space to test we haven't
|
|
* broken support for adding more signatures after the fact.
|
|
*/
|
|
DO_TEST (hi_double_extended, 1);
|
|
|
|
/*
|
|
* In enforcing mode, we shouldn't be able to load a certificate that isn't
|
|
* signed by an existing trusted key.
|
|
*
|
|
* However, procfs files automatically skip the verification test, so we can't
|
|
* easily test this.
|
|
*/
|
|
|
|
/* Verify that testing with 2 trusted certs works. */
|
|
DO_TEST (hi_signed_2nd, 0);
|
|
|
|
err = (cmd_trust->func) (cmd_trust, 1, trust_args);
|
|
grub_test_assert (err != GRUB_ERR_NONE, "unexpectedly reloaded certificate 1: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
|
|
err = (cmd_trust->func) (cmd_trust, 1, trust_args2);
|
|
grub_test_assert (err == GRUB_ERR_NONE, "loading certificate 2 failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
if (err != GRUB_ERR_NONE)
|
|
return;
|
|
|
|
DO_TEST (hi_signed_2nd, 1);
|
|
DO_TEST (hi_signed, 1);
|
|
DO_TEST (hi_double, 1);
|
|
DO_TEST (hi_double_extended, 1);
|
|
|
|
/*
|
|
* Check certificate removal. They're added to the _top_ of the db list and
|
|
* removed by position in the list. Current the list looks like [#2, #1].
|
|
*/
|
|
cmd_distrust = grub_command_find ("append_add_dbx_cert");
|
|
if (cmd_distrust == NULL)
|
|
{
|
|
grub_test_assert (0, "can't find command `%s'", "append_add_dbx_cert");
|
|
return;
|
|
}
|
|
|
|
/* Remove the certificate #1. */
|
|
err = (cmd_distrust->func) (cmd_distrust, 1, trust_args);
|
|
grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 1 failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
DO_TEST (hi_signed_2nd, 1);
|
|
DO_TEST (hi_signed, 0);
|
|
DO_TEST (hi_double, 1);
|
|
|
|
/* Now reload certificate #1. */
|
|
err = (cmd_trust->func) (cmd_trust, 1, trust_args);
|
|
grub_test_assert (err == GRUB_ERR_NONE, "reloading certificate 1 failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
DO_TEST (hi_signed_2nd, 1);
|
|
DO_TEST (hi_signed, 1);
|
|
DO_TEST (hi_double, 1);
|
|
|
|
/* Remove the certificate #2. */
|
|
err = (cmd_distrust->func) (cmd_distrust, 1, trust_args2);
|
|
grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 2 failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
DO_TEST (hi_signed_2nd, 0);
|
|
DO_TEST (hi_signed, 1);
|
|
DO_TEST (hi_double, 1);
|
|
|
|
/* Now reload certificate #2. */
|
|
err = (cmd_trust->func) (cmd_trust, 1, trust_args2);
|
|
grub_test_assert (err == GRUB_ERR_NONE, "reloading certificate 2 failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
DO_TEST (hi_signed_2nd, 1);
|
|
DO_TEST (hi_signed, 1);
|
|
DO_TEST (hi_double, 1);
|
|
|
|
/* Remove the certificate #1. */
|
|
err = (cmd_distrust->func) (cmd_distrust, 1, trust_args);
|
|
grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 1 failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
|
|
/* Remove the certificate #2. */
|
|
err = (cmd_distrust->func) (cmd_distrust, 1, trust_args2);
|
|
grub_test_assert (err == GRUB_ERR_NONE, "distrusting certificate 2 failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
|
|
/* Set appended signature key managment to dynamic. */
|
|
err = grub_env_set ("appendedsig_key_mgmt", "dynamic");
|
|
grub_test_assert (err == GRUB_ERR_NONE, "set of key management is failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
|
|
/* Get appended signatures key management. */
|
|
key_mgmt = grub_env_get ("appendedsig_key_mgmt");
|
|
grub_test_assert (grub_strncmp (key_mgmt, "dynamic", grub_strlen(key_mgmt)) == 0,
|
|
"getting unexpected key management: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
|
|
cmd_trust = grub_command_find ("append_add_db_cert");
|
|
err = (cmd_trust->func) (cmd_trust, 1, trust_args);
|
|
grub_test_assert ((err == GRUB_ERR_NONE || err == GRUB_ERR_EXISTS || GRUB_ERR_ACCESS_DENIED),
|
|
"loading certificate 1 failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
if (err != GRUB_ERR_NONE)
|
|
return;
|
|
|
|
DO_TEST (hi_signed, 1);
|
|
DO_TEST (hi_double, 1);
|
|
DO_TEST (hi_double_extended, 1);
|
|
|
|
err = (cmd_trust->func) (cmd_trust, 1, trust_args2);
|
|
grub_test_assert ((err == GRUB_ERR_NONE || err == GRUB_ERR_EXISTS || GRUB_ERR_ACCESS_DENIED),
|
|
"loading certificate 2 failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
if (err != GRUB_ERR_NONE)
|
|
return;
|
|
|
|
DO_TEST (hi_signed_2nd, 1);
|
|
DO_TEST (hi_signed, 1);
|
|
DO_TEST (hi_double, 1);
|
|
DO_TEST (hi_double_extended, 1);
|
|
|
|
cmd_distrust = grub_command_find ("append_add_dbx_cert");
|
|
if (cmd_distrust == NULL)
|
|
{
|
|
grub_test_assert (0, "can't find command `%s'", "append_add_dbx_cert");
|
|
return;
|
|
}
|
|
|
|
/* Now remove certificate #1. */
|
|
err = (cmd_distrust->func) (cmd_distrust, 1, trust_args);
|
|
grub_test_assert ((err == GRUB_ERR_NONE || err == GRUB_ERR_EXISTS),
|
|
"distrusting certificate 1 failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
DO_TEST (hi_signed_2nd, 1);
|
|
DO_TEST (hi_signed, 0);
|
|
DO_TEST (hi_double, 1);
|
|
|
|
/* Now reload certificate #1. */
|
|
err = (cmd_trust->func) (cmd_trust, 1, trust_args);
|
|
grub_test_assert (err != GRUB_ERR_NONE, "unexpectedly reloaded certificate 1: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
DO_TEST (hi_signed_2nd, 1);
|
|
DO_TEST (hi_signed, 0);
|
|
DO_TEST (hi_double, 1);
|
|
|
|
/* Remove the certificate #2. */
|
|
err = (cmd_distrust->func) (cmd_distrust, 1, trust_args2);
|
|
grub_test_assert ((err == GRUB_ERR_NONE || err == GRUB_ERR_EXISTS),
|
|
"distrusting certificate 2 failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
DO_TEST (hi_signed_2nd, 0);
|
|
DO_TEST (hi_signed, 0);
|
|
DO_TEST (hi_double, 0);
|
|
|
|
/* Now reload certificate #2. */
|
|
err = (cmd_trust->func) (cmd_trust, 1, trust_args2);
|
|
grub_test_assert (err != GRUB_ERR_NONE, "unexpectedly reloaded certificate 2: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
DO_TEST (hi_signed_2nd, 0);
|
|
DO_TEST (hi_signed, 0);
|
|
DO_TEST (hi_double, 0);
|
|
|
|
/*
|
|
* Lastly, check a certificate that uses printableString rather than utf8String
|
|
* loads properly, and that a certificate with an appropriate extended key usage
|
|
* loads.
|
|
*/
|
|
err = (cmd_trust->func) (cmd_trust, 1, trust_args_printable);
|
|
grub_test_assert (err == GRUB_ERR_NONE, "trusting printable certificate failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
|
|
err = (cmd_trust->func) (cmd_trust, 1, trust_args_eku);
|
|
grub_test_assert (err == GRUB_ERR_NONE, "trusting certificate with extended key usage failed: %d: %s",
|
|
grub_errno, grub_errmsg);
|
|
|
|
grub_procfs_unregister (&certificate_der_entry);
|
|
grub_procfs_unregister (&certificate2_der_entry);
|
|
grub_procfs_unregister (&certificate_printable_der_entry);
|
|
grub_procfs_unregister (&certificate_eku_der_entry);
|
|
}
|
|
|
|
GRUB_FUNCTIONAL_TEST (appended_signature_test, appended_signature_test);
|