From afb61e79027d2a5de9edfcab8de163609894f930 Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Tue, 15 Jan 2013 18:01:41 +0800 Subject: [PATCH] MokManager: support crypt() password hash The password format is introduced for the password hash generated by crypt(), so that the user can import the password hash from /etc/shadow. The packager, especially those who packages 3rd party drivers, can utilize this feature to import a 3rd party certificate without interfering the package installation. This commit implements the sha256-based crypt() hash function. Conflicts: Makefile MokManager.c --- Makefile | 6 +- MokManager.c | 153 +++++++++++++++++++++++++++++++++++------------- PasswordCrypt.c | 124 +++++++++++++++++++++++++++++++++++++++ PasswordCrypt.h | 26 ++++++++ 4 files changed, 265 insertions(+), 44 deletions(-) create mode 100644 PasswordCrypt.c create mode 100644 PasswordCrypt.h diff --git a/Makefile b/Makefile index 868fb95..0a7efd5 100644 --- a/Makefile +++ b/Makefile @@ -36,8 +36,8 @@ TARGET = shim.efi MokManager.efi.signed fallback.efi.signed OBJS = shim.o netboot.o cert.o dbx.o KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key SOURCES = shim.c shim.h netboot.c signature.h PeImage.h -MOK_OBJS = MokManager.o -MOK_SOURCES = MokManager.c shim.h console_control.h +MOK_OBJS = MokManager.o PasswordCrypt.o +MOK_SOURCES = MokManager.c shim.h console_control.h PasswordCrypt.c PasswordCrypt.h FALLBACK_OBJS = fallback.o FALLBACK_SRCS = fallback.c @@ -76,7 +76,7 @@ fallback.o: $(FALLBACK_SRCS) fallback.so: $(FALLBACK_OBJS) $(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS) -MokManager.o: $(SOURCES) +MokManager.o: $(MOK_SOURCES) MokManager.so: $(MOK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a $(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS) lib/lib.a diff --git a/MokManager.c b/MokManager.c index c254fdc..66e33ce 100644 --- a/MokManager.c +++ b/MokManager.c @@ -2,17 +2,18 @@ #include #include #include +#include "console_control.h" #include "shim.h" #include "signature.h" #include "PeImage.h" -#include "console_control.h" +#include "PasswordCrypt.h" #include "include/console.h" #include "include/simple_file.h" -#define PASSWORD_MAX 16 -#define PASSWORD_MIN 8 -#define SB_PASSWORD_LEN 8 +#define PASSWORD_MAX 256 +#define PASSWORD_MIN 1 +#define SB_PASSWORD_LEN 16 #ifndef SHIM_VENDOR #define SHIM_VENDOR L"Shim" @@ -43,7 +44,7 @@ typedef struct { typedef struct { UINT32 MokSBState; UINT32 PWLen; - CHAR16 Password[PASSWORD_MAX]; + CHAR16 Password[SB_PASSWORD_LEN]; } __attribute__ ((packed)) MokSBvar; static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes, @@ -586,8 +587,8 @@ static UINT8 get_line (UINT32 *length, CHAR16 *line, UINT32 line_max, UINT8 show return 1; } -static EFI_STATUS compute_pw_hash (void *MokNew, UINTN MokNewSize, CHAR16 *password, - UINT32 pw_length, UINT8 *hash) +static EFI_STATUS compute_pw_hash (void *Data, UINTN DataSize, UINT8 *password, + UINT32 pw_length, UINT8 *hash) { EFI_STATUS status; unsigned int ctxsize; @@ -607,15 +608,15 @@ static EFI_STATUS compute_pw_hash (void *MokNew, UINTN MokNewSize, CHAR16 *passw goto done; } - if (MokNew && MokNewSize) { - if (!(Sha256Update(ctx, MokNew, MokNewSize))) { + if (Data && DataSize) { + if (!(Sha256Update(ctx, Data, DataSize))) { console_notify(L"Unable to generate hash"); status = EFI_OUT_OF_RESOURCES; goto done; } } - if (!(Sha256Update(ctx, password, pw_length * sizeof(CHAR16)))) { + if (!(Sha256Update(ctx, password, pw_length))) { console_notify(L"Unable to generate hash"); status = EFI_OUT_OF_RESOURCES; goto done; @@ -632,15 +633,34 @@ done: return status; } -static EFI_STATUS match_password (void *Data, UINTN DataSize, - UINT8 auth[SHA256_DIGEST_SIZE], - CHAR16 *prompt) +static EFI_STATUS match_password (PASSWORD_CRYPT *pw_crypt, + void *Data, UINTN DataSize, + UINT8 *auth, CHAR16 *prompt) { - EFI_STATUS efi_status; + EFI_STATUS status; UINT8 hash[SHA256_DIGEST_SIZE]; + UINT8 *auth_hash; + UINT32 auth_size; CHAR16 password[PASSWORD_MAX]; UINT32 pw_length; UINT8 fail_count = 0; + int i; + + if (pw_crypt) { + /* + * Only support sha256 now + */ + if(pw_crypt->method != SHA256_BASED) + return EFI_INVALID_PARAMETER; + auth_hash = pw_crypt->hash; + /* FIXME assign auth_size according to pw_crypt->method */ + auth_size = SHA256_DIGEST_SIZE; + } else if (auth) { + auth_hash = auth; + auth_size = SHA256_DIGEST_SIZE; + } else { + return EFI_INVALID_PARAMETER; + } while (fail_count < 3) { if (prompt) { @@ -656,16 +676,30 @@ static EFI_STATUS match_password (void *Data, UINTN DataSize, continue; } - efi_status = compute_pw_hash(Data, DataSize, password, - pw_length, hash); + /* + * Compute password hash + */ + if (pw_crypt) { + char pw_ascii[PASSWORD_MAX + 1]; + for (i = 0; i < pw_length; i++) + pw_ascii[i] = (char)password[i]; + pw_ascii[pw_length] = '\0'; - if (efi_status != EFI_SUCCESS) { + status = password_crypt(pw_ascii, pw_length, pw_crypt, hash); + } else { + /* + * For backward compatibility + */ + status = compute_pw_hash(Data, DataSize, (UINT8 *)password, + pw_length * sizeof(CHAR16), hash); + } + if (status != EFI_SUCCESS) { Print(L"Unable to generate password hash\n"); fail_count++; continue; } - if (CompareMem(auth, hash, SHA256_DIGEST_SIZE) != 0) { + if (CompareMem(auth_hash, hash, auth_size) != 0) { Print(L"Password doesn't match\n"); fail_count++; continue; @@ -684,23 +718,29 @@ static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; EFI_STATUS efi_status; - UINT8 auth[SHA256_DIGEST_SIZE]; - UINTN auth_size; + UINT8 auth[PASSWORD_CRYPT_SIZE]; + UINTN auth_size = PASSWORD_CRYPT_SIZE; UINT32 attributes; if (authenticate) { - auth_size = SHA256_DIGEST_SIZE; efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth", &shim_lock_guid, &attributes, &auth_size, auth); - - if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) { + if (efi_status != EFI_SUCCESS || + (auth_size != SHA256_DIGEST_SIZE && + auth_size != PASSWORD_CRYPT_SIZE)) { console_error(L"Failed to get MokAuth", efi_status); return efi_status; } - efi_status = match_password(MokNew, MokNewSize, auth, NULL); + if (auth_size == PASSWORD_CRYPT_SIZE) { + efi_status = match_password((PASSWORD_CRYPT *)auth, + NULL, 0, NULL, NULL); + } else { + efi_status = match_password(NULL, MokNew, MokNewSize, + auth, NULL); + } if (efi_status != EFI_SUCCESS) return EFI_ACCESS_DENIED; } @@ -854,8 +894,8 @@ static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; EFI_STATUS efi_status; - UINT8 auth[SHA256_DIGEST_SIZE]; - UINTN auth_size = SHA256_DIGEST_SIZE; + UINT8 auth[PASSWORD_CRYPT_SIZE]; + UINTN auth_size = PASSWORD_CRYPT_SIZE; UINT32 attributes; void *MokListData = NULL; UINTN MokListDataSize = 0; @@ -867,12 +907,18 @@ static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize) &shim_lock_guid, &attributes, &auth_size, auth); - if (efi_status != EFI_SUCCESS || auth_size != SHA256_DIGEST_SIZE) { + if (efi_status != EFI_SUCCESS || + (auth_size != SHA256_DIGEST_SIZE && auth_size != PASSWORD_CRYPT_SIZE)) { console_error(L"Failed to get MokDelAuth", efi_status); return efi_status; } - efi_status = match_password(MokDel, MokDelSize, auth, NULL); + if (auth_size == PASSWORD_CRYPT_SIZE) { + efi_status = match_password((PASSWORD_CRYPT *)auth, NULL, 0, + NULL, NULL); + } else { + efi_status = match_password(NULL, MokDel, MokDelSize, auth, NULL); + } if (efi_status != EFI_SUCCESS) return EFI_ACCESS_DENIED; @@ -1045,18 +1091,27 @@ static INTN mok_sb_prompt (void *MokSB, UINTN MokSBSize) { static INTN mok_pw_prompt (void *MokPW, UINTN MokPWSize) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; EFI_STATUS efi_status; - UINT8 hash[SHA256_DIGEST_SIZE]; + UINT8 hash[PASSWORD_CRYPT_SIZE]; + UINT8 clear = 0; - if (MokPWSize != SHA256_DIGEST_SIZE) { + if (MokPWSize != SHA256_DIGEST_SIZE && MokPWSize != PASSWORD_CRYPT_SIZE) { console_notify(L"Invalid MokPW variable contents"); return -1; } uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); - SetMem(hash, SHA256_DIGEST_SIZE, 0); + SetMem(hash, PASSWORD_CRYPT_SIZE, 0); - if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) == 0) { + if (MokPWSize == PASSWORD_CRYPT_SIZE) { + if (CompareMem(MokPW, hash, PASSWORD_CRYPT_SIZE) == 0) + clear = 1; + } else { + if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) == 0) + clear = 1; + } + + if (clear) { if (console_yes_no((CHAR16 *[]){L"Clear MOK password?", NULL}) == 0) return 0; @@ -1065,7 +1120,14 @@ static INTN mok_pw_prompt (void *MokPW, UINTN MokPWSize) { return 0; } - efi_status = match_password(NULL, 0, MokPW, L"Confirm MOK passphrase: "); + if (MokPWSize == PASSWORD_CRYPT_SIZE) { + efi_status = match_password((PASSWORD_CRYPT *)MokPW, NULL, 0, + NULL, L"Confirm MOK passphrase: "); + } else { + efi_status = match_password(NULL, NULL, 0, MokPW, + L"Confirm MOK passphrase: "); + } + if (efi_status != EFI_SUCCESS) { console_notify(L"Password limit reached"); return -1; @@ -1280,8 +1342,8 @@ static BOOLEAN verify_pw(void) { EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; EFI_STATUS efi_status; - UINT8 pwhash[SHA256_DIGEST_SIZE]; - UINTN size = SHA256_DIGEST_SIZE; + UINT8 pwhash[PASSWORD_CRYPT_SIZE]; + UINTN size = PASSWORD_CRYPT_SIZE; UINT32 attributes; efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokPWStore", @@ -1293,7 +1355,8 @@ static BOOLEAN verify_pw(void) * known value, so there's no safety advantage in failing to validate * purely because of a failure to read the variable */ - if (efi_status != EFI_SUCCESS) + if (efi_status != EFI_SUCCESS || + (size != SHA256_DIGEST_SIZE && size != PASSWORD_CRYPT_SIZE)) return TRUE; if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) @@ -1301,7 +1364,13 @@ static BOOLEAN verify_pw(void) uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); - efi_status = match_password(NULL, 0, pwhash, L"Enter MOK password: "); + if (size == PASSWORD_CRYPT_SIZE) { + efi_status = match_password((PASSWORD_CRYPT *)pwhash, NULL, 0, + NULL, L"Enter MOK password: "); + } else { + efi_status = match_password(NULL, NULL, 0, pwhash, + L"Enter MOK password: "); + } if (efi_status != EFI_SUCCESS) { console_notify(L"Password limit reached"); return FALSE; @@ -1335,8 +1404,8 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, UINTN menucount = 3, i = 0; EFI_STATUS efi_status; EFI_GUID shim_lock_guid = SHIM_LOCK_GUID; - UINT8 auth[SHA256_DIGEST_SIZE]; - UINTN auth_size = SHA256_DIGEST_SIZE; + UINT8 auth[PASSWORD_CRYPT_SIZE]; + UINTN auth_size = PASSWORD_CRYPT_SIZE; UINT32 attributes; EFI_STATUS ret = EFI_SUCCESS; @@ -1347,14 +1416,16 @@ static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle, &shim_lock_guid, &attributes, &auth_size, auth); - if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE)) + if ((efi_status == EFI_SUCCESS) && + (auth_size == SHA256_DIGEST_SIZE || auth_size == PASSWORD_CRYPT_SIZE)) MokAuth = 1; efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth", &shim_lock_guid, &attributes, &auth_size, auth); - if ((efi_status == EFI_SUCCESS) && (auth_size == SHA256_DIGEST_SIZE)) + if ((efi_status == EFI_SUCCESS) && + (auth_size == SHA256_DIGEST_SIZE || auth_size == PASSWORD_CRYPT_SIZE)) MokDelAuth = 1; if (MokNew || MokAuth) diff --git a/PasswordCrypt.c b/PasswordCrypt.c new file mode 100644 index 0000000..bde23ed --- /dev/null +++ b/PasswordCrypt.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include "PasswordCrypt.h" + +static EFI_STATUS sha256_crypt (const char *key, UINT32 key_len, + const char *salt, UINT32 salt_size, + const UINT32 rounds, UINT8 *hash) +{ + SHA256_CTX ctx, alt_ctx; + UINT8 alt_result[SHA256_DIGEST_SIZE]; + UINT8 tmp_result[SHA256_DIGEST_SIZE]; + UINT8 *cp, *p_bytes, *s_bytes; + UINTN cnt; + + SHA256_Init(&ctx); + SHA256_Update(&ctx, key, key_len); + SHA256_Update(&ctx, salt, salt_size); + + SHA256_Init(&alt_ctx); + SHA256_Update(&alt_ctx, key, key_len); + SHA256_Update(&alt_ctx, salt, salt_size); + SHA256_Update(&alt_ctx, key, key_len); + SHA256_Final(alt_result, &alt_ctx); + + for (cnt = key_len; cnt > 32; cnt -= 32) + SHA256_Update(&ctx, alt_result, 32); + SHA256_Update(&ctx, alt_result, cnt); + + for (cnt = key_len; cnt > 0; cnt >>= 1) { + if ((cnt & 1) != 0) { + SHA256_Update(&ctx, alt_result, 32); + } else { + SHA256_Update(&ctx, key, key_len); + } + } + SHA256_Final(alt_result, &ctx); + + SHA256_Init(&alt_ctx); + for (cnt = 0; cnt < key_len; ++cnt) + SHA256_Update(&alt_ctx, key, key_len); + SHA256_Final(tmp_result, &alt_ctx); + + cp = p_bytes = AllocatePool(key_len); + for (cnt = key_len; cnt >= 32; cnt -= 32) { + CopyMem(cp, tmp_result, 32); + cp += 32; + } + CopyMem(cp, tmp_result, cnt); + + SHA256_Init(&alt_ctx); + for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt) + SHA256_Update(&alt_ctx, salt, salt_size); + SHA256_Final(tmp_result, &alt_ctx); + + cp = s_bytes = AllocatePool(salt_size); + for (cnt = salt_size; cnt >= 32; cnt -= 32) { + CopyMem(cp, tmp_result, 32); + cp += 32; + } + CopyMem(cp, tmp_result, cnt); + + for (cnt = 0; cnt < rounds; ++cnt) { + SHA256_Init(&ctx); + + if ((cnt & 1) != 0) + SHA256_Update(&ctx, p_bytes, key_len); + else + SHA256_Update(&ctx, alt_result, 32); + + if (cnt % 3 != 0) + SHA256_Update(&ctx, s_bytes, salt_size); + + if (cnt % 7 != 0) + SHA256_Update(&ctx, p_bytes, key_len); + + if ((cnt & 1) != 0) + SHA256_Update(&ctx, alt_result, 32); + else + SHA256_Update(&ctx, p_bytes, key_len); + + SHA256_Final(alt_result, &ctx); + } + + CopyMem(hash, alt_result, SHA256_DIGEST_SIZE); + + FreePool(p_bytes); + FreePool(s_bytes); + + return EFI_SUCCESS; +} + +EFI_STATUS password_crypt (const char *password, UINT32 pw_length, + const PASSWORD_CRYPT *pw_crypt, UINT8 *hash) +{ + EFI_STATUS status; + + if (!pw_crypt) + return EFI_INVALID_PARAMETER; + + switch (pw_crypt->method) { + case TRANDITIONAL_DES: + case EXTEND_BSDI_DES: + case MD5_BASED: + /* TODO unsupported */ + status = EFI_UNSUPPORTED; + break; + case SHA256_BASED: + status = sha256_crypt(password, pw_length, (char *)pw_crypt->salt, + pw_crypt->salt_size, pw_crypt->iter_count, + hash); + break; + case SHA512_BASED: + case BLOWFISH_BASED: + /* TODO unsupported */ + status = EFI_UNSUPPORTED; + break; + default: + return EFI_INVALID_PARAMETER; + } + + return status; +} diff --git a/PasswordCrypt.h b/PasswordCrypt.h new file mode 100644 index 0000000..c9e377a --- /dev/null +++ b/PasswordCrypt.h @@ -0,0 +1,26 @@ +#ifndef __PASSWORD_CRYPT_H__ +#define __PASSWORD_CRYPT_H__ + +enum HashMethod { + TRANDITIONAL_DES = 0, + EXTEND_BSDI_DES, + MD5_BASED, + SHA256_BASED, + SHA512_BASED, + BLOWFISH_BASED +}; + +typedef struct { + UINT16 method; + UINT64 iter_count; + UINT16 salt_size; + UINT8 salt[32]; + UINT8 hash[128]; +} __attribute__ ((packed)) PASSWORD_CRYPT; + +#define PASSWORD_CRYPT_SIZE sizeof(PASSWORD_CRYPT) + +EFI_STATUS password_crypt (const char *password, UINT32 pw_length, + const PASSWORD_CRYPT *pw_hash, UINT8 *hash); + +#endif /* __PASSWORD_CRYPT_H__ */