3 #include <Library/BaseCryptLib.h>
4 #include <openssl/x509.h>
9 #define PASSWORD_MAX 16
10 #define PASSWORD_MIN 8
11 #define SB_PASSWORD_LEN 8
14 #define SHIM_VENDOR L"Shim"
17 #define EFI_VARIABLE_APPEND_WRITE 0x00000040
19 #define CERT_STRING L"Select an X509 certificate to enroll:\n\n"
20 #define HASH_STRING L"Select a file to trust:\n\n"
24 INTN (* callback
)(void *data
, void *data2
, void *data3
);
34 } __attribute__ ((packed
)) MokListNode
;
38 UINT8 hash
[SHA256_DIGEST_SIZE
];
39 } __attribute__ ((packed
)) MokSBvar
;
41 static EFI_INPUT_KEY
get_keystroke (void)
46 uefi_call_wrapper(BS
->WaitForEvent
, 3, 1, &ST
->ConIn
->WaitForKey
,
48 uefi_call_wrapper(ST
->ConIn
->ReadKeyStroke
, 2, ST
->ConIn
, &key
);
53 static EFI_STATUS
get_sha1sum (void *Data
, int DataSize
, UINT8
*hash
)
59 ctxsize
= Sha1GetContextSize();
60 ctx
= AllocatePool(ctxsize
);
63 Print(L
"Unable to allocate memory for hash context\n");
64 return EFI_OUT_OF_RESOURCES
;
68 Print(L
"Unable to initialise hash\n");
69 status
= EFI_OUT_OF_RESOURCES
;
73 if (!(Sha1Update(ctx
, Data
, DataSize
))) {
74 Print(L
"Unable to generate hash\n");
75 status
= EFI_OUT_OF_RESOURCES
;
79 if (!(Sha1Final(ctx
, hash
))) {
80 Print(L
"Unable to finalise hash\n");
81 status
= EFI_OUT_OF_RESOURCES
;
90 static MokListNode
*build_mok_list(UINT32 num
, void *Data
, UINTN DataSize
) {
92 EFI_SIGNATURE_LIST
*CertList
= Data
;
93 EFI_SIGNATURE_DATA
*Cert
;
94 EFI_GUID CertType
= EfiCertX509Guid
;
95 EFI_GUID HashType
= EfiHashSha256Guid
;
96 UINTN dbsize
= DataSize
;
99 list
= AllocatePool(sizeof(MokListNode
) * num
);
102 Print(L
"Unable to allocate MOK list\n");
106 while ((dbsize
> 0) && (dbsize
>= CertList
->SignatureListSize
)) {
107 if ((CompareGuid (&CertList
->SignatureType
, &CertType
) != 0) &&
108 (CompareGuid (&CertList
->SignatureType
, &HashType
) != 0)) {
109 dbsize
-= CertList
->SignatureListSize
;
110 CertList
= (EFI_SIGNATURE_LIST
*)((UINT8
*) CertList
+
111 CertList
->SignatureSize
);
115 if ((CompareGuid (&CertList
->SignatureType
, &HashType
) == 0) &&
116 (CertList
->SignatureSize
!= 48)) {
117 dbsize
-= CertList
->SignatureListSize
;
118 CertList
= (EFI_SIGNATURE_LIST
*)((UINT8
*) CertList
+
119 CertList
->SignatureSize
);
123 Cert
= (EFI_SIGNATURE_DATA
*) (((UINT8
*) CertList
) +
124 sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
126 list
[count
].MokSize
= CertList
->SignatureSize
;
127 list
[count
].Mok
= (void *)Cert
->SignatureData
;
130 dbsize
-= CertList
->SignatureListSize
;
131 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
132 CertList
->SignatureSize
);
138 static void print_x509_name (X509_NAME
*X509Name
, CHAR16
*name
)
142 str
= X509_NAME_oneline(X509Name
, NULL
, 0);
144 Print(L
" %s:\n %a\n", name
, str
);
149 static const char *mon
[12]= {
150 "Jan","Feb","Mar","Apr","May","Jun",
151 "Jul","Aug","Sep","Oct","Nov","Dec"
154 static void print_x509_GENERALIZEDTIME_time (ASN1_TIME
*time
, CHAR16
*time_string
)
159 int y
= 0,M
= 0,d
= 0,h
= 0,m
= 0,s
= 0;
164 v
=(char *)time
->data
;
172 for (i
=0; i
<12; i
++) {
173 if ((v
[i
] > '9') || (v
[i
] < '0'))
177 y
= (v
[0]-'0')*1000+(v
[1]-'0')*100 + (v
[2]-'0')*10+(v
[3]-'0');
178 M
= (v
[4]-'0')*10+(v
[5]-'0');
180 if ((M
> 12) || (M
< 1))
183 d
= (v
[6]-'0')*10+(v
[7]-'0');
184 h
= (v
[8]-'0')*10+(v
[9]-'0');
185 m
= (v
[10]-'0')*10+(v
[11]-'0');
187 if (time
->length
>= 14 &&
188 (v
[12] >= '0') && (v
[12] <= '9') &&
189 (v
[13] >= '0') && (v
[13] <= '9')) {
190 s
= (v
[12]-'0')*10+(v
[13]-'0');
191 /* Check for fractions of seconds. */
192 if (time
->length
>= 15 && v
[14] == '.') {
193 int l
= time
->length
;
194 f
= &v
[14]; /* The decimal point. */
196 while (14 + f_len
< l
&& f
[f_len
] >= '0' &&
202 SPrint(time_string
, 0, L
"%a %2d %02d:%02d:%02d%.*a %d%a",
203 mon
[M
-1], d
, h
, m
, s
, f_len
, f
, y
, (gmt
)?" GMT":"");
208 static void print_x509_UTCTIME_time (ASN1_TIME
*time
, CHAR16
*time_string
)
213 int y
= 0,M
= 0,d
= 0,h
= 0,m
= 0,s
= 0;
216 v
=(char *)time
->data
;
225 if ((v
[i
] > '9') || (v
[i
] < '0'))
228 y
= (v
[0]-'0')*10+(v
[1]-'0');
233 M
= (v
[2]-'0')*10+(v
[3]-'0');
235 if ((M
> 12) || (M
< 1))
238 d
= (v
[4]-'0')*10+(v
[5]-'0');
239 h
= (v
[6]-'0')*10+(v
[7]-'0');
240 m
= (v
[8]-'0')*10+(v
[9]-'0');
242 if (time
->length
>=12 &&
243 (v
[10] >= '0') && (v
[10] <= '9') &&
244 (v
[11] >= '0') && (v
[11] <= '9'))
245 s
= (v
[10]-'0')*10+(v
[11]-'0');
247 SPrint(time_string
, 0, L
"%a %2d %02d:%02d:%02d %d%a",
248 mon
[M
-1], d
, h
, m
, s
, y
+1900, (gmt
)?" GMT":"");
253 static void print_x509_time (ASN1_TIME
*time
, CHAR16
*name
)
255 CHAR16 time_string
[30];
257 if (time
->type
== V_ASN1_UTCTIME
) {
258 print_x509_UTCTIME_time(time
, time_string
);
259 } else if (time
->type
== V_ASN1_GENERALIZEDTIME
) {
260 print_x509_GENERALIZEDTIME_time(time
, time_string
);
262 time_string
[0] = '\0';
265 Print(L
" %s:\n %s\n", name
, time_string
);
268 static void show_x509_info (X509
*X509Cert
)
270 ASN1_INTEGER
*serial
;
272 unsigned char hexbuf
[30];
276 serial
= X509_get_serialNumber(X509Cert
);
279 bnser
= ASN1_INTEGER_to_BN(serial
, NULL
);
280 n
= BN_bn2bin(bnser
, hexbuf
);
281 Print(L
" Serial Number:\n ");
282 for (i
= 0; i
< n
-1; i
++) {
283 Print(L
"%02x:", hexbuf
[i
]);
285 Print(L
"%02x\n", hexbuf
[n
-1]);
288 X509Name
= X509_get_issuer_name(X509Cert
);
290 print_x509_name(X509Name
, L
"Issuer");
293 X509Name
= X509_get_subject_name(X509Cert
);
295 print_x509_name(X509Name
, L
"Subject");
298 time
= X509_get_notBefore(X509Cert
);
300 print_x509_time(time
, L
"Validity from");
303 time
= X509_get_notAfter(X509Cert
);
305 print_x509_time(time
, L
"Validity till");
309 static void show_mok_info (void *Mok
, UINTN MokSize
)
311 EFI_STATUS efi_status
;
312 UINT8 hash
[SHA1_DIGEST_SIZE
];
316 if (!Mok
|| MokSize
== 0)
320 if (X509ConstructCertificate(Mok
, MokSize
, (UINT8
**) &X509Cert
) &&
322 show_x509_info(X509Cert
);
325 Print(L
" Not a valid X509 certificate: %x\n\n",
330 Print(L
"SHA256 hash:\n ");
331 for (i
= 0; i
< SHA256_DIGEST_SIZE
; i
++) {
332 Print(L
" %02x", ((UINT8
*)Mok
)[i
]);
338 efi_status
= get_sha1sum(Mok
, MokSize
, hash
);
340 if (efi_status
!= EFI_SUCCESS
) {
341 Print(L
"Failed to compute MOK fingerprint\n");
345 Print(L
" Fingerprint (SHA1):\n ");
346 for (i
= 0; i
< SHA1_DIGEST_SIZE
; i
++) {
347 Print(L
" %02x", hash
[i
]);
354 static INTN
get_number ()
356 EFI_INPUT_KEY input_key
;
361 input_key
= get_keystroke();
363 if ((input_key
.UnicodeChar
< '0' ||
364 input_key
.UnicodeChar
> '9' ||
366 input_key
.UnicodeChar
!= CHAR_BACKSPACE
) {
370 if (count
== 0 && input_key
.UnicodeChar
== CHAR_BACKSPACE
)
373 Print(L
"%c", input_key
.UnicodeChar
);
375 if (input_key
.UnicodeChar
== CHAR_BACKSPACE
) {
376 input
[--count
] = '\0';
380 input
[count
++] = input_key
.UnicodeChar
;
381 } while (input_key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
388 return (INTN
)Atoi(input
);
391 static UINT8
list_keys (void *MokNew
, UINTN MokNewSize
)
394 MokListNode
*keys
= NULL
;
397 EFI_SIGNATURE_LIST
*CertList
= MokNew
;
398 EFI_GUID CertType
= EfiCertX509Guid
;
399 EFI_GUID HashType
= EfiHashSha256Guid
;
400 UINTN dbsize
= MokNewSize
;
402 if (MokNewSize
< (sizeof(EFI_SIGNATURE_LIST
) +
403 sizeof(EFI_SIGNATURE_DATA
))) {
409 while ((dbsize
> 0) && (dbsize
>= CertList
->SignatureListSize
)) {
410 if ((CompareGuid (&CertList
->SignatureType
, &CertType
) != 0) &&
411 (CompareGuid (&CertList
->SignatureType
, &HashType
) != 0)) {
412 Print(L
"Doesn't look like a key or hash\n");
413 dbsize
-= CertList
->SignatureListSize
;
414 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
415 CertList
->SignatureSize
);
419 if ((CompareGuid (&CertList
->SignatureType
, &CertType
) != 0) &&
420 (CertList
->SignatureSize
!= 48)) {
421 Print(L
"Doesn't look like a valid hash\n");
422 dbsize
-= CertList
->SignatureListSize
;
423 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
424 CertList
->SignatureSize
);
429 dbsize
-= CertList
->SignatureListSize
;
430 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
431 CertList
->SignatureSize
);
434 keys
= build_mok_list(MokNum
, MokNew
, MokNewSize
);
437 Print(L
"Failed to construct key list in MokNew\n");
442 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
443 Print(L
"Input the key number to show the details of the key or\n"
444 L
"type \'0\' to continue\n\n");
445 Print(L
"%d key(s) in the new key list\n\n", MokNum
);
447 if (key_num
> MokNum
) {
448 Print(L
"[Key %d]\n", key_num
);
449 Print(L
"No such key\n\n");
450 } else if (initial
!= 1 && key_num
> 0){
451 Print(L
"[Key %d]\n", key_num
);
452 show_mok_info(keys
[key_num
-1].Mok
, keys
[key_num
-1].MokSize
);
455 Print(L
"Key Number: ");
457 key_num
= get_number();
465 } while (key_num
!= 0);
472 static UINT8
get_line (UINT32
*length
, CHAR16
*line
, UINT32 line_max
, UINT8 show
)
478 key
= get_keystroke();
480 if ((count
>= line_max
&&
481 key
.UnicodeChar
!= CHAR_BACKSPACE
) ||
482 key
.UnicodeChar
== CHAR_NULL
||
483 key
.UnicodeChar
== CHAR_TAB
||
484 key
.UnicodeChar
== CHAR_LINEFEED
||
485 key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
489 if (count
== 0 && key
.UnicodeChar
== CHAR_BACKSPACE
) {
491 } else if (key
.UnicodeChar
== CHAR_BACKSPACE
) {
495 line
[--count
] = '\0';
500 Print(L
"%c", key
.UnicodeChar
);
503 line
[count
++] = key
.UnicodeChar
;
504 } while (key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
512 static EFI_STATUS
compute_pw_hash (void *MokNew
, UINTN MokNewSize
, CHAR16
*password
,
513 UINT32 pw_length
, UINT8
*hash
)
516 unsigned int ctxsize
;
519 ctxsize
= Sha256GetContextSize();
520 ctx
= AllocatePool(ctxsize
);
523 Print(L
"Unable to allocate memory for hash context\n");
524 return EFI_OUT_OF_RESOURCES
;
527 if (!Sha256Init(ctx
)) {
528 Print(L
"Unable to initialise hash\n");
529 status
= EFI_OUT_OF_RESOURCES
;
533 if (MokNew
&& MokNewSize
) {
534 if (!(Sha256Update(ctx
, MokNew
, MokNewSize
))) {
535 Print(L
"Unable to generate hash\n");
536 status
= EFI_OUT_OF_RESOURCES
;
541 if (!(Sha256Update(ctx
, password
, pw_length
* sizeof(CHAR16
)))) {
542 Print(L
"Unable to generate hash\n");
543 status
= EFI_OUT_OF_RESOURCES
;
547 if (!(Sha256Final(ctx
, hash
))) {
548 Print(L
"Unable to finalise hash\n");
549 status
= EFI_OUT_OF_RESOURCES
;
553 status
= EFI_SUCCESS
;
558 static EFI_STATUS
store_keys (void *MokNew
, UINTN MokNewSize
, int authenticate
)
560 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
561 EFI_STATUS efi_status
;
562 UINT8 hash
[SHA256_DIGEST_SIZE
];
563 UINT8 auth
[SHA256_DIGEST_SIZE
];
566 CHAR16 password
[PASSWORD_MAX
];
568 UINT8 fail_count
= 0;
571 auth_size
= SHA256_DIGEST_SIZE
;
572 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokAuth",
574 &attributes
, &auth_size
, auth
);
577 if (efi_status
!= EFI_SUCCESS
|| auth_size
!= SHA256_DIGEST_SIZE
) {
578 Print(L
"Failed to get MokAuth %d\n", efi_status
);
582 while (fail_count
< 3) {
583 Print(L
"Password(%d-%d characters): ",
584 PASSWORD_MIN
, PASSWORD_MAX
);
585 get_line(&pw_length
, password
, PASSWORD_MAX
, 0);
588 Print(L
"At least %d characters for the password\n",
592 efi_status
= compute_pw_hash(MokNew
, MokNewSize
, password
,
595 if (efi_status
!= EFI_SUCCESS
) {
599 if (CompareMem(auth
, hash
, SHA256_DIGEST_SIZE
) != 0) {
600 Print(L
"Password doesn't match\n");
608 return EFI_ACCESS_DENIED
;
613 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, L
"MokList",
615 EFI_VARIABLE_NON_VOLATILE
616 | EFI_VARIABLE_BOOTSERVICE_ACCESS
617 | EFI_VARIABLE_APPEND_WRITE
,
621 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, L
"MokList",
623 EFI_VARIABLE_NON_VOLATILE
624 | EFI_VARIABLE_BOOTSERVICE_ACCESS
625 | EFI_VARIABLE_APPEND_WRITE
,
629 if (efi_status
!= EFI_SUCCESS
) {
630 Print(L
"Failed to set variable %d\n", efi_status
);
637 static UINTN
mok_enrollment_prompt (void *MokNew
, UINTN MokNewSize
, int auth
) {
640 EFI_STATUS efi_status
;
643 if (!list_keys(MokNew
, MokNewSize
)) {
647 Print(L
"Enroll the key(s)? (y/n): ");
649 get_line (&length
, line
, 1, 1);
651 if (line
[0] == 'Y' || line
[0] == 'y') {
652 efi_status
= store_keys(MokNew
, MokNewSize
, auth
);
654 if (efi_status
!= EFI_SUCCESS
) {
655 Print(L
"Failed to enroll keys\n");
660 } while (line
[0] != 'N' && line
[0] != 'n');
664 static INTN
mok_enrollment_prompt_callback (void *MokNew
, void *data2
,
666 return mok_enrollment_prompt(MokNew
, (UINTN
)data2
, TRUE
);
669 static INTN
mok_deletion_prompt (void *MokNew
, void *data2
, void *data3
) {
672 EFI_STATUS efi_status
;
674 Print(L
"Erase all stored keys? (y/N): ");
676 get_line (&length
, line
, 1, 1);
678 if (line
[0] == 'Y' || line
[0] == 'y') {
679 efi_status
= store_keys(NULL
, 0, TRUE
);
681 if (efi_status
!= EFI_SUCCESS
) {
682 Print(L
"Failed to erase keys\n");
690 static INTN
mok_sb_prompt (void *MokSB
, void *data2
, void *data3
) {
691 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
692 EFI_STATUS efi_status
;
693 UINTN MokSBSize
= (UINTN
)data2
;
694 MokSBvar
*var
= MokSB
;
695 CHAR16 password
[SB_PASSWORD_LEN
];
696 UINT8 fail_count
= 0;
697 UINT8 hash
[SHA256_DIGEST_SIZE
];
702 LibDeleteVariable(L
"MokSB", &shim_lock_guid
);
704 if (MokSBSize
!= sizeof(MokSBvar
)) {
705 Print(L
"Invalid MokSB variable contents\n");
709 while (fail_count
< 3) {
710 Print(L
"Enter Secure Boot passphrase: ");
711 get_line(&length
, password
, SB_PASSWORD_LEN
, 0);
713 if (length
!= SB_PASSWORD_LEN
) {
714 Print(L
"Invalid password length\n");
719 efi_status
= compute_pw_hash(NULL
, 0, password
,
720 SB_PASSWORD_LEN
, hash
);
722 if (efi_status
!= EFI_SUCCESS
) {
723 Print(L
"Unable to generate password hash\n");
728 if (CompareMem(var
->hash
, hash
, SHA256_DIGEST_SIZE
) != 0) {
729 Print(L
"Password doesn't match\n");
737 if (fail_count
>= 3) {
738 Print(L
"Password limit reached\n");
742 if (var
->MokSBState
== 0) {
743 Print(L
"Disable Secure Boot? (y/n): ");
745 Print(L
"Enable Secure Boot? (y/n): ");
749 get_line (&length
, line
, 1, 1);
751 if (line
[0] == 'Y' || line
[0] == 'y') {
752 if (var
->MokSBState
== 0) {
753 efi_status
= uefi_call_wrapper(RT
->SetVariable
,
756 EFI_VARIABLE_NON_VOLATILE
|
757 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
759 if (efi_status
!= EFI_SUCCESS
) {
760 Print(L
"Failed to set Secure Boot state\n");
764 LibDeleteVariable(L
"MokSBState",
768 Print(L
"Press a key to reboot system\n");
770 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
771 EFI_SUCCESS
, 0, NULL
);
772 Print(L
"Failed to reboot\n");
775 } while (line
[0] != 'N' && line
[0] != 'n');
781 static INTN
mok_pw_prompt (void *MokPW
, void *data2
, void *data3
) {
782 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
783 EFI_STATUS efi_status
;
784 UINTN MokPWSize
= (UINTN
)data2
;
785 UINT8 fail_count
= 0;
786 UINT8 hash
[SHA256_DIGEST_SIZE
];
787 CHAR16 password
[PASSWORD_MAX
];
791 if (MokPWSize
!= SHA256_DIGEST_SIZE
) {
792 Print(L
"Invalid MokPW variable contents\n");
796 LibDeleteVariable(L
"MokPW", &shim_lock_guid
);
798 while (fail_count
< 3) {
799 Print(L
"Confirm MOK passphrase: ");
800 get_line(&length
, password
, PASSWORD_MAX
, 0);
802 if ((length
< PASSWORD_MIN
) || (length
> PASSWORD_MAX
)) {
803 Print(L
"Invalid password length\n");
808 efi_status
= compute_pw_hash(NULL
, 0, password
,
809 SB_PASSWORD_LEN
, hash
);
811 if (efi_status
!= EFI_SUCCESS
) {
812 Print(L
"Unable to generate password hash\n");
817 if (CompareMem(MokPW
, hash
, SHA256_DIGEST_SIZE
) != 0) {
818 Print(L
"Password doesn't match\n");
826 if (fail_count
>= 3) {
827 Print(L
"Password limit reached\n");
831 Print(L
"Set MOK password? (y/n): ");
834 get_line (&length
, line
, 1, 1);
836 if (line
[0] == 'Y' || line
[0] == 'y') {
837 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5,
840 EFI_VARIABLE_NON_VOLATILE
|
841 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
843 if (efi_status
!= EFI_SUCCESS
) {
844 Print(L
"Failed to set MOK password\n");
848 Print(L
"Press a key to reboot system\n");
850 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
851 EFI_SUCCESS
, 0, NULL
);
852 Print(L
"Failed to reboot\n");
855 } while (line
[0] != 'N' && line
[0] != 'n');
860 static UINTN
draw_menu (CHAR16
*header
, UINTN lines
, struct menu_item
*items
,
864 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
866 uefi_call_wrapper(ST
->ConOut
->SetAttribute
, 2, ST
->ConOut
,
867 EFI_WHITE
| EFI_BACKGROUND_BLACK
);
869 Print(L
"%s UEFI key management\n\n", SHIM_VENDOR
);
872 Print(L
"%s", header
);
874 for (i
= 0; i
< count
; i
++) {
875 uefi_call_wrapper(ST
->ConOut
->SetAttribute
, 2, ST
->ConOut
,
876 items
[i
].colour
| EFI_BACKGROUND_BLACK
);
877 Print(L
" %s\n", items
[i
].text
);
880 uefi_call_wrapper(ST
->ConOut
->SetCursorPosition
, 3, ST
->ConOut
, 0, 0);
881 uefi_call_wrapper(ST
->ConOut
->EnableCursor
, 2, ST
->ConOut
, TRUE
);
886 static void free_menu (struct menu_item
*items
, UINTN count
) {
889 for (i
=0; i
<count
; i
++) {
891 FreePool(items
[i
].text
);
897 static void update_time (UINTN position
, UINTN timeout
)
899 uefi_call_wrapper(ST
->ConOut
->SetCursorPosition
, 3, ST
->ConOut
, 0,
902 uefi_call_wrapper(ST
->ConOut
->SetAttribute
, 2, ST
->ConOut
,
903 EFI_BLACK
| EFI_BACKGROUND_BLACK
);
905 Print(L
" ", timeout
);
907 uefi_call_wrapper(ST
->ConOut
->SetCursorPosition
, 3, ST
->ConOut
, 0,
910 uefi_call_wrapper(ST
->ConOut
->SetAttribute
, 2, ST
->ConOut
,
911 EFI_WHITE
| EFI_BACKGROUND_BLACK
);
914 Print(L
"Booting in %d seconds\n", timeout
);
916 Print(L
"Booting in %d second\n", timeout
);
919 static void run_menu (CHAR16
*header
, UINTN lines
, struct menu_item
*items
,
920 UINTN count
, UINTN timeout
) {
921 UINTN index
, pos
= 0, wait
= 0, offset
;
929 offset
= draw_menu (header
, lines
, items
, count
);
932 update_time(count
+ offset
+ 1, timeout
);
934 uefi_call_wrapper(ST
->ConOut
->SetCursorPosition
, 3, ST
->ConOut
,
936 status
= WaitForSingleEvent(ST
->ConIn
->WaitForKey
, wait
);
938 if (status
== EFI_TIMEOUT
) {
941 free_menu(items
, count
);
950 uefi_call_wrapper(BS
->WaitForEvent
, 3, 1,
951 &ST
->ConIn
->WaitForKey
, &index
);
952 uefi_call_wrapper(ST
->ConIn
->ReadKeyStroke
, 2, ST
->ConIn
,
955 switch(key
.ScanCode
) {
963 if (pos
== (count
- 1))
970 switch(key
.UnicodeChar
) {
972 case CHAR_CARRIAGE_RETURN
:
973 if (items
[pos
].callback
== NULL
) {
974 free_menu(items
, count
);
978 ret
= items
[pos
].callback(items
[pos
].data
,
982 Print(L
"Press a key to continue\n");
985 draw_menu (header
, lines
, items
, count
);
992 static UINTN
verify_certificate(void *cert
, UINTN size
)
995 if (!cert
|| size
== 0)
998 if (!(X509ConstructCertificate(cert
, size
, (UINT8
**) &X509Cert
)) ||
1000 Print(L
"Invalid X509 certificate\n");
1005 X509_free(X509Cert
);
1009 static INTN
file_callback (void *data
, void *data2
, void *data3
) {
1010 EFI_FILE_INFO
*buffer
= NULL
;
1011 UINTN buffersize
= 0, mokbuffersize
;
1014 CHAR16
*filename
= data
;
1015 EFI_FILE
*parent
= data2
;
1016 BOOLEAN hash
= !!data3
;
1017 EFI_GUID file_info_guid
= EFI_FILE_INFO_ID
;
1018 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1019 EFI_SIGNATURE_LIST
*CertList
;
1020 EFI_SIGNATURE_DATA
*CertData
;
1021 void *mokbuffer
= NULL
;
1023 status
= uefi_call_wrapper(parent
->Open
, 5, parent
, &file
, filename
,
1024 EFI_FILE_MODE_READ
, 0);
1026 if (status
!= EFI_SUCCESS
)
1029 status
= uefi_call_wrapper(file
->GetInfo
, 4, file
, &file_info_guid
,
1030 &buffersize
, buffer
);
1032 if (status
== EFI_BUFFER_TOO_SMALL
) {
1033 buffer
= AllocatePool(buffersize
);
1034 status
= uefi_call_wrapper(file
->GetInfo
, 4, file
,
1035 &file_info_guid
, &buffersize
,
1042 buffersize
= buffer
->FileSize
;
1046 UINT8 sha256
[SHA256_DIGEST_SIZE
];
1047 UINT8 sha1
[SHA1_DIGEST_SIZE
];
1048 SHIM_LOCK
*shim_lock
;
1049 EFI_GUID shim_guid
= SHIM_LOCK_GUID
;
1050 PE_COFF_LOADER_IMAGE_CONTEXT context
;
1052 status
= LibLocateProtocol(&shim_guid
, (VOID
**)&shim_lock
);
1054 if (status
!= EFI_SUCCESS
)
1057 mokbuffersize
= sizeof(EFI_SIGNATURE_LIST
) + sizeof(EFI_GUID
) +
1060 mokbuffer
= AllocatePool(mokbuffersize
);
1065 binary
= AllocatePool(buffersize
);
1067 status
= uefi_call_wrapper(file
->Read
, 3, file
, &buffersize
,
1070 if (status
!= EFI_SUCCESS
)
1073 status
= shim_lock
->Context(binary
, buffersize
, &context
);
1075 if (status
!= EFI_SUCCESS
)
1078 status
= shim_lock
->Hash(binary
, buffersize
, &context
, sha256
,
1081 if (status
!= EFI_SUCCESS
)
1084 CertList
= mokbuffer
;
1085 CertList
->SignatureType
= EfiHashSha256Guid
;
1086 CertList
->SignatureSize
= 16 + SHA256_DIGEST_SIZE
;
1087 CertData
= (EFI_SIGNATURE_DATA
*)(((UINT8
*)mokbuffer
) +
1088 sizeof(EFI_SIGNATURE_LIST
));
1089 CopyMem(CertData
->SignatureData
, sha256
, SHA256_DIGEST_SIZE
);
1091 mokbuffersize
= buffersize
+ sizeof(EFI_SIGNATURE_LIST
) +
1093 mokbuffer
= AllocatePool(mokbuffersize
);
1098 CertList
= mokbuffer
;
1099 CertList
->SignatureType
= EfiCertX509Guid
;
1100 CertList
->SignatureSize
= 16 + buffersize
;
1101 status
= uefi_call_wrapper(file
->Read
, 3, file
, &buffersize
,
1102 mokbuffer
+ sizeof(EFI_SIGNATURE_LIST
) + 16);
1104 if (status
!= EFI_SUCCESS
)
1106 CertData
= (EFI_SIGNATURE_DATA
*)(((UINT8
*)mokbuffer
) +
1107 sizeof(EFI_SIGNATURE_LIST
));
1110 CertList
->SignatureListSize
= mokbuffersize
;
1111 CertList
->SignatureHeaderSize
= 0;
1112 CertData
->SignatureOwner
= shim_lock_guid
;
1115 if (!verify_certificate(CertData
->SignatureData
, buffersize
))
1119 mok_enrollment_prompt(mokbuffer
, mokbuffersize
, FALSE
);
1125 FreePool(mokbuffer
);
1130 static INTN
directory_callback (void *data
, void *data2
, void *data3
) {
1131 EFI_FILE_INFO
*buffer
= NULL
;
1132 UINTN buffersize
= 0;
1134 UINTN dircount
= 0, i
= 0;
1135 struct menu_item
*dircontent
;
1137 CHAR16
*filename
= data
;
1138 EFI_FILE
*root
= data2
;
1139 BOOLEAN hash
= !!data3
;
1141 status
= uefi_call_wrapper(root
->Open
, 5, root
, &dir
, filename
,
1142 EFI_FILE_MODE_READ
, 0);
1144 if (status
!= EFI_SUCCESS
)
1148 status
= uefi_call_wrapper(dir
->Read
, 3, dir
, &buffersize
,
1151 if (status
== EFI_BUFFER_TOO_SMALL
) {
1152 buffer
= AllocatePool(buffersize
);
1153 status
= uefi_call_wrapper(dir
->Read
, 3, dir
,
1154 &buffersize
, buffer
);
1157 if (status
!= EFI_SUCCESS
)
1163 if ((StrCmp(buffer
->FileName
, L
".") == 0) ||
1164 (StrCmp(buffer
->FileName
, L
"..") == 0))
1175 dircontent
= AllocatePool(sizeof(struct menu_item
) * dircount
);
1177 dircontent
[0].text
= StrDuplicate(L
"..");
1178 dircontent
[0].callback
= NULL
;
1179 dircontent
[0].colour
= EFI_YELLOW
;
1182 uefi_call_wrapper(dir
->SetPosition
, 2, dir
, 0);
1185 status
= uefi_call_wrapper(dir
->Read
, 3, dir
, &buffersize
,
1188 if (status
== EFI_BUFFER_TOO_SMALL
) {
1189 buffer
= AllocatePool(buffersize
);
1190 status
= uefi_call_wrapper(dir
->Read
, 3, dir
,
1191 &buffersize
, buffer
);
1194 if (status
!= EFI_SUCCESS
)
1200 if ((StrCmp(buffer
->FileName
, L
".") == 0) ||
1201 (StrCmp(buffer
->FileName
, L
"..") == 0))
1204 if (buffer
->Attribute
& EFI_FILE_DIRECTORY
) {
1205 dircontent
[i
].text
= StrDuplicate(buffer
->FileName
);
1206 dircontent
[i
].callback
= directory_callback
;
1207 dircontent
[i
].data
= dircontent
[i
].text
;
1208 dircontent
[i
].data2
= dir
;
1209 dircontent
[i
].data3
= data3
;
1210 dircontent
[i
].colour
= EFI_YELLOW
;
1212 dircontent
[i
].text
= StrDuplicate(buffer
->FileName
);
1213 dircontent
[i
].callback
= file_callback
;
1214 dircontent
[i
].data
= dircontent
[i
].text
;
1215 dircontent
[i
].data2
= dir
;
1216 dircontent
[i
].data3
= data3
;
1217 dircontent
[i
].colour
= EFI_WHITE
;
1227 run_menu(HASH_STRING
, 2, dircontent
, dircount
, 0);
1229 run_menu(CERT_STRING
, 2, dircontent
, dircount
, 0);
1234 static INTN
filesystem_callback (void *data
, void *data2
, void *data3
) {
1235 EFI_FILE_INFO
*buffer
= NULL
;
1236 UINTN buffersize
= 0;
1238 UINTN dircount
= 0, i
= 0;
1239 struct menu_item
*dircontent
;
1240 EFI_FILE
*root
= data
;
1241 BOOLEAN hash
= !!data3
;
1243 uefi_call_wrapper(root
->SetPosition
, 2, root
, 0);
1246 status
= uefi_call_wrapper(root
->Read
, 3, root
, &buffersize
,
1249 if (status
== EFI_BUFFER_TOO_SMALL
) {
1250 buffer
= AllocatePool(buffersize
);
1251 status
= uefi_call_wrapper(root
->Read
, 3, root
,
1252 &buffersize
, buffer
);
1255 if (status
!= EFI_SUCCESS
)
1261 if ((StrCmp(buffer
->FileName
, L
".") == 0) ||
1262 (StrCmp(buffer
->FileName
, L
"..") == 0))
1273 dircontent
= AllocatePool(sizeof(struct menu_item
) * dircount
);
1275 dircontent
[0].text
= StrDuplicate(L
"Return to filesystem list");
1276 dircontent
[0].callback
= NULL
;
1277 dircontent
[0].colour
= EFI_YELLOW
;
1280 uefi_call_wrapper(root
->SetPosition
, 2, root
, 0);
1283 status
= uefi_call_wrapper(root
->Read
, 3, root
, &buffersize
,
1286 if (status
== EFI_BUFFER_TOO_SMALL
) {
1287 buffer
= AllocatePool(buffersize
);
1288 status
= uefi_call_wrapper(root
->Read
, 3, root
,
1289 &buffersize
, buffer
);
1292 if (status
!= EFI_SUCCESS
)
1298 if ((StrCmp(buffer
->FileName
, L
".") == 0) ||
1299 (StrCmp(buffer
->FileName
, L
"..") == 0))
1302 if (buffer
->Attribute
& EFI_FILE_DIRECTORY
) {
1303 dircontent
[i
].text
= StrDuplicate(buffer
->FileName
);
1304 dircontent
[i
].callback
= directory_callback
;
1305 dircontent
[i
].data
= dircontent
[i
].text
;
1306 dircontent
[i
].data2
= root
;
1307 dircontent
[i
].data3
= data3
;
1308 dircontent
[i
].colour
= EFI_YELLOW
;
1310 dircontent
[i
].text
= StrDuplicate(buffer
->FileName
);
1311 dircontent
[i
].callback
= file_callback
;
1312 dircontent
[i
].data
= dircontent
[i
].text
;
1313 dircontent
[i
].data2
= root
;
1314 dircontent
[i
].data3
= data3
;
1315 dircontent
[i
].colour
= EFI_WHITE
;
1325 run_menu(HASH_STRING
, 2, dircontent
, dircount
, 0);
1327 run_menu(CERT_STRING
, 2, dircontent
, dircount
, 0);
1332 static INTN
find_fs (void *data
, void *data2
, void *data3
) {
1333 EFI_GUID fs_guid
= SIMPLE_FILE_SYSTEM_PROTOCOL
;
1335 UINTN OldSize
, NewSize
;
1336 EFI_HANDLE
**filesystem_handles
;
1337 struct menu_item
*filesystems
;
1338 BOOLEAN hash
= !!data3
;
1340 uefi_call_wrapper(BS
->LocateHandleBuffer
, 5, ByProtocol
, &fs_guid
,
1341 NULL
, &count
, &filesystem_handles
);
1343 if (!count
|| !filesystem_handles
) {
1344 Print(L
"No filesystems?\n");
1350 filesystems
= AllocatePool(sizeof(struct menu_item
) * count
);
1352 filesystems
[0].text
= StrDuplicate(L
"Exit");
1353 filesystems
[0].callback
= NULL
;
1354 filesystems
[0].colour
= EFI_YELLOW
;
1356 for (i
=1; i
<count
; i
++) {
1357 EFI_HANDLE
*fs
= filesystem_handles
[i
-1];
1358 EFI_FILE_IO_INTERFACE
*fs_interface
;
1359 EFI_DEVICE_PATH
*path
;
1362 CHAR16
*VolumeLabel
= NULL
;
1363 EFI_FILE_SYSTEM_INFO
*buffer
= NULL
;
1364 UINTN buffersize
= 0;
1365 EFI_GUID file_info_guid
= EFI_FILE_INFO_ID
;
1367 status
= uefi_call_wrapper(BS
->HandleProtocol
, 3, fs
, &fs_guid
,
1370 if (status
!= EFI_SUCCESS
|| !fs_interface
)
1373 path
= DevicePathFromHandle(fs
);
1375 status
= uefi_call_wrapper(fs_interface
->OpenVolume
, 2,
1376 fs_interface
, &root
);
1378 if (status
!= EFI_SUCCESS
|| !root
)
1381 status
= uefi_call_wrapper(root
->GetInfo
, 4, root
,
1382 &file_info_guid
, &buffersize
,
1385 if (status
== EFI_BUFFER_TOO_SMALL
) {
1386 buffer
= AllocatePool(buffersize
);
1387 status
= uefi_call_wrapper(root
->GetInfo
, 4, root
,
1389 &buffersize
, buffer
);
1392 if (status
== EFI_SUCCESS
)
1393 VolumeLabel
= buffer
->VolumeLabel
;
1396 filesystems
[i
].text
= DevicePathToStr(path
);
1398 filesystems
[i
].text
= StrDuplicate(L
"Unknown device\n");
1400 OldSize
= (StrLen(filesystems
[i
].text
) + 1) * sizeof(CHAR16
);
1401 NewSize
= OldSize
+ StrLen(VolumeLabel
) * sizeof(CHAR16
);
1402 filesystems
[i
].text
= ReallocatePool(filesystems
[i
].text
,
1404 StrCat(filesystems
[i
].text
, VolumeLabel
);
1410 filesystems
[i
].data
= root
;
1411 filesystems
[i
].data2
= NULL
;
1412 filesystems
[i
].data3
= data3
;
1413 filesystems
[i
].callback
= filesystem_callback
;
1414 filesystems
[i
].colour
= EFI_YELLOW
;
1417 uefi_call_wrapper(BS
->FreePool
, 1, filesystem_handles
);
1420 run_menu(HASH_STRING
, 2, filesystems
, count
, 0);
1422 run_menu(CERT_STRING
, 2, filesystems
, count
, 0);
1427 static BOOLEAN
verify_pw(void)
1429 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1430 EFI_STATUS efi_status
;
1431 CHAR16 password
[PASSWORD_MAX
];
1432 UINT8 fail_count
= 0;
1433 UINT8 hash
[SHA256_DIGEST_SIZE
];
1434 UINT8 pwhash
[SHA256_DIGEST_SIZE
];
1435 UINTN size
= SHA256_DIGEST_SIZE
;
1439 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokPWStore",
1440 &shim_lock_guid
, &attributes
, &size
,
1444 * If anything can attack the password it could just set it to a
1445 * known value, so there's no safety advantage in failing to validate
1446 * purely because of a failure to read the variable
1448 if (efi_status
!= EFI_SUCCESS
)
1451 if (attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)
1454 while (fail_count
< 3) {
1455 Print(L
"Enter MOK password: ");
1456 get_line(&length
, password
, PASSWORD_MAX
, 0);
1458 if (length
< PASSWORD_MIN
|| length
> PASSWORD_MAX
) {
1459 Print(L
"Invalid password length\n");
1464 efi_status
= compute_pw_hash(NULL
, 0, password
, length
, hash
);
1466 if (efi_status
!= EFI_SUCCESS
) {
1467 Print(L
"Unable to generate password hash\n");
1472 if (CompareMem(pwhash
, hash
, SHA256_DIGEST_SIZE
) != 0) {
1473 Print(L
"Password doesn't match\n");
1481 Print(L
"Password limit reached\n");
1485 static EFI_STATUS
enter_mok_menu(EFI_HANDLE image_handle
, void *MokNew
,
1486 UINTN MokNewSize
, void *MokSB
,
1487 UINTN MokSBSize
, void *MokPW
, UINTN MokPWSize
)
1489 struct menu_item
*menu_item
;
1491 UINTN menucount
= 3, i
= 0;
1492 EFI_STATUS efi_status
;
1493 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1494 UINT8 auth
[SHA256_DIGEST_SIZE
];
1495 UINTN auth_size
= SHA256_DIGEST_SIZE
;
1498 if (verify_pw() == FALSE
)
1499 return EFI_ACCESS_DENIED
;
1501 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokAuth",
1503 &attributes
, &auth_size
, auth
);
1505 if ((efi_status
== EFI_SUCCESS
) && (auth_size
== SHA256_DIGEST_SIZE
))
1508 if (MokNew
|| MokAuth
)
1517 menu_item
= AllocateZeroPool(sizeof(struct menu_item
) * menucount
);
1520 return EFI_OUT_OF_RESOURCES
;
1522 menu_item
[i
].text
= StrDuplicate(L
"Continue boot");
1523 menu_item
[i
].colour
= EFI_WHITE
;
1524 menu_item
[i
].callback
= NULL
;
1528 if (MokNew
|| MokAuth
) {
1530 menu_item
[i
].text
= StrDuplicate(L
"Delete MOK");
1531 menu_item
[i
].colour
= EFI_WHITE
;
1532 menu_item
[i
].callback
= mok_deletion_prompt
;
1534 menu_item
[i
].text
= StrDuplicate(L
"Enroll MOK");
1535 menu_item
[i
].colour
= EFI_WHITE
;
1536 menu_item
[i
].data
= MokNew
;
1537 menu_item
[i
].data2
= (void *)MokNewSize
;
1538 menu_item
[i
].callback
= mok_enrollment_prompt_callback
;
1544 menu_item
[i
].text
= StrDuplicate(L
"Change Secure Boot state");
1545 menu_item
[i
].colour
= EFI_WHITE
;
1546 menu_item
[i
].callback
= mok_sb_prompt
;
1547 menu_item
[i
].data
= MokSB
;
1548 menu_item
[i
].data2
= (void *)MokSBSize
;
1553 menu_item
[i
].text
= StrDuplicate(L
"Set MOK password");
1554 menu_item
[i
].colour
= EFI_WHITE
;
1555 menu_item
[i
].callback
= mok_pw_prompt
;
1556 menu_item
[i
].data
= MokPW
;
1557 menu_item
[i
].data2
= (void *)MokPWSize
;
1561 menu_item
[i
].text
= StrDuplicate(L
"Enroll key from disk");
1562 menu_item
[i
].colour
= EFI_WHITE
;
1563 menu_item
[i
].callback
= find_fs
;
1564 menu_item
[i
].data3
= (void *)FALSE
;
1568 menu_item
[i
].text
= StrDuplicate(L
"Enroll hash from disk");
1569 menu_item
[i
].colour
= EFI_WHITE
;
1570 menu_item
[i
].callback
= find_fs
;
1571 menu_item
[i
].data3
= (void *)TRUE
;
1575 run_menu(NULL
, 0, menu_item
, menucount
, 10);
1577 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1582 static EFI_STATUS
check_mok_request(EFI_HANDLE image_handle
)
1584 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1585 UINTN MokNewSize
= 0, MokSBSize
= 0, MokPWSize
= 0;
1586 void *MokNew
= NULL
;
1590 MokNew
= LibGetVariableAndSize(L
"MokNew", &shim_lock_guid
, &MokNewSize
);
1592 MokSB
= LibGetVariableAndSize(L
"MokSB", &shim_lock_guid
, &MokSBSize
);
1594 MokPW
= LibGetVariableAndSize(L
"MokPW", &shim_lock_guid
, &MokPWSize
);
1596 enter_mok_menu(image_handle
, MokNew
, MokNewSize
, MokSB
, MokSBSize
,
1600 if (LibDeleteVariable(L
"MokNew", &shim_lock_guid
) != EFI_SUCCESS
) {
1601 Print(L
"Failed to delete MokNew\n");
1607 if (LibDeleteVariable(L
"MokSB", &shim_lock_guid
) != EFI_SUCCESS
) {
1608 Print(L
"Failed to delete MokSB\n");
1614 if (LibDeleteVariable(L
"MokPW", &shim_lock_guid
) != EFI_SUCCESS
) {
1615 Print(L
"Failed to delete MokPW\n");
1620 LibDeleteVariable(L
"MokAuth", &shim_lock_guid
);
1625 EFI_STATUS
efi_main (EFI_HANDLE image_handle
, EFI_SYSTEM_TABLE
*systab
)
1627 EFI_STATUS efi_status
;
1629 InitializeLib(image_handle
, systab
);
1631 efi_status
= check_mok_request(image_handle
);