From 747dfe4b952af3641dec17582c81725958d6cd7682c6f422b9cc73ec436374cc Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Wed, 30 Jan 2013 09:56:06 +0000 Subject: [PATCH] Accepting request 150393 from home:gary_lin:branches:Base:System - Merge patches for FATE#314506 + Add mokutil-support-crypt-hash-methods.patch to support the password hashes from /etc/shadow + Add mokutil-update-man-page.patch to update man page for the new added options - Add mokutil-lcrypt-ldflag.patch to correct LDFLAGS OBS-URL: https://build.opensuse.org/request/show/150393 OBS-URL: https://build.opensuse.org/package/show/Base:System/mokutil?expand=0&rev=6 --- mokutil-lcrypt-ldflag.patch | 29 + mokutil-support-crypt-hash-methods.patch | 1911 ++++++++++++++++++++++ mokutil-support-new-pw-hash.patch | 355 +--- mokutil-update-man-page.patch | 124 ++ mokutil.changes | 10 + mokutil.spec | 12 + 6 files changed, 2095 insertions(+), 346 deletions(-) create mode 100644 mokutil-lcrypt-ldflag.patch create mode 100644 mokutil-support-crypt-hash-methods.patch create mode 100644 mokutil-update-man-page.patch diff --git a/mokutil-lcrypt-ldflag.patch b/mokutil-lcrypt-ldflag.patch new file mode 100644 index 0000000..f98a574 --- /dev/null +++ b/mokutil-lcrypt-ldflag.patch @@ -0,0 +1,29 @@ +From aa48dc644fbf775970d01a368c532d0668015f18 Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +Date: Wed, 30 Jan 2013 16:30:23 +0800 +Subject: [PATCH] Include lcrypt in LDFLAGS + +--- + src/Makefile.am | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/Makefile.am b/src/Makefile.am +index afe1752..de7ddca 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -1,10 +1,10 @@ + bin_PROGRAMS = mokutil + + mokutil_CFLAGS = $(OPENSSL_CFLAGS) \ +- -lcrypt \ + $(WARNINGFLAGS_C) + +-mokutil_LDADD = $(OPENSSL_LIBS) ++mokutil_LDADD = $(OPENSSL_LIBS) \ ++ -lcrypt + + mokutil_SOURCES = efi.h \ + efilib.c \ +-- +1.7.10.4 + diff --git a/mokutil-support-crypt-hash-methods.patch b/mokutil-support-crypt-hash-methods.patch new file mode 100644 index 0000000..a1586f0 --- /dev/null +++ b/mokutil-support-crypt-hash-methods.patch @@ -0,0 +1,1911 @@ +From c5d08b63d47db48bd239599f8fb53b13f879e1ff Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +Date: Wed, 23 Jan 2013 18:31:19 +0800 +Subject: [PATCH 1/9] Use crypt_r() to generate the password hash + +1. We now use crypt_r() from glibc to generate the password hash. + +2. The password length is changed to be compatible with the password + hash from /etc/shadow. + +3. The password hash structure was modified to be compatible with + the change in MokManager. +--- + configure.ac | 2 +- + src/Makefile.am | 3 + + src/PasswordHash.h | 33 -------- + src/mokutil.c | 219 ++++++++++++++++++++++---------------------------- + src/password-crypt.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++++ + src/password-crypt.h | 42 ++++++++++ + 6 files changed, 359 insertions(+), 158 deletions(-) + delete mode 100644 src/PasswordHash.h + create mode 100644 src/password-crypt.c + create mode 100644 src/password-crypt.h + +diff --git a/configure.ac b/configure.ac +index 468b108..894790e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -15,7 +15,7 @@ AM_PROG_CC_C_O + AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [turn on debug]), CFLAGS="$CFLAGS -g") + + # Checks for header files. +-AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h unistd.h]) ++AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h unistd.h crypt.h]) + + # Checks for typedefs, structures, and compiler characteristics. + AC_C_INLINE +diff --git a/src/Makefile.am b/src/Makefile.am +index 036a62a..afe1752 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -1,6 +1,7 @@ + bin_PROGRAMS = mokutil + + mokutil_CFLAGS = $(OPENSSL_CFLAGS) \ ++ -lcrypt \ + $(WARNINGFLAGS_C) + + mokutil_LDADD = $(OPENSSL_LIBS) +@@ -8,4 +9,6 @@ mokutil_LDADD = $(OPENSSL_LIBS) + mokutil_SOURCES = efi.h \ + efilib.c \ + signature.h \ ++ password-crypt.h \ ++ password-crypt.c \ + mokutil.c +diff --git a/src/PasswordHash.h b/src/PasswordHash.h +deleted file mode 100644 +index 2aeded6..0000000 +--- a/src/PasswordHash.h ++++ /dev/null +@@ -1,33 +0,0 @@ +-#ifndef __PASSWORD_HASH_H__ +-#define __PASSWORD_HASH_H__ +- +-#include +- +-#define PASSWORD_HASH_SIZE 88 +- +-/* The max salt size (in bits) */ +-#define T_DES_SALT_MAX 12 +-#define E_BSI_DES_SALT_MAX 24 +-#define MD5_SALT_MAX 48 +-#define SHA256_SALT_MAX 96 +-#define SHA512_SALT_MAX 96 +-#define BLOWFISH_SALT_MAX 128 +- +-enum HashMethod { +- Tranditional_DES = 0, +- Extend_BSDI_DES, +- MD5_BASED, +- SHA256_BASED, +- SHA512_BASED, +- BLOWFISH_BASED +-}; +- +-typedef struct { +- uint16_t method; +- uint32_t iter_count; +- uint16_t salt_size; +- uint8_t salt[16]; +- uint8_t hash[64]; +-} __attribute__ ((packed)) pw_hash_t; +- +-#endif /* __PASSWORD_HASH_H__ */ +diff --git a/src/mokutil.c b/src/mokutil.c +index 38039b9..f71cb6a 100644 +--- a/src/mokutil.c ++++ b/src/mokutil.c +@@ -11,15 +11,20 @@ + #include + #include + ++#define __USE_GNU ++#include ++ + #include "efi.h" + #include "signature.h" +-#include "PasswordHash.h" ++#include "password-crypt.h" + + #define SHIM_LOCK_GUID \ + EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23) + +-#define PASSWORD_MAX 16 +-#define PASSWORD_MIN 8 ++#define PASSWORD_MAX 256 ++#define PASSWORD_MIN 1 ++#define SB_PASSWORD_MAX 16 ++#define SB_PASSWORD_MIN 8 + + #define HELP 0x1 + #define LIST_ENROLLED 0x2 +@@ -38,6 +43,9 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, + #define HASH_FILE 0x4000 + #define GENERATE_PW_HASH 0x8000 + ++#define DEFAULT_CRYPT_METHOD SHA256_BASED ++#define DEFAULT_SALT_SIZE SHA256_SALT_MAX ++ + typedef struct { + uint32_t mok_size; + void *mok; +@@ -46,7 +54,7 @@ typedef struct { + typedef struct { + uint32_t mok_sb_state; + uint32_t password_length; +- uint16_t password[PASSWORD_MAX]; ++ uint16_t password[SB_PASSWORD_MAX]; + } MokSBVar; + + static void +@@ -71,8 +79,6 @@ print_help () + 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"); +@@ -310,7 +316,7 @@ get_password (char **password, int *len, int min, int max) + fail = 0; + + while (fail < 3) { +- printf ("input password (%d~%d characters): ", min, max); ++ printf ("input password: "); + len_1 = read_hidden_line (&password_1, &n); + printf ("\n"); + +@@ -361,103 +367,79 @@ error: + static unsigned int + generate_salt (uint8_t salt[], unsigned int max_size, unsigned int min_size) + { +- unsigned int salt_len = max_size / 8; ++ unsigned int salt_size = max_size; + int i; + ++ /* TODO use a better random number generator */ + srand (time (NULL)); + +- for (i = 0; i < salt_len; i++) +- salt[i] = rand() % 256; ++ for (i = 0; i < salt_size; i++) ++ salt[i] = int_to_b64 (rand() % 0x3f); + +- return max_size; ++ return salt_size; + } + + static int +-generate_hash (void *salt, unsigned int salt_len, char *password, +- int pw_len, uint8_t *auth) ++generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len) + { +- SHA256_CTX ctx; +- +- if (!password || !auth) ++ pw_crypt_t new_crypt; ++ struct crypt_data data; ++ char settings[64]; ++ char *crypt_string; ++ const char *prefix; ++ int hash_len, prefix_len; ++ ++ if (!password || !pw_crypt) + return -1; + +- SHA256_Init (&ctx); +- +- if (salt) +- SHA256_Update (&ctx, salt, salt_len); +- +- SHA256_Update (&ctx, password, pw_len); +- +- SHA256_Final (auth, &ctx); +- +- return 0; +-} +- +-static int +-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); ++ prefix = get_crypt_prefix (pw_crypt->method); ++ if (!prefix) ++ return -1; ++ prefix_len = strlen(prefix); + +- return -1; +-} ++ strncpy (settings, prefix, prefix_len); ++ strncpy (settings + prefix_len, (const char *)pw_crypt->salt, ++ pw_crypt->salt_size); ++ settings[pw_crypt->salt_size + prefix_len] = '\0'; + +-static int +-read_hex_array (const char *string, uint8_t *out, unsigned int len) +-{ +- int i, digit_1, digit_2; ++ crypt_string = crypt_r (password, settings, &data); ++ if (!crypt_string) ++ return -1; + +- 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; ++ if (decode_pass (crypt_string, &new_crypt) < 0) ++ return -1; + +- out[i] = (uint8_t)digit_1 * 16 + (uint8_t)digit_2; +- } ++ hash_len = get_hash_size (new_crypt.method); ++ if (hash_len < 0) ++ return -1; ++ memcpy (pw_crypt->hash, new_crypt.hash, hash_len); ++ pw_crypt->iter_count = new_crypt.iter_count; + + return 0; + } + + static int +-get_hash_from_file (const char *file, pw_hash_t *pw_hash) ++get_hash_from_file (const char *file, pw_crypt_t *pw_crypt) + { +- FILE *fptr; +- unsigned int method, iter_count, salt_size; +- char salt_string[2*(SHA256_SALT_MAX/8)]; +- char hash_string[2*SHA256_DIGEST_LENGTH]; ++ char string[300]; ++ ssize_t read_len; ++ int fd; + +- fptr = fopen (file, "r"); +- if (fptr == NULL) { ++ fd = open (file, O_RDONLY); ++ if (fd < 0) { + fprintf (stderr, "Failed to open %s\n", file); + return -1; + } ++ read_len = read (fd, string, 300); ++ close (fd); + +- memset (salt_string, 0, 2*(SHA256_SALT_MAX/8)); +- memset (hash_string, 0, 2*SHA256_DIGEST_LENGTH); +- +- fscanf (fptr, "%x.%x.%x.%24c.%64c", &method, &iter_count, &salt_size, +- salt_string, hash_string); +- +- fclose (fptr); +- +- pw_hash->method = (uint16_t)method; +- pw_hash->iter_count = (uint32_t)iter_count; +- pw_hash->salt_size = (uint16_t)salt_size; +- +- if (read_hex_array (salt_string, pw_hash->salt, salt_size/8) < 0) { +- fprintf (stderr, "Corrupted salt\n"); ++ if (string[read_len] != '\0') { ++ fprintf (stderr, "corrupted string\n"); + return -1; + } + +- if (read_hex_array (hash_string, pw_hash->hash, SHA256_DIGEST_LENGTH) < 0) { +- fprintf (stderr, "Corrupted hash\n"); ++ if (decode_pass (string, pw_crypt) < 0) { ++ fprintf (stderr, "Failed to parse the string\n"); + return -1; + } + +@@ -470,15 +452,13 @@ update_request (void *new_list, int list_len, uint8_t import, + { + efi_variable_t var; + const char *req_name, *auth_name; +- pw_hash_t pw_hash; ++ pw_crypt_t pw_crypt; + char *password = NULL; + int pw_len; + int ret = -1; + +- bzero (&pw_hash, sizeof(pw_hash_t)); +- pw_hash.method = SHA256_BASED; +- pw_hash.iter_count = 1; +- pw_hash.salt_size = SHA256_SALT_MAX; ++ bzero (&pw_crypt, sizeof(pw_crypt_t)); ++ pw_crypt.method = DEFAULT_CRYPT_METHOD; + + if (import) { + req_name = "MokNew"; +@@ -489,7 +469,7 @@ update_request (void *new_list, int list_len, uint8_t import, + } + + if (hash_file) { +- if (get_hash_from_file (hash_file, &pw_hash) < 0) { ++ if (get_hash_from_file (hash_file, &pw_crypt) < 0) { + fprintf (stderr, "Failed to read hash\n"); + goto error; + } +@@ -499,9 +479,10 @@ update_request (void *new_list, int list_len, uint8_t import, + goto error; + } + +- generate_salt (pw_hash.salt, SHA256_SALT_MAX, 0); +- if (generate_hash (pw_hash.salt, SHA256_SALT_MAX/8, password, +- pw_len, pw_hash.hash) < 0) { ++ pw_crypt.salt_size = generate_salt (pw_crypt.salt, ++ DEFAULT_SALT_SIZE, ++ DEFAULT_SALT_SIZE); ++ if (generate_hash (&pw_crypt, password, pw_len) < 0) { + fprintf (stderr, "Couldn't generate hash\n"); + goto error; + } +@@ -528,8 +509,8 @@ update_request (void *new_list, int list_len, uint8_t import, + } + + /* Write MokAuth or MokDelAuth */ +- var.Data = (void *)&pw_hash; +- var.DataSize = PASSWORD_HASH_SIZE; ++ var.Data = (void *)&pw_crypt; ++ var.DataSize = PASSWORD_CRYPT_SIZE; + var.VariableName = auth_name; + + var.VendorGuid = SHIM_LOCK_GUID; +@@ -853,18 +834,16 @@ static int + set_password (const char *hash_file) + { + efi_variable_t var; +- pw_hash_t pw_hash; ++ pw_crypt_t pw_crypt; + char *password = NULL; + int pw_len; + int ret = -1; + +- bzero (&pw_hash, sizeof(pw_hash_t)); +- pw_hash.method = SHA256_BASED; +- pw_hash.iter_count = 1; +- pw_hash.salt_size = SHA256_SALT_MAX; ++ bzero (&pw_crypt, sizeof(pw_crypt_t)); ++ pw_crypt.method = DEFAULT_CRYPT_METHOD; + + if (hash_file) { +- if (get_hash_from_file (hash_file, &pw_hash) < 0) { ++ if (get_hash_from_file (hash_file, &pw_crypt) < 0) { + fprintf (stderr, "Failed to read hash\n"); + goto error; + } +@@ -874,16 +853,17 @@ set_password (const char *hash_file) + goto error; + } + +- generate_salt (pw_hash.salt, SHA256_SALT_MAX, 0); +- if (generate_hash (pw_hash.salt, SHA256_SALT_MAX/8, password, +- pw_len, pw_hash.hash) < 0) { ++ pw_crypt.salt_size = generate_salt (pw_crypt.salt, ++ DEFAULT_SALT_SIZE, ++ DEFAULT_SALT_SIZE); ++ if (generate_hash (&pw_crypt, password, pw_len) < 0) { + fprintf (stderr, "Couldn't generate hash\n"); + goto error; + } + } + +- var.Data = (void *)&pw_hash; +- var.DataSize = PASSWORD_HASH_SIZE; ++ var.Data = (void *)&pw_crypt; ++ var.DataSize = PASSWORD_CRYPT_SIZE; + var.VariableName = "MokPW"; + + var.VendorGuid = SHIM_LOCK_GUID; +@@ -910,10 +890,11 @@ set_validation (uint32_t state) + MokSBVar sbvar; + char *password = NULL; + int pw_len; +- efi_char16_t efichar_pass[PASSWORD_MAX]; ++ efi_char16_t efichar_pass[SB_PASSWORD_MAX]; + int ret = -1; + +- if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { ++ printf ("password length: %d~%d\n", SB_PASSWORD_MIN, SB_PASSWORD_MAX); ++ if (get_password (&password, &pw_len, SB_PASSWORD_MIN, SB_PASSWORD_MAX) < 0) { + fprintf (stderr, "Abort\n"); + goto error; + } +@@ -921,10 +902,10 @@ set_validation (uint32_t state) + sbvar.password_length = pw_len; + + efichar_from_char (efichar_pass, password, +- PASSWORD_MAX * sizeof(efi_char16_t)); ++ SB_PASSWORD_MAX * sizeof(efi_char16_t)); + + memcpy(sbvar.password, efichar_pass, +- PASSWORD_MAX * sizeof(efi_char16_t)); ++ SB_PASSWORD_MAX * sizeof(efi_char16_t)); + + sbvar.mok_sb_state = state; + +@@ -1051,20 +1032,16 @@ reset_moks (const char *hash_file) + static int + generate_pw_hash (const char *input_pw) + { +- pw_hash_t pw_hash; ++ struct crypt_data data; ++ char settings[SHA256_SALT_MAX + 3 + 1]; + char *password = NULL; +- int pw_len, i, ret = -1; +- +- bzero (&pw_hash, sizeof(pw_hash_t)); +- pw_hash.method = SHA256_BASED; +- pw_hash.iter_count = 1; +- pw_hash.salt_size = SHA256_SALT_MAX; ++ char *crypt_string; ++ int pw_len, 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); ++ fprintf (stderr, "invalid password length\n"); + return -1; + } + +@@ -1081,23 +1058,17 @@ generate_pw_hash (const char *input_pw) + } + } + +- generate_salt (pw_hash.salt, SHA256_SALT_MAX, 0); +- if (generate_hash (pw_hash.salt, SHA256_SALT_MAX/8, password, +- pw_len, pw_hash.hash) < 0) { +- fprintf (stderr, "Couldn't generate hash\n"); ++ strncpy (settings, "$5$", 3); ++ generate_salt ((uint8_t *)(settings + 3), SHA256_SALT_MAX, 0); ++ settings[SHA256_SALT_MAX + 3] = '\0'; ++ ++ crypt_string = crypt_r (password, settings, &data); ++ if (!crypt_string) { ++ fprintf (stderr, "Failed to generate hash\n"); + goto error; + } + +- /* Print the salt and hash */ +- printf ("%x.%x.%x.", pw_hash.method, pw_hash.iter_count, +- pw_hash.salt_size); +- for (i = 0; i < (SHA256_SALT_MAX/8); i++) { +- printf ("%x%x", pw_hash.salt[i]/16, pw_hash.salt[i]%16); +- } +- putchar ('.'); +- for (i = 0; i < SHA256_DIGEST_LENGTH; i++) +- printf ("%x%x", pw_hash.hash[i]/16, pw_hash.hash[i]%16); +- putchar ('\n'); ++ printf ("%s\n", crypt_string); + + ret = 0; + error: +diff --git a/src/password-crypt.c b/src/password-crypt.c +new file mode 100644 +index 0000000..f004049 +--- /dev/null ++++ b/src/password-crypt.c +@@ -0,0 +1,218 @@ ++#include ++#include ++#include ++#include ++#include "password-crypt.h" ++ ++#define MIN(a,b) ((a)<(b)?(a):(b)) ++ ++#define SHA256_DEFAULT_ROUNDS 5000 ++ ++static const char b64t[64] = ++"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; ++ ++static const char sha256_prefix[] = "$5$"; ++static const char sha512_prefix[] = "$6$"; ++ ++static const char sha256_rounds_prefix[] = "rounds="; ++ ++static int restore_sha256_array (const char *string, uint8_t *hash); ++ ++int ++get_hash_size (int method) ++{ ++ switch (method) { ++ case TRANDITIONAL_DES: ++ return 64 / 8; /* per "man crypt" */ ++ case EXTEND_BSDI_DES: ++ return 64 / 8; /* per "man crypt" */ ++ case MD5_BASED: ++ return MD5_DIGEST_LENGTH; ++ case SHA256_BASED: ++ return SHA256_DIGEST_LENGTH; ++ case SHA512_BASED: ++ return SHA512_DIGEST_LENGTH; ++ case BLOWFISH_BASED: ++ return 184 / 8; /* per "man crypt" */ ++ } ++ ++ return -1; ++} ++ ++const char * ++get_crypt_prefix (int method) ++{ ++ switch (method) { ++ case TRANDITIONAL_DES: ++ return ""; /* per "man crypt" */ ++ case EXTEND_BSDI_DES: ++ return "_"; /* per "man crypt" */ ++ case MD5_BASED: ++ return "$1$"; ++ case SHA256_BASED: ++ return "$5$"; ++ case SHA512_BASED: ++ return "$6$"; ++ case BLOWFISH_BASED: ++ return "$2y$"; /* per "man crypt" */ ++ } ++ ++ return NULL; ++} ++ ++static int ++decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt) ++{ ++ /* Expected string: (rounds=[0-9]{1,9}\$)?([./0-9A-Za-z]{1,16})?\$[./0-9A-Za-z]{43} */ ++ char *tmp, *ptr = (char *)string; ++ char *b64_hash; ++ int count = 0; ++ ++ /* get rounds */ ++ pw_crypt->iter_count = SHA256_DEFAULT_ROUNDS; ++ if (strncmp (ptr, sha256_rounds_prefix, sizeof(sha256_rounds_prefix) - 1) == 0) { ++ const char *num = ptr + sizeof(sha256_rounds_prefix) - 1; ++ char *endp; ++ unsigned long int srounds = strtoul (num, &endp, 10); ++ if (*endp == '$') { ++ ptr = endp + 1; ++ pw_crypt->iter_count = (uint32_t)srounds; ++ } else { ++ return -1; ++ } ++ } ++ ++ /* get salt */ ++ for (tmp = ptr; *tmp != '$'; tmp++) { ++ if (tmp == '\0') ++ return -1; ++ count++; ++ } ++ count = MIN(count, SHA256_SALT_MAX); ++ memcpy (pw_crypt->salt, ptr, count); ++ pw_crypt->salt_size = count; ++ ptr = tmp + 1; ++ ++ /* get hash */ ++ if (strlen(ptr) < SHA256_B64_LENGTH) ++ return -1; ++ b64_hash = malloc (SHA256_B64_LENGTH + 1); ++ if (!b64_hash) ++ return -1; ++ memcpy (b64_hash, ptr, SHA256_B64_LENGTH); ++ b64_hash[SHA256_B64_LENGTH] = '\0'; ++ ++ if (restore_sha256_array (b64_hash, pw_crypt->hash) < 0) ++ return -1; ++ ++ free (b64_hash); ++ ++ return 0; ++} ++ ++int ++decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt) ++{ ++ if (!pw_crypt) ++ return -1; ++ ++ if (strncmp (crypt_pass, sha256_prefix, 3) == 0) { ++ pw_crypt->method = SHA256_BASED; ++ return decode_sha256_pass (crypt_pass + 3, pw_crypt); ++ } ++ ++ return -1; ++} ++ ++char ++int_to_b64 (const int i) ++{ ++ return b64t[i & 0x3f]; ++} ++ ++int ++b64_to_int (const char c) ++{ ++ if (c == '.') ++ return 0; ++ ++ if (c == '/') ++ return 1; ++ ++ if (c >= '0' && c <= '9') ++ return (c - '0' + 2); ++ ++ if (c >= 'A' && c <= 'Z') ++ return (c - 'A' + 12); ++ ++ if (c >= 'a' && c <= 'z') ++ return (c - 'a' + 38); ++ ++ return -1; ++} ++ ++static int ++split_24bit (const char *string, uint8_t *hash, int start, int n, ++ uint32_t b2, uint32_t b1, uint32_t b0) ++{ ++ uint32_t tmp = 0; ++ int i, value; ++ ++ for (i = start; i < start + n; i++) { ++ value = b64_to_int (string[i]); ++ if (value < 0) ++ return -1; ++ tmp |= value << (6*(i - start)); ++ } ++ ++ hash[b0] = (uint8_t)(tmp & 0xff); ++ hash[b1] = (uint8_t)((tmp >> 8) & 0xff); ++ hash[b2] = (uint8_t)((tmp >> 16) & 0xff); ++ ++ return 0; ++} ++ ++int ++restore_sha256_array (const char *string, uint8_t *hash) ++{ ++ uint32_t tmp = 0; ++ int i, value; ++ ++ if (strlen (string) != SHA256_B64_LENGTH) ++ return -1; ++ ++ if (split_24bit (string, hash, 0, 4, 0, 10, 20) < 0) ++ return -1; ++ if (split_24bit (string, hash, 4, 4, 21, 1, 11) < 0) ++ return -1; ++ if (split_24bit (string, hash, 8, 4, 12, 22, 2) < 0) ++ return -1; ++ if (split_24bit (string, hash, 12, 4, 3, 13, 23) < 0) ++ return -1; ++ if (split_24bit (string, hash, 16, 4, 24, 4, 14) < 0) ++ return -1; ++ if (split_24bit (string, hash, 20, 4, 15, 25, 5) < 0) ++ return -1; ++ if (split_24bit (string, hash, 24, 4, 6, 16, 26) < 0) ++ return -1; ++ if (split_24bit (string, hash, 28, 4, 27, 7, 17) < 0) ++ return -1; ++ if (split_24bit (string, hash, 32, 4, 18, 28, 8) < 0) ++ return -1; ++ if (split_24bit (string, hash, 36, 4, 9, 19, 29) < 0) ++ return -1; ++ ++ for (i = 40; i < 43 ; i++) { ++ value = b64_to_int (string[i]); ++ if (value < 0) ++ return -1; ++ tmp |= value << (6*(i - 40)); ++ } ++ ++ hash[30] = (uint8_t)(tmp & 0xff); ++ hash[31] = (uint8_t)((tmp >> 8) & 0xff); ++ ++ return 0; ++} ++ ++ +diff --git a/src/password-crypt.h b/src/password-crypt.h +new file mode 100644 +index 0000000..149a05e +--- /dev/null ++++ b/src/password-crypt.h +@@ -0,0 +1,42 @@ ++#ifndef __PASSWORD_CRYPT_H__ ++#define __PASSWORD_CRYPT_H__ ++ ++#include ++ ++/* The max salt size (in characters [./0-9A-Za-z]) */ ++#define T_DES_SALT_MAX 2 ++#define E_BSI_DES_SALT_MAX 4 ++#define MD5_SALT_MAX 8 ++#define SHA256_SALT_MAX 16 ++#define SHA512_SALT_MAX 16 ++/* The max salt size of Blowfish in UINT8 */ ++#define BLOWFISH_SALT_MAX 16 ++ ++enum HashMethod { ++ TRANDITIONAL_DES = 0, ++ EXTEND_BSDI_DES, ++ MD5_BASED, ++ SHA256_BASED, ++ SHA512_BASED, ++ BLOWFISH_BASED ++}; ++ ++typedef struct { ++ uint16_t method; ++ uint64_t iter_count; ++ uint16_t salt_size; ++ uint8_t salt[32]; ++ uint8_t hash[128]; ++} __attribute__ ((packed)) pw_crypt_t; ++ ++#define PASSWORD_CRYPT_SIZE sizeof(pw_crypt_t) ++ ++#define SHA256_B64_LENGTH 43 ++ ++int get_hash_size (int method); ++const char *get_crypt_prefix (int method); ++int decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt); ++char int_to_b64 (const int i); ++int b64_to_int (const char c); ++ ++#endif /* __PASSWORD_CRYPT_H__ */ +-- +1.7.10.4 + + +From 80ddd5d426e96d251f53bf5653a3bd20aebb32ab Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +Date: Thu, 24 Jan 2013 18:37:33 +0800 +Subject: [PATCH 2/9] Support SHA512-based crypt_r() hash + +--- + src/mokutil.c | 23 ++++++--- + src/password-crypt.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++-- + src/password-crypt.h | 1 + + 3 files changed, 140 insertions(+), 11 deletions(-) + +diff --git a/src/mokutil.c b/src/mokutil.c +index f71cb6a..d1c3763 100644 +--- a/src/mokutil.c ++++ b/src/mokutil.c +@@ -43,8 +43,9 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, + #define HASH_FILE 0x4000 + #define GENERATE_PW_HASH 0x8000 + +-#define DEFAULT_CRYPT_METHOD SHA256_BASED +-#define DEFAULT_SALT_SIZE SHA256_SALT_MAX ++#define DEFAULT_CRYPT_METHOD SHA512_BASED ++#define DEFAULT_SALT_SIZE SHA512_SALT_MAX ++#define SETTINGS_LEN (DEFAULT_SALT_SIZE*2) + + typedef struct { + uint32_t mok_size; +@@ -384,7 +385,7 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len) + { + pw_crypt_t new_crypt; + struct crypt_data data; +- char settings[64]; ++ char settings[SETTINGS_LEN]; + char *crypt_string; + const char *prefix; + int hash_len, prefix_len; +@@ -1033,9 +1034,11 @@ static int + generate_pw_hash (const char *input_pw) + { + struct crypt_data data; +- char settings[SHA256_SALT_MAX + 3 + 1]; ++ char settings[SETTINGS_LEN]; + char *password = NULL; + char *crypt_string; ++ const char *prefix; ++ int prefix_len; + int pw_len, ret = -1; + + if (input_pw) { +@@ -1058,9 +1061,15 @@ generate_pw_hash (const char *input_pw) + } + } + +- strncpy (settings, "$5$", 3); +- generate_salt ((uint8_t *)(settings + 3), SHA256_SALT_MAX, 0); +- settings[SHA256_SALT_MAX + 3] = '\0'; ++ prefix = get_crypt_prefix (DEFAULT_CRYPT_METHOD); ++ if (!prefix) ++ return -1; ++ prefix_len = strlen(prefix); ++ ++ strncpy (settings, prefix, prefix_len); ++ generate_salt ((uint8_t *)(settings + prefix_len), ++ DEFAULT_SALT_SIZE, DEFAULT_SALT_SIZE); ++ settings[DEFAULT_SALT_SIZE + prefix_len] = '\0'; + + crypt_string = crypt_r (password, settings, &data); + if (!crypt_string) { +diff --git a/src/password-crypt.c b/src/password-crypt.c +index f004049..84ee079 100644 +--- a/src/password-crypt.c ++++ b/src/password-crypt.c +@@ -7,6 +7,7 @@ + #define MIN(a,b) ((a)<(b)?(a):(b)) + + #define SHA256_DEFAULT_ROUNDS 5000 ++#define SHA512_DEFAULT_ROUNDS 5000 + + static const char b64t[64] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +@@ -14,9 +15,10 @@ static const char b64t[64] = + static const char sha256_prefix[] = "$5$"; + static const char sha512_prefix[] = "$6$"; + +-static const char sha256_rounds_prefix[] = "rounds="; ++static const char sha_rounds_prefix[] = "rounds="; + + static int restore_sha256_array (const char *string, uint8_t *hash); ++static int restore_sha512_array (const char *string, uint8_t *hash); + + int + get_hash_size (int method) +@@ -70,8 +72,8 @@ decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt) + + /* get rounds */ + pw_crypt->iter_count = SHA256_DEFAULT_ROUNDS; +- if (strncmp (ptr, sha256_rounds_prefix, sizeof(sha256_rounds_prefix) - 1) == 0) { +- const char *num = ptr + sizeof(sha256_rounds_prefix) - 1; ++ if (strncmp (ptr, sha_rounds_prefix, sizeof(sha_rounds_prefix) - 1) == 0) { ++ const char *num = ptr + sizeof(sha_rounds_prefix) - 1; + char *endp; + unsigned long int srounds = strtoul (num, &endp, 10); + if (*endp == '$') { +@@ -110,6 +112,56 @@ decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt) + return 0; + } + ++static int ++decode_sha512_pass (const char *string, pw_crypt_t *pw_crypt) ++{ ++ /* Expected string: (rounds=[0-9]{1,9}\$)?([./0-9A-Za-z]{1,16})?\$[./0-9A-Za-z]{86} */ ++ char *tmp, *ptr = (char *)string; ++ char *b64_hash; ++ int count = 0; ++ ++ /* get rounds */ ++ pw_crypt->iter_count = SHA512_DEFAULT_ROUNDS; ++ if (strncmp (ptr, sha_rounds_prefix, sizeof(sha_rounds_prefix) - 1) == 0) { ++ const char *num = ptr + sizeof(sha_rounds_prefix) - 1; ++ char *endp; ++ unsigned long int srounds = strtoul (num, &endp, 10); ++ if (*endp == '$') { ++ ptr = endp + 1; ++ pw_crypt->iter_count = (uint32_t)srounds; ++ } else { ++ return -1; ++ } ++ } ++ ++ /* get salt */ ++ for (tmp = ptr; *tmp != '$'; tmp++) { ++ if (tmp == '\0') ++ return -1; ++ count++; ++ } ++ count = MIN(count, SHA512_SALT_MAX); ++ memcpy (pw_crypt->salt, ptr, count); ++ pw_crypt->salt_size = count; ++ ptr = tmp + 1; ++ ++ /* get hash */ ++ if (strlen(ptr) < SHA512_B64_LENGTH) ++ return -1; ++ b64_hash = malloc (SHA512_B64_LENGTH + 1); ++ if (!b64_hash) ++ return -1; ++ memcpy (b64_hash, ptr, SHA512_B64_LENGTH); ++ b64_hash[SHA512_B64_LENGTH] = '\0'; ++ ++ if (restore_sha512_array (b64_hash, pw_crypt->hash) < 0) ++ return -1; ++ ++ free (b64_hash); ++ ++ return 0; ++} ++ + int + decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt) + { +@@ -118,7 +170,12 @@ decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt) + + if (strncmp (crypt_pass, sha256_prefix, 3) == 0) { + pw_crypt->method = SHA256_BASED; +- return decode_sha256_pass (crypt_pass + 3, pw_crypt); ++ return decode_sha256_pass (crypt_pass + strlen (sha256_prefix), pw_crypt); ++ } ++ ++ if (strncmp (crypt_pass, sha512_prefix, 3) == 0) { ++ pw_crypt->method = SHA512_BASED; ++ return decode_sha512_pass (crypt_pass + strlen (sha512_prefix), pw_crypt); + } + + return -1; +@@ -215,4 +272,66 @@ restore_sha256_array (const char *string, uint8_t *hash) + return 0; + } + ++int ++restore_sha512_array (const char *string, uint8_t *hash) ++{ ++ uint32_t tmp = 0; ++ int value1, value2; ++ ++ if (strlen (string) != SHA512_B64_LENGTH) ++ return -1; ++ ++ if (split_24bit (string, hash, 0, 4, 0, 21, 42) < 0) ++ return -1; ++ if (split_24bit (string, hash, 4, 4, 22, 43, 1) < 0) ++ return -1; ++ if (split_24bit (string, hash, 8, 4, 44, 2, 23) < 0) ++ return -1; ++ if (split_24bit (string, hash, 12, 4, 3, 24, 45) < 0) ++ return -1; ++ if (split_24bit (string, hash, 16, 4, 25, 46, 4) < 0) ++ return -1; ++ if (split_24bit (string, hash, 20, 4, 47, 5, 26) < 0) ++ return -1; ++ if (split_24bit (string, hash, 24, 4, 6, 27, 48) < 0) ++ return -1; ++ if (split_24bit (string, hash, 28, 4, 28, 49, 7) < 0) ++ return -1; ++ if (split_24bit (string, hash, 32, 4, 50, 8, 29) < 0) ++ return -1; ++ if (split_24bit (string, hash, 36, 4, 9, 30, 51) < 0) ++ return -1; ++ if (split_24bit (string, hash, 40, 4, 31, 52, 10) < 0) ++ return -1; ++ if (split_24bit (string, hash, 44, 4, 53, 11, 32) < 0) ++ return -1; ++ if (split_24bit (string, hash, 48, 4, 12, 33, 54) < 0) ++ return -1; ++ if (split_24bit (string, hash, 52, 4, 34, 55, 13) < 0) ++ return -1; ++ if (split_24bit (string, hash, 56, 4, 56, 14, 35) < 0) ++ return -1; ++ if (split_24bit (string, hash, 60, 4, 15, 36, 57) < 0) ++ return -1; ++ if (split_24bit (string, hash, 64, 4, 37, 58, 16) < 0) ++ return -1; ++ if (split_24bit (string, hash, 68, 4, 59, 17, 38) < 0) ++ return -1; ++ if (split_24bit (string, hash, 72, 4, 18, 39, 60) < 0) ++ return -1; ++ if (split_24bit (string, hash, 76, 4, 40, 61, 19) < 0) ++ return -1; ++ if (split_24bit (string, hash, 80, 4, 62, 20, 41) < 0) ++ return -1; ++ ++ value1 = b64_to_int (string[85]); ++ if (value1 < 0) ++ return -1; ++ value2 = b64_to_int (string[84]); ++ if (value2 < 0) ++ return -1; ++ tmp = (value1 << 6) | value2; ++ hash[63] = (uint8_t)tmp; + ++ return 0; ++} +diff --git a/src/password-crypt.h b/src/password-crypt.h +index 149a05e..a1f7710 100644 +--- a/src/password-crypt.h ++++ b/src/password-crypt.h +@@ -32,6 +32,7 @@ typedef struct { + #define PASSWORD_CRYPT_SIZE sizeof(pw_crypt_t) + + #define SHA256_B64_LENGTH 43 ++#define SHA512_B64_LENGTH 86 + + int get_hash_size (int method); + const char *get_crypt_prefix (int method); +-- +1.7.10.4 + + +From 032018daddfe6bca086c5ef1f79d147e3ac0b02a Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +Date: Fri, 25 Jan 2013 14:22:02 +0800 +Subject: [PATCH 3/9] Add the new option to import root password hash + +--- + src/mokutil.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 63 insertions(+), 15 deletions(-) + +diff --git a/src/mokutil.c b/src/mokutil.c +index d1c3763..006eff1 100644 +--- a/src/mokutil.c ++++ b/src/mokutil.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -42,6 +43,7 @@ EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, + #define RESET 0x2000 + #define HASH_FILE 0x4000 + #define GENERATE_PW_HASH 0x8000 ++#define ROOT_PW 0x10000 + + #define DEFAULT_CRYPT_METHOD SHA512_BASED + #define DEFAULT_SALT_SIZE SHA512_SALT_MAX +@@ -83,6 +85,9 @@ print_help () + 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"); ++ printf (" --root-pw\t\t\t\tUse the root password\n"); ++ printf (" \t\t\t\t(Only valid with --import, --delete,\n"); ++ printf (" \t\t\t\t --password, and --reset)\n"); + } + + static int +@@ -448,8 +453,23 @@ get_hash_from_file (const char *file, pw_crypt_t *pw_crypt) + } + + static int ++get_password_from_shadow (pw_crypt_t *pw_crypt) ++{ ++ struct spwd *pw_ent; ++ ++ pw_ent = getspnam ("root"); ++ if (!pw_ent) ++ return -1; ++ ++ if (decode_pass (pw_ent->sp_pwdp, pw_crypt) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static int + update_request (void *new_list, int list_len, uint8_t import, +- const char *hash_file) ++ const char *hash_file, const int root_pw) + { + efi_variable_t var; + const char *req_name, *auth_name; +@@ -474,6 +494,11 @@ update_request (void *new_list, int list_len, uint8_t import, + fprintf (stderr, "Failed to read hash\n"); + goto error; + } ++ } else if (root_pw) { ++ if (get_password_from_shadow (&pw_crypt) < 0) { ++ fprintf (stderr, "Failed to get root password hash\n"); ++ goto error; ++ } + } else { + if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { + fprintf (stderr, "Abort\n"); +@@ -618,7 +643,7 @@ 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, +- const char *hash_file) ++ const char *hash_file, const int root_pw) + { + efi_variable_t old_req; + const char *req_name; +@@ -731,7 +756,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, hash_file) < 0) { ++ if (update_request (new_list, real_size, import, hash_file, root_pw) < 0) { + goto error; + } + +@@ -748,15 +773,17 @@ error: + } + + static int +-import_moks (char **files, uint32_t total, const char *hash_file) ++import_moks (char **files, uint32_t total, const char *hash_file, ++ const int root_pw) + { +- return issue_mok_request (files, total, 1, hash_file); ++ return issue_mok_request (files, total, 1, hash_file, root_pw); + } + + static int +-delete_moks (char **files, uint32_t total, const char *hash_file) ++delete_moks (char **files, uint32_t total, const char *hash_file, ++ const int root_pw) + { +- return issue_mok_request (files, total, 0, hash_file); ++ return issue_mok_request (files, total, 0, hash_file, root_pw); + } + + static int +@@ -832,7 +859,7 @@ error: + } + + static int +-set_password (const char *hash_file) ++set_password (const char *hash_file, const int root_pw) + { + efi_variable_t var; + pw_crypt_t pw_crypt; +@@ -848,6 +875,11 @@ set_password (const char *hash_file) + fprintf (stderr, "Failed to read hash\n"); + goto error; + } ++ } else if (root_pw) { ++ if (get_password_from_shadow (&pw_crypt) < 0) { ++ fprintf (stderr, "Failed to get root password hash\n"); ++ goto error; ++ } + } else { + if (get_password (&password, &pw_len, PASSWORD_MIN, PASSWORD_MAX) < 0) { + fprintf (stderr, "Abort\n"); +@@ -1020,9 +1052,9 @@ error: + } + + static int +-reset_moks (const char *hash_file) ++reset_moks (const char *hash_file, const int root_pw) + { +- if (update_request (NULL, 0, 1, hash_file)) { ++ if (update_request (NULL, 0, 1, hash_file, root_pw)) { + fprintf (stderr, "Failed to issue a reset request\n"); + return -1; + } +@@ -1117,11 +1149,12 @@ main (int argc, char *argv[]) + {"reset", no_argument, 0, 0 }, + {"hash-file", required_argument, 0, 'f'}, + {"generate-hash", optional_argument, 0, 'g'}, ++ {"root-pw", no_argument, 0, 'P'}, + {0, 0, 0, 0} + }; + + int option_index = 0; +- c = getopt_long (argc, argv, "d:f:g::hi:pt:x", ++ c = getopt_long (argc, argv, "d:f:g::hi:pt:xP", + long_options, &option_index); + + if (c == -1) +@@ -1189,6 +1222,9 @@ main (int argc, char *argv[]) + case 'p': + command |= PASSWORD; + break; ++ case 'P': ++ command |= ROOT_PW; ++ break; + case 't': + key_file = strdup (optarg); + +@@ -1215,11 +1251,17 @@ main (int argc, char *argv[]) + break; + case IMPORT: + case IMPORT | HASH_FILE: +- ret = import_moks (files, total, hash_file); ++ ret = import_moks (files, total, hash_file, 0); ++ break; ++ case IMPORT | ROOT_PW: ++ ret = import_moks (files, total, NULL, 1); + break; + case DELETE: + case DELETE | HASH_FILE: +- ret = delete_moks (files, total, hash_file); ++ ret = delete_moks (files, total, hash_file, 0); ++ break; ++ case DELETE | ROOT_PW: ++ ret = delete_moks (files, total, NULL, 1); + break; + case REVOKE_IMPORT: + ret = revoke_request (1); +@@ -1232,7 +1274,10 @@ main (int argc, char *argv[]) + break; + case PASSWORD: + case PASSWORD | HASH_FILE: +- ret = set_password (hash_file); ++ ret = set_password (hash_file, 0); ++ break; ++ case PASSWORD | ROOT_PW: ++ ret = set_password (NULL, 1); + break; + case DISABLE_VALIDATION: + ret = disable_validation (); +@@ -1248,7 +1293,10 @@ main (int argc, char *argv[]) + break; + case RESET: + case RESET | HASH_FILE: +- ret = reset_moks (hash_file); ++ ret = reset_moks (hash_file, 0); ++ break; ++ case RESET | ROOT_PW: ++ ret = reset_moks (NULL, 1); + break; + case GENERATE_PW_HASH: + ret = generate_pw_hash (input_pw); +-- +1.7.10.4 + + +From 282c97b30c87687e43a019fcde3db8d809f8d227 Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +Date: Fri, 25 Jan 2013 18:29:06 +0800 +Subject: [PATCH 4/9] Support blowfish-based crypt() hash + +--- + src/mokutil.c | 15 +++++++++++++++ + src/password-crypt.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- + src/password-crypt.h | 3 +-- + 3 files changed, 62 insertions(+), 4 deletions(-) + +diff --git a/src/mokutil.c b/src/mokutil.c +index 006eff1..b6c665d 100644 +--- a/src/mokutil.c ++++ b/src/mokutil.c +@@ -508,10 +508,18 @@ update_request (void *new_list, int list_len, uint8_t import, + pw_crypt.salt_size = generate_salt (pw_crypt.salt, + DEFAULT_SALT_SIZE, + DEFAULT_SALT_SIZE); ++ + if (generate_hash (&pw_crypt, password, pw_len) < 0) { + fprintf (stderr, "Couldn't generate hash\n"); + goto error; + } ++ if (pw_crypt.method == BLOWFISH_BASED) { ++ const char *prefix = get_crypt_prefix (BLOWFISH_BASED); ++ memmove (pw_crypt.salt + 7, pw_crypt.salt, BLOWFISH_SALT_MAX); ++ memcpy (pw_crypt.salt, prefix, 7); ++ pw_crypt.salt[7 + BLOWFISH_SALT_MAX] = '\0'; ++ pw_crypt.salt_size = BLOWFISH_SALT_MAX + 7 + 1; ++ } + } + + if (new_list) { +@@ -893,6 +901,13 @@ set_password (const char *hash_file, const int root_pw) + fprintf (stderr, "Couldn't generate hash\n"); + goto error; + } ++ if (pw_crypt.method == BLOWFISH_BASED) { ++ const char *prefix = get_crypt_prefix (BLOWFISH_BASED); ++ memmove (pw_crypt.salt + 7, pw_crypt.salt, BLOWFISH_SALT_MAX); ++ memcpy (pw_crypt.salt, prefix, 7); ++ pw_crypt.salt[7 + BLOWFISH_SALT_MAX] = '\0'; ++ pw_crypt.salt_size = BLOWFISH_SALT_MAX + 7 + 1; ++ } + } + + var.Data = (void *)&pw_crypt; +diff --git a/src/password-crypt.c b/src/password-crypt.c +index 84ee079..3ecb6ff 100644 +--- a/src/password-crypt.c ++++ b/src/password-crypt.c +@@ -6,6 +6,8 @@ + + #define MIN(a,b) ((a)<(b)?(a):(b)) + ++#define BLOWFISH_HASH_SIZE 31 /* 184 / 6 + 1 */ ++ + #define SHA256_DEFAULT_ROUNDS 5000 + #define SHA512_DEFAULT_ROUNDS 5000 + +@@ -15,6 +17,10 @@ static const char b64t[64] = + static const char sha256_prefix[] = "$5$"; + static const char sha512_prefix[] = "$6$"; + ++static const char bf_a_prefix[] = "$2a$"; ++static const char bf_x_prefix[] = "$2x$"; ++static const char bf_y_prefix[] = "$2y$"; ++ + static const char sha_rounds_prefix[] = "rounds="; + + static int restore_sha256_array (const char *string, uint8_t *hash); +@@ -35,7 +41,7 @@ get_hash_size (int method) + case SHA512_BASED: + return SHA512_DIGEST_LENGTH; + case BLOWFISH_BASED: +- return 184 / 8; /* per "man crypt" */ ++ return BLOWFISH_HASH_SIZE; + } + + return -1; +@@ -56,7 +62,7 @@ get_crypt_prefix (int method) + case SHA512_BASED: + return "$6$"; + case BLOWFISH_BASED: +- return "$2y$"; /* per "man crypt" */ ++ return "$2y$10$"; /* FIXME change the count */ + } + + return NULL; +@@ -162,6 +168,37 @@ decode_sha512_pass (const char *string, pw_crypt_t *pw_crypt) + return 0; + } + ++static int ++decode_blowfish_pass (const char *string, pw_crypt_t *pw_crypt) ++{ ++ /* Expected string: \$2[axy]\$[0-9]{2}\$[./A-Za-z0-9]{53} */ ++ /* Store the first (22+7) bytes in salt[] and the rest in hash */ ++ ++ if (strlen(string) != (53 + 7)) ++ return -1; ++ ++ if (string[0] != '$' || ++ string[1] != '2' || ++ (string[2] != 'a' && string[2] != 'x' && string[2] != 'y') || ++ string[3] != '$' || ++ string[4] < '0' || string[4] > '3' || ++ string[5] < '0' || string[5] > '9' || ++ (string[4] == '3' && string[5] > '1') || ++ string[6] != '$') { ++ return -1; ++ } ++ ++ pw_crypt->iter_count = 0; ++ ++ memcpy (pw_crypt->salt, string, (22 + 7)); ++ pw_crypt->salt[22 + 7] = '\0'; ++ pw_crypt->salt_size = 22 + 7 + 1; ++ ++ memcpy (pw_crypt->hash, string + 22 + 7, BLOWFISH_HASH_SIZE); ++ ++ return 0; ++} ++ + int + decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt) + { +@@ -178,6 +215,13 @@ decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt) + return decode_sha512_pass (crypt_pass + strlen (sha512_prefix), pw_crypt); + } + ++ if (strncmp (crypt_pass, bf_a_prefix, 4) == 0 || ++ strncmp (crypt_pass, bf_x_prefix, 4) == 0 || ++ strncmp (crypt_pass, bf_y_prefix, 4) == 0) { ++ pw_crypt->method = BLOWFISH_BASED; ++ return decode_blowfish_pass (crypt_pass, pw_crypt); ++ } ++ + return -1; + } + +diff --git a/src/password-crypt.h b/src/password-crypt.h +index a1f7710..701dfd9 100644 +--- a/src/password-crypt.h ++++ b/src/password-crypt.h +@@ -9,8 +9,7 @@ + #define MD5_SALT_MAX 8 + #define SHA256_SALT_MAX 16 + #define SHA512_SALT_MAX 16 +-/* The max salt size of Blowfish in UINT8 */ +-#define BLOWFISH_SALT_MAX 16 ++#define BLOWFISH_SALT_MAX 22 + + enum HashMethod { + TRANDITIONAL_DES = 0, +-- +1.7.10.4 + + +From 97f0dec8aa8f63a7ef81e060a512b13bcdf4e3a7 Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +Date: Mon, 28 Jan 2013 16:12:44 +0800 +Subject: [PATCH 5/9] Simplify the hash generation + +--- + src/mokutil.c | 30 +++++++++--------------------- + 1 file changed, 9 insertions(+), 21 deletions(-) + +diff --git a/src/mokutil.c b/src/mokutil.c +index b6c665d..ecf9e00 100644 +--- a/src/mokutil.c ++++ b/src/mokutil.c +@@ -403,6 +403,10 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len) + return -1; + prefix_len = strlen(prefix); + ++ pw_crypt->salt_size = generate_salt (pw_crypt->salt, ++ DEFAULT_SALT_SIZE, ++ DEFAULT_SALT_SIZE); ++ + strncpy (settings, prefix, prefix_len); + strncpy (settings + prefix_len, (const char *)pw_crypt->salt, + pw_crypt->salt_size); +@@ -421,6 +425,11 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len) + memcpy (pw_crypt->hash, new_crypt.hash, hash_len); + pw_crypt->iter_count = new_crypt.iter_count; + ++ if (pw_crypt->method == BLOWFISH_BASED) { ++ pw_crypt->salt_size = new_crypt.salt_size; ++ memcpy (pw_crypt->salt, new_crypt.salt, new_crypt.salt_size); ++ } ++ + return 0; + } + +@@ -505,21 +514,10 @@ update_request (void *new_list, int list_len, uint8_t import, + goto error; + } + +- pw_crypt.salt_size = generate_salt (pw_crypt.salt, +- DEFAULT_SALT_SIZE, +- DEFAULT_SALT_SIZE); +- + if (generate_hash (&pw_crypt, password, pw_len) < 0) { + fprintf (stderr, "Couldn't generate hash\n"); + goto error; + } +- if (pw_crypt.method == BLOWFISH_BASED) { +- const char *prefix = get_crypt_prefix (BLOWFISH_BASED); +- memmove (pw_crypt.salt + 7, pw_crypt.salt, BLOWFISH_SALT_MAX); +- memcpy (pw_crypt.salt, prefix, 7); +- pw_crypt.salt[7 + BLOWFISH_SALT_MAX] = '\0'; +- pw_crypt.salt_size = BLOWFISH_SALT_MAX + 7 + 1; +- } + } + + if (new_list) { +@@ -894,20 +892,10 @@ set_password (const char *hash_file, const int root_pw) + goto error; + } + +- pw_crypt.salt_size = generate_salt (pw_crypt.salt, +- DEFAULT_SALT_SIZE, +- DEFAULT_SALT_SIZE); + if (generate_hash (&pw_crypt, password, pw_len) < 0) { + fprintf (stderr, "Couldn't generate hash\n"); + goto error; + } +- if (pw_crypt.method == BLOWFISH_BASED) { +- const char *prefix = get_crypt_prefix (BLOWFISH_BASED); +- memmove (pw_crypt.salt + 7, pw_crypt.salt, BLOWFISH_SALT_MAX); +- memcpy (pw_crypt.salt, prefix, 7); +- pw_crypt.salt[7 + BLOWFISH_SALT_MAX] = '\0'; +- pw_crypt.salt_size = BLOWFISH_SALT_MAX + 7 + 1; +- } + } + + var.Data = (void *)&pw_crypt; +-- +1.7.10.4 + + +From 9205203a929aac32fc1e4a53cd8e1c1bb74cfde3 Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +Date: Tue, 29 Jan 2013 12:16:17 +0800 +Subject: [PATCH 6/9] Support MD5-based crypt() hash + +--- + src/password-crypt.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ + src/password-crypt.h | 1 + + 2 files changed, 77 insertions(+) + +diff --git a/src/password-crypt.c b/src/password-crypt.c +index 3ecb6ff..e435ad3 100644 +--- a/src/password-crypt.c ++++ b/src/password-crypt.c +@@ -14,6 +14,8 @@ + static const char b64t[64] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + ++static const char md5_prefix[] = "$1$"; ++ + static const char sha256_prefix[] = "$5$"; + static const char sha512_prefix[] = "$6$"; + +@@ -23,6 +25,7 @@ static const char bf_y_prefix[] = "$2y$"; + + static const char sha_rounds_prefix[] = "rounds="; + ++static int restore_md5_array (const char *string, uint8_t *hash); + static int restore_sha256_array (const char *string, uint8_t *hash); + static int restore_sha512_array (const char *string, uint8_t *hash); + +@@ -69,6 +72,39 @@ get_crypt_prefix (int method) + } + + static int ++decode_md5_pass (const char *string, pw_crypt_t *pw_crypt) ++{ ++ /* Expected string: [./0-9A-Za-z]{1,8}\$[./0-9A-Za-z]{22} */ ++ char *tmp, *ptr = (char *)string; ++ char b64_hash[MD5_B64_LENGTH + 1]; ++ int count = 0; ++ ++ pw_crypt->iter_count = 1000; ++ ++ /* get salt */ ++ for (tmp = ptr; *tmp != '$'; tmp++) { ++ if (*tmp == '\0') ++ return -1; ++ count++; ++ } ++ count = MIN(count, MD5_SALT_MAX); ++ memcpy (pw_crypt->salt, ptr, count); ++ pw_crypt->salt_size = count; ++ ptr = tmp + 1; ++ ++ /* get hash */ ++ if (strlen(ptr) != MD5_B64_LENGTH) ++ return -1; ++ memcpy (b64_hash, ptr, MD5_B64_LENGTH); ++ b64_hash[MD5_B64_LENGTH] = '\0'; ++ ++ if (restore_md5_array (b64_hash, pw_crypt->hash) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++static int + decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt) + { + /* Expected string: (rounds=[0-9]{1,9}\$)?([./0-9A-Za-z]{1,16})?\$[./0-9A-Za-z]{43} */ +@@ -205,6 +241,11 @@ decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt) + if (!pw_crypt) + return -1; + ++ if (strncmp (crypt_pass, md5_prefix, 3) == 0) { ++ pw_crypt->method = MD5_BASED; ++ return decode_md5_pass (crypt_pass + strlen (md5_prefix), pw_crypt); ++ } ++ + if (strncmp (crypt_pass, sha256_prefix, 3) == 0) { + pw_crypt->method = SHA256_BASED; + return decode_sha256_pass (crypt_pass + strlen (sha256_prefix), pw_crypt); +@@ -273,6 +314,41 @@ split_24bit (const char *string, uint8_t *hash, int start, int n, + return 0; + } + ++int restore_md5_array (const char *string, uint8_t *hash) ++{ ++ uint32_t tmp = 0; ++ int value1, value2; ++ ++ if (strlen (string) != MD5_B64_LENGTH) ++ return -1; ++ ++ if (split_24bit (string, hash, 0, 4, 0, 6, 12) < 0) ++ return -1; ++ ++ if (split_24bit (string, hash, 4, 4, 1, 7, 13) < 0) ++ return -1; ++ ++ if (split_24bit (string, hash, 8, 4, 2, 8, 14) < 0) ++ return -1; ++ ++ if (split_24bit (string, hash, 12, 4, 3, 9, 15) < 0) ++ return -1; ++ ++ if (split_24bit (string, hash, 16, 4, 4, 10, 5) < 0) ++ return -1; ++ ++ value1 = b64_to_int (string[21]); ++ if (value1 < 0) ++ return -1; ++ value2 = b64_to_int (string[20]); ++ if (value2 < 0) ++ return -1; ++ tmp = (value1 << 6) | value2; ++ hash[11] = (uint8_t)tmp; ++ ++ return 0; ++} ++ + int + restore_sha256_array (const char *string, uint8_t *hash) + { +diff --git a/src/password-crypt.h b/src/password-crypt.h +index 701dfd9..aba6975 100644 +--- a/src/password-crypt.h ++++ b/src/password-crypt.h +@@ -30,6 +30,7 @@ typedef struct { + + #define PASSWORD_CRYPT_SIZE sizeof(pw_crypt_t) + ++#define MD5_B64_LENGTH 22 + #define SHA256_B64_LENGTH 43 + #define SHA512_B64_LENGTH 86 + +-- +1.7.10.4 + + +From 472dbeefd87085e4164369110e0ba3d8bf05a964 Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +Date: Tue, 29 Jan 2013 13:59:36 +0800 +Subject: [PATCH 7/9] Fix SHA256/SHA512 parsing on hashes with no salt + +--- + src/password-crypt.c | 60 +++++++++++++++++++++++++++----------------------- + 1 file changed, 32 insertions(+), 28 deletions(-) + +diff --git a/src/password-crypt.c b/src/password-crypt.c +index e435ad3..de15193 100644 +--- a/src/password-crypt.c ++++ b/src/password-crypt.c +@@ -109,7 +109,7 @@ decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt) + { + /* Expected string: (rounds=[0-9]{1,9}\$)?([./0-9A-Za-z]{1,16})?\$[./0-9A-Za-z]{43} */ + char *tmp, *ptr = (char *)string; +- char *b64_hash; ++ char b64_hash[SHA256_B64_LENGTH + 1]; + int count = 0; + + /* get rounds */ +@@ -127,30 +127,32 @@ decode_sha256_pass (const char *string, pw_crypt_t *pw_crypt) + } + + /* get salt */ +- for (tmp = ptr; *tmp != '$'; tmp++) { +- if (tmp == '\0') +- return -1; +- count++; ++ tmp = ptr; ++ if (strlen (ptr) > SHA256_B64_LENGTH) { ++ while (*tmp != '$') { ++ if (tmp == '\0') ++ return -1; ++ count++; ++ tmp++; ++ } ++ ++ count = MIN(count, SHA256_SALT_MAX); ++ memcpy (pw_crypt->salt, ptr, count); ++ pw_crypt->salt_size = count; ++ ptr = tmp + 1; ++ } else { ++ pw_crypt->salt_size = 0; + } +- count = MIN(count, SHA256_SALT_MAX); +- memcpy (pw_crypt->salt, ptr, count); +- pw_crypt->salt_size = count; +- ptr = tmp + 1; + + /* get hash */ + if (strlen(ptr) < SHA256_B64_LENGTH) + return -1; +- b64_hash = malloc (SHA256_B64_LENGTH + 1); +- if (!b64_hash) +- return -1; + memcpy (b64_hash, ptr, SHA256_B64_LENGTH); + b64_hash[SHA256_B64_LENGTH] = '\0'; + + if (restore_sha256_array (b64_hash, pw_crypt->hash) < 0) + return -1; + +- free (b64_hash); +- + return 0; + } + +@@ -159,7 +161,7 @@ decode_sha512_pass (const char *string, pw_crypt_t *pw_crypt) + { + /* Expected string: (rounds=[0-9]{1,9}\$)?([./0-9A-Za-z]{1,16})?\$[./0-9A-Za-z]{86} */ + char *tmp, *ptr = (char *)string; +- char *b64_hash; ++ char b64_hash[SHA512_B64_LENGTH + 1]; + int count = 0; + + /* get rounds */ +@@ -177,30 +179,32 @@ decode_sha512_pass (const char *string, pw_crypt_t *pw_crypt) + } + + /* get salt */ +- for (tmp = ptr; *tmp != '$'; tmp++) { +- if (tmp == '\0') +- return -1; +- count++; ++ tmp = ptr; ++ if (strlen (ptr) > SHA512_B64_LENGTH) { ++ while (*tmp != '$') { ++ if (tmp == '\0') ++ return -1; ++ count++; ++ tmp++; ++ } ++ ++ count = MIN(count, SHA512_SALT_MAX); ++ memcpy (pw_crypt->salt, ptr, count); ++ pw_crypt->salt_size = count; ++ ptr = tmp + 1; ++ } else { ++ pw_crypt->salt_size = 0; + } +- count = MIN(count, SHA512_SALT_MAX); +- memcpy (pw_crypt->salt, ptr, count); +- pw_crypt->salt_size = count; +- ptr = tmp + 1; + + /* get hash */ + if (strlen(ptr) < SHA512_B64_LENGTH) + return -1; +- b64_hash = malloc (SHA512_B64_LENGTH + 1); +- if (!b64_hash) +- return -1; + memcpy (b64_hash, ptr, SHA512_B64_LENGTH); + b64_hash[SHA512_B64_LENGTH] = '\0'; + + if (restore_sha512_array (b64_hash, pw_crypt->hash) < 0) + return -1; + +- free (b64_hash); +- + return 0; + } + +-- +1.7.10.4 + + +From ddd501071734325a213fe994471dac269c69153a Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +Date: Tue, 29 Jan 2013 16:34:59 +0800 +Subject: [PATCH 8/9] Just use crypt() to generate hashes + +--- + src/mokutil.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/src/mokutil.c b/src/mokutil.c +index ecf9e00..27ebf09 100644 +--- a/src/mokutil.c ++++ b/src/mokutil.c +@@ -12,7 +12,6 @@ + #include + #include + +-#define __USE_GNU + #include + + #include "efi.h" +@@ -389,7 +388,6 @@ static int + generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len) + { + pw_crypt_t new_crypt; +- struct crypt_data data; + char settings[SETTINGS_LEN]; + char *crypt_string; + const char *prefix; +@@ -412,7 +410,7 @@ generate_hash (pw_crypt_t *pw_crypt, char *password, int pw_len) + pw_crypt->salt_size); + settings[pw_crypt->salt_size + prefix_len] = '\0'; + +- crypt_string = crypt_r (password, settings, &data); ++ crypt_string = crypt (password, settings); + if (!crypt_string) + return -1; + +@@ -1068,7 +1066,6 @@ reset_moks (const char *hash_file, const int root_pw) + static int + generate_pw_hash (const char *input_pw) + { +- struct crypt_data data; + char settings[SETTINGS_LEN]; + char *password = NULL; + char *crypt_string; +@@ -1106,7 +1103,7 @@ generate_pw_hash (const char *input_pw) + DEFAULT_SALT_SIZE, DEFAULT_SALT_SIZE); + settings[DEFAULT_SALT_SIZE + prefix_len] = '\0'; + +- crypt_string = crypt_r (password, settings, &data); ++ crypt_string = crypt (password, settings); + if (!crypt_string) { + fprintf (stderr, "Failed to generate hash\n"); + goto error; +-- +1.7.10.4 + + +From f944da88acfffe80279de37c4181c9c19ff9a864 Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +Date: Tue, 29 Jan 2013 16:35:30 +0800 +Subject: [PATCH 9/9] Support Traditional DES hash + +--- + src/password-crypt.c | 29 +++++++++++++++++++++++++---- + src/password-crypt.h | 2 +- + 2 files changed, 26 insertions(+), 5 deletions(-) + +diff --git a/src/password-crypt.c b/src/password-crypt.c +index de15193..95bb687 100644 +--- a/src/password-crypt.c ++++ b/src/password-crypt.c +@@ -6,6 +6,8 @@ + + #define MIN(a,b) ((a)<(b)?(a):(b)) + ++#define TRAD_DES_HASH_SIZE 13 /* (64/6+1) + (12/6) */ ++#define BSDI_DES_HASH_SIZE 20 /* (64/6+1) + (24/6) + 4 + 1 */ + #define BLOWFISH_HASH_SIZE 31 /* 184 / 6 + 1 */ + + #define SHA256_DEFAULT_ROUNDS 5000 +@@ -33,10 +35,10 @@ int + get_hash_size (int method) + { + switch (method) { +- case TRANDITIONAL_DES: +- return 64 / 8; /* per "man crypt" */ ++ case TRADITIONAL_DES: ++ return TRAD_DES_HASH_SIZE; + case EXTEND_BSDI_DES: +- return 64 / 8; /* per "man crypt" */ ++ return BSDI_DES_HASH_SIZE; + case MD5_BASED: + return MD5_DIGEST_LENGTH; + case SHA256_BASED: +@@ -54,7 +56,7 @@ const char * + get_crypt_prefix (int method) + { + switch (method) { +- case TRANDITIONAL_DES: ++ case TRADITIONAL_DES: + return ""; /* per "man crypt" */ + case EXTEND_BSDI_DES: + return "_"; /* per "man crypt" */ +@@ -72,6 +74,20 @@ get_crypt_prefix (int method) + } + + static int ++decode_trad_des_pass (const char *string, pw_crypt_t *pw_crypt) ++{ ++ /* Expected string: [./0-9A-Za-z]{13} */ ++ pw_crypt->iter_count = 25; ++ pw_crypt->salt_size = 2; ++ memcpy (pw_crypt->salt, string, 2); ++ pw_crypt->salt[2] = '\0'; ++ memcpy (pw_crypt->hash, string, TRAD_DES_HASH_SIZE); ++ pw_crypt->hash[TRAD_DES_HASH_SIZE] = '\0'; ++ ++ return 0; ++} ++ ++static int + decode_md5_pass (const char *string, pw_crypt_t *pw_crypt) + { + /* Expected string: [./0-9A-Za-z]{1,8}\$[./0-9A-Za-z]{22} */ +@@ -267,6 +283,11 @@ decode_pass (const char *crypt_pass, pw_crypt_t *pw_crypt) + return decode_blowfish_pass (crypt_pass, pw_crypt); + } + ++ if (strlen (crypt_pass) == TRAD_DES_HASH_SIZE) { ++ pw_crypt->method = TRADITIONAL_DES; ++ return decode_trad_des_pass (crypt_pass, pw_crypt); ++ } ++ + return -1; + } + +diff --git a/src/password-crypt.h b/src/password-crypt.h +index aba6975..92338ad 100644 +--- a/src/password-crypt.h ++++ b/src/password-crypt.h +@@ -12,7 +12,7 @@ + #define BLOWFISH_SALT_MAX 22 + + enum HashMethod { +- TRANDITIONAL_DES = 0, ++ TRADITIONAL_DES = 0, + EXTEND_BSDI_DES, + MD5_BASED, + SHA256_BASED, +-- +1.7.10.4 + diff --git a/mokutil-support-new-pw-hash.patch b/mokutil-support-new-pw-hash.patch index a5f6e8b..82702e2 100644 --- a/mokutil-support-new-pw-hash.patch +++ b/mokutil-support-new-pw-hash.patch @@ -1,7 +1,7 @@ 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 01/10] Use getopt() to parse options +Subject: [PATCH 1/9] Use getopt() to parse options --- src/mokutil.c | 259 +++++++++++++++++++++++++++------------------------------ @@ -350,7 +350,7 @@ index ea8481a..2ab005c 100644 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 02/10] Adopt new password hash format +Subject: [PATCH 2/9] Adopt new password hash format old format: MokNew + sha256sum(MokNew + password) new format: salt + sha256sum(salt + password) @@ -555,7 +555,7 @@ index 2ab005c..61c432d 100644 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 03/10] Close the key file +Subject: [PATCH 3/9] Close the key file --- src/mokutil.c | 2 ++ @@ -581,7 +581,7 @@ index 61c432d..86d5328 100644 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 04/10] Get rid of misused while statement +Subject: [PATCH 4/9] Get rid of misused while statement --- src/mokutil.c | 4 ++-- @@ -616,7 +616,7 @@ index 86d5328..36783cb 100644 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 05/10] Read the password hash from the file +Subject: [PATCH 5/9] Read the password hash from the file --- src/mokutil.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++----------- @@ -916,7 +916,7 @@ index 36783cb..4b9002e 100644 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 06/10] Add a new command to generate the password hash +Subject: [PATCH 6/9] Add a new command to generate the password hash --- src/mokutil.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- @@ -1053,7 +1053,7 @@ index 4b9002e..fdb1a2b 100644 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 07/10] Amend help +Subject: [PATCH 7/9] Amend help --- src/mokutil.c | 59 ++++++++++++++++++++++----------------------------------- @@ -1136,7 +1136,7 @@ index fdb1a2b..72a651a 100644 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 08/10] New commands to revoke the import or delete request +Subject: [PATCH 8/9] New commands to revoke the import or delete request --- src/mokutil.c | 58 +++++++++++++++++++++++++++++++++++---------------------- @@ -1254,7 +1254,7 @@ index 72a651a..7392845 100644 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 09/10] Apply stricter permissions to some variables +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. @@ -1340,340 +1340,3 @@ index 7392845..c1a0ffc 100644 -- 1.7.10.4 - -From 47645170396e2800980044c7054bcd1078bbba93 Mon Sep 17 00:00:00 2001 -From: Gary Ching-Pang Lin -Date: Fri, 18 Jan 2013 17:47:04 +0800 -Subject: [PATCH 10/10] Extend the password hash format - -Several new fields were added to support hash from /etc/shadow. - -[Hash Method][Interation Count][Salt Size][Salt][hash] - -Besides, the salt is hashed with the 8-bit char password instead of -an efi_char16_t password array. ---- - src/PasswordHash.h | 33 ++++++++++++++++ - src/mokutil.c | 106 +++++++++++++++++++++++++++++----------------------- - 2 files changed, 93 insertions(+), 46 deletions(-) - create mode 100644 src/PasswordHash.h - -diff --git a/src/PasswordHash.h b/src/PasswordHash.h -new file mode 100644 -index 0000000..2aeded6 ---- /dev/null -+++ b/src/PasswordHash.h -@@ -0,0 +1,33 @@ -+#ifndef __PASSWORD_HASH_H__ -+#define __PASSWORD_HASH_H__ -+ -+#include -+ -+#define PASSWORD_HASH_SIZE 88 -+ -+/* The max salt size (in bits) */ -+#define T_DES_SALT_MAX 12 -+#define E_BSI_DES_SALT_MAX 24 -+#define MD5_SALT_MAX 48 -+#define SHA256_SALT_MAX 96 -+#define SHA512_SALT_MAX 96 -+#define BLOWFISH_SALT_MAX 128 -+ -+enum HashMethod { -+ Tranditional_DES = 0, -+ Extend_BSDI_DES, -+ MD5_BASED, -+ SHA256_BASED, -+ SHA512_BASED, -+ BLOWFISH_BASED -+}; -+ -+typedef struct { -+ uint16_t method; -+ uint32_t iter_count; -+ uint16_t salt_size; -+ uint8_t salt[16]; -+ uint8_t hash[64]; -+} __attribute__ ((packed)) pw_hash_t; -+ -+#endif /* __PASSWORD_HASH_H__ */ -diff --git a/src/mokutil.c b/src/mokutil.c -index c1a0ffc..38039b9 100644 ---- a/src/mokutil.c -+++ b/src/mokutil.c -@@ -13,6 +13,7 @@ - - #include "efi.h" - #include "signature.h" -+#include "PasswordHash.h" - - #define SHIM_LOCK_GUID \ - EFI_GUID (0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23) -@@ -20,8 +21,6 @@ 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 -@@ -359,37 +358,35 @@ error: - return ret; - } - --static void --generate_salt (uint8_t salt[], unsigned int salt_len) -+static unsigned int -+generate_salt (uint8_t salt[], unsigned int max_size, unsigned int min_size) - { -+ unsigned int salt_len = max_size / 8; - int i; - - srand (time (NULL)); - - for (i = 0; i < salt_len; i++) - salt[i] = rand() % 256; -+ -+ return max_size; - } - - static int - generate_hash (void *salt, unsigned int salt_len, char *password, - int pw_len, uint8_t *auth) - { -- efi_char16_t efichar_pass[PASSWORD_MAX+1]; -- unsigned long efichar_len; - SHA256_CTX ctx; - - if (!password || !auth) - return -1; - -- efichar_len = efichar_from_char (efichar_pass, password, -- (PASSWORD_MAX+1)*sizeof(efi_char16_t)); -- - SHA256_Init (&ctx); - - if (salt) - SHA256_Update (&ctx, salt, salt_len); - -- SHA256_Update (&ctx, efichar_pass, efichar_len); -+ SHA256_Update (&ctx, password, pw_len); - - SHA256_Final (auth, &ctx); - -@@ -412,7 +409,7 @@ char_to_int (const char c) - } - - static int --read_hex_array (const char *string, char *out, int len) -+read_hex_array (const char *string, uint8_t *out, unsigned int len) - { - int i, digit_1, digit_2; - -@@ -422,17 +419,18 @@ read_hex_array (const char *string, char *out, int len) - if (digit_1 < 0 || digit_2 < 0) - return -1; - -- out[i] = (char)digit_1 * 16 + (char)digit_2; -+ out[i] = (uint8_t)digit_1 * 16 + (uint8_t)digit_2; - } - - return 0; - } - - static int --get_hash_from_file (const char *file, void *salt, void *hash) -+get_hash_from_file (const char *file, pw_hash_t *pw_hash) - { - FILE *fptr; -- char salt_string[2*SALT_SIZE]; -+ unsigned int method, iter_count, salt_size; -+ char salt_string[2*(SHA256_SALT_MAX/8)]; - char hash_string[2*SHA256_DIGEST_LENGTH]; - - fptr = fopen (file, "r"); -@@ -441,19 +439,24 @@ get_hash_from_file (const char *file, void *salt, void *hash) - return -1; - } - -- memset (salt_string, 0, 2*SALT_SIZE); -+ memset (salt_string, 0, 2*(SHA256_SALT_MAX/8)); - memset (hash_string, 0, 2*SHA256_DIGEST_LENGTH); - -- fscanf (fptr, "%32c.%64c", salt_string, hash_string); -+ fscanf (fptr, "%x.%x.%x.%24c.%64c", &method, &iter_count, &salt_size, -+ salt_string, hash_string); - - fclose (fptr); - -- if (read_hex_array (salt_string, salt, SALT_SIZE) < 0) { -+ pw_hash->method = (uint16_t)method; -+ pw_hash->iter_count = (uint32_t)iter_count; -+ pw_hash->salt_size = (uint16_t)salt_size; -+ -+ if (read_hex_array (salt_string, pw_hash->salt, salt_size/8) < 0) { - fprintf (stderr, "Corrupted salt\n"); - return -1; - } - -- if (read_hex_array (hash_string, hash, SHA256_DIGEST_LENGTH) < 0) { -+ if (read_hex_array (hash_string, pw_hash->hash, SHA256_DIGEST_LENGTH) < 0) { - fprintf (stderr, "Corrupted hash\n"); - return -1; - } -@@ -467,13 +470,16 @@ update_request (void *new_list, int list_len, uint8_t import, - { - efi_variable_t var; - const char *req_name, *auth_name; -- uint8_t salt[SALT_SIZE]; -- uint8_t hash[SHA256_DIGEST_LENGTH]; -- uint8_t auth[SALT_SIZE + SHA256_DIGEST_LENGTH]; -+ pw_hash_t pw_hash; - char *password = NULL; - int pw_len; - int ret = -1; - -+ bzero (&pw_hash, sizeof(pw_hash_t)); -+ pw_hash.method = SHA256_BASED; -+ pw_hash.iter_count = 1; -+ pw_hash.salt_size = SHA256_SALT_MAX; -+ - if (import) { - req_name = "MokNew"; - auth_name = "MokAuth"; -@@ -483,7 +489,7 @@ update_request (void *new_list, int list_len, uint8_t import, - } - - if (hash_file) { -- if (get_hash_from_file (hash_file, salt, hash) < 0) { -+ if (get_hash_from_file (hash_file, &pw_hash) < 0) { - fprintf (stderr, "Failed to read hash\n"); - goto error; - } -@@ -493,14 +499,13 @@ update_request (void *new_list, int list_len, uint8_t import, - goto error; - } - -- generate_salt (salt, SALT_SIZE); -- if (generate_hash (salt, SALT_SIZE, password, pw_len, hash) < 0) { -+ generate_salt (pw_hash.salt, SHA256_SALT_MAX, 0); -+ if (generate_hash (pw_hash.salt, SHA256_SALT_MAX/8, password, -+ pw_len, pw_hash.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*/ -@@ -522,9 +527,9 @@ update_request (void *new_list, int list_len, uint8_t import, - test_and_delete_var (req_name); - } - -- /* Write MokAuth */ -- var.Data = auth; -- var.DataSize = SHA256_DIGEST_LENGTH + SALT_SIZE; -+ /* Write MokAuth or MokDelAuth */ -+ var.Data = (void *)&pw_hash; -+ var.DataSize = PASSWORD_HASH_SIZE; - var.VariableName = auth_name; - - var.VendorGuid = SHIM_LOCK_GUID; -@@ -848,15 +853,18 @@ static int - set_password (const char *hash_file) - { - efi_variable_t var; -- uint8_t salt[SALT_SIZE]; -- uint8_t hash[SHA256_DIGEST_LENGTH]; -- uint8_t auth[SHA256_DIGEST_LENGTH + SALT_SIZE]; -+ pw_hash_t pw_hash; - char *password = NULL; - int pw_len; - int ret = -1; - -+ bzero (&pw_hash, sizeof(pw_hash_t)); -+ pw_hash.method = SHA256_BASED; -+ pw_hash.iter_count = 1; -+ pw_hash.salt_size = SHA256_SALT_MAX; -+ - if (hash_file) { -- if (get_hash_from_file (hash_file, salt, hash) < 0) { -+ if (get_hash_from_file (hash_file, &pw_hash) < 0) { - fprintf (stderr, "Failed to read hash\n"); - goto error; - } -@@ -866,17 +874,16 @@ set_password (const char *hash_file) - goto error; - } - -- generate_salt (salt, SALT_SIZE); -- if (generate_hash (salt, SALT_SIZE, password, pw_len, hash) < 0) { -+ generate_salt (pw_hash.salt, SHA256_SALT_MAX, 0); -+ if (generate_hash (pw_hash.salt, SHA256_SALT_MAX/8, password, -+ pw_len, pw_hash.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 + SALT_SIZE; -+ var.Data = (void *)&pw_hash; -+ var.DataSize = PASSWORD_HASH_SIZE; - var.VariableName = "MokPW"; - - var.VendorGuid = SHIM_LOCK_GUID; -@@ -1044,11 +1051,15 @@ reset_moks (const char *hash_file) - static int - generate_pw_hash (const char *input_pw) - { -- uint8_t salt[SALT_SIZE]; -- uint8_t hash[SHA256_DIGEST_LENGTH]; -+ pw_hash_t pw_hash; - char *password = NULL; - int pw_len, i, ret = -1; - -+ bzero (&pw_hash, sizeof(pw_hash_t)); -+ pw_hash.method = SHA256_BASED; -+ pw_hash.iter_count = 1; -+ pw_hash.salt_size = SHA256_SALT_MAX; -+ - if (input_pw) { - pw_len = strlen (input_pw); - if (pw_len > PASSWORD_MAX || pw_len < PASSWORD_MIN) { -@@ -1070,19 +1081,22 @@ generate_pw_hash (const char *input_pw) - } - } - -- generate_salt (salt, SALT_SIZE); -- if (generate_hash (salt, SALT_SIZE, password, pw_len, hash) < 0) { -+ generate_salt (pw_hash.salt, SHA256_SALT_MAX, 0); -+ if (generate_hash (pw_hash.salt, SHA256_SALT_MAX/8, password, -+ pw_len, pw_hash.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); -+ printf ("%x.%x.%x.", pw_hash.method, pw_hash.iter_count, -+ pw_hash.salt_size); -+ for (i = 0; i < (SHA256_SALT_MAX/8); i++) { -+ printf ("%x%x", pw_hash.salt[i]/16, pw_hash.salt[i]%16); - } - putchar ('.'); - for (i = 0; i < SHA256_DIGEST_LENGTH; i++) -- printf ("%x%x", hash[i]/16, hash[i]%16); -+ printf ("%x%x", pw_hash.hash[i]/16, pw_hash.hash[i]%16); - putchar ('\n'); - - ret = 0; --- -1.7.10.4 - diff --git a/mokutil-update-man-page.patch b/mokutil-update-man-page.patch new file mode 100644 index 0000000..22e5cee --- /dev/null +++ b/mokutil-update-man-page.patch @@ -0,0 +1,124 @@ +From 53a40965390cfa3b99d636874c6b9d968380f312 Mon Sep 17 00:00:00 2001 +From: Gary Ching-Pang Lin +Date: Wed, 30 Jan 2013 14:16:16 +0800 +Subject: [PATCH] Update man page + +--- + man/mokutil.1 | 59 +++++++++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 43 insertions(+), 16 deletions(-) + +diff --git a/man/mokutil.1 b/man/mokutil.1 +index 7a70d3e..fabd7a9 100644 +--- a/man/mokutil.1 ++++ b/man/mokutil.1 +@@ -1,27 +1,41 @@ +-.TH MOKUTIL 1 "Wed Nov 07 2012" ++.TH MOKUTIL 1 "Wed Jan 30 2013" + .SH NAME + + mokutil \- utility to manipulate machine owner keys + + .SH SYNOPSIS +-\fBmokutil\fR [--list-enrolled | -le] ++\fBmokutil\fR [--list-enrolled] + .br +-\fBmokutil\fR [--list-new | -ln] ++\fBmokutil\fR [--list-new] + .br +-\fBmokutil\fR [--import | -i] ... ++\fBmokutil\fR [--import \fIkeylist\fR| -i \fIkeylist\fR] ++ ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P]) + .br +-\fBmokutil\fR [--delete-all | -D] ++\fBmokutil\fR [--delete \fIkeylist\fR | -d \fIkeylist\fR] ++ ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P]) + .br +-\fBmokutil\fR [--revoke | -r] ++\fBmokutil\fR [--revoke-import] ++.br ++\fBmokutil\fR [--revoke-delete] + .br + \fBmokutil\fR [--export | -x] + .br + \fBmokutil\fR [--password | -p] ++ ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P]) + .br + \fBmokutil\fR [--disable-validation] + .br + \fBmokutil\fR [--enable-validation] + .br ++\fBmokutil\fR [--sb-state] ++.br ++\fBmokutil\fR [--test-key | -t] ... ++.br ++\fBmokutil\fR [--reset] ++ ([--hash-file \fIhashfile\fR | -f \fIhashfile\fR] | [--root-pw | -P]) ++.br ++\fBmokutil\fR [--generate-hash=\fIpassword\fR | -g\fIpassword\fR] ++.br + + .SH DESCRIPTION + \fBmokutil\fR is a tool to import or delete the machines owner keys +@@ -31,36 +45,49 @@ mokutil \- utility to manipulate machine owner keys + .TP + \fB--list-enrolled\fR + List the keys the already stored in the database +- + .TP + \fB--list-new\fR + List the keys to be enrolled +- + .TP + \fB--import\fR + Collect the followed files and form a request to shim. The files must be in DER + format. +- + .TP + \fB--delete-all\fR + Request shim to delete all stored keys +- + .TP +-\fB--revoke\fR +-Revoke the current request +- ++\fB--revoke-import\fR ++Revoke the current import request (MokNew) ++.TP ++\fB--revoke-delete\fR ++Revoke the current delete request (MokDel) + .TP + \fB--export\fR + Export the keys stored in MokListRT +- + .TP + \fB--password\fR + Setup the password for MokManager +- + .TP + \fB--disable-validation\fR + Disable the validation process in shim +- + .TP + \fB--enrolled-validation\fR + Enable the validation process in shim ++.TP ++\fB--sb-state\fR ++Show SecureBoot State ++.TP ++\fB--test-key\fR ++Test if the key is enrolled or not ++.TP ++\fB--reset\fR ++Reset MOK list ++.TP ++\fB--generate-hash\fR ++Generate the password hash ++.TP ++\fB--hash-file\fR ++Use the password hash from a specific file ++.TP ++\fB--root-pw\fR ++Use the root password hash from /etc/shadow +-- +1.7.10.4 + diff --git a/mokutil.changes b/mokutil.changes index ea06c6c..98e6689 100644 --- a/mokutil.changes +++ b/mokutil.changes @@ -1,3 +1,13 @@ +------------------------------------------------------------------- +Wed Jan 30 08:00:22 UTC 2013 - glin@suse.com + +- Merge patches for FATE#314506 + + Add mokutil-support-crypt-hash-methods.patch to support the + password hashes from /etc/shadow + + Add mokutil-update-man-page.patch to update man page for the + new added options +- Add mokutil-lcrypt-ldflag.patch to correct LDFLAGS + ------------------------------------------------------------------- Fri Jan 18 10:05:27 UTC 2013 - glin@suse.com diff --git a/mokutil.spec b/mokutil.spec index 1ff4115..cbe3d52 100644 --- a/mokutil.spec +++ b/mokutil.spec @@ -34,6 +34,14 @@ Patch3: mokutil-allow-password-from-pipe.patch Patch4: mokutil-support-delete-keys.patch # PATCH-FIX-UPSTREAM mokutil-support-new-pw-hash.patch glin@suse.com -- Support the new password hash format Patch5: mokutil-support-new-pw-hash.patch +# PATCH-FIX-UPSTREAM mokutil-support-crypt-hash-methods.patch glin@suse.com -- Support the hash methods used for /etc/shadow +Patch6: mokutil-support-crypt-hash-methods.patch +# PATCH-FIX-UPSTREAM mokutil-update-man-page.patch glin@suse.com -- Update man page +Patch7: mokutil-update-man-page.patch +# PATCH-FIX-UPSTREAM mokutil-lcrypt-ldflag.patch glin@suse.com -- Add -lcrpyt correctly +Patch8: mokutil-lcrypt-ldflag.patch +BuildRequires: autoconf +BuildRequires: automake BuildRequires: libopenssl-devel >= 0.9.8 BuildRequires: pkg-config BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -56,8 +64,12 @@ Authors: %patch3 -p1 %patch4 -p1 %patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 %build +autoreconf -i -f %configure make