summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Ching-Pang Lin <glin@suse.com>2013-01-15 18:01:41 +0800
committerPeter Jones <pjones@redhat.com>2013-09-26 11:58:01 -0400
commitafb61e79027d2a5de9edfcab8de163609894f930 (patch)
treeba4b6929522867b84d46ef795bf1decbbda81b4e
parent4a7f9bd4a687f1bca25e86644e53c5ca5ab2bac8 (diff)
downloadefi-boot-shim-afb61e79027d2a5de9edfcab8de163609894f930.tar.gz
efi-boot-shim-afb61e79027d2a5de9edfcab8de163609894f930.zip
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
-rw-r--r--Makefile6
-rw-r--r--MokManager.c153
-rw-r--r--PasswordCrypt.c124
-rw-r--r--PasswordCrypt.h26
4 files changed, 265 insertions, 44 deletions
diff --git a/Makefile b/Makefile
index 868fb958..0a7efd50 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 c254fdc9..66e33ce9 100644
--- a/MokManager.c
+++ b/MokManager.c
@@ -2,17 +2,18 @@
#include <efilib.h>
#include <Library/BaseCryptLib.h>
#include <openssl/x509.h>
+#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 (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 (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) == 0) {
+ 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 00000000..bde23ed3
--- /dev/null
+++ b/PasswordCrypt.c
@@ -0,0 +1,124 @@
+#include <efi.h>
+#include <efilib.h>
+#include <Library/BaseCryptLib.h>
+#include <openssl/sha.h>
+#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 00000000..c9e377a2
--- /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__ */