4 #include <Library/BaseCryptLib.h>
5 #include <openssl/x509.h>
8 #include "PasswordCrypt.h"
12 #include "variables.h"
13 #include "simple_file.h"
14 #include "efiauthenticated.h"
16 #define PASSWORD_MAX 256
17 #define PASSWORD_MIN 1
18 #define SB_PASSWORD_LEN 16
20 #define NAME_LINE_MAX 70
23 #define SHIM_VENDOR L"Shim"
26 #define EFI_VARIABLE_APPEND_WRITE 0x00000040
28 EFI_GUID SHIM_LOCK_GUID
= { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
30 #define CERT_STRING L"Select an X509 certificate to enroll:\n\n"
31 #define HASH_STRING L"Select a file to trust:\n\n"
35 INTN (* callback
)(void *data
, void *data2
, void *data3
);
46 } __attribute__ ((packed
)) MokListNode
;
51 CHAR16 Password
[SB_PASSWORD_LEN
];
52 } __attribute__ ((packed
)) MokSBvar
;
57 CHAR16 Password
[SB_PASSWORD_LEN
];
58 } __attribute__ ((packed
)) MokDBvar
;
60 static EFI_STATUS
get_sha1sum (void *Data
, int DataSize
, UINT8
*hash
)
66 ctxsize
= Sha1GetContextSize();
67 ctx
= AllocatePool(ctxsize
);
70 console_notify(L
"Unable to allocate memory for hash context");
71 return EFI_OUT_OF_RESOURCES
;
75 console_notify(L
"Unable to initialise hash");
76 status
= EFI_OUT_OF_RESOURCES
;
80 if (!(Sha1Update(ctx
, Data
, DataSize
))) {
81 console_notify(L
"Unable to generate hash");
82 status
= EFI_OUT_OF_RESOURCES
;
86 if (!(Sha1Final(ctx
, hash
))) {
87 console_notify(L
"Unable to finalise hash");
88 status
= EFI_OUT_OF_RESOURCES
;
97 static UINT32
count_keys(void *Data
, UINTN DataSize
)
99 EFI_SIGNATURE_LIST
*CertList
= Data
;
100 EFI_GUID CertType
= X509_GUID
;
101 EFI_GUID HashType
= EFI_CERT_SHA256_GUID
;
102 UINTN dbsize
= DataSize
;
104 void *end
= Data
+ DataSize
;
106 while ((dbsize
> 0) && (dbsize
>= CertList
->SignatureListSize
)) {
108 /* Use ptr arithmetics to ensure bounded access. Do not allow 0
109 * SignatureListSize that will cause endless loop.
111 if ((void *)(CertList
+ 1) > end
|| CertList
->SignatureListSize
== 0) {
112 console_notify(L
"Invalid MOK detected! Ignoring MOK List.");
116 if ((CompareGuid (&CertList
->SignatureType
, &CertType
) != 0) &&
117 (CompareGuid (&CertList
->SignatureType
, &HashType
) != 0)) {
118 console_notify(L
"Doesn't look like a key or hash");
119 dbsize
-= CertList
->SignatureListSize
;
120 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
121 CertList
->SignatureListSize
);
125 if ((CompareGuid (&CertList
->SignatureType
, &CertType
) != 0) &&
126 (CertList
->SignatureSize
!= 48)) {
127 console_notify(L
"Doesn't look like a valid hash");
128 dbsize
-= CertList
->SignatureListSize
;
129 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
130 CertList
->SignatureListSize
);
135 dbsize
-= CertList
->SignatureListSize
;
136 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
137 CertList
->SignatureListSize
);
143 static MokListNode
*build_mok_list(UINT32 num
, void *Data
, UINTN DataSize
) {
145 EFI_SIGNATURE_LIST
*CertList
= Data
;
146 EFI_SIGNATURE_DATA
*Cert
;
147 EFI_GUID CertType
= X509_GUID
;
148 EFI_GUID HashType
= EFI_CERT_SHA256_GUID
;
149 UINTN dbsize
= DataSize
;
151 void *end
= Data
+ DataSize
;
153 list
= AllocatePool(sizeof(MokListNode
) * num
);
156 console_notify(L
"Unable to allocate MOK list");
160 while ((dbsize
> 0) && (dbsize
>= CertList
->SignatureListSize
)) {
161 /* CertList out of bounds? */
162 if ((void *)(CertList
+ 1) > end
|| CertList
->SignatureListSize
== 0) {
166 if ((CompareGuid (&CertList
->SignatureType
, &CertType
) != 0) &&
167 (CompareGuid (&CertList
->SignatureType
, &HashType
) != 0)) {
168 dbsize
-= CertList
->SignatureListSize
;
169 CertList
= (EFI_SIGNATURE_LIST
*)((UINT8
*) CertList
+
170 CertList
->SignatureListSize
);
174 if ((CompareGuid (&CertList
->SignatureType
, &HashType
) == 0) &&
175 (CertList
->SignatureSize
!= 48)) {
176 dbsize
-= CertList
->SignatureListSize
;
177 CertList
= (EFI_SIGNATURE_LIST
*)((UINT8
*) CertList
+
178 CertList
->SignatureListSize
);
182 Cert
= (EFI_SIGNATURE_DATA
*) (((UINT8
*) CertList
) +
183 sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
185 /* Cert out of bounds? */
186 if ((void *)(Cert
+ 1) > end
|| CertList
->SignatureSize
<= sizeof(EFI_GUID
)) {
191 list
[count
].Type
= CertList
->SignatureType
;
192 if (CompareGuid (&CertList
->SignatureType
, &CertType
) == 0) {
193 list
[count
].MokSize
= CertList
->SignatureSize
-
195 list
[count
].Mok
= (void *)Cert
->SignatureData
;
197 list
[count
].MokSize
= CertList
->SignatureListSize
-
198 sizeof(EFI_SIGNATURE_LIST
);
199 list
[count
].Mok
= (void *)Cert
;
202 /* MOK out of bounds? */
203 if (list
[count
].MokSize
> (unsigned long)end
-
204 (unsigned long)list
[count
].Mok
) {
210 dbsize
-= CertList
->SignatureListSize
;
211 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
212 CertList
->SignatureListSize
);
223 static NidName nidname
[] = {
224 {NID_commonName
, L
"CN"},
225 {NID_organizationName
, L
"O"},
226 {NID_countryName
, L
"C"},
227 {NID_stateOrProvinceName
, L
"ST"},
228 {NID_localityName
, L
"L"},
232 static CHAR16
* get_x509_name (X509_NAME
*X509Name
)
234 CHAR16 name
[NAME_LINE_MAX
+1];
235 CHAR16 part
[NAME_LINE_MAX
+1];
236 char str
[NAME_LINE_MAX
];
237 int i
, len
, rest
, first
;
240 rest
= NAME_LINE_MAX
;
242 for (i
= 0; nidname
[i
].name
!= NULL
; i
++) {
244 len
= X509_NAME_get_text_by_NID (X509Name
, nidname
[i
].nid
,
250 add
= len
+ (int)StrLen(nidname
[i
].name
) + 1;
252 add
= len
+ (int)StrLen(nidname
[i
].name
) + 3;
258 SPrint(part
, NAME_LINE_MAX
* sizeof(CHAR16
), L
"%s=%a",
259 nidname
[i
].name
, str
);
261 SPrint(part
, NAME_LINE_MAX
* sizeof(CHAR16
), L
", %s=%a",
262 nidname
[i
].name
, str
);
269 if (rest
>= 0 && rest
< NAME_LINE_MAX
)
270 return PoolPrint(L
"%s", name
);
275 static CHAR16
* get_x509_time (ASN1_TIME
*time
)
277 BIO
*bio
= BIO_new (BIO_s_mem());
281 ASN1_TIME_print (bio
, time
);
282 len
= BIO_read(bio
, str
, 29);
288 return PoolPrint(L
"%a", str
);
291 static void show_x509_info (X509
*X509Cert
, UINT8
*hash
)
293 ASN1_INTEGER
*serial
;
295 unsigned char hexbuf
[30];
298 CHAR16
*issuer
= NULL
;
299 CHAR16
*subject
= NULL
;
301 CHAR16
*until
= NULL
;
302 POOL_PRINT hash_string1
;
303 POOL_PRINT hash_string2
;
304 POOL_PRINT serial_string
;
309 ZeroMem(&hash_string1
, sizeof(hash_string1
));
310 ZeroMem(&hash_string2
, sizeof(hash_string2
));
311 ZeroMem(&serial_string
, sizeof(serial_string
));
313 serial
= X509_get_serialNumber(X509Cert
);
316 bnser
= ASN1_INTEGER_to_BN(serial
, NULL
);
317 n
= BN_bn2bin(bnser
, hexbuf
);
318 for (i
= 0; i
< n
; i
++) {
319 CatPrint(&serial_string
, L
"%02x:", hexbuf
[i
]);
323 if (serial_string
.str
)
326 X509Name
= X509_get_issuer_name(X509Cert
);
328 issuer
= get_x509_name(X509Name
);
333 X509Name
= X509_get_subject_name(X509Cert
);
335 subject
= get_x509_name(X509Name
);
340 time
= X509_get_notBefore(X509Cert
);
342 from
= get_x509_time(time
);
347 time
= X509_get_notAfter(X509Cert
);
349 until
= get_x509_time(time
);
355 CatPrint(&hash_string1
, L
"%02x ", hash
[i
]);
356 for (i
=10; i
<20; i
++)
357 CatPrint(&hash_string2
, L
"%02x ", hash
[i
]);
359 if (hash_string1
.str
)
362 if (hash_string2
.str
)
369 text
= AllocateZeroPool(sizeof(CHAR16
*) * (fields
*3 + 1));
370 if (serial_string
.str
) {
371 text
[i
++] = StrDuplicate(L
"[Serial Number]");
372 text
[i
++] = serial_string
.str
;
373 text
[i
++] = StrDuplicate(L
"");
376 text
[i
++] = StrDuplicate(L
"[Issuer]");
378 text
[i
++] = StrDuplicate(L
"");
381 text
[i
++] = StrDuplicate(L
"[Subject]");
383 text
[i
++] = StrDuplicate(L
"");
386 text
[i
++] = StrDuplicate(L
"[Valid Not Before]");
388 text
[i
++] = StrDuplicate(L
"");
391 text
[i
++] = StrDuplicate(L
"[Valid Not After]");
393 text
[i
++] = StrDuplicate(L
"");
395 if (hash_string1
.str
) {
396 text
[i
++] = StrDuplicate(L
"[Fingerprint]");
397 text
[i
++] = hash_string1
.str
;
399 if (hash_string2
.str
) {
400 text
[i
++] = hash_string2
.str
;
401 text
[i
++] = StrDuplicate(L
"");
405 console_print_box(text
, -1);
407 for (i
=0; text
[i
] != NULL
; i
++)
413 static void show_sha256_digest (UINT8
*hash
)
416 POOL_PRINT hash_string1
;
417 POOL_PRINT hash_string2
;
420 ZeroMem(&hash_string1
, sizeof(hash_string1
));
421 ZeroMem(&hash_string2
, sizeof(hash_string2
));
423 text
[0] = L
"SHA256 hash";
427 CatPrint(&hash_string1
, L
"%02x ", hash
[i
]);
428 for (i
=16; i
<32; i
++)
429 CatPrint(&hash_string2
, L
"%02x ", hash
[i
]);
431 text
[2] = hash_string1
.str
;
432 text
[3] = hash_string2
.str
;
435 console_print_box(text
, -1);
437 if (hash_string1
.str
)
438 FreePool(hash_string1
.str
);
440 if (hash_string2
.str
)
441 FreePool(hash_string2
.str
);
444 static void show_efi_hash (void *Mok
, UINTN MokSize
)
449 CHAR16
**menu_strings
;
453 sig_size
= SHA256_DIGEST_SIZE
+ sizeof(EFI_GUID
);
454 if ((MokSize
% sig_size
) != 0) {
455 console_errorbox(L
"Corrupted Hash List");
458 hash_num
= MokSize
/ sig_size
;
461 hash
= (UINT8
*)Mok
+ sizeof(EFI_GUID
);
462 show_sha256_digest(hash
);
466 menu_strings
= AllocateZeroPool(sizeof(CHAR16
*) * (hash_num
+ 2));
468 console_errorbox(L
"Out of Resources");
471 for (i
=0; i
<hash_num
; i
++) {
472 menu_strings
[i
] = PoolPrint(L
"View hash %d", i
);
474 menu_strings
[i
] = StrDuplicate(L
"Back");
475 menu_strings
[i
+1] = NULL
;
477 while (key_num
< hash_num
) {
478 key_num
= console_select((CHAR16
*[]){ L
"[Hash List]", NULL
},
479 menu_strings
, key_num
);
481 if (key_num
< 0 || key_num
>= hash_num
)
484 hash
= (UINT8
*)Mok
+ sig_size
*key_num
+ sizeof(EFI_GUID
);
485 show_sha256_digest(hash
);
488 for (i
=0; menu_strings
[i
] != NULL
; i
++)
489 FreePool(menu_strings
[i
]);
491 FreePool(menu_strings
);
494 static void show_mok_info (EFI_GUID Type
, void *Mok
, UINTN MokSize
)
496 EFI_STATUS efi_status
;
497 UINT8 hash
[SHA1_DIGEST_SIZE
];
499 EFI_GUID CertType
= X509_GUID
;
500 EFI_GUID HashType
= EFI_CERT_SHA256_GUID
;
502 if (!Mok
|| MokSize
== 0)
505 if (CompareGuid (&Type
, &CertType
) == 0) {
506 efi_status
= get_sha1sum(Mok
, MokSize
, hash
);
508 if (efi_status
!= EFI_SUCCESS
) {
509 console_notify(L
"Failed to compute MOK fingerprint");
513 if (X509ConstructCertificate(Mok
, MokSize
,
514 (UINT8
**) &X509Cert
) && X509Cert
!= NULL
) {
515 show_x509_info(X509Cert
, hash
);
518 console_notify(L
"Not a valid X509 certificate");
521 } else if (CompareGuid (&Type
, &HashType
) == 0) {
522 show_efi_hash(Mok
, MokSize
);
526 static EFI_STATUS
list_keys (void *KeyList
, UINTN KeyListSize
, CHAR16
*title
)
529 MokListNode
*keys
= NULL
;
531 CHAR16
**menu_strings
;
534 if (KeyListSize
< (sizeof(EFI_SIGNATURE_LIST
) +
535 sizeof(EFI_SIGNATURE_DATA
))) {
536 console_notify(L
"No MOK keys found");
540 MokNum
= count_keys(KeyList
, KeyListSize
);
543 keys
= build_mok_list(MokNum
, KeyList
, KeyListSize
);
546 console_notify(L
"Failed to construct key list");
550 menu_strings
= AllocateZeroPool(sizeof(CHAR16
*) * (MokNum
+ 2));
553 return EFI_OUT_OF_RESOURCES
;
555 for (i
=0; i
<MokNum
; i
++) {
556 menu_strings
[i
] = PoolPrint(L
"View key %d", i
);
558 menu_strings
[i
] = StrDuplicate(L
"Continue");
560 menu_strings
[i
+1] = NULL
;
562 while (key_num
< MokNum
) {
563 key_num
= console_select((CHAR16
*[]){ title
, NULL
},
564 menu_strings
, key_num
);
566 if (key_num
< 0 || key_num
>= MokNum
)
569 show_mok_info(keys
[key_num
].Type
, keys
[key_num
].Mok
,
570 keys
[key_num
].MokSize
);
573 for (i
=0; menu_strings
[i
] != NULL
; i
++)
574 FreePool(menu_strings
[i
]);
576 FreePool(menu_strings
);
583 static EFI_STATUS
get_line (UINT32
*length
, CHAR16
*line
, UINT32 line_max
, UINT8 show
)
587 unsigned int count
= 0;
590 status
= console_get_keystroke(&key
);
591 if (EFI_ERROR (status
)) {
592 console_error(L
"Failed to read the keystroke", status
);
597 if ((count
>= line_max
&&
598 key
.UnicodeChar
!= CHAR_BACKSPACE
) ||
599 key
.UnicodeChar
== CHAR_NULL
||
600 key
.UnicodeChar
== CHAR_TAB
||
601 key
.UnicodeChar
== CHAR_LINEFEED
||
602 key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
606 if (count
== 0 && key
.UnicodeChar
== CHAR_BACKSPACE
) {
608 } else if (key
.UnicodeChar
== CHAR_BACKSPACE
) {
612 line
[--count
] = '\0';
617 Print(L
"%c", key
.UnicodeChar
);
620 line
[count
++] = key
.UnicodeChar
;
621 } while (key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
629 static EFI_STATUS
compute_pw_hash (void *Data
, UINTN DataSize
, UINT8
*password
,
630 UINT32 pw_length
, UINT8
*hash
)
633 unsigned int ctxsize
;
636 ctxsize
= Sha256GetContextSize();
637 ctx
= AllocatePool(ctxsize
);
640 console_notify(L
"Unable to allocate memory for hash context");
641 return EFI_OUT_OF_RESOURCES
;
644 if (!Sha256Init(ctx
)) {
645 console_notify(L
"Unable to initialise hash");
646 status
= EFI_OUT_OF_RESOURCES
;
650 if (Data
&& DataSize
) {
651 if (!(Sha256Update(ctx
, Data
, DataSize
))) {
652 console_notify(L
"Unable to generate hash");
653 status
= EFI_OUT_OF_RESOURCES
;
658 if (!(Sha256Update(ctx
, password
, pw_length
))) {
659 console_notify(L
"Unable to generate hash");
660 status
= EFI_OUT_OF_RESOURCES
;
664 if (!(Sha256Final(ctx
, hash
))) {
665 console_notify(L
"Unable to finalise hash");
666 status
= EFI_OUT_OF_RESOURCES
;
670 status
= EFI_SUCCESS
;
675 static void console_save_and_set_mode (SIMPLE_TEXT_OUTPUT_MODE
*SavedMode
)
678 Print(L
"Invalid parameter: SavedMode\n");
682 CopyMem(SavedMode
, ST
->ConOut
->Mode
, sizeof(SIMPLE_TEXT_OUTPUT_MODE
));
683 uefi_call_wrapper(ST
->ConOut
->EnableCursor
, 2, ST
->ConOut
, FALSE
);
684 uefi_call_wrapper(ST
->ConOut
->SetAttribute
, 2, ST
->ConOut
,
685 EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
);
688 static void console_restore_mode (SIMPLE_TEXT_OUTPUT_MODE
*SavedMode
)
690 uefi_call_wrapper(ST
->ConOut
->EnableCursor
, 2, ST
->ConOut
,
691 SavedMode
->CursorVisible
);
692 uefi_call_wrapper(ST
->ConOut
->SetCursorPosition
, 3, ST
->ConOut
,
693 SavedMode
->CursorColumn
, SavedMode
->CursorRow
);
694 uefi_call_wrapper(ST
->ConOut
->SetAttribute
, 2, ST
->ConOut
,
695 SavedMode
->Attribute
);
698 static UINT32
get_password (CHAR16
*prompt
, CHAR16
*password
, UINT32 max
)
700 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
707 prompt
= L
"Password:";
709 console_save_and_set_mode(&SavedMode
);
711 str
= PoolPrint(L
"%s ", prompt
);
713 console_errorbox(L
"Failed to allocate prompt");
719 length
= StrLen(message
[0]);
720 console_print_box_at(message
, -1, -length
-4, -5, length
+4, 3, 0, 1);
721 get_line(&pw_length
, password
, max
, 0);
723 console_restore_mode(&SavedMode
);
730 static EFI_STATUS
match_password (PASSWORD_CRYPT
*pw_crypt
,
731 void *Data
, UINTN DataSize
,
732 UINT8
*auth
, CHAR16
*prompt
)
738 CHAR16 password
[PASSWORD_MAX
];
740 UINT8 fail_count
= 0;
744 auth_hash
= pw_crypt
->hash
;
745 auth_size
= get_hash_size (pw_crypt
->method
);
747 return EFI_INVALID_PARAMETER
;
750 auth_size
= SHA256_DIGEST_SIZE
;
752 return EFI_INVALID_PARAMETER
;
755 while (fail_count
< 3) {
756 pw_length
= get_password(prompt
, password
, PASSWORD_MAX
);
758 if (pw_length
< PASSWORD_MIN
|| pw_length
> PASSWORD_MAX
) {
759 console_errorbox(L
"Invalid password length");
765 * Compute password hash
768 char pw_ascii
[PASSWORD_MAX
+ 1];
769 for (i
= 0; i
< pw_length
; i
++)
770 pw_ascii
[i
] = (char)password
[i
];
771 pw_ascii
[pw_length
] = '\0';
773 status
= password_crypt(pw_ascii
, pw_length
, pw_crypt
, hash
);
776 * For backward compatibility
778 status
= compute_pw_hash(Data
, DataSize
, (UINT8
*)password
,
779 pw_length
* sizeof(CHAR16
), hash
);
781 if (status
!= EFI_SUCCESS
) {
782 console_errorbox(L
"Unable to generate password hash");
787 if (CompareMem(auth_hash
, hash
, auth_size
) != 0) {
788 console_errorbox(L
"Password doesn't match");
797 return EFI_ACCESS_DENIED
;
802 static EFI_STATUS
store_keys (void *MokNew
, UINTN MokNewSize
, int authenticate
,
805 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
806 EFI_STATUS efi_status
;
809 UINT8 auth
[PASSWORD_CRYPT_SIZE
];
810 UINTN auth_size
= PASSWORD_CRYPT_SIZE
;
814 db_name
= L
"MokListX";
815 auth_name
= L
"MokXAuth";
817 db_name
= L
"MokList";
818 auth_name
= L
"MokAuth";
822 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, auth_name
,
824 &attributes
, &auth_size
, auth
);
826 if (efi_status
!= EFI_SUCCESS
||
827 (auth_size
!= SHA256_DIGEST_SIZE
&&
828 auth_size
!= PASSWORD_CRYPT_SIZE
)) {
830 console_error(L
"Failed to get MokXAuth", efi_status
);
832 console_error(L
"Failed to get MokAuth", efi_status
);
836 if (auth_size
== PASSWORD_CRYPT_SIZE
) {
837 efi_status
= match_password((PASSWORD_CRYPT
*)auth
,
838 NULL
, 0, NULL
, NULL
);
840 efi_status
= match_password(NULL
, MokNew
, MokNewSize
,
843 if (efi_status
!= EFI_SUCCESS
)
844 return EFI_ACCESS_DENIED
;
849 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, db_name
,
851 EFI_VARIABLE_NON_VOLATILE
852 | EFI_VARIABLE_BOOTSERVICE_ACCESS
,
856 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, db_name
,
858 EFI_VARIABLE_NON_VOLATILE
859 | EFI_VARIABLE_BOOTSERVICE_ACCESS
860 | EFI_VARIABLE_APPEND_WRITE
,
864 if (efi_status
!= EFI_SUCCESS
) {
865 console_error(L
"Failed to set variable", efi_status
);
872 static UINTN
mok_enrollment_prompt (void *MokNew
, UINTN MokNewSize
, int auth
,
875 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
876 EFI_STATUS efi_status
;
880 title
= L
"[Enroll MOKX]";
882 title
= L
"[Enroll MOK]";
884 if (list_keys(MokNew
, MokNewSize
, title
) != EFI_SUCCESS
)
887 if (console_yes_no((CHAR16
*[]){L
"Enroll the key(s)?", NULL
}) == 0)
890 efi_status
= store_keys(MokNew
, MokNewSize
, auth
, MokX
);
892 if (efi_status
!= EFI_SUCCESS
) {
893 console_notify(L
"Failed to enroll keys\n");
899 LibDeleteVariable(L
"MokXNew", &shim_lock_guid
);
900 LibDeleteVariable(L
"MokXAuth", &shim_lock_guid
);
902 LibDeleteVariable(L
"MokNew", &shim_lock_guid
);
903 LibDeleteVariable(L
"MokAuth", &shim_lock_guid
);
906 console_notify(L
"The system must now be rebooted");
907 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
908 EFI_SUCCESS
, 0, NULL
);
909 console_notify(L
"Failed to reboot");
916 static INTN
mok_reset_prompt (BOOLEAN MokX
)
918 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
919 EFI_STATUS efi_status
;
922 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
925 prompt
= L
"Erase all stored keys in MokListX?";
927 prompt
= L
"Erase all stored keys in MokList?";
928 if (console_yes_no((CHAR16
*[]){prompt
, NULL
}) == 0)
931 efi_status
= store_keys(NULL
, 0, TRUE
, MokX
);
933 if (efi_status
!= EFI_SUCCESS
) {
934 console_notify(L
"Failed to erase keys\n");
939 LibDeleteVariable(L
"MokXNew", &shim_lock_guid
);
940 LibDeleteVariable(L
"MokXAuth", &shim_lock_guid
);
942 LibDeleteVariable(L
"MokNew", &shim_lock_guid
);
943 LibDeleteVariable(L
"MokAuth", &shim_lock_guid
);
946 console_notify(L
"The system must now be rebooted");
947 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
948 EFI_SUCCESS
, 0, NULL
);
949 console_notify(L
"Failed to reboot\n");
953 static EFI_STATUS
write_back_mok_list (MokListNode
*list
, INTN key_num
,
956 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
957 EFI_GUID CertType
= X509_GUID
;
958 EFI_STATUS efi_status
;
959 EFI_SIGNATURE_LIST
*CertList
;
960 EFI_SIGNATURE_DATA
*CertData
;
961 void *Data
= NULL
, *ptr
;
967 db_name
= L
"MokListX";
969 db_name
= L
"MokList";
971 for (i
= 0; i
< key_num
; i
++) {
972 if (list
[i
].Mok
== NULL
)
975 DataSize
+= sizeof(EFI_SIGNATURE_LIST
);
976 if (CompareGuid(&(list
[i
].Type
), &CertType
) == 0)
977 DataSize
+= sizeof(EFI_GUID
);
978 DataSize
+= list
[i
].MokSize
;
981 Data
= AllocatePool(DataSize
);
982 if (Data
== NULL
&& DataSize
!= 0)
983 return EFI_OUT_OF_RESOURCES
;
987 for (i
= 0; i
< key_num
; i
++) {
988 if (list
[i
].Mok
== NULL
)
991 CertList
= (EFI_SIGNATURE_LIST
*)ptr
;
992 CertData
= (EFI_SIGNATURE_DATA
*)(((uint8_t *)ptr
) +
993 sizeof(EFI_SIGNATURE_LIST
));
995 CertList
->SignatureType
= list
[i
].Type
;
996 CertList
->SignatureHeaderSize
= 0;
998 if (CompareGuid(&(list
[i
].Type
), &CertType
) == 0) {
999 CertList
->SignatureListSize
= list
[i
].MokSize
+
1000 sizeof(EFI_SIGNATURE_LIST
) +
1002 CertList
->SignatureSize
= list
[i
].MokSize
+ sizeof(EFI_GUID
);
1004 CertData
->SignatureOwner
= shim_lock_guid
;
1005 CopyMem(CertData
->SignatureData
, list
[i
].Mok
, list
[i
].MokSize
);
1007 CertList
->SignatureListSize
= list
[i
].MokSize
+
1008 sizeof(EFI_SIGNATURE_LIST
);
1009 CertList
->SignatureSize
= SHA256_DIGEST_SIZE
+ sizeof(EFI_GUID
);
1011 CopyMem(CertData
, list
[i
].Mok
, list
[i
].MokSize
);
1013 ptr
= (uint8_t *)ptr
+ CertList
->SignatureListSize
;
1016 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, db_name
,
1018 EFI_VARIABLE_NON_VOLATILE
1019 | EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1024 if (efi_status
!= EFI_SUCCESS
) {
1025 console_error(L
"Failed to set variable", efi_status
);
1032 static void delete_cert (void *key
, UINT32 key_size
,
1033 MokListNode
*mok
, INTN mok_num
)
1035 EFI_GUID CertType
= X509_GUID
;
1038 for (i
= 0; i
< mok_num
; i
++) {
1039 if (CompareGuid(&(mok
[i
].Type
), &CertType
) != 0)
1042 if (mok
[i
].MokSize
== key_size
&&
1043 CompareMem(key
, mok
[i
].Mok
, key_size
) == 0) {
1044 /* Remove the key */
1051 static int match_hash (UINT8
*hash
, UINT32 hash_size
, int start
,
1052 void *hash_list
, UINT32 list_num
)
1057 ptr
= hash_list
+ sizeof(EFI_GUID
);
1058 for (i
= start
; i
< list_num
; i
++) {
1059 if (CompareMem(hash
, ptr
, hash_size
) == 0)
1061 ptr
+= hash_size
+ sizeof(EFI_GUID
);
1067 static void mem_move (void *dest
, void *src
, UINTN size
)
1074 for (i
= 0; i
< size
; i
++)
1078 static void delete_hash_in_list (UINT8
*hash
, UINT32 hash_size
,
1079 MokListNode
*mok
, INTN mok_num
)
1081 EFI_GUID HashType
= EFI_CERT_SHA256_GUID
;
1088 sig_size
= hash_size
+ sizeof(EFI_GUID
);
1090 for (i
= 0; i
< mok_num
; i
++) {
1091 if ((CompareGuid(&(mok
[i
].Type
), &HashType
) != 0) ||
1092 (mok
[i
].MokSize
< sig_size
))
1095 list_num
= mok
[i
].MokSize
/ sig_size
;
1097 del_ind
= match_hash(hash
, hash_size
, 0, mok
[i
].Mok
,
1099 while (del_ind
>= 0) {
1100 /* Remove the hash */
1101 if (sig_size
== mok
[i
].MokSize
) {
1107 start
= mok
[i
].Mok
+ del_ind
* sig_size
;
1108 end
= start
+ sig_size
;
1109 remain
= mok
[i
].MokSize
- (del_ind
+ 1)*sig_size
;
1111 mem_move(start
, end
, remain
);
1112 mok
[i
].MokSize
-= sig_size
;
1115 del_ind
= match_hash(hash
, hash_size
, del_ind
,
1116 mok
[i
].Mok
, list_num
);
1121 static void delete_hash_list (void *hash_list
, UINT32 list_size
,
1122 MokListNode
*mok
, INTN mok_num
)
1130 hash_size
= SHA256_DIGEST_SIZE
;
1131 sig_size
= hash_size
+ sizeof(EFI_GUID
);
1132 if (list_size
< sig_size
)
1135 hash_num
= list_size
/ sig_size
;
1137 hash
= hash_list
+ sizeof(EFI_GUID
);
1139 for (i
= 0; i
< hash_num
; i
++) {
1140 delete_hash_in_list (hash
, hash_size
, mok
, mok_num
);
1145 static EFI_STATUS
delete_keys (void *MokDel
, UINTN MokDelSize
, BOOLEAN MokX
)
1147 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1148 EFI_GUID CertType
= X509_GUID
;
1149 EFI_GUID HashType
= EFI_CERT_SHA256_GUID
;
1150 EFI_STATUS efi_status
;
1155 UINT8 auth
[PASSWORD_CRYPT_SIZE
];
1156 UINTN auth_size
= PASSWORD_CRYPT_SIZE
;
1158 UINT8
*MokListData
= NULL
;
1159 UINTN MokListDataSize
= 0;
1160 MokListNode
*mok
, *del_key
;
1161 INTN mok_num
, del_num
;
1165 db_name
= L
"MokListX";
1166 auth_name
= L
"MokXDelAuth";
1168 db_name
= L
"MokList";
1169 auth_name
= L
"MokDelAuth";
1172 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, auth_name
,
1174 &attributes
, &auth_size
, auth
);
1176 if (efi_status
!= EFI_SUCCESS
||
1177 (auth_size
!= SHA256_DIGEST_SIZE
&& auth_size
!= PASSWORD_CRYPT_SIZE
)) {
1179 console_error(L
"Failed to get MokXDelAuth", efi_status
);
1181 console_error(L
"Failed to get MokDelAuth", efi_status
);
1185 if (auth_size
== PASSWORD_CRYPT_SIZE
) {
1186 efi_status
= match_password((PASSWORD_CRYPT
*)auth
, NULL
, 0,
1189 efi_status
= match_password(NULL
, MokDel
, MokDelSize
, auth
, NULL
);
1191 if (efi_status
!= EFI_SUCCESS
)
1192 return EFI_ACCESS_DENIED
;
1194 efi_status
= get_variable_attr (db_name
, &MokListData
, &MokListDataSize
,
1195 shim_lock_guid
, &attributes
);
1196 if (attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) {
1198 err_str1
= L
"MokListX is compromised!";
1199 err_str2
= L
"Erase all keys in MokListX!";
1201 err_str1
= L
"MokList is compromised!";
1202 err_str2
= L
"Erase all keys in MokList!";
1204 console_alertbox((CHAR16
*[]){err_str1
, err_str2
, NULL
});
1205 LibDeleteVariable(db_name
, &shim_lock_guid
);
1206 return EFI_ACCESS_DENIED
;
1210 if (!MokListData
|| MokListDataSize
== 0)
1213 /* Construct lists */
1214 mok_num
= count_keys(MokListData
, MokListDataSize
);
1215 mok
= build_mok_list(mok_num
, MokListData
, MokListDataSize
);
1216 del_num
= count_keys(MokDel
, MokDelSize
);
1217 del_key
= build_mok_list(del_num
, MokDel
, MokDelSize
);
1219 /* Search and destroy */
1220 for (i
= 0; i
< del_num
; i
++) {
1221 if (CompareGuid(&(del_key
[i
].Type
), &CertType
) == 0) {
1222 delete_cert(del_key
[i
].Mok
, del_key
[i
].MokSize
,
1224 } else if (CompareGuid(&(del_key
[i
].Type
), &HashType
) == 0) {
1225 delete_hash_list(del_key
[i
].Mok
, del_key
[i
].MokSize
,
1230 efi_status
= write_back_mok_list(mok
, mok_num
, MokX
);
1233 FreePool(MokListData
);
1242 static INTN
mok_deletion_prompt (void *MokDel
, UINTN MokDelSize
, BOOLEAN MokX
)
1244 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1245 EFI_STATUS efi_status
;
1249 title
= L
"[Delete MOKX]";
1251 title
= L
"[Delete MOK]";
1253 if (list_keys(MokDel
, MokDelSize
, title
) != EFI_SUCCESS
) {
1257 if (console_yes_no((CHAR16
*[]){L
"Delete the key(s)?", NULL
}) == 0)
1260 efi_status
= delete_keys(MokDel
, MokDelSize
, MokX
);
1262 if (efi_status
!= EFI_SUCCESS
) {
1263 console_notify(L
"Failed to delete keys");
1268 LibDeleteVariable(L
"MokXDel", &shim_lock_guid
);
1269 LibDeleteVariable(L
"MokXDelAuth", &shim_lock_guid
);
1271 LibDeleteVariable(L
"MokDel", &shim_lock_guid
);
1272 LibDeleteVariable(L
"MokDelAuth", &shim_lock_guid
);
1275 console_notify(L
"The system must now be rebooted");
1276 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
1277 EFI_SUCCESS
, 0, NULL
);
1278 console_notify(L
"Failed to reboot");
1282 static CHAR16
get_password_charater (CHAR16
*prompt
)
1284 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1292 prompt
= L
"Password charater: ";
1294 console_save_and_set_mode(&SavedMode
);
1296 message
[0] = prompt
;
1298 length
= StrLen(message
[0]);
1299 console_print_box_at(message
, -1, -length
-4, -5, length
+4, 3, 0, 1);
1300 status
= get_line(&pw_length
, &character
, 1, 0);
1301 if (EFI_ERROR(status
))
1304 console_restore_mode(&SavedMode
);
1309 static INTN
mok_sb_prompt (void *MokSB
, UINTN MokSBSize
) {
1310 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1311 EFI_STATUS efi_status
;
1312 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1313 MokSBvar
*var
= MokSB
;
1315 CHAR16 pass1
, pass2
, pass3
;
1317 UINT8 fail_count
= 0;
1319 UINT8 pos1
, pos2
, pos3
;
1322 if (MokSBSize
!= sizeof(MokSBvar
)) {
1323 console_notify(L
"Invalid MokSB variable contents");
1327 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1329 message
[0] = L
"Change Secure Boot state";
1332 console_save_and_set_mode(&SavedMode
);
1333 console_print_box_at(message
, -1, 0, 0, -1, -1, 1, 1);
1334 console_restore_mode(&SavedMode
);
1336 while (fail_count
< 3) {
1337 RandomBytes (&pos1
, sizeof(pos1
));
1338 pos1
= (pos1
% var
->PWLen
);
1341 RandomBytes (&pos2
, sizeof(pos2
));
1342 pos2
= (pos2
% var
->PWLen
);
1343 } while (pos2
== pos1
);
1346 RandomBytes (&pos3
, sizeof(pos3
));
1347 pos3
= (pos3
% var
->PWLen
) ;
1348 } while (pos3
== pos2
|| pos3
== pos1
);
1350 str
= PoolPrint(L
"Enter password character %d: ", pos1
+ 1);
1352 console_errorbox(L
"Failed to allocate buffer");
1355 pass1
= get_password_charater(str
);
1358 str
= PoolPrint(L
"Enter password character %d: ", pos2
+ 1);
1360 console_errorbox(L
"Failed to allocate buffer");
1363 pass2
= get_password_charater(str
);
1366 str
= PoolPrint(L
"Enter password character %d: ", pos3
+ 1);
1368 console_errorbox(L
"Failed to allocate buffer");
1371 pass3
= get_password_charater(str
);
1374 if (pass1
!= var
->Password
[pos1
] ||
1375 pass2
!= var
->Password
[pos2
] ||
1376 pass3
!= var
->Password
[pos3
]) {
1377 Print(L
"Invalid character\n");
1384 if (fail_count
>= 3) {
1385 console_notify(L
"Password limit reached");
1389 if (var
->MokSBState
== 0)
1390 ret
= console_yes_no((CHAR16
*[]){L
"Disable Secure Boot", NULL
});
1392 ret
= console_yes_no((CHAR16
*[]){L
"Enable Secure Boot", NULL
});
1395 LibDeleteVariable(L
"MokSB", &shim_lock_guid
);
1399 if (var
->MokSBState
== 0) {
1400 efi_status
= uefi_call_wrapper(RT
->SetVariable
,
1403 EFI_VARIABLE_NON_VOLATILE
|
1404 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1406 if (efi_status
!= EFI_SUCCESS
) {
1407 console_notify(L
"Failed to set Secure Boot state");
1411 efi_status
= uefi_call_wrapper(RT
->SetVariable
,
1414 EFI_VARIABLE_NON_VOLATILE
|
1415 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1417 if (efi_status
!= EFI_SUCCESS
) {
1418 console_notify(L
"Failed to delete Secure Boot state");
1423 console_notify(L
"The system must now be rebooted");
1424 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
1425 EFI_SUCCESS
, 0, NULL
);
1426 console_notify(L
"Failed to reboot");
1430 static INTN
mok_db_prompt (void *MokDB
, UINTN MokDBSize
) {
1431 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1432 EFI_STATUS efi_status
;
1433 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1434 MokDBvar
*var
= MokDB
;
1436 CHAR16 pass1
, pass2
, pass3
;
1438 UINT8 fail_count
= 0;
1440 UINT8 pos1
, pos2
, pos3
;
1443 if (MokDBSize
!= sizeof(MokDBvar
)) {
1444 console_notify(L
"Invalid MokDB variable contents");
1448 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1450 message
[0] = L
"Change DB state";
1453 console_save_and_set_mode(&SavedMode
);
1454 console_print_box_at(message
, -1, 0, 0, -1, -1, 1, 1);
1455 console_restore_mode(&SavedMode
);
1457 while (fail_count
< 3) {
1458 RandomBytes (&pos1
, sizeof(pos1
));
1459 pos1
= (pos1
% var
->PWLen
);
1462 RandomBytes (&pos2
, sizeof(pos2
));
1463 pos2
= (pos2
% var
->PWLen
);
1464 } while (pos2
== pos1
);
1467 RandomBytes (&pos3
, sizeof(pos3
));
1468 pos3
= (pos3
% var
->PWLen
) ;
1469 } while (pos3
== pos2
|| pos3
== pos1
);
1471 str
= PoolPrint(L
"Enter password character %d: ", pos1
+ 1);
1473 console_errorbox(L
"Failed to allocate buffer");
1476 pass1
= get_password_charater(str
);
1479 str
= PoolPrint(L
"Enter password character %d: ", pos2
+ 1);
1481 console_errorbox(L
"Failed to allocate buffer");
1484 pass2
= get_password_charater(str
);
1487 str
= PoolPrint(L
"Enter password character %d: ", pos3
+ 1);
1489 console_errorbox(L
"Failed to allocate buffer");
1492 pass3
= get_password_charater(str
);
1495 if (pass1
!= var
->Password
[pos1
] ||
1496 pass2
!= var
->Password
[pos2
] ||
1497 pass3
!= var
->Password
[pos3
]) {
1498 Print(L
"Invalid character\n");
1505 if (fail_count
>= 3) {
1506 console_notify(L
"Password limit reached");
1510 if (var
->MokDBState
== 0)
1511 ret
= console_yes_no((CHAR16
*[]){L
"Ignore DB certs/hashes", NULL
});
1513 ret
= console_yes_no((CHAR16
*[]){L
"Use DB certs/hashes", NULL
});
1516 LibDeleteVariable(L
"MokDB", &shim_lock_guid
);
1520 if (var
->MokDBState
== 0) {
1521 efi_status
= uefi_call_wrapper(RT
->SetVariable
,
1524 EFI_VARIABLE_NON_VOLATILE
|
1525 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1527 if (efi_status
!= EFI_SUCCESS
) {
1528 console_notify(L
"Failed to set DB state");
1532 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5,
1535 EFI_VARIABLE_NON_VOLATILE
|
1536 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1538 if (efi_status
!= EFI_SUCCESS
) {
1539 console_notify(L
"Failed to delete DB state");
1544 console_notify(L
"The system must now be rebooted");
1545 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
1546 EFI_SUCCESS
, 0, NULL
);
1547 console_notify(L
"Failed to reboot");
1551 static INTN
mok_pw_prompt (void *MokPW
, UINTN MokPWSize
) {
1552 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1553 EFI_STATUS efi_status
;
1554 UINT8 hash
[PASSWORD_CRYPT_SIZE
];
1557 if (MokPWSize
!= SHA256_DIGEST_SIZE
&& MokPWSize
!= PASSWORD_CRYPT_SIZE
) {
1558 console_notify(L
"Invalid MokPW variable contents");
1562 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1564 SetMem(hash
, PASSWORD_CRYPT_SIZE
, 0);
1566 if (MokPWSize
== PASSWORD_CRYPT_SIZE
) {
1567 if (CompareMem(MokPW
, hash
, PASSWORD_CRYPT_SIZE
) == 0)
1570 if (CompareMem(MokPW
, hash
, SHA256_DIGEST_SIZE
) == 0)
1575 if (console_yes_no((CHAR16
*[]){L
"Clear MOK password?", NULL
}) == 0)
1578 uefi_call_wrapper(RT
->SetVariable
, 5, L
"MokPWStore",
1580 EFI_VARIABLE_NON_VOLATILE
1581 | EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1583 LibDeleteVariable(L
"MokPW", &shim_lock_guid
);
1584 console_notify(L
"The system must now be rebooted");
1585 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
, EFI_SUCCESS
, 0,
1587 console_notify(L
"Failed to reboot");
1591 if (MokPWSize
== PASSWORD_CRYPT_SIZE
) {
1592 efi_status
= match_password((PASSWORD_CRYPT
*)MokPW
, NULL
, 0,
1593 NULL
, L
"Confirm MOK passphrase: ");
1595 efi_status
= match_password(NULL
, NULL
, 0, MokPW
,
1596 L
"Confirm MOK passphrase: ");
1599 if (efi_status
!= EFI_SUCCESS
) {
1600 console_notify(L
"Password limit reached");
1604 if (console_yes_no((CHAR16
*[]){L
"Set MOK password?", NULL
}) == 0)
1607 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5,
1610 EFI_VARIABLE_NON_VOLATILE
|
1611 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1613 if (efi_status
!= EFI_SUCCESS
) {
1614 console_notify(L
"Failed to set MOK password");
1618 LibDeleteVariable(L
"MokPW", &shim_lock_guid
);
1620 console_notify(L
"The system must now be rebooted");
1621 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
, EFI_SUCCESS
, 0,
1623 console_notify(L
"Failed to reboot");
1627 static BOOLEAN
verify_certificate(UINT8
*cert
, UINTN size
)
1631 if (!cert
|| size
< 0)
1635 * A DER encoding x509 certificate starts with SEQUENCE(0x30),
1636 * the number of length bytes, and the number of value bytes.
1637 * The size of a x509 certificate is usually between 127 bytes
1638 * and 64KB. For convenience, assume the number of value bytes
1639 * is 2, i.e. the second byte is 0x82.
1641 if (cert
[0] != 0x30 || cert
[1] != 0x82) {
1642 console_notify(L
"Not a DER encoding X509 certificate");
1646 length
= (cert
[2]<<8 | cert
[3]);
1647 if (length
!= (size
- 4)) {
1648 console_notify(L
"Invalid X509 certificate: Inconsistent size");
1652 if (!(X509ConstructCertificate(cert
, size
, (UINT8
**) &X509Cert
)) ||
1654 console_notify(L
"Invalid X509 certificate");
1658 X509_free(X509Cert
);
1662 static EFI_STATUS
enroll_file (void *data
, UINTN datasize
, BOOLEAN hash
)
1664 EFI_STATUS status
= EFI_SUCCESS
;
1665 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1666 EFI_SIGNATURE_LIST
*CertList
;
1667 EFI_SIGNATURE_DATA
*CertData
;
1668 UINTN mokbuffersize
;
1669 void *mokbuffer
= NULL
;
1672 UINT8 sha256
[SHA256_DIGEST_SIZE
];
1673 UINT8 sha1
[SHA1_DIGEST_SIZE
];
1674 SHIM_LOCK
*shim_lock
;
1675 EFI_GUID shim_guid
= SHIM_LOCK_GUID
;
1676 PE_COFF_LOADER_IMAGE_CONTEXT context
;
1678 status
= LibLocateProtocol(&shim_guid
, (VOID
**)&shim_lock
);
1680 if (status
!= EFI_SUCCESS
)
1683 mokbuffersize
= sizeof(EFI_SIGNATURE_LIST
) + sizeof(EFI_GUID
) +
1686 mokbuffer
= AllocatePool(mokbuffersize
);
1691 status
= shim_lock
->Context(data
, datasize
, &context
);
1693 if (status
!= EFI_SUCCESS
)
1696 status
= shim_lock
->Hash(data
, datasize
, &context
, sha256
,
1699 if (status
!= EFI_SUCCESS
)
1702 CertList
= mokbuffer
;
1703 CertList
->SignatureType
= EFI_CERT_SHA256_GUID
;
1704 CertList
->SignatureSize
= 16 + SHA256_DIGEST_SIZE
;
1705 CertData
= (EFI_SIGNATURE_DATA
*)(((UINT8
*)mokbuffer
) +
1706 sizeof(EFI_SIGNATURE_LIST
));
1707 CopyMem(CertData
->SignatureData
, sha256
, SHA256_DIGEST_SIZE
);
1709 mokbuffersize
= datasize
+ sizeof(EFI_SIGNATURE_LIST
) +
1711 mokbuffer
= AllocatePool(mokbuffersize
);
1716 CertList
= mokbuffer
;
1717 CertList
->SignatureType
= X509_GUID
;
1718 CertList
->SignatureSize
= 16 + datasize
;
1720 memcpy(mokbuffer
+ sizeof(EFI_SIGNATURE_LIST
) + 16, data
,
1723 CertData
= (EFI_SIGNATURE_DATA
*)(((UINT8
*)mokbuffer
) +
1724 sizeof(EFI_SIGNATURE_LIST
));
1727 CertList
->SignatureListSize
= mokbuffersize
;
1728 CertList
->SignatureHeaderSize
= 0;
1729 CertData
->SignatureOwner
= shim_lock_guid
;
1732 if (!verify_certificate(CertData
->SignatureData
, datasize
))
1736 mok_enrollment_prompt(mokbuffer
, mokbuffersize
, FALSE
, FALSE
);
1739 FreePool(mokbuffer
);
1744 static void mok_hash_enroll(void)
1746 EFI_STATUS efi_status
;
1747 CHAR16
*file_name
= NULL
;
1748 EFI_HANDLE im
= NULL
;
1749 EFI_FILE
*file
= NULL
;
1753 simple_file_selector(&im
, (CHAR16
*[]){
1756 L
"The Selected Binary will have its hash Enrolled",
1757 L
"This means it will Subsequently Boot with no prompting",
1758 L
"Remember to make sure it is a genuine binary before Enroling its hash",
1760 }, L
"\\", L
"", &file_name
);
1765 efi_status
= simple_file_open(im
, file_name
, &file
, EFI_FILE_MODE_READ
);
1767 if (efi_status
!= EFI_SUCCESS
) {
1768 console_error(L
"Unable to open file", efi_status
);
1772 simple_file_read_all(file
, &filesize
, &data
);
1773 simple_file_close(file
);
1776 console_error(L
"Unable to read file", efi_status
);
1780 efi_status
= enroll_file(data
, filesize
, TRUE
);
1782 if (efi_status
!= EFI_SUCCESS
)
1783 console_error(L
"Hash failed (did you select a valid EFI binary?)", efi_status
);
1788 static CHAR16
*der_suffix
[] = {
1795 static BOOLEAN
check_der_suffix (CHAR16
*file_name
)
1800 if (!file_name
|| StrLen(file_name
) <= 4)
1804 StrCat(suffix
, file_name
+ StrLen(file_name
) - 4);
1807 for (i
= 0; der_suffix
[i
] != NULL
; i
++) {
1808 if (StrCmp(suffix
, der_suffix
[i
]) == 0) {
1816 static void mok_key_enroll(void)
1818 EFI_STATUS efi_status
;
1819 CHAR16
*file_name
= NULL
;
1820 EFI_HANDLE im
= NULL
;
1821 EFI_FILE
*file
= NULL
;
1825 simple_file_selector(&im
, (CHAR16
*[]){
1828 L
"The selected key will be enrolled into the MOK database",
1829 L
"This means any binaries signed with it will be run without prompting",
1830 L
"Remember to make sure it is a genuine key before Enroling it",
1832 }, L
"\\", L
"", &file_name
);
1837 if (!check_der_suffix(file_name
)) {
1838 console_alertbox((CHAR16
*[]){
1839 L
"Unsupported Format",
1841 L
"Only DER encoded certificate (*.cer/der/crt) is supported",
1846 efi_status
= simple_file_open(im
, file_name
, &file
, EFI_FILE_MODE_READ
);
1848 if (efi_status
!= EFI_SUCCESS
) {
1849 console_error(L
"Unable to open file", efi_status
);
1853 simple_file_read_all(file
, &filesize
, &data
);
1854 simple_file_close(file
);
1857 console_error(L
"Unable to read file", efi_status
);
1861 enroll_file(data
, filesize
, FALSE
);
1865 static BOOLEAN
verify_pw(BOOLEAN
*protected)
1867 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1868 EFI_STATUS efi_status
;
1869 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1870 UINT8 pwhash
[PASSWORD_CRYPT_SIZE
];
1871 UINTN size
= PASSWORD_CRYPT_SIZE
;
1877 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokPWStore",
1878 &shim_lock_guid
, &attributes
, &size
,
1882 * If anything can attack the password it could just set it to a
1883 * known value, so there's no safety advantage in failing to validate
1884 * purely because of a failure to read the variable
1886 if (efi_status
!= EFI_SUCCESS
||
1887 (size
!= SHA256_DIGEST_SIZE
&& size
!= PASSWORD_CRYPT_SIZE
))
1890 if (attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)
1893 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1895 /* Draw the background */
1896 console_save_and_set_mode(&SavedMode
);
1897 message
[0] = PoolPrint (L
"%s UEFI key management", SHIM_VENDOR
);
1899 console_print_box_at(message
, -1, 0, 0, -1, -1, 1, 1);
1900 FreePool(message
[0]);
1901 console_restore_mode(&SavedMode
);
1903 if (size
== PASSWORD_CRYPT_SIZE
) {
1904 efi_status
= match_password((PASSWORD_CRYPT
*)pwhash
, NULL
, 0,
1905 NULL
, L
"Enter MOK password:");
1907 efi_status
= match_password(NULL
, NULL
, 0, pwhash
,
1908 L
"Enter MOK password:");
1910 if (efi_status
!= EFI_SUCCESS
) {
1911 console_notify(L
"Password limit reached");
1920 static int draw_countdown()
1922 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1927 CHAR16
*message
= L
"Press any key to perform MOK management";
1928 int timeout
= 10, wait
= 10000000;
1930 console_save_and_set_mode (&SavedMode
);
1932 title
[0] = PoolPrint (L
"%s UEFI key management", SHIM_VENDOR
);
1935 console_print_box_at(title
, -1, 0, 0, -1, -1, 1, 1);
1937 uefi_call_wrapper(ST
->ConOut
->QueryMode
, 4, ST
->ConOut
,
1938 ST
->ConOut
->Mode
->Mode
, &cols
, &rows
);
1940 PrintAt((cols
- StrLen(message
))/2, rows
/2, message
);
1943 PrintAt(2, rows
- 3, L
"Booting in %d seconds ", timeout
);
1945 PrintAt(2, rows
- 3, L
"Booting in %d second ", timeout
);
1947 status
= WaitForSingleEvent(ST
->ConIn
->WaitForKey
, wait
);
1949 if (status
!= EFI_TIMEOUT
) {
1950 /* Clear the key in the queue */
1951 uefi_call_wrapper(ST
->ConIn
->ReadKeyStroke
, 2,
1963 console_restore_mode(&SavedMode
);
1983 static EFI_STATUS
enter_mok_menu(EFI_HANDLE image_handle
,
1984 void *MokNew
, UINTN MokNewSize
,
1985 void *MokDel
, UINTN MokDelSize
,
1986 void *MokSB
, UINTN MokSBSize
,
1987 void *MokPW
, UINTN MokPWSize
,
1988 void *MokDB
, UINTN MokDBSize
,
1989 void *MokXNew
, UINTN MokXNewSize
,
1990 void *MokXDel
, UINTN MokXDelSize
)
1992 CHAR16
**menu_strings
;
1993 mok_menu_item
*menu_item
;
1996 UINT32 MokDelAuth
= 0;
1997 UINT32 MokXAuth
= 0;
1998 UINT32 MokXDelAuth
= 0;
1999 UINTN menucount
= 3, i
= 0;
2000 EFI_STATUS efi_status
;
2001 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
2002 UINT8 auth
[PASSWORD_CRYPT_SIZE
];
2003 UINTN auth_size
= PASSWORD_CRYPT_SIZE
;
2006 EFI_STATUS ret
= EFI_SUCCESS
;
2008 if (verify_pw(&protected) == FALSE
)
2009 return EFI_ACCESS_DENIED
;
2011 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokAuth",
2013 &attributes
, &auth_size
, auth
);
2015 if ((efi_status
== EFI_SUCCESS
) &&
2016 (auth_size
== SHA256_DIGEST_SIZE
|| auth_size
== PASSWORD_CRYPT_SIZE
))
2019 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokDelAuth",
2021 &attributes
, &auth_size
, auth
);
2023 if ((efi_status
== EFI_SUCCESS
) &&
2024 (auth_size
== SHA256_DIGEST_SIZE
|| auth_size
== PASSWORD_CRYPT_SIZE
))
2027 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokXAuth",
2029 &attributes
, &auth_size
, auth
);
2031 if ((efi_status
== EFI_SUCCESS
) &&
2032 (auth_size
== SHA256_DIGEST_SIZE
|| auth_size
== PASSWORD_CRYPT_SIZE
))
2035 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokXDelAuth",
2037 &attributes
, &auth_size
, auth
);
2039 if ((efi_status
== EFI_SUCCESS
) &&
2040 (auth_size
== SHA256_DIGEST_SIZE
|| auth_size
== PASSWORD_CRYPT_SIZE
))
2043 if (MokNew
|| MokAuth
)
2046 if (MokDel
|| MokDelAuth
)
2049 if (MokXNew
|| MokXAuth
)
2052 if (MokXDel
|| MokXDelAuth
)
2064 menu_strings
= AllocateZeroPool(sizeof(CHAR16
*) * (menucount
+ 1));
2067 return EFI_OUT_OF_RESOURCES
;
2069 menu_item
= AllocateZeroPool(sizeof(mok_menu_item
) * menucount
);
2072 FreePool(menu_strings
);
2073 return EFI_OUT_OF_RESOURCES
;
2076 menu_strings
[i
] = L
"Continue boot";
2077 menu_item
[i
] = MOK_CONTINUE_BOOT
;
2081 if (MokNew
|| MokAuth
) {
2083 menu_strings
[i
] = L
"Reset MOK";
2084 menu_item
[i
] = MOK_RESET_MOK
;
2086 menu_strings
[i
] = L
"Enroll MOK";
2087 menu_item
[i
] = MOK_ENROLL_MOK
;
2092 if (MokDel
|| MokDelAuth
) {
2093 menu_strings
[i
] = L
"Delete MOK";
2094 menu_item
[i
] = MOK_DELETE_MOK
;
2098 if (MokXNew
|| MokXAuth
) {
2100 menu_strings
[i
] = L
"Reset MOKX";
2101 menu_item
[i
] = MOK_RESET_MOKX
;
2103 menu_strings
[i
] = L
"Enroll MOKX";
2104 menu_item
[i
] = MOK_ENROLL_MOKX
;
2109 if (MokXDel
|| MokXDelAuth
) {
2110 menu_strings
[i
] = L
"Delete MOKX";
2111 menu_item
[i
] = MOK_DELETE_MOKX
;
2116 menu_strings
[i
] = L
"Change Secure Boot state";
2117 menu_item
[i
] = MOK_CHANGE_SB
;
2122 menu_strings
[i
] = L
"Set MOK password";
2123 menu_item
[i
] = MOK_SET_PW
;
2128 menu_strings
[i
] = L
"Change DB state";
2129 menu_item
[i
] = MOK_CHANGE_DB
;
2133 menu_strings
[i
] = L
"Enroll key from disk";
2134 menu_item
[i
] = MOK_KEY_ENROLL
;
2137 menu_strings
[i
] = L
"Enroll hash from disk";
2138 menu_item
[i
] = MOK_HASH_ENROLL
;
2141 menu_strings
[i
] = NULL
;
2143 if (protected == FALSE
&& draw_countdown() == 0)
2146 while (choice
>= 0) {
2147 choice
= console_select((CHAR16
*[]){ L
"Perform MOK management", NULL
},
2153 switch (menu_item
[choice
]) {
2154 case MOK_CONTINUE_BOOT
:
2157 mok_reset_prompt(FALSE
);
2159 case MOK_ENROLL_MOK
:
2160 mok_enrollment_prompt(MokNew
, MokNewSize
, TRUE
, FALSE
);
2162 case MOK_DELETE_MOK
:
2163 mok_deletion_prompt(MokDel
, MokDelSize
, FALSE
);
2165 case MOK_RESET_MOKX
:
2166 mok_reset_prompt(TRUE
);
2168 case MOK_ENROLL_MOKX
:
2169 mok_enrollment_prompt(MokXNew
, MokXNewSize
, TRUE
, TRUE
);
2171 case MOK_DELETE_MOKX
:
2172 mok_deletion_prompt(MokXDel
, MokXDelSize
, TRUE
);
2175 mok_sb_prompt(MokSB
, MokSBSize
);
2178 mok_pw_prompt(MokPW
, MokPWSize
);
2181 mok_db_prompt(MokDB
, MokDBSize
);
2183 case MOK_KEY_ENROLL
:
2186 case MOK_HASH_ENROLL
:
2195 FreePool(menu_strings
);
2198 FreePool(menu_item
);
2203 static EFI_STATUS
check_mok_request(EFI_HANDLE image_handle
)
2205 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
2206 UINTN MokNewSize
= 0, MokDelSize
= 0, MokSBSize
= 0, MokPWSize
= 0;
2207 UINTN MokDBSize
= 0, MokXNewSize
= 0, MokXDelSize
= 0;
2208 void *MokNew
= NULL
;
2209 void *MokDel
= NULL
;
2213 void *MokXNew
= NULL
;
2214 void *MokXDel
= NULL
;
2217 status
= get_variable(L
"MokNew", (UINT8
**)&MokNew
, &MokNewSize
,
2219 if (status
== EFI_SUCCESS
) {
2220 if (LibDeleteVariable(L
"MokNew", &shim_lock_guid
) != EFI_SUCCESS
) {
2221 console_notify(L
"Failed to delete MokNew");
2223 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2224 console_error(L
"Could not retrieve MokNew", status
);
2227 status
= get_variable(L
"MokDel", (UINT8
**)&MokDel
, &MokDelSize
,
2229 if (status
== EFI_SUCCESS
) {
2230 if (LibDeleteVariable(L
"MokDel", &shim_lock_guid
) != EFI_SUCCESS
) {
2231 console_notify(L
"Failed to delete MokDel");
2233 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2234 console_error(L
"Could not retrieve MokDel", status
);
2237 status
= get_variable(L
"MokSB", (UINT8
**)&MokSB
, &MokSBSize
,
2239 if (status
== EFI_SUCCESS
) {
2240 if (LibDeleteVariable(L
"MokSB", &shim_lock_guid
) != EFI_SUCCESS
) {
2241 console_notify(L
"Failed to delete MokSB");
2243 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2244 console_error(L
"Could not retrieve MokSB", status
);
2247 status
= get_variable(L
"MokPW", (UINT8
**)&MokPW
, &MokPWSize
,
2249 if (status
== EFI_SUCCESS
) {
2250 if (LibDeleteVariable(L
"MokPW", &shim_lock_guid
) != EFI_SUCCESS
) {
2251 console_notify(L
"Failed to delete MokPW");
2253 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2254 console_error(L
"Could not retrieve MokPW", status
);
2257 status
= get_variable(L
"MokDB", (UINT8
**)&MokDB
, &MokDBSize
,
2259 if (status
== EFI_SUCCESS
) {
2260 if (LibDeleteVariable(L
"MokDB", &shim_lock_guid
) != EFI_SUCCESS
) {
2261 console_notify(L
"Failed to delete MokDB");
2263 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2264 console_error(L
"Could not retrieve MokDB", status
);
2267 status
= get_variable(L
"MokXNew", (UINT8
**)&MokXNew
, &MokXNewSize
,
2269 if (status
== EFI_SUCCESS
) {
2270 if (LibDeleteVariable(L
"MokXNew", &shim_lock_guid
) != EFI_SUCCESS
) {
2271 console_notify(L
"Failed to delete MokXNew");
2273 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2274 console_error(L
"Could not retrieve MokXNew", status
);
2277 status
= get_variable(L
"MokXDel", (UINT8
**)&MokXDel
, &MokXDelSize
,
2279 if (status
== EFI_SUCCESS
) {
2280 if (LibDeleteVariable(L
"MokXDel", &shim_lock_guid
) != EFI_SUCCESS
) {
2281 console_notify(L
"Failed to delete MokXDel");
2283 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2284 console_error(L
"Could not retrieve MokXDel", status
);
2287 enter_mok_menu(image_handle
, MokNew
, MokNewSize
, MokDel
, MokDelSize
,
2288 MokSB
, MokSBSize
, MokPW
, MokPWSize
, MokDB
, MokDBSize
,
2289 MokXNew
, MokXNewSize
, MokXDel
, MokXDelSize
);
2312 LibDeleteVariable(L
"MokAuth", &shim_lock_guid
);
2313 LibDeleteVariable(L
"MokDelAuth", &shim_lock_guid
);
2314 LibDeleteVariable(L
"MokXAuth", &shim_lock_guid
);
2315 LibDeleteVariable(L
"MokXDelAuth", &shim_lock_guid
);
2320 static EFI_STATUS
setup_rand (void)
2323 EFI_STATUS efi_status
;
2327 efi_status
= uefi_call_wrapper(RT
->GetTime
, 2, &time
, NULL
);
2329 if (efi_status
!= EFI_SUCCESS
)
2332 seed
= ((UINT64
)time
.Year
<< 48) | ((UINT64
)time
.Month
<< 40) |
2333 ((UINT64
)time
.Day
<< 32) | ((UINT64
)time
.Hour
<< 24) |
2334 ((UINT64
)time
.Minute
<< 16) | ((UINT64
)time
.Second
<< 8) |
2335 ((UINT64
)time
.Daylight
);
2337 status
= RandomSeed((UINT8
*)&seed
, sizeof(seed
));
2345 EFI_STATUS
efi_main (EFI_HANDLE image_handle
, EFI_SYSTEM_TABLE
*systab
)
2347 EFI_STATUS efi_status
;
2349 InitializeLib(image_handle
, systab
);
2355 efi_status
= check_mok_request(image_handle
);