3 #include <Library/BaseCryptLib.h>
4 #include <openssl/x509.h>
7 #include "PasswordCrypt.h"
11 #include "variables.h"
12 #include "simple_file.h"
13 #include "efiauthenticated.h"
15 #define PASSWORD_MAX 256
16 #define PASSWORD_MIN 1
17 #define SB_PASSWORD_LEN 16
19 #define NAME_LINE_MAX 70
22 #define SHIM_VENDOR L"Shim"
25 #define EFI_VARIABLE_APPEND_WRITE 0x00000040
27 EFI_GUID SHIM_LOCK_GUID
= { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
29 #define CERT_STRING L"Select an X509 certificate to enroll:\n\n"
30 #define HASH_STRING L"Select a file to trust:\n\n"
34 INTN (* callback
)(void *data
, void *data2
, void *data3
);
45 } __attribute__ ((packed
)) MokListNode
;
50 CHAR16 Password
[SB_PASSWORD_LEN
];
51 } __attribute__ ((packed
)) MokSBvar
;
56 CHAR16 Password
[SB_PASSWORD_LEN
];
57 } __attribute__ ((packed
)) MokDBvar
;
59 static EFI_STATUS
get_sha1sum (void *Data
, int DataSize
, UINT8
*hash
)
65 ctxsize
= Sha1GetContextSize();
66 ctx
= AllocatePool(ctxsize
);
69 console_notify(L
"Unable to allocate memory for hash context");
70 return EFI_OUT_OF_RESOURCES
;
74 console_notify(L
"Unable to initialise hash");
75 status
= EFI_OUT_OF_RESOURCES
;
79 if (!(Sha1Update(ctx
, Data
, DataSize
))) {
80 console_notify(L
"Unable to generate hash");
81 status
= EFI_OUT_OF_RESOURCES
;
85 if (!(Sha1Final(ctx
, hash
))) {
86 console_notify(L
"Unable to finalise hash");
87 status
= EFI_OUT_OF_RESOURCES
;
96 static UINT32
count_keys(void *Data
, UINTN DataSize
)
98 EFI_SIGNATURE_LIST
*CertList
= Data
;
99 EFI_GUID CertType
= X509_GUID
;
100 EFI_GUID HashType
= EFI_CERT_SHA256_GUID
;
101 UINTN dbsize
= DataSize
;
104 while ((dbsize
> 0) && (dbsize
>= CertList
->SignatureListSize
)) {
105 if ((CompareGuid (&CertList
->SignatureType
, &CertType
) != 0) &&
106 (CompareGuid (&CertList
->SignatureType
, &HashType
) != 0)) {
107 console_notify(L
"Doesn't look like a key or hash");
108 dbsize
-= CertList
->SignatureListSize
;
109 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
110 CertList
->SignatureListSize
);
114 if ((CompareGuid (&CertList
->SignatureType
, &CertType
) != 0) &&
115 (CertList
->SignatureSize
!= 48)) {
116 console_notify(L
"Doesn't look like a valid hash");
117 dbsize
-= CertList
->SignatureListSize
;
118 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
119 CertList
->SignatureListSize
);
124 dbsize
-= CertList
->SignatureListSize
;
125 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
126 CertList
->SignatureListSize
);
132 static MokListNode
*build_mok_list(UINT32 num
, void *Data
, UINTN DataSize
) {
134 EFI_SIGNATURE_LIST
*CertList
= Data
;
135 EFI_SIGNATURE_DATA
*Cert
;
136 EFI_GUID CertType
= X509_GUID
;
137 EFI_GUID HashType
= EFI_CERT_SHA256_GUID
;
138 UINTN dbsize
= DataSize
;
141 list
= AllocatePool(sizeof(MokListNode
) * num
);
144 console_notify(L
"Unable to allocate MOK list");
148 while ((dbsize
> 0) && (dbsize
>= CertList
->SignatureListSize
)) {
149 if ((CompareGuid (&CertList
->SignatureType
, &CertType
) != 0) &&
150 (CompareGuid (&CertList
->SignatureType
, &HashType
) != 0)) {
151 dbsize
-= CertList
->SignatureListSize
;
152 CertList
= (EFI_SIGNATURE_LIST
*)((UINT8
*) CertList
+
153 CertList
->SignatureListSize
);
157 if ((CompareGuid (&CertList
->SignatureType
, &HashType
) == 0) &&
158 (CertList
->SignatureSize
!= 48)) {
159 dbsize
-= CertList
->SignatureListSize
;
160 CertList
= (EFI_SIGNATURE_LIST
*)((UINT8
*) CertList
+
161 CertList
->SignatureListSize
);
165 Cert
= (EFI_SIGNATURE_DATA
*) (((UINT8
*) CertList
) +
166 sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
168 list
[count
].MokSize
= CertList
->SignatureSize
- sizeof(EFI_GUID
);
169 list
[count
].Mok
= (void *)Cert
->SignatureData
;
170 list
[count
].Type
= CertList
->SignatureType
;
173 dbsize
-= CertList
->SignatureListSize
;
174 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
175 CertList
->SignatureListSize
);
186 static NidName nidname
[] = {
187 {NID_commonName
, L
"CN"},
188 {NID_organizationName
, L
"O"},
189 {NID_countryName
, L
"C"},
190 {NID_stateOrProvinceName
, L
"ST"},
191 {NID_localityName
, L
"L"},
195 static CHAR16
* get_x509_name (X509_NAME
*X509Name
)
197 CHAR16 name
[NAME_LINE_MAX
+1];
198 CHAR16 part
[NAME_LINE_MAX
+1];
199 char str
[NAME_LINE_MAX
];
200 int i
, len
, rest
, first
;
203 rest
= NAME_LINE_MAX
;
205 for (i
= 0; nidname
[i
].name
!= NULL
; i
++) {
207 len
= X509_NAME_get_text_by_NID (X509Name
, nidname
[i
].nid
,
213 add
= len
+ (int)StrLen(nidname
[i
].name
) + 1;
215 add
= len
+ (int)StrLen(nidname
[i
].name
) + 3;
221 SPrint(part
, NAME_LINE_MAX
* sizeof(CHAR16
), L
"%s=%a",
222 nidname
[i
].name
, str
);
224 SPrint(part
, NAME_LINE_MAX
* sizeof(CHAR16
), L
", %s=%a",
225 nidname
[i
].name
, str
);
232 if (rest
>= 0 && rest
< NAME_LINE_MAX
)
233 return PoolPrint(L
"%s", name
);
238 static CHAR16
* get_x509_time (ASN1_TIME
*time
)
240 BIO
*bio
= BIO_new (BIO_s_mem());
244 ASN1_TIME_print (bio
, time
);
245 len
= BIO_read(bio
, str
, 29);
251 return PoolPrint(L
"%a", str
);
254 static void show_x509_info (X509
*X509Cert
, UINT8
*hash
)
256 ASN1_INTEGER
*serial
;
258 unsigned char hexbuf
[30];
261 CHAR16
*issuer
= NULL
;
262 CHAR16
*subject
= NULL
;
264 CHAR16
*until
= NULL
;
265 POOL_PRINT hash_string1
;
266 POOL_PRINT hash_string2
;
267 POOL_PRINT serial_string
;
272 ZeroMem(&hash_string1
, sizeof(hash_string1
));
273 ZeroMem(&hash_string2
, sizeof(hash_string2
));
274 ZeroMem(&serial_string
, sizeof(serial_string
));
276 serial
= X509_get_serialNumber(X509Cert
);
279 bnser
= ASN1_INTEGER_to_BN(serial
, NULL
);
280 n
= BN_bn2bin(bnser
, hexbuf
);
281 for (i
= 0; i
< n
; i
++) {
282 CatPrint(&serial_string
, L
"%02x:", hexbuf
[i
]);
286 if (serial_string
.str
)
289 X509Name
= X509_get_issuer_name(X509Cert
);
291 issuer
= get_x509_name(X509Name
);
296 X509Name
= X509_get_subject_name(X509Cert
);
298 subject
= get_x509_name(X509Name
);
303 time
= X509_get_notBefore(X509Cert
);
305 from
= get_x509_time(time
);
310 time
= X509_get_notAfter(X509Cert
);
312 until
= get_x509_time(time
);
318 CatPrint(&hash_string1
, L
"%02x ", hash
[i
]);
319 for (i
=10; i
<20; i
++)
320 CatPrint(&hash_string2
, L
"%02x ", hash
[i
]);
322 if (hash_string1
.str
)
325 if (hash_string2
.str
)
332 text
= AllocateZeroPool(sizeof(CHAR16
*) * (fields
*3 + 1));
333 if (serial_string
.str
) {
334 text
[i
++] = StrDuplicate(L
"[Serial Number]");
335 text
[i
++] = serial_string
.str
;
336 text
[i
++] = StrDuplicate(L
"");
339 text
[i
++] = StrDuplicate(L
"[Issuer]");
341 text
[i
++] = StrDuplicate(L
"");
344 text
[i
++] = StrDuplicate(L
"[Subject]");
346 text
[i
++] = StrDuplicate(L
"");
349 text
[i
++] = StrDuplicate(L
"[Valid Not Before]");
351 text
[i
++] = StrDuplicate(L
"");
354 text
[i
++] = StrDuplicate(L
"[Valid Not After]");
356 text
[i
++] = StrDuplicate(L
"");
358 if (hash_string1
.str
) {
359 text
[i
++] = StrDuplicate(L
"[Fingerprint]");
360 text
[i
++] = hash_string1
.str
;
362 if (hash_string2
.str
) {
363 text
[i
++] = hash_string2
.str
;
364 text
[i
++] = StrDuplicate(L
"");
368 console_print_box(text
, -1);
370 for (i
=0; text
[i
] != NULL
; i
++)
376 static void show_efi_hash (UINT8
*hash
)
379 POOL_PRINT hash_string1
;
380 POOL_PRINT hash_string2
;
383 ZeroMem(&hash_string1
, sizeof(hash_string1
));
384 ZeroMem(&hash_string2
, sizeof(hash_string2
));
386 text
[0] = L
"SHA256 hash";
390 CatPrint(&hash_string1
, L
"%02x ", hash
[i
]);
391 for (i
=16; i
<32; i
++)
392 CatPrint(&hash_string2
, L
"%02x ", hash
[i
]);
394 text
[2] = hash_string1
.str
;
395 text
[3] = hash_string2
.str
;
398 console_print_box(text
, -1);
400 if (hash_string1
.str
)
401 FreePool(hash_string1
.str
);
403 if (hash_string2
.str
)
404 FreePool(hash_string2
.str
);
407 static void show_mok_info (void *Mok
, UINTN MokSize
)
409 EFI_STATUS efi_status
;
410 UINT8 hash
[SHA1_DIGEST_SIZE
];
413 if (!Mok
|| MokSize
== 0)
416 if (MokSize
!= SHA256_DIGEST_SIZE
) {
417 efi_status
= get_sha1sum(Mok
, MokSize
, hash
);
419 if (efi_status
!= EFI_SUCCESS
) {
420 console_notify(L
"Failed to compute MOK fingerprint");
424 if (X509ConstructCertificate(Mok
, MokSize
,
425 (UINT8
**) &X509Cert
) && X509Cert
!= NULL
) {
426 show_x509_info(X509Cert
, hash
);
429 console_notify(L
"Not a valid X509 certificate");
437 static EFI_STATUS
list_keys (void *KeyList
, UINTN KeyListSize
, CHAR16
*title
)
440 MokListNode
*keys
= NULL
;
442 CHAR16
**menu_strings
;
445 if (KeyListSize
< (sizeof(EFI_SIGNATURE_LIST
) +
446 sizeof(EFI_SIGNATURE_DATA
))) {
447 console_notify(L
"No MOK keys found");
451 MokNum
= count_keys(KeyList
, KeyListSize
);
452 keys
= build_mok_list(MokNum
, KeyList
, KeyListSize
);
455 console_notify(L
"Failed to construct key list");
459 menu_strings
= AllocateZeroPool(sizeof(CHAR16
*) * (MokNum
+ 2));
462 return EFI_OUT_OF_RESOURCES
;
464 for (i
=0; i
<MokNum
; i
++) {
465 menu_strings
[i
] = PoolPrint(L
"View key %d", i
);
467 menu_strings
[i
] = StrDuplicate(L
"Continue");
469 menu_strings
[i
+1] = NULL
;
471 while (key_num
< MokNum
) {
472 key_num
= console_select((CHAR16
*[]){ title
, NULL
},
477 else if (key_num
< MokNum
)
478 show_mok_info(keys
[key_num
].Mok
, keys
[key_num
].MokSize
);
481 for (i
=0; menu_strings
[i
] != NULL
; i
++)
482 FreePool(menu_strings
[i
]);
484 FreePool(menu_strings
);
491 static EFI_STATUS
get_line (UINT32
*length
, CHAR16
*line
, UINT32 line_max
, UINT8 show
)
495 unsigned int count
= 0;
498 status
= console_get_keystroke(&key
);
499 if (EFI_ERROR (status
)) {
500 console_error(L
"Failed to read the keystroke", status
);
505 if ((count
>= line_max
&&
506 key
.UnicodeChar
!= CHAR_BACKSPACE
) ||
507 key
.UnicodeChar
== CHAR_NULL
||
508 key
.UnicodeChar
== CHAR_TAB
||
509 key
.UnicodeChar
== CHAR_LINEFEED
||
510 key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
514 if (count
== 0 && key
.UnicodeChar
== CHAR_BACKSPACE
) {
516 } else if (key
.UnicodeChar
== CHAR_BACKSPACE
) {
520 line
[--count
] = '\0';
525 Print(L
"%c", key
.UnicodeChar
);
528 line
[count
++] = key
.UnicodeChar
;
529 } while (key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
537 static EFI_STATUS
compute_pw_hash (void *Data
, UINTN DataSize
, UINT8
*password
,
538 UINT32 pw_length
, UINT8
*hash
)
541 unsigned int ctxsize
;
544 ctxsize
= Sha256GetContextSize();
545 ctx
= AllocatePool(ctxsize
);
548 console_notify(L
"Unable to allocate memory for hash context");
549 return EFI_OUT_OF_RESOURCES
;
552 if (!Sha256Init(ctx
)) {
553 console_notify(L
"Unable to initialise hash");
554 status
= EFI_OUT_OF_RESOURCES
;
558 if (Data
&& DataSize
) {
559 if (!(Sha256Update(ctx
, Data
, DataSize
))) {
560 console_notify(L
"Unable to generate hash");
561 status
= EFI_OUT_OF_RESOURCES
;
566 if (!(Sha256Update(ctx
, password
, pw_length
))) {
567 console_notify(L
"Unable to generate hash");
568 status
= EFI_OUT_OF_RESOURCES
;
572 if (!(Sha256Final(ctx
, hash
))) {
573 console_notify(L
"Unable to finalise hash");
574 status
= EFI_OUT_OF_RESOURCES
;
578 status
= EFI_SUCCESS
;
583 static void console_save_and_set_mode (SIMPLE_TEXT_OUTPUT_MODE
*SavedMode
)
586 Print(L
"Invalid parameter: SavedMode\n");
590 CopyMem(SavedMode
, ST
->ConOut
->Mode
, sizeof(SIMPLE_TEXT_OUTPUT_MODE
));
591 uefi_call_wrapper(ST
->ConOut
->EnableCursor
, 2, ST
->ConOut
, FALSE
);
592 uefi_call_wrapper(ST
->ConOut
->SetAttribute
, 2, ST
->ConOut
,
593 EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
);
596 static void console_restore_mode (SIMPLE_TEXT_OUTPUT_MODE
*SavedMode
)
598 uefi_call_wrapper(ST
->ConOut
->EnableCursor
, 2, ST
->ConOut
,
599 SavedMode
->CursorVisible
);
600 uefi_call_wrapper(ST
->ConOut
->SetCursorPosition
, 3, ST
->ConOut
,
601 SavedMode
->CursorColumn
, SavedMode
->CursorRow
);
602 uefi_call_wrapper(ST
->ConOut
->SetAttribute
, 2, ST
->ConOut
,
603 SavedMode
->Attribute
);
606 static UINT32
get_password (CHAR16
*prompt
, CHAR16
*password
, UINT32 max
)
608 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
615 prompt
= L
"Password:";
617 console_save_and_set_mode(&SavedMode
);
619 str
= PoolPrint(L
"%s ", prompt
);
621 console_errorbox(L
"Failed to allocate prompt");
627 length
= StrLen(message
[0]);
628 console_print_box_at(message
, -1, -length
-4, -5, length
+4, 3, 0, 1);
629 get_line(&pw_length
, password
, max
, 0);
631 console_restore_mode(&SavedMode
);
638 static EFI_STATUS
match_password (PASSWORD_CRYPT
*pw_crypt
,
639 void *Data
, UINTN DataSize
,
640 UINT8
*auth
, CHAR16
*prompt
)
646 CHAR16 password
[PASSWORD_MAX
];
648 UINT8 fail_count
= 0;
652 auth_hash
= pw_crypt
->hash
;
653 auth_size
= get_hash_size (pw_crypt
->method
);
655 return EFI_INVALID_PARAMETER
;
658 auth_size
= SHA256_DIGEST_SIZE
;
660 return EFI_INVALID_PARAMETER
;
663 while (fail_count
< 3) {
664 pw_length
= get_password(prompt
, password
, PASSWORD_MAX
);
666 if (pw_length
< PASSWORD_MIN
|| pw_length
> PASSWORD_MAX
) {
667 console_errorbox(L
"Invalid password length");
673 * Compute password hash
676 char pw_ascii
[PASSWORD_MAX
+ 1];
677 for (i
= 0; i
< pw_length
; i
++)
678 pw_ascii
[i
] = (char)password
[i
];
679 pw_ascii
[pw_length
] = '\0';
681 status
= password_crypt(pw_ascii
, pw_length
, pw_crypt
, hash
);
684 * For backward compatibility
686 status
= compute_pw_hash(Data
, DataSize
, (UINT8
*)password
,
687 pw_length
* sizeof(CHAR16
), hash
);
689 if (status
!= EFI_SUCCESS
) {
690 console_errorbox(L
"Unable to generate password hash");
695 if (CompareMem(auth_hash
, hash
, auth_size
) != 0) {
696 console_errorbox(L
"Password doesn't match");
705 return EFI_ACCESS_DENIED
;
710 static EFI_STATUS
store_keys (void *MokNew
, UINTN MokNewSize
, int authenticate
)
712 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
713 EFI_STATUS efi_status
;
714 UINT8 auth
[PASSWORD_CRYPT_SIZE
];
715 UINTN auth_size
= PASSWORD_CRYPT_SIZE
;
719 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokAuth",
721 &attributes
, &auth_size
, auth
);
723 if (efi_status
!= EFI_SUCCESS
||
724 (auth_size
!= SHA256_DIGEST_SIZE
&&
725 auth_size
!= PASSWORD_CRYPT_SIZE
)) {
726 console_error(L
"Failed to get MokAuth", efi_status
);
730 if (auth_size
== PASSWORD_CRYPT_SIZE
) {
731 efi_status
= match_password((PASSWORD_CRYPT
*)auth
,
732 NULL
, 0, NULL
, NULL
);
734 efi_status
= match_password(NULL
, MokNew
, MokNewSize
,
737 if (efi_status
!= EFI_SUCCESS
)
738 return EFI_ACCESS_DENIED
;
743 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, L
"MokList",
745 EFI_VARIABLE_NON_VOLATILE
746 | EFI_VARIABLE_BOOTSERVICE_ACCESS
,
750 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, L
"MokList",
752 EFI_VARIABLE_NON_VOLATILE
753 | EFI_VARIABLE_BOOTSERVICE_ACCESS
754 | EFI_VARIABLE_APPEND_WRITE
,
758 if (efi_status
!= EFI_SUCCESS
) {
759 console_error(L
"Failed to set variable", efi_status
);
766 static UINTN
mok_enrollment_prompt (void *MokNew
, UINTN MokNewSize
, int auth
) {
767 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
768 EFI_STATUS efi_status
;
770 if (list_keys(MokNew
, MokNewSize
, L
"[Enroll MOK]") != EFI_SUCCESS
)
773 if (console_yes_no((CHAR16
*[]){L
"Enroll the key(s)?", NULL
}) == 0)
776 efi_status
= store_keys(MokNew
, MokNewSize
, auth
);
778 if (efi_status
!= EFI_SUCCESS
) {
779 console_notify(L
"Failed to enroll keys\n");
784 LibDeleteVariable(L
"MokNew", &shim_lock_guid
);
785 LibDeleteVariable(L
"MokAuth", &shim_lock_guid
);
787 console_notify(L
"The system must now be rebooted");
788 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
789 EFI_SUCCESS
, 0, NULL
);
790 console_notify(L
"Failed to reboot");
797 static INTN
mok_reset_prompt ()
799 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
800 EFI_STATUS efi_status
;
802 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
804 if (console_yes_no((CHAR16
*[]){L
"Erase all stored keys?", NULL
}) == 0)
807 efi_status
= store_keys(NULL
, 0, TRUE
);
809 if (efi_status
!= EFI_SUCCESS
) {
810 console_notify(L
"Failed to erase keys\n");
814 LibDeleteVariable(L
"MokNew", &shim_lock_guid
);
815 LibDeleteVariable(L
"MokAuth", &shim_lock_guid
);
817 console_notify(L
"The system must now be rebooted");
818 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
819 EFI_SUCCESS
, 0, NULL
);
820 console_notify(L
"Failed to reboot\n");
824 static EFI_STATUS
write_back_mok_list (MokListNode
*list
, INTN key_num
)
826 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
827 EFI_STATUS efi_status
;
828 EFI_SIGNATURE_LIST
*CertList
;
829 EFI_SIGNATURE_DATA
*CertData
;
830 void *Data
= NULL
, *ptr
;
834 for (i
= 0; i
< key_num
; i
++) {
835 if (list
[i
].Mok
== NULL
)
838 DataSize
+= sizeof(EFI_SIGNATURE_LIST
) + sizeof(EFI_GUID
);
839 DataSize
+= list
[i
].MokSize
;
842 Data
= AllocatePool(DataSize
);
843 if (Data
== NULL
&& DataSize
!= 0)
844 return EFI_OUT_OF_RESOURCES
;
848 for (i
= 0; i
< key_num
; i
++) {
849 if (list
[i
].Mok
== NULL
)
852 CertList
= (EFI_SIGNATURE_LIST
*)ptr
;
853 CertData
= (EFI_SIGNATURE_DATA
*)(((uint8_t *)ptr
) +
854 sizeof(EFI_SIGNATURE_LIST
));
856 CertList
->SignatureType
= list
[i
].Type
;
857 CertList
->SignatureListSize
= list
[i
].MokSize
+
858 sizeof(EFI_SIGNATURE_LIST
) +
859 sizeof(EFI_SIGNATURE_DATA
) - 1;
860 CertList
->SignatureHeaderSize
= 0;
861 CertList
->SignatureSize
= list
[i
].MokSize
+ sizeof(EFI_GUID
);
863 CertData
->SignatureOwner
= shim_lock_guid
;
864 CopyMem(CertData
->SignatureData
, list
[i
].Mok
, list
[i
].MokSize
);
866 ptr
= (uint8_t *)ptr
+ sizeof(EFI_SIGNATURE_LIST
) +
867 sizeof(EFI_GUID
) + list
[i
].MokSize
;
870 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, L
"MokList",
872 EFI_VARIABLE_NON_VOLATILE
873 | EFI_VARIABLE_BOOTSERVICE_ACCESS
,
878 if (efi_status
!= EFI_SUCCESS
) {
879 console_error(L
"Failed to set variable", efi_status
);
886 static EFI_STATUS
delete_keys (void *MokDel
, UINTN MokDelSize
)
888 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
889 EFI_STATUS efi_status
;
890 UINT8 auth
[PASSWORD_CRYPT_SIZE
];
891 UINTN auth_size
= PASSWORD_CRYPT_SIZE
;
893 UINT8
*MokListData
= NULL
;
894 UINTN MokListDataSize
= 0;
895 MokListNode
*mok
, *del_key
;
896 INTN mok_num
, del_num
;
899 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokDelAuth",
901 &attributes
, &auth_size
, auth
);
903 if (efi_status
!= EFI_SUCCESS
||
904 (auth_size
!= SHA256_DIGEST_SIZE
&& auth_size
!= PASSWORD_CRYPT_SIZE
)) {
905 console_error(L
"Failed to get MokDelAuth", efi_status
);
909 if (auth_size
== PASSWORD_CRYPT_SIZE
) {
910 efi_status
= match_password((PASSWORD_CRYPT
*)auth
, NULL
, 0,
913 efi_status
= match_password(NULL
, MokDel
, MokDelSize
, auth
, NULL
);
915 if (efi_status
!= EFI_SUCCESS
)
916 return EFI_ACCESS_DENIED
;
918 efi_status
= get_variable_attr (L
"MokList", &MokListData
, &MokListDataSize
,
919 shim_lock_guid
, &attributes
);
920 if (attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) {
921 console_alertbox((CHAR16
*[]){L
"MokList is compromised!",
922 L
"Erase all keys in MokList!",
924 if (LibDeleteVariable(L
"MokList", &shim_lock_guid
) != EFI_SUCCESS
) {
925 console_notify(L
"Failed to erase MokList");
927 return EFI_ACCESS_DENIED
;
931 if (!MokListData
|| MokListDataSize
== 0)
934 /* Construct lists */
935 mok_num
= count_keys(MokListData
, MokListDataSize
);
936 mok
= build_mok_list(mok_num
, MokListData
, MokListDataSize
);
937 del_num
= count_keys(MokDel
, MokDelSize
);
938 del_key
= build_mok_list(del_num
, MokDel
, MokDelSize
);
940 /* Search and destroy */
941 for (i
= 0; i
< del_num
; i
++) {
942 UINT32 key_size
= del_key
[i
].MokSize
;
943 void *key
= del_key
[i
].Mok
;
944 for (j
= 0; j
< mok_num
; j
++) {
945 if (mok
[j
].MokSize
== key_size
&&
946 CompareMem(key
, mok
[j
].Mok
, key_size
) == 0) {
954 efi_status
= write_back_mok_list(mok
, mok_num
);
957 FreePool(MokListData
);
966 static INTN
mok_deletion_prompt (void *MokDel
, UINTN MokDelSize
)
968 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
969 EFI_STATUS efi_status
;
971 if (list_keys(MokDel
, MokDelSize
, L
"[Delete MOK]") != EFI_SUCCESS
) {
975 if (console_yes_no((CHAR16
*[]){L
"Delete the key(s)?", NULL
}) == 0)
978 efi_status
= delete_keys(MokDel
, MokDelSize
);
980 if (efi_status
!= EFI_SUCCESS
) {
981 console_notify(L
"Failed to delete keys");
985 LibDeleteVariable(L
"MokDel", &shim_lock_guid
);
986 LibDeleteVariable(L
"MokDelAuth", &shim_lock_guid
);
988 console_notify(L
"The system must now be rebooted");
989 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
990 EFI_SUCCESS
, 0, NULL
);
991 console_notify(L
"Failed to reboot");
995 static CHAR16
get_password_charater (CHAR16
*prompt
)
997 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1005 prompt
= L
"Password charater: ";
1007 console_save_and_set_mode(&SavedMode
);
1009 message
[0] = prompt
;
1011 length
= StrLen(message
[0]);
1012 console_print_box_at(message
, -1, -length
-4, -5, length
+4, 3, 0, 1);
1013 status
= get_line(&pw_length
, &character
, 1, 0);
1014 if (EFI_ERROR(status
))
1017 console_restore_mode(&SavedMode
);
1022 static INTN
mok_sb_prompt (void *MokSB
, UINTN MokSBSize
) {
1023 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1024 EFI_STATUS efi_status
;
1025 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1026 MokSBvar
*var
= MokSB
;
1028 CHAR16 pass1
, pass2
, pass3
;
1030 UINT8 fail_count
= 0;
1032 UINT8 pos1
, pos2
, pos3
;
1035 if (MokSBSize
!= sizeof(MokSBvar
)) {
1036 console_notify(L
"Invalid MokSB variable contents");
1040 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1042 message
[0] = L
"Change Secure Boot state";
1045 console_save_and_set_mode(&SavedMode
);
1046 console_print_box_at(message
, -1, 0, 0, -1, -1, 1, 1);
1047 console_restore_mode(&SavedMode
);
1049 while (fail_count
< 3) {
1050 RandomBytes (&pos1
, sizeof(pos1
));
1051 pos1
= (pos1
% var
->PWLen
);
1054 RandomBytes (&pos2
, sizeof(pos2
));
1055 pos2
= (pos2
% var
->PWLen
);
1056 } while (pos2
== pos1
);
1059 RandomBytes (&pos3
, sizeof(pos3
));
1060 pos3
= (pos3
% var
->PWLen
) ;
1061 } while (pos3
== pos2
|| pos3
== pos1
);
1063 str
= PoolPrint(L
"Enter password character %d: ", pos1
+ 1);
1065 console_errorbox(L
"Failed to allocate buffer");
1068 pass1
= get_password_charater(str
);
1071 str
= PoolPrint(L
"Enter password character %d: ", pos2
+ 1);
1073 console_errorbox(L
"Failed to allocate buffer");
1076 pass2
= get_password_charater(str
);
1079 str
= PoolPrint(L
"Enter password character %d: ", pos3
+ 1);
1081 console_errorbox(L
"Failed to allocate buffer");
1084 pass3
= get_password_charater(str
);
1087 if (pass1
!= var
->Password
[pos1
] ||
1088 pass2
!= var
->Password
[pos2
] ||
1089 pass3
!= var
->Password
[pos3
]) {
1090 Print(L
"Invalid character\n");
1097 if (fail_count
>= 3) {
1098 console_notify(L
"Password limit reached");
1102 if (var
->MokSBState
== 0)
1103 ret
= console_yes_no((CHAR16
*[]){L
"Disable Secure Boot", NULL
});
1105 ret
= console_yes_no((CHAR16
*[]){L
"Enable Secure Boot", NULL
});
1108 LibDeleteVariable(L
"MokSB", &shim_lock_guid
);
1112 if (var
->MokSBState
== 0) {
1113 efi_status
= uefi_call_wrapper(RT
->SetVariable
,
1116 EFI_VARIABLE_NON_VOLATILE
|
1117 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1119 if (efi_status
!= EFI_SUCCESS
) {
1120 console_notify(L
"Failed to set Secure Boot state");
1124 efi_status
= uefi_call_wrapper(RT
->SetVariable
,
1127 EFI_VARIABLE_NON_VOLATILE
|
1128 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1130 if (efi_status
!= EFI_SUCCESS
) {
1131 console_notify(L
"Failed to delete Secure Boot state");
1136 console_notify(L
"The system must now be rebooted");
1137 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
1138 EFI_SUCCESS
, 0, NULL
);
1139 console_notify(L
"Failed to reboot");
1143 static INTN
mok_db_prompt (void *MokDB
, UINTN MokDBSize
) {
1144 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1145 EFI_STATUS efi_status
;
1146 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1147 MokDBvar
*var
= MokDB
;
1149 CHAR16 pass1
, pass2
, pass3
;
1151 UINT8 fail_count
= 0;
1153 UINT8 pos1
, pos2
, pos3
;
1156 if (MokDBSize
!= sizeof(MokDBvar
)) {
1157 console_notify(L
"Invalid MokDB variable contents");
1161 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1163 message
[0] = L
"Change DB state";
1166 console_save_and_set_mode(&SavedMode
);
1167 console_print_box_at(message
, -1, 0, 0, -1, -1, 1, 1);
1168 console_restore_mode(&SavedMode
);
1170 while (fail_count
< 3) {
1171 RandomBytes (&pos1
, sizeof(pos1
));
1172 pos1
= (pos1
% var
->PWLen
);
1175 RandomBytes (&pos2
, sizeof(pos2
));
1176 pos2
= (pos2
% var
->PWLen
);
1177 } while (pos2
== pos1
);
1180 RandomBytes (&pos3
, sizeof(pos3
));
1181 pos3
= (pos3
% var
->PWLen
) ;
1182 } while (pos3
== pos2
|| pos3
== pos1
);
1184 str
= PoolPrint(L
"Enter password character %d: ", pos1
+ 1);
1186 console_errorbox(L
"Failed to allocate buffer");
1189 pass1
= get_password_charater(str
);
1192 str
= PoolPrint(L
"Enter password character %d: ", pos2
+ 1);
1194 console_errorbox(L
"Failed to allocate buffer");
1197 pass2
= get_password_charater(str
);
1200 str
= PoolPrint(L
"Enter password character %d: ", pos3
+ 1);
1202 console_errorbox(L
"Failed to allocate buffer");
1205 pass3
= get_password_charater(str
);
1208 if (pass1
!= var
->Password
[pos1
] ||
1209 pass2
!= var
->Password
[pos2
] ||
1210 pass3
!= var
->Password
[pos3
]) {
1211 Print(L
"Invalid character\n");
1218 if (fail_count
>= 3) {
1219 console_notify(L
"Password limit reached");
1223 if (var
->MokDBState
== 0)
1224 ret
= console_yes_no((CHAR16
*[]){L
"Ignore DB certs/hashes", NULL
});
1226 ret
= console_yes_no((CHAR16
*[]){L
"Use DB certs/hashes", NULL
});
1229 LibDeleteVariable(L
"MokDB", &shim_lock_guid
);
1233 if (var
->MokDBState
== 0) {
1234 efi_status
= uefi_call_wrapper(RT
->SetVariable
,
1237 EFI_VARIABLE_NON_VOLATILE
|
1238 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1240 if (efi_status
!= EFI_SUCCESS
) {
1241 console_notify(L
"Failed to set DB state");
1245 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5,
1248 EFI_VARIABLE_NON_VOLATILE
|
1249 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1251 if (efi_status
!= EFI_SUCCESS
) {
1252 console_notify(L
"Failed to delete DB state");
1257 console_notify(L
"The system must now be rebooted");
1258 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
1259 EFI_SUCCESS
, 0, NULL
);
1260 console_notify(L
"Failed to reboot");
1264 static INTN
mok_pw_prompt (void *MokPW
, UINTN MokPWSize
) {
1265 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1266 EFI_STATUS efi_status
;
1267 UINT8 hash
[PASSWORD_CRYPT_SIZE
];
1270 if (MokPWSize
!= SHA256_DIGEST_SIZE
&& MokPWSize
!= PASSWORD_CRYPT_SIZE
) {
1271 console_notify(L
"Invalid MokPW variable contents");
1275 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1277 SetMem(hash
, PASSWORD_CRYPT_SIZE
, 0);
1279 if (MokPWSize
== PASSWORD_CRYPT_SIZE
) {
1280 if (CompareMem(MokPW
, hash
, PASSWORD_CRYPT_SIZE
) == 0)
1283 if (CompareMem(MokPW
, hash
, SHA256_DIGEST_SIZE
) == 0)
1288 if (console_yes_no((CHAR16
*[]){L
"Clear MOK password?", NULL
}) == 0)
1291 uefi_call_wrapper(RT
->SetVariable
, 5, L
"MokPWStore",
1293 EFI_VARIABLE_NON_VOLATILE
1294 | EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1296 LibDeleteVariable(L
"MokPW", &shim_lock_guid
);
1297 console_notify(L
"The system must now be rebooted");
1298 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
, EFI_SUCCESS
, 0,
1300 console_notify(L
"Failed to reboot");
1304 if (MokPWSize
== PASSWORD_CRYPT_SIZE
) {
1305 efi_status
= match_password((PASSWORD_CRYPT
*)MokPW
, NULL
, 0,
1306 NULL
, L
"Confirm MOK passphrase: ");
1308 efi_status
= match_password(NULL
, NULL
, 0, MokPW
,
1309 L
"Confirm MOK passphrase: ");
1312 if (efi_status
!= EFI_SUCCESS
) {
1313 console_notify(L
"Password limit reached");
1317 if (console_yes_no((CHAR16
*[]){L
"Set MOK password?", NULL
}) == 0)
1320 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5,
1323 EFI_VARIABLE_NON_VOLATILE
|
1324 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1326 if (efi_status
!= EFI_SUCCESS
) {
1327 console_notify(L
"Failed to set MOK password");
1331 LibDeleteVariable(L
"MokPW", &shim_lock_guid
);
1333 console_notify(L
"The system must now be rebooted");
1334 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
, EFI_SUCCESS
, 0,
1336 console_notify(L
"Failed to reboot");
1340 static BOOLEAN
verify_certificate(UINT8
*cert
, UINTN size
)
1344 if (!cert
|| size
< 0)
1348 * A DER encoding x509 certificate starts with SEQUENCE(0x30),
1349 * the number of length bytes, and the number of value bytes.
1350 * The size of a x509 certificate is usually between 127 bytes
1351 * and 64KB. For convenience, assume the number of value bytes
1352 * is 2, i.e. the second byte is 0x82.
1354 if (cert
[0] != 0x30 || cert
[1] != 0x82) {
1355 console_notify(L
"Not a DER encoding X509 certificate");
1359 length
= (cert
[2]<<8 | cert
[3]);
1360 if (length
!= (size
- 4)) {
1361 console_notify(L
"Invalid X509 certificate: Inconsistent size");
1365 if (!(X509ConstructCertificate(cert
, size
, (UINT8
**) &X509Cert
)) ||
1367 console_notify(L
"Invalid X509 certificate");
1371 X509_free(X509Cert
);
1375 static EFI_STATUS
enroll_file (void *data
, UINTN datasize
, BOOLEAN hash
)
1377 EFI_STATUS status
= EFI_SUCCESS
;
1378 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1379 EFI_SIGNATURE_LIST
*CertList
;
1380 EFI_SIGNATURE_DATA
*CertData
;
1381 UINTN mokbuffersize
;
1382 void *mokbuffer
= NULL
;
1385 UINT8 sha256
[SHA256_DIGEST_SIZE
];
1386 UINT8 sha1
[SHA1_DIGEST_SIZE
];
1387 SHIM_LOCK
*shim_lock
;
1388 EFI_GUID shim_guid
= SHIM_LOCK_GUID
;
1389 PE_COFF_LOADER_IMAGE_CONTEXT context
;
1391 status
= LibLocateProtocol(&shim_guid
, (VOID
**)&shim_lock
);
1393 if (status
!= EFI_SUCCESS
)
1396 mokbuffersize
= sizeof(EFI_SIGNATURE_LIST
) + sizeof(EFI_GUID
) +
1399 mokbuffer
= AllocatePool(mokbuffersize
);
1404 status
= shim_lock
->Context(data
, datasize
, &context
);
1406 if (status
!= EFI_SUCCESS
)
1409 status
= shim_lock
->Hash(data
, datasize
, &context
, sha256
,
1412 if (status
!= EFI_SUCCESS
)
1415 CertList
= mokbuffer
;
1416 CertList
->SignatureType
= EFI_CERT_SHA256_GUID
;
1417 CertList
->SignatureSize
= 16 + SHA256_DIGEST_SIZE
;
1418 CertData
= (EFI_SIGNATURE_DATA
*)(((UINT8
*)mokbuffer
) +
1419 sizeof(EFI_SIGNATURE_LIST
));
1420 CopyMem(CertData
->SignatureData
, sha256
, SHA256_DIGEST_SIZE
);
1422 mokbuffersize
= datasize
+ sizeof(EFI_SIGNATURE_LIST
) +
1424 mokbuffer
= AllocatePool(mokbuffersize
);
1429 CertList
= mokbuffer
;
1430 CertList
->SignatureType
= X509_GUID
;
1431 CertList
->SignatureSize
= 16 + datasize
;
1433 memcpy(mokbuffer
+ sizeof(EFI_SIGNATURE_LIST
) + 16, data
,
1436 CertData
= (EFI_SIGNATURE_DATA
*)(((UINT8
*)mokbuffer
) +
1437 sizeof(EFI_SIGNATURE_LIST
));
1440 CertList
->SignatureListSize
= mokbuffersize
;
1441 CertList
->SignatureHeaderSize
= 0;
1442 CertData
->SignatureOwner
= shim_lock_guid
;
1445 if (!verify_certificate(CertData
->SignatureData
, datasize
))
1449 mok_enrollment_prompt(mokbuffer
, mokbuffersize
, FALSE
);
1452 FreePool(mokbuffer
);
1457 static void mok_hash_enroll(void)
1459 EFI_STATUS efi_status
;
1460 CHAR16
*file_name
= NULL
;
1461 EFI_HANDLE im
= NULL
;
1462 EFI_FILE
*file
= NULL
;
1466 simple_file_selector(&im
, (CHAR16
*[]){
1469 L
"The Selected Binary will have its hash Enrolled",
1470 L
"This means it will Subsequently Boot with no prompting",
1471 L
"Remember to make sure it is a genuine binary before Enroling its hash",
1473 }, L
"\\", L
"", &file_name
);
1478 efi_status
= simple_file_open(im
, file_name
, &file
, EFI_FILE_MODE_READ
);
1480 if (efi_status
!= EFI_SUCCESS
) {
1481 console_error(L
"Unable to open file", efi_status
);
1485 simple_file_read_all(file
, &filesize
, &data
);
1486 simple_file_close(file
);
1489 console_error(L
"Unable to read file", efi_status
);
1493 efi_status
= enroll_file(data
, filesize
, TRUE
);
1495 if (efi_status
!= EFI_SUCCESS
)
1496 console_error(L
"Hash failed (did you select a valid EFI binary?)", efi_status
);
1501 static CHAR16
*der_suffix
[] = {
1508 static BOOLEAN
check_der_suffix (CHAR16
*file_name
)
1513 if (!file_name
|| StrLen(file_name
) <= 4)
1517 StrCat(suffix
, file_name
+ StrLen(file_name
) - 4);
1520 for (i
= 0; der_suffix
[i
] != NULL
; i
++) {
1521 if (StrCmp(suffix
, der_suffix
[i
]) == 0) {
1529 static void mok_key_enroll(void)
1531 EFI_STATUS efi_status
;
1532 CHAR16
*file_name
= NULL
;
1533 EFI_HANDLE im
= NULL
;
1534 EFI_FILE
*file
= NULL
;
1538 simple_file_selector(&im
, (CHAR16
*[]){
1541 L
"The selected key will be enrolled into the MOK database",
1542 L
"This means any binaries signed with it will be run without prompting",
1543 L
"Remember to make sure it is a genuine key before Enroling it",
1545 }, L
"\\", L
"", &file_name
);
1550 if (!check_der_suffix(file_name
)) {
1551 console_alertbox((CHAR16
*[]){
1552 L
"Unsupported Format",
1554 L
"Only DER encoded certificate (*.cer/der/crt) is supported",
1559 efi_status
= simple_file_open(im
, file_name
, &file
, EFI_FILE_MODE_READ
);
1561 if (efi_status
!= EFI_SUCCESS
) {
1562 console_error(L
"Unable to open file", efi_status
);
1566 simple_file_read_all(file
, &filesize
, &data
);
1567 simple_file_close(file
);
1570 console_error(L
"Unable to read file", efi_status
);
1574 enroll_file(data
, filesize
, FALSE
);
1578 static BOOLEAN
verify_pw(BOOLEAN
*protected)
1580 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1581 EFI_STATUS efi_status
;
1582 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1583 UINT8 pwhash
[PASSWORD_CRYPT_SIZE
];
1584 UINTN size
= PASSWORD_CRYPT_SIZE
;
1590 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokPWStore",
1591 &shim_lock_guid
, &attributes
, &size
,
1595 * If anything can attack the password it could just set it to a
1596 * known value, so there's no safety advantage in failing to validate
1597 * purely because of a failure to read the variable
1599 if (efi_status
!= EFI_SUCCESS
||
1600 (size
!= SHA256_DIGEST_SIZE
&& size
!= PASSWORD_CRYPT_SIZE
))
1603 if (attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)
1606 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1608 /* Draw the background */
1609 console_save_and_set_mode(&SavedMode
);
1610 message
[0] = PoolPrint (L
"%s UEFI key management", SHIM_VENDOR
);
1612 console_print_box_at(message
, -1, 0, 0, -1, -1, 1, 1);
1613 FreePool(message
[0]);
1614 console_restore_mode(&SavedMode
);
1616 if (size
== PASSWORD_CRYPT_SIZE
) {
1617 efi_status
= match_password((PASSWORD_CRYPT
*)pwhash
, NULL
, 0,
1618 NULL
, L
"Enter MOK password:");
1620 efi_status
= match_password(NULL
, NULL
, 0, pwhash
,
1621 L
"Enter MOK password:");
1623 if (efi_status
!= EFI_SUCCESS
) {
1624 console_notify(L
"Password limit reached");
1633 static int draw_countdown()
1635 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1640 CHAR16
*message
= L
"Press any key to perform MOK management";
1641 int timeout
= 10, wait
= 10000000;
1643 console_save_and_set_mode (&SavedMode
);
1645 title
[0] = PoolPrint (L
"%s UEFI key management", SHIM_VENDOR
);
1648 console_print_box_at(title
, -1, 0, 0, -1, -1, 1, 1);
1650 uefi_call_wrapper(ST
->ConOut
->QueryMode
, 4, ST
->ConOut
,
1651 ST
->ConOut
->Mode
->Mode
, &cols
, &rows
);
1653 PrintAt((cols
- StrLen(message
))/2, rows
/2, message
);
1656 PrintAt(2, rows
- 3, L
"Booting in %d seconds ", timeout
);
1658 PrintAt(2, rows
- 3, L
"Booting in %d second ", timeout
);
1660 status
= WaitForSingleEvent(ST
->ConIn
->WaitForKey
, wait
);
1662 if (status
!= EFI_TIMEOUT
) {
1663 /* Clear the key in the queue */
1664 uefi_call_wrapper(ST
->ConIn
->ReadKeyStroke
, 2,
1676 console_restore_mode(&SavedMode
);
1693 static EFI_STATUS
enter_mok_menu(EFI_HANDLE image_handle
,
1694 void *MokNew
, UINTN MokNewSize
,
1695 void *MokDel
, UINTN MokDelSize
,
1696 void *MokSB
, UINTN MokSBSize
,
1697 void *MokPW
, UINTN MokPWSize
,
1698 void *MokDB
, UINTN MokDBSize
)
1700 CHAR16
**menu_strings
;
1701 mok_menu_item
*menu_item
;
1704 UINT32 MokDelAuth
= 0;
1705 UINTN menucount
= 3, i
= 0;
1706 EFI_STATUS efi_status
;
1707 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1708 UINT8 auth
[PASSWORD_CRYPT_SIZE
];
1709 UINTN auth_size
= PASSWORD_CRYPT_SIZE
;
1712 EFI_STATUS ret
= EFI_SUCCESS
;
1714 if (verify_pw(&protected) == FALSE
)
1715 return EFI_ACCESS_DENIED
;
1717 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokAuth",
1719 &attributes
, &auth_size
, auth
);
1721 if ((efi_status
== EFI_SUCCESS
) &&
1722 (auth_size
== SHA256_DIGEST_SIZE
|| auth_size
== PASSWORD_CRYPT_SIZE
))
1725 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokDelAuth",
1727 &attributes
, &auth_size
, auth
);
1729 if ((efi_status
== EFI_SUCCESS
) &&
1730 (auth_size
== SHA256_DIGEST_SIZE
|| auth_size
== PASSWORD_CRYPT_SIZE
))
1733 if (MokNew
|| MokAuth
)
1736 if (MokDel
|| MokDelAuth
)
1748 menu_strings
= AllocateZeroPool(sizeof(CHAR16
*) * (menucount
+ 1));
1751 return EFI_OUT_OF_RESOURCES
;
1753 menu_item
= AllocateZeroPool(sizeof(mok_menu_item
) * menucount
);
1756 FreePool(menu_strings
);
1757 return EFI_OUT_OF_RESOURCES
;
1760 menu_strings
[i
] = L
"Continue boot";
1761 menu_item
[i
] = MOK_CONTINUE_BOOT
;
1765 if (MokNew
|| MokAuth
) {
1767 menu_strings
[i
] = L
"Reset MOK";
1768 menu_item
[i
] = MOK_RESET_MOK
;
1770 menu_strings
[i
] = L
"Enroll MOK";
1771 menu_item
[i
] = MOK_ENROLL_MOK
;
1776 if (MokDel
|| MokDelAuth
) {
1777 menu_strings
[i
] = L
"Delete MOK";
1778 menu_item
[i
] = MOK_DELETE_MOK
;
1783 menu_strings
[i
] = L
"Change Secure Boot state";
1784 menu_item
[i
] = MOK_CHANGE_SB
;
1789 menu_strings
[i
] = L
"Set MOK password";
1790 menu_item
[i
] = MOK_SET_PW
;
1795 menu_strings
[i
] = L
"Change DB state";
1796 menu_item
[i
] = MOK_CHANGE_DB
;
1800 menu_strings
[i
] = L
"Enroll key from disk";
1801 menu_item
[i
] = MOK_KEY_ENROLL
;
1804 menu_strings
[i
] = L
"Enroll hash from disk";
1805 menu_item
[i
] = MOK_HASH_ENROLL
;
1808 menu_strings
[i
] = NULL
;
1810 if (protected == FALSE
&& draw_countdown() == 0)
1813 while (choice
>= 0) {
1814 choice
= console_select((CHAR16
*[]){ L
"Perform MOK management", NULL
},
1820 switch (menu_item
[choice
]) {
1821 case MOK_CONTINUE_BOOT
:
1826 case MOK_ENROLL_MOK
:
1827 mok_enrollment_prompt(MokNew
, MokNewSize
, TRUE
);
1829 case MOK_DELETE_MOK
:
1830 mok_deletion_prompt(MokDel
, MokDelSize
);
1833 mok_sb_prompt(MokSB
, MokSBSize
);
1836 mok_pw_prompt(MokPW
, MokPWSize
);
1839 mok_db_prompt(MokDB
, MokDBSize
);
1841 case MOK_KEY_ENROLL
:
1844 case MOK_HASH_ENROLL
:
1853 FreePool(menu_strings
);
1856 FreePool(menu_item
);
1861 static EFI_STATUS
check_mok_request(EFI_HANDLE image_handle
)
1863 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1864 UINTN MokNewSize
= 0, MokDelSize
= 0, MokSBSize
= 0, MokPWSize
= 0,
1866 void *MokNew
= NULL
;
1867 void *MokDel
= NULL
;
1873 status
= get_variable(L
"MokNew", (UINT8
**)&MokNew
, &MokNewSize
,
1875 if (status
== EFI_SUCCESS
) {
1876 if (LibDeleteVariable(L
"MokNew", &shim_lock_guid
) != EFI_SUCCESS
) {
1877 console_notify(L
"Failed to delete MokNew");
1879 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
1880 console_error(L
"Could not retrieve MokNew", status
);
1883 status
= get_variable(L
"MokDel", (UINT8
**)&MokDel
, &MokDelSize
,
1885 if (status
== EFI_SUCCESS
) {
1886 if (LibDeleteVariable(L
"MokDel", &shim_lock_guid
) != EFI_SUCCESS
) {
1887 console_notify(L
"Failed to delete MokDel");
1889 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
1890 console_error(L
"Could not retrieve MokDel", status
);
1893 status
= get_variable(L
"MokSB", (UINT8
**)&MokSB
, &MokSBSize
,
1895 if (status
== EFI_SUCCESS
) {
1896 if (LibDeleteVariable(L
"MokSB", &shim_lock_guid
) != EFI_SUCCESS
) {
1897 console_notify(L
"Failed to delete MokSB");
1899 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
1900 console_error(L
"Could not retrieve MokSB", status
);
1903 status
= get_variable(L
"MokPW", (UINT8
**)&MokPW
, &MokPWSize
,
1905 if (status
== EFI_SUCCESS
) {
1906 if (LibDeleteVariable(L
"MokPW", &shim_lock_guid
) != EFI_SUCCESS
) {
1907 console_notify(L
"Failed to delete MokPW");
1909 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
1910 console_error(L
"Could not retrieve MokPW", status
);
1913 status
= get_variable(L
"MokDB", (UINT8
**)&MokDB
, &MokDBSize
,
1915 if (status
== EFI_SUCCESS
) {
1916 if (LibDeleteVariable(L
"MokDB", &shim_lock_guid
) != EFI_SUCCESS
) {
1917 console_notify(L
"Failed to delete MokDB");
1919 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
1920 console_error(L
"Could not retrieve MokDB", status
);
1923 enter_mok_menu(image_handle
, MokNew
, MokNewSize
, MokDel
, MokDelSize
,
1924 MokSB
, MokSBSize
, MokPW
, MokPWSize
, MokDB
, MokDBSize
);
1941 LibDeleteVariable(L
"MokAuth", &shim_lock_guid
);
1942 LibDeleteVariable(L
"MokDelAuth", &shim_lock_guid
);
1947 static EFI_STATUS
setup_rand (void)
1950 EFI_STATUS efi_status
;
1954 efi_status
= uefi_call_wrapper(RT
->GetTime
, 2, &time
, NULL
);
1956 if (efi_status
!= EFI_SUCCESS
)
1959 seed
= ((UINT64
)time
.Year
<< 48) | ((UINT64
)time
.Month
<< 40) |
1960 ((UINT64
)time
.Day
<< 32) | ((UINT64
)time
.Hour
<< 24) |
1961 ((UINT64
)time
.Minute
<< 16) | ((UINT64
)time
.Second
<< 8) |
1962 ((UINT64
)time
.Daylight
);
1964 status
= RandomSeed((UINT8
*)&seed
, sizeof(seed
));
1972 EFI_STATUS
efi_main (EFI_HANDLE image_handle
, EFI_SYSTEM_TABLE
*systab
)
1974 EFI_STATUS efi_status
;
1976 InitializeLib(image_handle
, systab
);
1982 efi_status
= check_mok_request(image_handle
);