diff options
Diffstat (limited to 'lib/security/common.c')
-rw-r--r-- | lib/security/common.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/lib/security/common.c b/lib/security/common.c new file mode 100644 index 0000000..df04054 --- /dev/null +++ b/lib/security/common.c @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2016 Raptor Engineering, LLC + * Copyright (C) 2018 Opengear, Inc + * + * This program 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; version 2 of the License. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif + +#include <stdbool.h> +#include <stdlib.h> +#include <assert.h> +#include <dirent.h> +#include <string.h> +#include <fcntl.h> +#include <locale.h> +#include <sys/types.h> + +#include <log/log.h> +#include <file/file.h> +#include <talloc/talloc.h> +#include <url/url.h> +#include <util/util.h> +#include <i18n/i18n.h> + +#include "security.h" + +struct pb_url * get_signature_url(void *ctx, struct pb_url *base_file) +{ + struct pb_url *signature_file = NULL; + + signature_file = pb_url_copy(ctx, base_file); + talloc_free(signature_file->file); + signature_file->file = talloc_asprintf(signature_file, + "%s.sig", base_file->file); + talloc_free(signature_file->path); + signature_file->path = talloc_asprintf(signature_file, + "%s.sig", base_file->path); + + return signature_file; +} + +int validate_boot_files(struct boot_task *boot_task) { + int result = 0; + char *kernel_filename = NULL; + char *initrd_filename = NULL; + char *dtb_filename = NULL; + + FILE *authorized_signatures_handle = NULL; + + char cmdline_template[] = "/tmp/petitbootXXXXXX"; + int cmdline_fd = mkstemp(cmdline_template); + FILE *cmdline_handle = NULL; + + const char* local_initrd_signature = (boot_task->verify_signature) ? + boot_task->local_initrd_signature : NULL; + const char* local_dtb_signature = (boot_task->verify_signature) ? + boot_task->local_dtb_signature : NULL; + const char* local_image_signature = (boot_task->verify_signature) ? + boot_task->local_image_signature : NULL; + const char* local_cmdline_signature = + (boot_task->verify_signature || boot_task->decrypt_files) ? + boot_task->local_cmdline_signature : NULL; + + if ((!boot_task->verify_signature) && (!boot_task->decrypt_files)) + return result; + + /* Load authorized signatures file */ + authorized_signatures_handle = fopen(LOCKDOWN_FILE, "r"); + if (!authorized_signatures_handle) { + pb_log("%s: unable to read lockdown file\n", __func__); + return KEXEC_LOAD_SIG_SETUP_INVALID; + } + + /* Copy files to temporary directory for verification / boot */ + result = copy_file_secure_dest(boot_task, + boot_task->local_image, + &kernel_filename); + if (result) { + pb_log("%s: image copy failed: (%d)\n", + __func__, result); + return result; + } + if (boot_task->local_initrd) { + result = copy_file_secure_dest(boot_task, + boot_task->local_initrd, + &initrd_filename); + if (result) { + pb_log("%s: initrd copy failed: (%d)\n", + __func__, result); + return result; + } + } + if (boot_task->local_dtb) { + result = copy_file_secure_dest(boot_task, + boot_task->local_dtb, + &dtb_filename); + if (result) { + pb_log("%s: dtb copy failed: (%d)\n", + __func__, result); + return result; + } + } + boot_task->local_image_override = talloc_strdup(boot_task, + kernel_filename); + if (boot_task->local_initrd) + boot_task->local_initrd_override = talloc_strdup(boot_task, + initrd_filename); + if (boot_task->local_dtb) + boot_task->local_dtb_override = talloc_strdup(boot_task, + dtb_filename); + + /* Write command line to temporary file for verification */ + if (cmdline_fd < 0) { + /* mkstemp failed */ + pb_log("%s: failed: unable to create command line" + " temporary file for verification\n", + __func__); + result = -1; + } + else { + cmdline_handle = fdopen(cmdline_fd, "w"); + } + if (!cmdline_handle) { + /* Failed to open file */ + pb_log("%s: failed: unable to write command line" + " temporary file for verification\n", + __func__); + result = -1; + } + else { + fwrite(boot_task->args, sizeof(char), + strlen(boot_task->args), cmdline_handle); + fflush(cmdline_handle); + } + + if (boot_task->verify_signature) { + /* Check signatures */ + if (verify_file_signature(kernel_filename, + local_image_signature, + authorized_signatures_handle, + KEYRING_PATH)) + result = KEXEC_LOAD_SIGNATURE_FAILURE; + if (verify_file_signature(cmdline_template, + local_cmdline_signature, + authorized_signatures_handle, + KEYRING_PATH)) + result = KEXEC_LOAD_SIGNATURE_FAILURE; + + if (boot_task->local_initrd_signature) + if (verify_file_signature(initrd_filename, + local_initrd_signature, + authorized_signatures_handle, + KEYRING_PATH)) + result = KEXEC_LOAD_SIGNATURE_FAILURE; + if (boot_task->local_dtb_signature) + if (verify_file_signature(dtb_filename, + local_dtb_signature, + authorized_signatures_handle, + KEYRING_PATH)) + result = KEXEC_LOAD_SIGNATURE_FAILURE; + + /* Clean up */ + if (cmdline_handle) { + fclose(cmdline_handle); + unlink(cmdline_template); + } + fclose(authorized_signatures_handle); + } else if (boot_task->decrypt_files) { + /* Decrypt files */ + if (decrypt_file(kernel_filename, + authorized_signatures_handle, + KEYRING_PATH)) + result = KEXEC_LOAD_DECRYPTION_FALURE; + if (verify_file_signature(cmdline_template, + local_cmdline_signature, + authorized_signatures_handle, + KEYRING_PATH)) + result = KEXEC_LOAD_SIGNATURE_FAILURE; + if (boot_task->local_initrd) + if (decrypt_file(initrd_filename, + authorized_signatures_handle, + KEYRING_PATH)) + result = KEXEC_LOAD_DECRYPTION_FALURE; + if (boot_task->local_dtb) + if (decrypt_file(dtb_filename, + authorized_signatures_handle, + KEYRING_PATH)) + result = KEXEC_LOAD_DECRYPTION_FALURE; + + /* Clean up */ + if (cmdline_handle) { + fclose(cmdline_handle); + unlink(cmdline_template); + } + fclose(authorized_signatures_handle); + } + + return result; +} + +void validate_boot_files_cleanup(struct boot_task *boot_task) { + if ((boot_task->verify_signature) || (boot_task->decrypt_files)) { + unlink(boot_task->local_image_override); + if (boot_task->local_initrd_override) + unlink(boot_task->local_initrd_override); + if (boot_task->local_dtb_override) + unlink(boot_task->local_dtb_override); + + talloc_free(boot_task->local_image_override); + if (boot_task->local_initrd_override) + talloc_free(boot_task->local_initrd_override); + if (boot_task->local_dtb_override) + talloc_free(boot_task->local_dtb_override); + } +} + |