Introducing the following db and dbx commands 1. append_list_db: It will show the list of trusted certificates and binary hashes 2. append_list_dbx: It will show the list of distrusted certificates and binary/certificate hashes 3. append_add_db_cert: It will add the trusted certificate to the db list 4. append_add_db_sig: It will add the certificate/binary hash to the db list 5. append_rm_dbx_cert: It will remove the trusted certificate from the db list 6. append_add_dbx_sig: It will add the certificate/binary hash to the dbx list
Note:- The addition/deletion of trusted certificates and binary hashes are not allowed in GRUB command prompt while secure boot is enabled. Signed-off-by: Sudhakar Kuppusamy <sudha...@linux.ibm.com> Reviewed-by: Avnish Chouhan <avn...@linux.ibm.com> --- grub-core/commands/appendedsig/appendedsig.c | 351 +++++++++++++++---- 1 file changed, 286 insertions(+), 65 deletions(-) diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c index 1356babaf..f25e4734b 100644 --- a/grub-core/commands/appendedsig/appendedsig.c +++ b/grub-core/commands/appendedsig/appendedsig.c @@ -102,6 +102,38 @@ static enum CHECK_SIGS_FORCED = 2 } check_sigs = CHECK_SIGS_NO; +enum +{ + OPTION_BINARY_HASH = 0, + OPTION_CERT_HASH = 1 +}; + +static const struct grub_arg_option options[] = +{ + {"binary-hash", 'b', 0, N_("hash file of the binary."), 0, ARG_TYPE_NONE}, + {"cert-hash", 'c', 1, N_("hash file of the certificate."), 0, ARG_TYPE_NONE}, + {0, 0, 0, 0, 0, 0} +}; + +static void +print_hex (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\t "); + count = 0; + } + } + + grub_printf ("%02x\n", data[i]); +} + /* * GUID can be used to determine the hashing function and * generate the hash using determined hashing function. @@ -634,37 +666,203 @@ grub_cmd_verify_signature (grub_command_t cmd __attribute__ ((unused)), int argc { grub_file_t signed_file; grub_err_t err; - grub_uint8_t *data; - grub_size_t file_size; + grub_uint8_t *signed_data; + grub_size_t signed_size; if (argc != 1) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "one argument expected."); + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "a signed file is expected.\nExample:\n\tappend_verify <SIGNED FILE>\n"); 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_BAD_FILE_TYPE, "could not open %s file.", args[0]); + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "could not open %s file.", args[0]); - err = file_read_all (signed_file, &data, &file_size); + err = file_read_all (signed_file, &signed_data, &signed_size); if (err == GRUB_ERR_NONE) - err = grub_verify_appended_signature (data, file_size); + err = grub_verify_appended_signature (signed_data, signed_size); grub_file_close (signed_file); - grub_free (data); + grub_free (signed_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_size_t i, cert_num = 1; + + for (cert = db.certs; cert; cert = cert->next) + { + grub_printf ("trusted X.509 certificate %" PRIuGRUB_SIZE ":\n", cert_num); + grub_printf ("\tserial: "); + + 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 ("\tCN: %s\n\n", cert->subject); + cert_num++; + } + + for (i = 0; i < db.signature_entries; i++) + { + grub_printf ("trusted binary hash %" PRIuGRUB_SIZE ":\n", i + 1); + grub_printf ("\thash: "); + print_hex (db.signatures[i], db.signature_size[i]); + } + + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_list_dbx (grub_command_t cmd __attribute__((unused)), + int argc __attribute__((unused)), char **args __attribute__((unused))) +{ + struct x509_certificate *cert; + grub_size_t i, cert_num = 1; + + for (cert = dbx.certs; cert; cert = cert->next) + { + grub_printf ("distrusted X.509 certificate %" PRIuGRUB_SIZE ":\n", cert_num); + grub_printf ("\tserial: "); + + 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 ("\tCN: %s\n\n", cert->subject); + cert_num++; + } + + for (i = 0; i < dbx.signature_entries; i++) + { + grub_printf ("distrusted certificate/binary hash %" PRIuGRUB_SIZE ":\n", i + 1); + grub_printf ("\thash: "); + print_hex (dbx.signatures[i], dbx.signature_size[i]); + } + + return GRUB_ERR_NONE; +} + +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; + struct x509_certificate *cert; + + 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 <CERT FILE>\n"); + + if (check_sigs == CHECK_SIGS_FORCED) + return grub_error (GRUB_ERR_ACCESS_DENIED, + "since secure boot is enabled, " + "adding of trusted X.509 certificate is not permitted!\n"); + + if (grub_strlen (args[0]) == 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_FILE_NOT_FOUND, + "unable to open the trusted X.509 certificate file."); + + cert = grub_zalloc (sizeof (struct x509_certificate)); + if (cert == NULL) + return grub_error (GRUB_ERR_OUT_OF_MEMORY, "could not allocate memory for certificate."); + + err = read_cert_from_file (cert_file, cert); + grub_file_close (cert_file); + if (err != GRUB_ERR_NONE) + { + grub_free (cert); + return err; + } + + grub_dprintf ("appendedsig", "added the certificate with CN: %s\n", cert->subject); + + cert->next = db.certs; + db.certs = cert; + db.cert_entries++; return err; } static grub_err_t -grub_cmd_dbx (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) +grub_cmd_db_sig (grub_command_t cmd __attribute__((unused)), int argc, char**args) +{ + grub_err_t rc; + grub_file_t hash_file; + grub_uint8_t *hash_data = NULL; + grub_size_t hash_data_size = 0; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "a trusted binary hash file is expected.\n" + "Example:\n\tappend_add_db_sig <BINARY HASH FILE>\n"); + + if (check_sigs == CHECK_SIGS_FORCED) + return grub_error (GRUB_ERR_ACCESS_DENIED, + "since secure boot is enabled, " + "adding of trusted binary hash is not permitted.\n"); + + if (grub_strlen (args[0]) == 0) + return grub_error (GRUB_ERR_BAD_FILENAME, "missing trusted binary hash file."); + + hash_file = grub_file_open (args[0], GRUB_FILE_TYPE_TO_HASH | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (hash_file == NULL) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "unable to open the trusted binary hash file."); + + rc = file_read_all (hash_file, &hash_data, &hash_data_size); + grub_file_close (hash_file); + if (rc == GRUB_ERR_NONE) + { + grub_dprintf ("appendedsig", + "adding a trusted binary hash %s\n with size of %" PRIuGRUB_SIZE "\n", + hash_data, hash_data_size); + + /* Only accept SHA256, SHA384 and SHA512 binary hash */ + if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64) + return grub_error (GRUB_ERR_BAD_SIGNATURE, "unacceptable trusted binary hash type."); + + rc = add_hash ((const grub_uint8_t **) &hash_data, hash_data_size, &db.signatures, + &db.signature_size, &db.signature_entries); + grub_free (hash_data); + if (rc != GRUB_ERR_NONE) + { + free_db_list (); + free_dbx_list (); + return grub_error (rc, "adding of trusted binary hash failed."); + } + } + + return rc; +} + +static grub_err_t +grub_cmd_dbx_cert (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { unsigned long cert_num, i = 0; const char *end; struct x509_certificate *cert, *prev_cert; if (argc != 1) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "one argument expected."); + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "a distrusted certificate number is expected.\n" + "Example:\n\tappend_rm_dbx_cert <CERT NUMBER>\n"); + + if (check_sigs == CHECK_SIGS_FORCED) + return grub_error (GRUB_ERR_ACCESS_DENIED, + "since secure boot is enabled, " + "removing of distrusted X.509 certificate is not permitted.\n"); cert_num = grub_strtoul (args[0], &end, 10); if (*(args[0]) == '\0' || *end != '\0') @@ -703,62 +901,69 @@ grub_cmd_dbx (grub_command_t cmd __attribute__ ((unused)), int argc, char **args } static grub_err_t -grub_cmd_db (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) +grub_cmd_dbx_sig (grub_extcmd_context_t ctxt, int argc, char **args) { - grub_file_t certf; - struct x509_certificate *cert = NULL; - grub_err_t err; - - if (argc != 1) - return grub_error (GRUB_ERR_BAD_ARGUMENT, "one argument expected."); - - certf = grub_file_open (args[0], GRUB_FILE_TYPE_CERTIFICATE_TRUST | GRUB_FILE_TYPE_NO_DECOMPRESS); - if (certf == NULL) - return grub_error (GRUB_ERR_BAD_FILE_TYPE, "could not open %s file.", args[0]); + grub_err_t rc; + grub_file_t hash_file = NULL; + grub_uint8_t *hash_data = NULL; + grub_size_t hash_data_size = 0; - cert = grub_zalloc (sizeof (struct x509_certificate)); - if (cert == NULL) - return grub_error (GRUB_ERR_OUT_OF_MEMORY, "could not allocate memory for certificate."); + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "a distrusted certificate/binary hash file is expected\n" + "Example:\n\tappend_rm_dbx_sig [option] <FILE>\n" + "option:\n[-b|--binary-hash] FILE [BINARY HASH FILE]\n" + "[-c|--cert-hash] FILE [CERTFICATE HASH FILE]\n"); - err = read_cert_from_file (certf, cert); - grub_file_close (certf); - if (err != GRUB_ERR_NONE) - { - grub_free (cert); - return err; - } + if (check_sigs == CHECK_SIGS_FORCED) + return grub_error (GRUB_ERR_ACCESS_DENIED, + "since secure boot is enabled, " + "adding of distrusted certificate/binary hash is not permitted!\n"); - grub_dprintf ("appendedsig", "loaded certificate with CN: %s\n", cert->subject); + if (!ctxt->state[OPTION_BINARY_HASH].set && !ctxt->state[OPTION_CERT_HASH].set) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing options and use --help to konw."); - cert->next = db.certs; - db.certs = cert; - db.cert_entries++; + if (grub_strlen (args[1]) == 0) + return grub_error (GRUB_ERR_BAD_FILENAME, "missing distrusted certificate/binary hash file."); - return GRUB_ERR_NONE; -} + hash_file = grub_file_open (args[1], GRUB_FILE_TYPE_TO_HASH | GRUB_FILE_TYPE_NO_DECOMPRESS); + if (hash_file == NULL) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, + "unable to open the distrusted certificate/binary hash file."); -static grub_err_t -grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), - char **args __attribute__ ((unused))) -{ - struct x509_certificate *cert; - int cert_num = 1; - grub_size_t i; - - for (cert = db.certs; cert != NULL; cert = cert->next) + rc = file_read_all (hash_file, &hash_data, &hash_data_size); + grub_file_close (hash_file); + if (rc == GRUB_ERR_NONE) { - grub_printf ("Certificate %d:\n", cert_num); - grub_printf ("\tSerial: "); + grub_dprintf ("appendedsig", + "adding a distrusted certificate/binary hash %s\n" + " with size of %" PRIuGRUB_SIZE "\n", hash_data, hash_data_size); - for (i = 0; i < cert->serial_len - 1; i++) - grub_printf ("%02x:", cert->serial[i]); + if (ctxt->state[OPTION_BINARY_HASH].set) + { + /* Only accept SHA256, SHA384 and SHA512 binary hash */ + if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64) + return grub_error (GRUB_ERR_BAD_SIGNATURE, "unacceptable distrusted binary hash type."); + } + else if (ctxt->state[OPTION_CERT_HASH].set) + { + /* Only accept SHA256, SHA384 and SHA512 certificate hash */ + if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64) + return grub_error (GRUB_ERR_BAD_SIGNATURE, "unacceptable distrusted certificate hash type."); + } - grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]); - grub_printf ("\tCN: %s\n\n", cert->subject); - cert_num++; + rc = add_hash ((const grub_uint8_t **) &hash_data, hash_data_size, &dbx.signatures, + &dbx.signature_size, &dbx.signature_entries); + grub_free (hash_data); + if (rc != GRUB_ERR_NONE) + { + free_db_list (); + free_dbx_list (); + return grub_error (rc, "adding of distrusted binary/certificate hash failed."); + } } - return GRUB_ERR_NONE; + return rc; } static grub_err_t @@ -834,8 +1039,6 @@ static struct grub_fs pseudo_fs = { .fs_read = pseudo_read }; -static grub_command_t cmd_verify, cmd_list, cmd_dbx, cmd_db; - /* Check the certificate hash presence in the dbx list. */ static bool is_dbx_cert_hash (const grub_uint8_t *data, const grub_size_t data_size) @@ -1102,6 +1305,10 @@ load_static_keys (const struct grub_module_header *header, const bool is_pks) return rc; } +static grub_extcmd_t cmd_dbx_sig; +static grub_command_t cmd_verify, cmd_list_db, cmd_db_cert, cmd_db_sig, + cmd_list_dbx, cmd_dbx_cert; + GRUB_MOD_INIT (appendedsig) { int rc; @@ -1164,14 +1371,25 @@ GRUB_MOD_INIT (appendedsig) grub_pks_free_keystore (); } - cmd_db = grub_register_command ("append_add_db_cert", grub_cmd_db, N_("X509_CERTIFICATE"), - N_("Add trusted X509_CERTIFICATE to the db")); - cmd_list = grub_register_command ("append_list_db", grub_cmd_list, 0, - N_("Show the list of trusted X.509 certificates from the db")); + cmd_db_cert = grub_register_command ("append_add_db_cert", grub_cmd_db_cert, N_("X509_CERTIFICATE"), + N_("Add X509_CERTIFICATE to the db list.")); + cmd_db_sig = grub_register_command ("append_add_db_sig", grub_cmd_db_sig, N_("BINARY HASH FILE"), + N_("Add trusted BINARY HASH to the db list.")); + cmd_dbx_cert = grub_register_command ("append_rm_dbx_cert", grub_cmd_dbx_cert, N_("CERT_NUMBER"), + N_("Remove CERT_NUMBER (as listed by append_list_db) from the db")); + cmd_dbx_sig = grub_register_extcmd ("append_add_dbx_sig", grub_cmd_dbx_sig, 0, + N_("[-b|--binary-hash] FILE [BINARY HASH FILE]\n" + "[-c|--cert-hash] FILE [CERTFICATE HASH FILE]"), + N_("Add distrusted CERTFICATE/BINARY HASH to the db list."), options); + cmd_list_db = grub_register_command ("append_list_db", grub_cmd_list_db, 0, + N_("Show the list of trusted x509 certificates and" + " trusted binary hashes from the db list.")); + cmd_list_dbx = grub_register_command ("append_list_dbx", grub_cmd_list_dbx, 0, + N_("Show the list of distrusted certificates and" + " certificate/binary hashes from the dbx list")); cmd_verify = grub_register_command ("append_verify", grub_cmd_verify_signature, N_("FILE"), - N_("Verify FILE against the trusted X.509 certificates in the db")); - cmd_dbx = grub_register_command ("append_rm_dbx_cert", grub_cmd_dbx, N_("CERT_NUMBER"), - N_("Remove CERT_NUMBER (as listed by append_list_db) from the db")); + N_("Verify FILE against the trusted x509 certificates/" + "trusted binary hashes.")); grub_verifier_register (&grub_appendedsig_verifier); grub_dl_set_persistent (mod); @@ -1185,7 +1403,10 @@ GRUB_MOD_FINI (appendedsig) */ grub_verifier_unregister (&grub_appendedsig_verifier); grub_unregister_command (cmd_verify); - grub_unregister_command (cmd_list); - grub_unregister_command (cmd_db); - grub_unregister_command (cmd_dbx); + grub_unregister_command (cmd_list_db); + grub_unregister_command (cmd_list_dbx); + grub_unregister_command (cmd_db_cert); + grub_unregister_command (cmd_db_sig); + grub_unregister_command (cmd_dbx_cert); + grub_unregister_extcmd (cmd_dbx_sig); } -- 2.39.5 (Apple Git-154) _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel