From bd29992e580e9a48dc698e2e108c73b51a98f05f Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Wed, 9 Jan 2013 15:44:42 +0800 Subject: [PATCH 1/9] Use getopt() to parse options --- src/mokutil.c | 259 +++++++++++++++++++++++++++------------------------------ 1 file changed, 124 insertions(+), 135 deletions(-) diff --git a/src/mokutil.c b/src/mokutil.c index ea8481a..2ab005c 100644 --- a/src/mokutil.c +++ b/src/mokutil.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,20 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, #define PASSWORD_MAX 16 #define PASSWORD_MIN 8 +#define HELP 0x1 +#define LIST_ENROLLED 0x2 +#define LIST_NEW 0x4 +#define IMPORT 0x8 +#define DELETE 0x10 +#define REVOKE 0x20 +#define EXPORT 0x40 +#define PASSWORD 0x80 +#define DISABLE_VALIDATION 0x100 +#define ENABLE_VALIDATION 0x200 +#define SB_STATE 0x400 +#define TEST_KEY 0x800 +#define RESET 0x1000 + typedef struct { uint32_t mok_size; void *mok; @@ -30,21 +45,6 @@ typedef struct { uint16_t password[PASSWORD_MAX]; } MokSBVar; -enum Command { - COMMAND_LIST_ENROLLED, - COMMAND_LIST_NEW, - COMMAND_IMPORT, - COMMAND_DELETE, - COMMAND_REVOKE, - COMMAND_EXPORT, - COMMAND_PASSWORD, - COMMAND_DISABLE_VALIDATION, - COMMAND_ENABLE_VALIDATION, - COMMAND_SB_STATE, - COMMAND_TEST_KEY, - COMMAND_RESET, -}; - static void print_help () { @@ -80,7 +80,7 @@ print_help () printf(" mokutil --sb-state\n\n"); printf("Test if the key is enrolled or not:\n"); - printf(" mokutil --test-key\n\n"); + printf(" mokutil --test-key \n\n"); printf("Reset MOK list:\n"); printf(" mokutil --reset\n\n"); @@ -998,163 +998,152 @@ main (int argc, char *argv[]) { char **files = NULL; char *key_file = NULL; - int i, total; - int command; + const char *option; + int c, i, f_ind, total = 0; + unsigned int command = 0; int ret = -1; - if (argc < 2) { - print_help (); - return 0; - } - - if (strcmp (argv[1], "-h") == 0 || - strcmp (argv[1], "--help") == 0) { - - print_help (); - return 0; - - } else if (strcmp (argv[1], "-le") == 0 || - strcmp (argv[1], "--list-enrolled") == 0) { - - command = COMMAND_LIST_ENROLLED; - - } else if (strcmp (argv[1], "-ln") == 0 || - strcmp (argv[1], "--list-new") == 0) { - - command = COMMAND_LIST_NEW; - - } else if (strcmp (argv[1], "-i") == 0 || - strcmp (argv[1], "--import") == 0) { - - if (argc < 3) { - print_help (); - return -1; - } - total = argc - 2; - - files = malloc (total * sizeof(char *)); - if (!files) { - fprintf (stderr, "Failed to allocate file list\n"); - return -1; - } - - for (i = 0; i < total; i++) - files[i] = argv[i+2]; - - command = COMMAND_IMPORT; - - } else if (strcmp (argv[1], "-d") == 0 || - strcmp (argv[1], "--delete") == 0) { - - if (argc < 3) { - print_help (); - return -1; - } - total = argc - 2; - - files = malloc (total * sizeof(char *)); - if (!files) { - fprintf (stderr, "Failed to allocate file list\n"); - return -1; - } - - for (i = 0; i < total; i++) - files[i] = argv[i+2]; - - command = COMMAND_DELETE; - - } else if (strcmp (argv[1], "-r") == 0 || - strcmp (argv[1], "--revoke") == 0) { - - command = COMMAND_REVOKE; - - } else if (strcmp (argv[1], "-x") == 0 || - strcmp (argv[1], "--export") == 0) { - - command = COMMAND_EXPORT; - - } else if (strcmp (argv[1], "-p") == 0 || - strcmp (argv[1], "--password") == 0) { - - command = COMMAND_PASSWORD; - - } else if (strcmp (argv[1], "--disable-validation") == 0) { - - command = COMMAND_DISABLE_VALIDATION; - - } else if (strcmp (argv[1], "--enable-validation") == 0) { - - command = COMMAND_ENABLE_VALIDATION; - - } else if (strcmp (argv[1], "--sb-state") == 0) { + while (1) { + static struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"list-enrolled", no_argument, 0, 0 }, + {"list-new", no_argument, 0, 0 }, + {"import", required_argument, 0, 'i'}, + {"delete", required_argument, 0, 'd'}, + {"revoke", no_argument, 0, 0 }, + {"export", no_argument, 0, 'x'}, + {"password", no_argument, 0, 'p'}, + {"disable-validation", no_argument, 0, 0 }, + {"enable-validation", no_argument, 0, 0 }, + {"sb-state", no_argument, 0, 0 }, + {"test-key", required_argument, 0, 't'}, + {"reset", no_argument, 0, 0 }, + {0, 0, 0, 0} + }; + + int option_index = 0; + c = getopt_long (argc, argv, "d:hi:pt:x", + long_options, &option_index); + + if (c == -1) + break; - command = COMMAND_SB_STATE; + switch (c) { + case 0: + option = long_options[option_index].name; + if (strcmp (option, "list-enrolled") == 0) { + command |= LIST_ENROLLED; + } else if (strcmp (option, "list-new") == 0) { + command |= LIST_NEW; + } else if (strcmp (option, "revoke") == 0) { + command |= REVOKE; + } else if (strcmp (option, "disable-validation") == 0) { + command |= DISABLE_VALIDATION; + } else if (strcmp (option, "enable-validation") == 0) { + command |= ENABLE_VALIDATION; + } else if (strcmp (option, "sb-state") == 0) { + command |= SB_STATE; + } else if (strcmp (option, "reset") == 0) { + command |= RESET; + } + break; + case 'd': + case 'i': + if (c == 'd') + command |= DELETE; + else + command |= IMPORT; + + if (files) { + command |= HELP; + break; + } + + total = 0; + for (f_ind = optind - 1; + f_ind < argc && *argv[f_ind] != '-'; + f_ind++) { + total++; + } + + files = malloc (total * sizeof (char *)); + for (i = 0; i < total; i++) { + f_ind = i + optind - 1; + files[i] = malloc (strlen(argv[f_ind]) + 1); + strcpy (files[i], argv[f_ind]); + } - } else if (strcmp (argv[1], "--test-key") == 0) { + break; + case 'p': + command |= PASSWORD; + break; + case 't': + key_file = strdup (optarg); - if (argc < 3) { - print_help (); - return -1; + command |= TEST_KEY; + break; + case 'x': + command |= EXPORT; + break; + case 'h': + case '?': + command |= HELP; + break; + default: + abort (); } - - key_file = argv[2]; - - command = COMMAND_TEST_KEY; - - } else if (strcmp (argv[1], "--reset") == 0) { - - command = COMMAND_RESET; - - } else { - fprintf (stderr, "Unknown argument: %s\n\n", argv[1]); - print_help (); - return -1; } switch (command) { - case COMMAND_LIST_ENROLLED: + case LIST_ENROLLED: ret = list_enrolled_keys (); break; - case COMMAND_LIST_NEW: + case LIST_NEW: ret = list_new_keys (); break; - case COMMAND_IMPORT: + case IMPORT: ret = import_moks (files, total); break; - case COMMAND_DELETE: + case DELETE: ret = delete_moks (files, total); break; - case COMMAND_REVOKE: + case REVOKE: ret = revoke_request (); break; - case COMMAND_EXPORT: + case EXPORT: ret = export_moks (); break; - case COMMAND_PASSWORD: + case PASSWORD: ret = set_password (); break; - case COMMAND_DISABLE_VALIDATION: + case DISABLE_VALIDATION: ret = disable_validation (); break; - case COMMAND_ENABLE_VALIDATION: + case ENABLE_VALIDATION: ret = enable_validation (); break; - case COMMAND_SB_STATE: + case SB_STATE: ret = sb_state (); break; - case COMMAND_TEST_KEY: + case TEST_KEY: ret = test_key (key_file); break; - case COMMAND_RESET: + case RESET: ret = reset_moks (); break; default: - fprintf (stderr, "Unknown command\n"); + print_help (); break; } - if (files) + if (files) { + for (i = 0; i < total; i++) + free (files[i]); free (files); + } + + if (key_file) + free (key_file); return ret; } -- 1.7.10.4 From 32a919cd2ca89ea0dfcc7644c05a3cf88cbb13c4 Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Wed, 9 Jan 2013 17:37:30 +0800 Subject: [PATCH 2/9] Adopt new password hash format old format: MokNew + sha256sum(MokNew + password) new format: salt + sha256sum(salt + password) The new format makes a preset hash possible. --- src/mokutil.c | 102 ++++++++++++++++++++------------------------------------- 1 file changed, 35 insertions(+), 67 deletions(-) diff --git a/src/mokutil.c b/src/mokutil.c index 2ab005c..61c432d 100644 --- a/src/mokutil.c +++ b/src/mokutil.c @@ -20,6 +20,8 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, #define PASSWORD_MAX 16 #define PASSWORD_MIN 8 +#define SALT_SIZE 16 + #define HELP 0x1 #define LIST_ENROLLED 0x2 #define LIST_NEW 0x4 @@ -366,8 +368,19 @@ error: return ret; } +static void +generate_salt (uint8_t salt[], unsigned int salt_len) +{ + int i; + + srand (time (NULL)); + + for (i = 0; i < salt_len; i++) + salt[i] = rand() % 256; +} + static int -generate_auth (void *new_list, unsigned long list_len, char *password, +generate_hash (void *salt, unsigned int salt_len, char *password, int pw_len, uint8_t *auth) { efi_char16_t efichar_pass[PASSWORD_MAX+1]; @@ -382,8 +395,8 @@ generate_auth (void *new_list, unsigned long list_len, char *password, SHA256_Init (&ctx); - if (new_list) - SHA256_Update (&ctx, new_list, list_len); + if (salt) + SHA256_Update (&ctx, salt, salt_len); SHA256_Update (&ctx, efichar_pass, efichar_len); @@ -397,7 +410,9 @@ update_request (void *new_list, int list_len, uint8_t import) { efi_variable_t var; const char *req_name, *auth_name; - uint8_t auth[SHA256_DIGEST_LENGTH]; + uint8_t salt[SALT_SIZE]; + uint8_t hash[SHA256_DIGEST_LENGTH]; + uint8_t auth[SALT_SIZE + SHA256_DIGEST_LENGTH]; char *password = NULL; int pw_len; int ret = -1; @@ -415,7 +430,13 @@ update_request (void *new_list, int list_len, uint8_t import) goto error; } - generate_auth (new_list, list_len, password, pw_len, auth); + generate_salt (salt, SALT_SIZE); + if (generate_hash (salt, SALT_SIZE, password, pw_len, hash) < 0) { + fprintf (stderr, "Couldn't generate hash\n"); + goto error; + } + memcpy (auth, salt, SALT_SIZE); + memcpy (auth + SALT_SIZE, hash, SHA256_DIGEST_LENGTH); if (new_list) { /* Write MokNew*/ @@ -439,7 +460,7 @@ update_request (void *new_list, int list_len, uint8_t import) /* Write MokAuth */ var.Data = auth; - var.DataSize = SHA256_DIGEST_LENGTH; + var.DataSize = SHA256_DIGEST_LENGTH + SALT_SIZE; var.VariableName = auth_name; var.VendorGuid = SHIM_LOCK_GUID; @@ -545,57 +566,6 @@ is_valid_request (void *mok, uint32_t mok_size, uint8_t import) } static int -verify_old_req (void *old_req, unsigned long old_req_size, uint8_t import) -{ - efi_variable_t req_auth; - const char *auth_name; - uint8_t auth[SHA256_DIGEST_LENGTH]; - char *password = NULL; - int pw_len, fail = 0; - size_t n; - int ret = 0; - - if (import) - auth_name = "MokAuth"; - else - auth_name = "MokDelAuth"; - - memset (&req_auth, 0, sizeof(req_auth)); - req_auth.VariableName = auth_name; - req_auth.VendorGuid = SHIM_LOCK_GUID; - if (read_variable (&req_auth) != EFI_SUCCESS) { - fprintf (stderr, "Failed to read %s\n", auth_name); - return 0; - } - - while (fail < 3) { - printf ("input old password: "); - pw_len = read_hidden_line (&password, &n); - printf ("\n"); - - if (pw_len > PASSWORD_MAX || pw_len < PASSWORD_MIN) { - free (password); - fprintf (stderr, "invalid password\n"); - fail++; - continue; - } - - generate_auth (old_req, old_req_size, password, pw_len, auth); - if (memcmp (auth, req_auth.Data, SHA256_DIGEST_LENGTH) == 0) { - ret = 1; - break; - } - - fail++; - } - - if (req_auth.Data) - free (req_auth.Data); - - return ret; -} - -static int issue_mok_request (char **files, uint32_t total, uint8_t import) { efi_variable_t old_req; @@ -705,11 +675,6 @@ issue_mok_request (char **files, uint32_t total, uint8_t import) /* append the keys to the previous request */ if (old_req.Data) { - /* request the previous password to verify the keys */ - if (!verify_old_req (old_req.Data, old_req.DataSize, import)) { - goto error; - } - memcpy (new_list + real_size, old_req.Data, old_req.DataSize); real_size += old_req.DataSize; } @@ -745,8 +710,6 @@ delete_moks (char **files, uint32_t total) static int revoke_request () { - /* TODO request the old password? */ - if (test_and_delete_var ("MokNew") < 0) return -1; @@ -814,7 +777,9 @@ static int set_password () { efi_variable_t var; - uint8_t auth[SHA256_DIGEST_LENGTH]; + uint8_t salt[SALT_SIZE]; + uint8_t hash[SHA256_DIGEST_LENGTH]; + uint8_t auth[SHA256_DIGEST_LENGTH + SALT_SIZE]; char *password = NULL; int pw_len; int ret = -1; @@ -824,13 +789,16 @@ set_password () goto error; } - if (generate_auth (NULL, 0, password, pw_len, auth) < 0) { + generate_salt (salt, SALT_SIZE); + if (generate_hash (salt, SALT_SIZE, password, pw_len, hash) < 0) { fprintf (stderr, "Couldn't generate hash\n"); goto error; } + memcpy (auth, salt, SALT_SIZE); + memcpy (auth + SALT_SIZE, hash, SHA256_DIGEST_LENGTH); var.Data = auth; - var.DataSize = SHA256_DIGEST_LENGTH; + var.DataSize = SHA256_DIGEST_LENGTH + SALT_SIZE; var.VariableName = "MokPW"; var.VendorGuid = SHIM_LOCK_GUID; -- 1.7.10.4 From 326082d300337b347ae2cc42808ce905dd92eb3b Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Wed, 9 Jan 2013 17:59:01 +0800 Subject: [PATCH 3/9] Close the key file --- src/mokutil.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mokutil.c b/src/mokutil.c index 61c432d..86d5328 100644 --- a/src/mokutil.c +++ b/src/mokutil.c @@ -947,6 +947,8 @@ error: if (key) free (key); + close (fd); + return ret; } -- 1.7.10.4 From 97d977246991f750827764fb48662c8be4b40f78 Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Thu, 10 Jan 2013 17:07:36 +0800 Subject: [PATCH 4/9] Get rid of misused while statement --- src/mokutil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mokutil.c b/src/mokutil.c index 86d5328..36783cb 100644 --- a/src/mokutil.c +++ b/src/mokutil.c @@ -784,7 +784,7 @@ set_password () int pw_len; int ret = -1; - while (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { + if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { fprintf (stderr, "Abort\n"); goto error; } @@ -828,7 +828,7 @@ set_validation (uint32_t state) efi_char16_t efichar_pass[PASSWORD_MAX]; int ret = -1; - while (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { + if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { fprintf (stderr, "Abort\n"); goto error; } -- 1.7.10.4 From ca1978555253562c4ad39ff8b050cbbbe485474b Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Thu, 10 Jan 2013 17:24:58 +0800 Subject: [PATCH 5/9] Read the password hash from the file --- src/mokutil.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 127 insertions(+), 31 deletions(-) diff --git a/src/mokutil.c b/src/mokutil.c index 36783cb..4b9002e 100644 --- a/src/mokutil.c +++ b/src/mokutil.c @@ -35,6 +35,7 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, #define SB_STATE 0x400 #define TEST_KEY 0x800 #define RESET 0x1000 +#define HASH_FILE 0x2000 typedef struct { uint32_t mok_size; @@ -406,7 +407,73 @@ generate_hash (void *salt, unsigned int salt_len, char *password, } static int -update_request (void *new_list, int list_len, uint8_t import) +char_to_int (const char c) +{ + if (c >= '0' && c <= '9') + return (c - '0'); + + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + + if (c >= 'a' && c <= 'f') + return (c - 'a' + 10); + + return -1; +} + +static int +read_hex_array (const char *string, char *out, int len) +{ + int i, digit_1, digit_2; + + for (i = 0; i < len; i++) { + digit_1 = char_to_int (string[2*i]); + digit_2 = char_to_int (string[2*i + 1]); + if (digit_1 < 0 || digit_2 < 0) + return -1; + + out[i] = (char)digit_1 * 16 + (char)digit_2; + } + + return 0; +} + +static int +get_hash_from_file (const char *file, void *salt, void *hash) +{ + FILE *fptr; + char salt_string[2*SALT_SIZE]; + char hash_string[2*SHA256_DIGEST_LENGTH]; + + fptr = fopen (file, "r"); + if (fptr == NULL) { + fprintf (stderr, "Failed to open %s\n", file); + return -1; + } + + memset (salt_string, 0, 2*SALT_SIZE); + memset (hash_string, 0, 2*SHA256_DIGEST_LENGTH); + + fscanf (fptr, "%32c.%64c", salt_string, hash_string); + + fclose (fptr); + + if (read_hex_array (salt_string, salt, SALT_SIZE) < 0) { + fprintf (stderr, "Corrupted salt\n"); + return -1; + } + + if (read_hex_array (hash_string, hash, SHA256_DIGEST_LENGTH) < 0) { + fprintf (stderr, "Corrupted hash\n"); + return -1; + } + + return 0; +} + +static int +update_request (void *new_list, int list_len, uint8_t import, + const char *hash_file) { efi_variable_t var; const char *req_name, *auth_name; @@ -425,15 +492,22 @@ update_request (void *new_list, int list_len, uint8_t import) auth_name = "MokDelAuth"; } - if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { - fprintf (stderr, "Abort\n"); - goto error; - } + if (hash_file) { + if (get_hash_from_file (hash_file, salt, hash) < 0) { + fprintf (stderr, "Failed to read hash\n"); + goto error; + } + } else { + if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { + fprintf (stderr, "Abort\n"); + goto error; + } - generate_salt (salt, SALT_SIZE); - if (generate_hash (salt, SALT_SIZE, password, pw_len, hash) < 0) { - fprintf (stderr, "Couldn't generate hash\n"); - goto error; + generate_salt (salt, SALT_SIZE); + if (generate_hash (salt, SALT_SIZE, password, pw_len, hash) < 0) { + fprintf (stderr, "Couldn't generate hash\n"); + goto error; + } } memcpy (auth, salt, SALT_SIZE); memcpy (auth + SALT_SIZE, hash, SHA256_DIGEST_LENGTH); @@ -566,7 +640,8 @@ is_valid_request (void *mok, uint32_t mok_size, uint8_t import) } static int -issue_mok_request (char **files, uint32_t total, uint8_t import) +issue_mok_request (char **files, uint32_t total, uint8_t import, + const char *hash_file) { efi_variable_t old_req; const char *req_name; @@ -679,7 +754,7 @@ issue_mok_request (char **files, uint32_t total, uint8_t import) real_size += old_req.DataSize; } - if (update_request (new_list, real_size, import) < 0) { + if (update_request (new_list, real_size, import, hash_file) < 0) { goto error; } @@ -696,15 +771,15 @@ error: } static int -import_moks (char **files, uint32_t total) +import_moks (char **files, uint32_t total, const char *hash_file) { - return issue_mok_request (files, total, 1); + return issue_mok_request (files, total, 1, hash_file); } static int -delete_moks (char **files, uint32_t total) +delete_moks (char **files, uint32_t total, const char *hash_file) { - return issue_mok_request (files, total, 0); + return issue_mok_request (files, total, 0, hash_file); } static int @@ -774,7 +849,7 @@ error: } static int -set_password () +set_password (const char *hash_file) { efi_variable_t var; uint8_t salt[SALT_SIZE]; @@ -784,15 +859,22 @@ set_password () int pw_len; int ret = -1; - if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { - fprintf (stderr, "Abort\n"); - goto error; - } + if (hash_file) { + if (get_hash_from_file (hash_file, salt, hash) < 0) { + fprintf (stderr, "Failed to read hash\n"); + goto error; + } + } else { + if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { + fprintf (stderr, "Abort\n"); + goto error; + } - generate_salt (salt, SALT_SIZE); - if (generate_hash (salt, SALT_SIZE, password, pw_len, hash) < 0) { - fprintf (stderr, "Couldn't generate hash\n"); - goto error; + generate_salt (salt, SALT_SIZE); + if (generate_hash (salt, SALT_SIZE, password, pw_len, hash) < 0) { + fprintf (stderr, "Couldn't generate hash\n"); + goto error; + } } memcpy (auth, salt, SALT_SIZE); memcpy (auth + SALT_SIZE, hash, SHA256_DIGEST_LENGTH); @@ -953,9 +1035,9 @@ error: } static int -reset_moks () +reset_moks (const char *hash_file) { - if (update_request (NULL, 0, 1)) { + if (update_request (NULL, 0, 1, hash_file)) { fprintf (stderr, "Failed to issue a reset request\n"); return -1; } @@ -968,6 +1050,7 @@ main (int argc, char *argv[]) { char **files = NULL; char *key_file = NULL; + char *hash_file = NULL; const char *option; int c, i, f_ind, total = 0; unsigned int command = 0; @@ -988,11 +1071,12 @@ main (int argc, char *argv[]) {"sb-state", no_argument, 0, 0 }, {"test-key", required_argument, 0, 't'}, {"reset", no_argument, 0, 0 }, + {"hash-file", required_argument, 0, 'f'}, {0, 0, 0, 0} }; int option_index = 0; - c = getopt_long (argc, argv, "d:hi:pt:x", + c = getopt_long (argc, argv, "d:f:hi:pt:x", long_options, &option_index); if (c == -1) @@ -1044,6 +1128,11 @@ main (int argc, char *argv[]) } break; + case 'f': + hash_file = strdup (optarg); + + command |= HASH_FILE; + break; case 'p': command |= PASSWORD; break; @@ -1072,10 +1161,12 @@ main (int argc, char *argv[]) ret = list_new_keys (); break; case IMPORT: - ret = import_moks (files, total); + case IMPORT | HASH_FILE: + ret = import_moks (files, total, hash_file); break; case DELETE: - ret = delete_moks (files, total); + case DELETE | HASH_FILE: + ret = delete_moks (files, total, hash_file); break; case REVOKE: ret = revoke_request (); @@ -1084,7 +1175,8 @@ main (int argc, char *argv[]) ret = export_moks (); break; case PASSWORD: - ret = set_password (); + case PASSWORD | HASH_FILE: + ret = set_password (hash_file); break; case DISABLE_VALIDATION: ret = disable_validation (); @@ -1099,7 +1191,8 @@ main (int argc, char *argv[]) ret = test_key (key_file); break; case RESET: - ret = reset_moks (); + case RESET | HASH_FILE: + ret = reset_moks (hash_file); break; default: print_help (); @@ -1115,5 +1208,8 @@ main (int argc, char *argv[]) if (key_file) free (key_file); + if (hash_file) + free (hash_file); + return ret; } -- 1.7.10.4 From c45ffc0d42c0564cf817a1682c0cbd5be164197d Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Thu, 10 Jan 2013 18:29:17 +0800 Subject: [PATCH 6/9] Add a new command to generate the password hash --- src/mokutil.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/src/mokutil.c b/src/mokutil.c index 4b9002e..fdb1a2b 100644 --- a/src/mokutil.c +++ b/src/mokutil.c @@ -36,6 +36,7 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, #define TEST_KEY 0x800 #define RESET 0x1000 #define HASH_FILE 0x2000 +#define GENERATE_PW_HASH 0x4000 typedef struct { uint32_t mok_size; @@ -1045,12 +1046,65 @@ reset_moks (const char *hash_file) return 0; } +static int +generate_pw_hash (const char *input_pw) +{ + uint8_t salt[SALT_SIZE]; + uint8_t hash[SHA256_DIGEST_LENGTH]; + char *password = NULL; + int pw_len, i, ret = -1; + + if (input_pw) { + pw_len = strlen (input_pw); + if (pw_len > PASSWORD_MAX || pw_len < PASSWORD_MIN) { + fprintf (stderr, "password should be %d~%d characters\n", + PASSWORD_MIN, PASSWORD_MAX); + return -1; + } + + password = strdup (input_pw); + + if (!password) { + fprintf (stderr, "Failed to duplicate string\n"); + return -1; + } + } else { + if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { + fprintf (stderr, "Abort\n"); + return -1; + } + } + + generate_salt (salt, SALT_SIZE); + if (generate_hash (salt, SALT_SIZE, password, pw_len, hash) < 0) { + fprintf (stderr, "Couldn't generate hash\n"); + goto error; + } + + /* Print the salt and hash */ + for (i = 0; i < SALT_SIZE; i++) { + printf ("%x%x", salt[i]/16, salt[i]%16); + } + putchar ('.'); + for (i = 0; i < SHA256_DIGEST_LENGTH; i++) + printf ("%x%x", hash[i]/16, hash[i]%16); + putchar ('\n'); + + ret = 0; +error: + if (password) + free (password); + + return ret; +} + int main (int argc, char *argv[]) { char **files = NULL; char *key_file = NULL; char *hash_file = NULL; + char *input_pw = NULL; const char *option; int c, i, f_ind, total = 0; unsigned int command = 0; @@ -1072,11 +1126,12 @@ main (int argc, char *argv[]) {"test-key", required_argument, 0, 't'}, {"reset", no_argument, 0, 0 }, {"hash-file", required_argument, 0, 'f'}, + {"generate-hash", optional_argument, 0, 'g'}, {0, 0, 0, 0} }; int option_index = 0; - c = getopt_long (argc, argv, "d:f:hi:pt:x", + c = getopt_long (argc, argv, "d:f:g::hi:pt:x", long_options, &option_index); if (c == -1) @@ -1133,6 +1188,12 @@ main (int argc, char *argv[]) command |= HASH_FILE; break; + case 'g': + if (optarg) + input_pw = strdup (optarg); + + command |= GENERATE_PW_HASH; + break; case 'p': command |= PASSWORD; break; @@ -1194,6 +1255,9 @@ main (int argc, char *argv[]) case RESET | HASH_FILE: ret = reset_moks (hash_file); break; + case GENERATE_PW_HASH: + ret = generate_pw_hash (input_pw); + break; default: print_help (); break; @@ -1211,5 +1275,8 @@ main (int argc, char *argv[]) if (hash_file) free (hash_file); + if (input_pw) + free (input_pw); + return ret; } -- 1.7.10.4 From ba347d456e80101b7c4306e7b30465c47c0fbea6 Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Tue, 15 Jan 2013 16:14:32 +0800 Subject: [PATCH 7/9] Amend help --- src/mokutil.c | 59 ++++++++++++++++++++++----------------------------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/src/mokutil.c b/src/mokutil.c index fdb1a2b..72a651a 100644 --- a/src/mokutil.c +++ b/src/mokutil.c @@ -52,42 +52,29 @@ typedef struct { static void print_help () { - printf("Usage:\n"); - printf("List the enrolled keys:\n"); - printf(" mokutil --list-enrolled\n\n"); - - printf("List the keys to be enrolled:\n"); - printf(" mokutil --list-new\n\n"); - - printf("Import keys:\n"); - printf(" mokutil --import ...\n\n"); - - printf("Request to delete specific keys\n"); - printf(" mokutil --delete ...\n\n"); - - printf("Revoke the request:\n"); - printf(" mokutil --revoke\n\n"); - - printf("Export enrolled keys to files:\n"); - printf(" mokutil --export\n\n"); - - printf("Set MOK password:\n"); - printf(" mokutil --password\n\n"); - - printf("Disable signature validation:\n"); - printf(" mokutil --disable-validation\n\n"); - - printf("Enable signature validation:\n"); - printf(" mokutil --enable-validation\n\n"); - - printf("SecureBoot State:\n"); - printf(" mokutil --sb-state\n\n"); - - printf("Test if the key is enrolled or not:\n"); - printf(" mokutil --test-key \n\n"); - - printf("Reset MOK list:\n"); - printf(" mokutil --reset\n\n"); + printf ("Usage:\n"); + printf (" mokutil OPTIONS [ARGS...]\n"); + printf ("\n"); + printf ("Options:\n"); + printf (" --help\t\t\t\tShow help\n"); + printf (" --list-enrolled\t\t\tList the enrolled keys\n"); + printf (" --list-new\t\t\t\tList the keys to be enrolled\n"); + printf (" --import \t\tImport keys\n"); + printf (" --delete \t\tDelete specific keys\n"); + printf (" --revoke\t\t\t\tRevoke the import request\n"); + printf (" --export\t\t\t\tExport enrolled keys to files\n"); + printf (" --password\t\t\t\tSet MOK password\n"); + printf (" --disable-validation\t\t\tDisable signature validation\n"); + printf (" --enable-validation\t\t\tEnable signature validation\n"); + printf (" --sb-state\t\t\t\tShow SecureBoot State\n"); + printf (" --test-key \t\t\tTest if the key is enrolled or not\n"); + printf (" --reset\t\t\t\tReset MOK list\n"); + printf (" --generate-hash[=password]\t\tGenerate the password hash\n"); + printf ("\n"); + printf ("Suboptions:\n"); + printf (" --hash-file \t\tUse the specific password hash\n"); + printf (" \t\t(Only valid with --import, --delete,\n"); + printf (" \t\t --password, and --reset)\n"); } static int -- 1.7.10.4 From f1a1c7abd8fde13afcb5196c599c662109936d49 Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Tue, 15 Jan 2013 17:48:04 +0800 Subject: [PATCH 8/9] New commands to revoke the import or delete request --- src/mokutil.c | 58 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/src/mokutil.c b/src/mokutil.c index 72a651a..7392845 100644 --- a/src/mokutil.c +++ b/src/mokutil.c @@ -27,16 +27,17 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, #define LIST_NEW 0x4 #define IMPORT 0x8 #define DELETE 0x10 -#define REVOKE 0x20 -#define EXPORT 0x40 -#define PASSWORD 0x80 -#define DISABLE_VALIDATION 0x100 -#define ENABLE_VALIDATION 0x200 -#define SB_STATE 0x400 -#define TEST_KEY 0x800 -#define RESET 0x1000 -#define HASH_FILE 0x2000 -#define GENERATE_PW_HASH 0x4000 +#define REVOKE_IMPORT 0x20 +#define REVOKE_DELETE 0x40 +#define EXPORT 0x80 +#define PASSWORD 0x100 +#define DISABLE_VALIDATION 0x200 +#define ENABLE_VALIDATION 0x400 +#define SB_STATE 0x800 +#define TEST_KEY 0x1000 +#define RESET 0x2000 +#define HASH_FILE 0x4000 +#define GENERATE_PW_HASH 0x8000 typedef struct { uint32_t mok_size; @@ -61,7 +62,8 @@ print_help () printf (" --list-new\t\t\t\tList the keys to be enrolled\n"); printf (" --import \t\tImport keys\n"); printf (" --delete \t\tDelete specific keys\n"); - printf (" --revoke\t\t\t\tRevoke the import request\n"); + printf (" --revoke-import\t\t\tRevoke the import request\n"); + printf (" --revoke-delete\t\t\tRevoke the delete request\n"); printf (" --export\t\t\t\tExport enrolled keys to files\n"); printf (" --password\t\t\t\tSet MOK password\n"); printf (" --disable-validation\t\t\tDisable signature validation\n"); @@ -771,13 +773,19 @@ delete_moks (char **files, uint32_t total, const char *hash_file) } static int -revoke_request () +revoke_request (uint8_t import) { - if (test_and_delete_var ("MokNew") < 0) - return -1; - - if (test_and_delete_var ("MokAuth") < 0) - return -1; + if (import == 1) { + if (test_and_delete_var ("MokNew") < 0) + return -1; + if (test_and_delete_var ("MokAuth") < 0) + return -1; + } else { + if (test_and_delete_var ("MokDel") < 0) + return -1; + if (test_and_delete_var ("MokDelAuth") < 0) + return -1; + } return 0; } @@ -1104,7 +1112,8 @@ main (int argc, char *argv[]) {"list-new", no_argument, 0, 0 }, {"import", required_argument, 0, 'i'}, {"delete", required_argument, 0, 'd'}, - {"revoke", no_argument, 0, 0 }, + {"revoke-import", no_argument, 0, 0 }, + {"revoke-delete", no_argument, 0, 0 }, {"export", no_argument, 0, 'x'}, {"password", no_argument, 0, 'p'}, {"disable-validation", no_argument, 0, 0 }, @@ -1131,8 +1140,10 @@ main (int argc, char *argv[]) command |= LIST_ENROLLED; } else if (strcmp (option, "list-new") == 0) { command |= LIST_NEW; - } else if (strcmp (option, "revoke") == 0) { - command |= REVOKE; + } else if (strcmp (option, "revoke-import") == 0) { + command |= REVOKE_IMPORT; + } else if (strcmp (option, "revoke-delete") == 0) { + command |= REVOKE_DELETE; } else if (strcmp (option, "disable-validation") == 0) { command |= DISABLE_VALIDATION; } else if (strcmp (option, "enable-validation") == 0) { @@ -1216,8 +1227,11 @@ main (int argc, char *argv[]) case DELETE | HASH_FILE: ret = delete_moks (files, total, hash_file); break; - case REVOKE: - ret = revoke_request (); + case REVOKE_IMPORT: + ret = revoke_request (1); + break; + case REVOKE_DELETE: + ret = revoke_request (0); break; case EXPORT: ret = export_moks (); -- 1.7.10.4 From 5cd7872982361be10755e3c8e7ecf228da92e164 Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Wed, 16 Jan 2013 15:12:28 +0800 Subject: [PATCH 9/9] Apply stricter permissions to some variables The UEFI variables which contain the password or the password hash should not be accessed by normal users. --- src/efi.h | 1 + src/efilib.c | 22 ++++++++++++++++++++++ src/mokutil.c | 6 +++--- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/efi.h b/src/efi.h index d2640b4..ceed6c2 100644 --- a/src/efi.h +++ b/src/efi.h @@ -360,6 +360,7 @@ extern efi_status_t test_variable (efi_variable_t *var); extern efi_status_t read_variable (efi_variable_t *var); extern efi_status_t edit_variable (efi_variable_t *var); extern efi_status_t delete_variable (efi_variable_t *var); +extern efi_status_t edit_protected_variable (efi_variable_t *var); extern int efichar_strlen (const efi_char16_t *p, int max); extern unsigned long efichar_from_char (efi_char16_t *dest, const char *src, size_t dest_len); diff --git a/src/efilib.c b/src/efilib.c index f192c1a..cb1aca6 100644 --- a/src/efilib.c +++ b/src/efilib.c @@ -215,3 +215,25 @@ delete_variable(efi_variable_t *var) return EFI_OUT_OF_RESOURCES; } + +efi_status_t +edit_protected_variable (efi_variable_t *var) +{ + char name[PATH_MAX]; + char filename[PATH_MAX]; + int ret; + if (!var) + return EFI_INVALID_PARAMETER; + + variable_to_name(var, name); + + snprintf(filename, PATH_MAX-1, "%s/%s", SYSFS_DIR_EFI_VARS, name); + ret = write_variable (filename, var); + if (ret != EFI_SUCCESS) + return ret; + + if (chmod (filename, S_IRUSR | S_IWUSR) < 0) + return EFI_UNSUPPORTED; + + return EFI_SUCCESS; +} diff --git a/src/mokutil.c b/src/mokutil.c index 7392845..c1a0ffc 100644 --- a/src/mokutil.c +++ b/src/mokutil.c @@ -532,7 +532,7 @@ update_request (void *new_list, int list_len, uint8_t import, | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; - if (edit_variable (&var) != EFI_SUCCESS) { + if (edit_protected_variable (&var) != EFI_SUCCESS) { fprintf (stderr, "Failed to write %s\n", auth_name); test_and_delete_var (req_name); goto error; @@ -884,7 +884,7 @@ set_password (const char *hash_file) | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; - if (edit_variable (&var) != EFI_SUCCESS) { + if (edit_protected_variable (&var) != EFI_SUCCESS) { fprintf (stderr, "Failed to write MokPW\n"); goto error; } @@ -929,7 +929,7 @@ set_validation (uint32_t state) | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; - if (edit_variable (&var) != EFI_SUCCESS) { + if (edit_protected_variable (&var) != EFI_SUCCESS) { fprintf (stderr, "Failed to request new SB state\n"); goto error; } -- 1.7.10.4