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 BOOLEAN
is_sha_hash (EFI_GUID Type
)
99 EFI_GUID Sha1
= EFI_CERT_SHA1_GUID
;
100 EFI_GUID Sha256
= EFI_CERT_SHA256_GUID
;
102 if (CompareGuid(&Type
, &Sha1
) == 0)
104 else if (CompareGuid(&Type
, &Sha256
) == 0)
110 static UINT32
sha_size (EFI_GUID Type
)
112 EFI_GUID Sha1
= EFI_CERT_SHA1_GUID
;
113 EFI_GUID Sha256
= EFI_CERT_SHA256_GUID
;
115 if (CompareGuid(&Type
, &Sha1
) == 0)
116 return SHA1_DIGEST_SIZE
;
117 else if (CompareGuid(&Type
, &Sha256
) == 0)
118 return SHA256_DIGEST_SIZE
;
123 static BOOLEAN
is_valid_siglist (EFI_GUID Type
, UINT32 SigSize
)
125 EFI_GUID CertType
= X509_GUID
;
126 UINT32 hash_sig_size
;
128 if (CompareGuid (&Type
, &CertType
) == 0 && SigSize
!= 0)
131 if (!is_sha_hash (Type
))
134 hash_sig_size
= sha_size (Type
) + sizeof(EFI_GUID
);
135 if (SigSize
!= hash_sig_size
)
141 static UINT32
count_keys(void *Data
, UINTN DataSize
)
143 EFI_SIGNATURE_LIST
*CertList
= Data
;
144 UINTN dbsize
= DataSize
;
146 void *end
= Data
+ DataSize
;
148 while ((dbsize
> 0) && (dbsize
>= CertList
->SignatureListSize
)) {
150 /* Use ptr arithmetics to ensure bounded access. Do not allow 0
151 * SignatureListSize that will cause endless loop.
153 if ((void *)(CertList
+ 1) > end
|| CertList
->SignatureListSize
== 0) {
154 console_notify(L
"Invalid MOK detected! Ignoring MOK List.");
158 if (!is_valid_siglist(CertList
->SignatureType
, CertList
->SignatureSize
)) {
159 dbsize
-= CertList
->SignatureListSize
;
160 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
161 CertList
->SignatureListSize
);
166 dbsize
-= CertList
->SignatureListSize
;
167 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
168 CertList
->SignatureListSize
);
174 static MokListNode
*build_mok_list(UINT32 num
, void *Data
, UINTN DataSize
) {
176 EFI_SIGNATURE_LIST
*CertList
= Data
;
177 EFI_SIGNATURE_DATA
*Cert
;
178 EFI_GUID CertType
= X509_GUID
;
179 UINTN dbsize
= DataSize
;
181 void *end
= Data
+ DataSize
;
183 list
= AllocatePool(sizeof(MokListNode
) * num
);
186 console_notify(L
"Unable to allocate MOK list");
190 while ((dbsize
> 0) && (dbsize
>= CertList
->SignatureListSize
)) {
191 /* CertList out of bounds? */
192 if ((void *)(CertList
+ 1) > end
|| CertList
->SignatureListSize
== 0) {
196 if (!is_valid_siglist(CertList
->SignatureType
, CertList
->SignatureSize
)) {
197 dbsize
-= CertList
->SignatureListSize
;
198 CertList
= (EFI_SIGNATURE_LIST
*)((UINT8
*) CertList
+
199 CertList
->SignatureListSize
);
203 Cert
= (EFI_SIGNATURE_DATA
*) (((UINT8
*) CertList
) +
204 sizeof (EFI_SIGNATURE_LIST
) + CertList
->SignatureHeaderSize
);
206 /* Cert out of bounds? */
207 if ((void *)(Cert
+ 1) > end
|| CertList
->SignatureSize
<= sizeof(EFI_GUID
)) {
212 list
[count
].Type
= CertList
->SignatureType
;
213 if (CompareGuid (&CertList
->SignatureType
, &CertType
) == 0) {
214 list
[count
].MokSize
= CertList
->SignatureSize
-
216 list
[count
].Mok
= (void *)Cert
->SignatureData
;
218 list
[count
].MokSize
= CertList
->SignatureListSize
-
219 sizeof(EFI_SIGNATURE_LIST
);
220 list
[count
].Mok
= (void *)Cert
;
223 /* MOK out of bounds? */
224 if (list
[count
].MokSize
> (unsigned long)end
-
225 (unsigned long)list
[count
].Mok
) {
231 dbsize
-= CertList
->SignatureListSize
;
232 CertList
= (EFI_SIGNATURE_LIST
*) ((UINT8
*) CertList
+
233 CertList
->SignatureListSize
);
244 static NidName nidname
[] = {
245 {NID_commonName
, L
"CN"},
246 {NID_organizationName
, L
"O"},
247 {NID_countryName
, L
"C"},
248 {NID_stateOrProvinceName
, L
"ST"},
249 {NID_localityName
, L
"L"},
253 static CHAR16
* get_x509_name (X509_NAME
*X509Name
)
255 CHAR16 name
[NAME_LINE_MAX
+1];
256 CHAR16 part
[NAME_LINE_MAX
+1];
257 char str
[NAME_LINE_MAX
];
258 int i
, len
, rest
, first
;
261 rest
= NAME_LINE_MAX
;
263 for (i
= 0; nidname
[i
].name
!= NULL
; i
++) {
265 len
= X509_NAME_get_text_by_NID (X509Name
, nidname
[i
].nid
,
271 add
= len
+ (int)StrLen(nidname
[i
].name
) + 1;
273 add
= len
+ (int)StrLen(nidname
[i
].name
) + 3;
279 SPrint(part
, NAME_LINE_MAX
* sizeof(CHAR16
), L
"%s=%a",
280 nidname
[i
].name
, str
);
282 SPrint(part
, NAME_LINE_MAX
* sizeof(CHAR16
), L
", %s=%a",
283 nidname
[i
].name
, str
);
290 if (rest
>= 0 && rest
< NAME_LINE_MAX
)
291 return PoolPrint(L
"%s", name
);
296 static CHAR16
* get_x509_time (ASN1_TIME
*time
)
298 BIO
*bio
= BIO_new (BIO_s_mem());
302 ASN1_TIME_print (bio
, time
);
303 len
= BIO_read(bio
, str
, 29);
309 return PoolPrint(L
"%a", str
);
312 static void show_x509_info (X509
*X509Cert
, UINT8
*hash
)
314 ASN1_INTEGER
*serial
;
316 unsigned char hexbuf
[30];
319 CHAR16
*issuer
= NULL
;
320 CHAR16
*subject
= NULL
;
322 CHAR16
*until
= NULL
;
323 POOL_PRINT hash_string1
;
324 POOL_PRINT hash_string2
;
325 POOL_PRINT serial_string
;
330 ZeroMem(&hash_string1
, sizeof(hash_string1
));
331 ZeroMem(&hash_string2
, sizeof(hash_string2
));
332 ZeroMem(&serial_string
, sizeof(serial_string
));
334 serial
= X509_get_serialNumber(X509Cert
);
337 bnser
= ASN1_INTEGER_to_BN(serial
, NULL
);
338 n
= BN_bn2bin(bnser
, hexbuf
);
339 for (i
= 0; i
< n
; i
++) {
340 CatPrint(&serial_string
, L
"%02x:", hexbuf
[i
]);
344 if (serial_string
.str
)
347 X509Name
= X509_get_issuer_name(X509Cert
);
349 issuer
= get_x509_name(X509Name
);
354 X509Name
= X509_get_subject_name(X509Cert
);
356 subject
= get_x509_name(X509Name
);
361 time
= X509_get_notBefore(X509Cert
);
363 from
= get_x509_time(time
);
368 time
= X509_get_notAfter(X509Cert
);
370 until
= get_x509_time(time
);
376 CatPrint(&hash_string1
, L
"%02x ", hash
[i
]);
377 for (i
=10; i
<20; i
++)
378 CatPrint(&hash_string2
, L
"%02x ", hash
[i
]);
380 if (hash_string1
.str
)
383 if (hash_string2
.str
)
390 text
= AllocateZeroPool(sizeof(CHAR16
*) * (fields
*3 + 1));
391 if (serial_string
.str
) {
392 text
[i
++] = StrDuplicate(L
"[Serial Number]");
393 text
[i
++] = serial_string
.str
;
394 text
[i
++] = StrDuplicate(L
"");
397 text
[i
++] = StrDuplicate(L
"[Issuer]");
399 text
[i
++] = StrDuplicate(L
"");
402 text
[i
++] = StrDuplicate(L
"[Subject]");
404 text
[i
++] = StrDuplicate(L
"");
407 text
[i
++] = StrDuplicate(L
"[Valid Not Before]");
409 text
[i
++] = StrDuplicate(L
"");
412 text
[i
++] = StrDuplicate(L
"[Valid Not After]");
414 text
[i
++] = StrDuplicate(L
"");
416 if (hash_string1
.str
) {
417 text
[i
++] = StrDuplicate(L
"[Fingerprint]");
418 text
[i
++] = hash_string1
.str
;
420 if (hash_string2
.str
) {
421 text
[i
++] = hash_string2
.str
;
422 text
[i
++] = StrDuplicate(L
"");
426 console_print_box(text
, -1);
428 for (i
=0; text
[i
] != NULL
; i
++)
434 static void show_sha_digest (EFI_GUID Type
, UINT8
*hash
)
436 EFI_GUID Sha1
= EFI_CERT_SHA1_GUID
;
437 EFI_GUID Sha256
= EFI_CERT_SHA256_GUID
;
439 POOL_PRINT hash_string1
;
440 POOL_PRINT hash_string2
;
444 if (CompareGuid(&Type
, &Sha1
) == 0) {
445 length
= SHA1_DIGEST_SIZE
;
446 text
[0] = L
"SHA1 hash";
447 } else if (CompareGuid(&Type
, &Sha256
) == 0) {
448 length
= SHA256_DIGEST_SIZE
;
449 text
[0] = L
"SHA256 hash";
454 ZeroMem(&hash_string1
, sizeof(hash_string1
));
455 ZeroMem(&hash_string2
, sizeof(hash_string2
));
459 for (i
=0; i
<length
/2; i
++)
460 CatPrint(&hash_string1
, L
"%02x ", hash
[i
]);
461 for (i
=length
/2; i
<length
; i
++)
462 CatPrint(&hash_string2
, L
"%02x ", hash
[i
]);
464 text
[2] = hash_string1
.str
;
465 text
[3] = hash_string2
.str
;
468 console_print_box(text
, -1);
470 if (hash_string1
.str
)
471 FreePool(hash_string1
.str
);
473 if (hash_string2
.str
)
474 FreePool(hash_string2
.str
);
477 static void show_efi_hash (EFI_GUID Type
, void *Mok
, UINTN MokSize
)
482 CHAR16
**menu_strings
;
486 sig_size
= sha_size(Type
) + sizeof(EFI_GUID
);
487 if ((MokSize
% sig_size
) != 0) {
488 console_errorbox(L
"Corrupted Hash List");
491 hash_num
= MokSize
/ sig_size
;
494 hash
= (UINT8
*)Mok
+ sizeof(EFI_GUID
);
495 show_sha_digest(Type
, hash
);
499 menu_strings
= AllocateZeroPool(sizeof(CHAR16
*) * (hash_num
+ 2));
501 console_errorbox(L
"Out of Resources");
504 for (i
=0; i
<hash_num
; i
++) {
505 menu_strings
[i
] = PoolPrint(L
"View hash %d", i
);
507 menu_strings
[i
] = StrDuplicate(L
"Back");
508 menu_strings
[i
+1] = NULL
;
510 while (key_num
< hash_num
) {
511 key_num
= console_select((CHAR16
*[]){ L
"[Hash List]", NULL
},
512 menu_strings
, key_num
);
514 if (key_num
< 0 || key_num
>= hash_num
)
517 hash
= (UINT8
*)Mok
+ sig_size
*key_num
+ sizeof(EFI_GUID
);
518 show_sha_digest(Type
, hash
);
521 for (i
=0; menu_strings
[i
] != NULL
; i
++)
522 FreePool(menu_strings
[i
]);
524 FreePool(menu_strings
);
527 static void show_mok_info (EFI_GUID Type
, void *Mok
, UINTN MokSize
)
529 EFI_STATUS efi_status
;
530 UINT8 hash
[SHA1_DIGEST_SIZE
];
532 EFI_GUID CertType
= X509_GUID
;
534 if (!Mok
|| MokSize
== 0)
537 if (CompareGuid (&Type
, &CertType
) == 0) {
538 efi_status
= get_sha1sum(Mok
, MokSize
, hash
);
540 if (efi_status
!= EFI_SUCCESS
) {
541 console_notify(L
"Failed to compute MOK fingerprint");
545 if (X509ConstructCertificate(Mok
, MokSize
,
546 (UINT8
**) &X509Cert
) && X509Cert
!= NULL
) {
547 show_x509_info(X509Cert
, hash
);
550 console_notify(L
"Not a valid X509 certificate");
553 } else if (is_sha_hash(Type
)) {
554 show_efi_hash(Type
, Mok
, MokSize
);
558 static EFI_STATUS
list_keys (void *KeyList
, UINTN KeyListSize
, CHAR16
*title
)
561 MokListNode
*keys
= NULL
;
563 CHAR16
**menu_strings
;
566 if (KeyListSize
< (sizeof(EFI_SIGNATURE_LIST
) +
567 sizeof(EFI_SIGNATURE_DATA
))) {
568 console_notify(L
"No MOK keys found");
572 MokNum
= count_keys(KeyList
, KeyListSize
);
575 keys
= build_mok_list(MokNum
, KeyList
, KeyListSize
);
578 console_notify(L
"Failed to construct key list");
582 menu_strings
= AllocateZeroPool(sizeof(CHAR16
*) * (MokNum
+ 2));
585 return EFI_OUT_OF_RESOURCES
;
587 for (i
=0; i
<MokNum
; i
++) {
588 menu_strings
[i
] = PoolPrint(L
"View key %d", i
);
590 menu_strings
[i
] = StrDuplicate(L
"Continue");
592 menu_strings
[i
+1] = NULL
;
594 while (key_num
< MokNum
) {
595 key_num
= console_select((CHAR16
*[]){ title
, NULL
},
596 menu_strings
, key_num
);
598 if (key_num
< 0 || key_num
>= MokNum
)
601 show_mok_info(keys
[key_num
].Type
, keys
[key_num
].Mok
,
602 keys
[key_num
].MokSize
);
605 for (i
=0; menu_strings
[i
] != NULL
; i
++)
606 FreePool(menu_strings
[i
]);
608 FreePool(menu_strings
);
615 static EFI_STATUS
get_line (UINT32
*length
, CHAR16
*line
, UINT32 line_max
, UINT8 show
)
619 unsigned int count
= 0;
622 status
= console_get_keystroke(&key
);
623 if (EFI_ERROR (status
)) {
624 console_error(L
"Failed to read the keystroke", status
);
629 if ((count
>= line_max
&&
630 key
.UnicodeChar
!= CHAR_BACKSPACE
) ||
631 key
.UnicodeChar
== CHAR_NULL
||
632 key
.UnicodeChar
== CHAR_TAB
||
633 key
.UnicodeChar
== CHAR_LINEFEED
||
634 key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
638 if (count
== 0 && key
.UnicodeChar
== CHAR_BACKSPACE
) {
640 } else if (key
.UnicodeChar
== CHAR_BACKSPACE
) {
644 line
[--count
] = '\0';
649 Print(L
"%c", key
.UnicodeChar
);
652 line
[count
++] = key
.UnicodeChar
;
653 } while (key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
661 static EFI_STATUS
compute_pw_hash (void *Data
, UINTN DataSize
, UINT8
*password
,
662 UINT32 pw_length
, UINT8
*hash
)
665 unsigned int ctxsize
;
668 ctxsize
= Sha256GetContextSize();
669 ctx
= AllocatePool(ctxsize
);
672 console_notify(L
"Unable to allocate memory for hash context");
673 return EFI_OUT_OF_RESOURCES
;
676 if (!Sha256Init(ctx
)) {
677 console_notify(L
"Unable to initialise hash");
678 status
= EFI_OUT_OF_RESOURCES
;
682 if (Data
&& DataSize
) {
683 if (!(Sha256Update(ctx
, Data
, DataSize
))) {
684 console_notify(L
"Unable to generate hash");
685 status
= EFI_OUT_OF_RESOURCES
;
690 if (!(Sha256Update(ctx
, password
, pw_length
))) {
691 console_notify(L
"Unable to generate hash");
692 status
= EFI_OUT_OF_RESOURCES
;
696 if (!(Sha256Final(ctx
, hash
))) {
697 console_notify(L
"Unable to finalise hash");
698 status
= EFI_OUT_OF_RESOURCES
;
702 status
= EFI_SUCCESS
;
707 static void console_save_and_set_mode (SIMPLE_TEXT_OUTPUT_MODE
*SavedMode
)
710 Print(L
"Invalid parameter: SavedMode\n");
714 CopyMem(SavedMode
, ST
->ConOut
->Mode
, sizeof(SIMPLE_TEXT_OUTPUT_MODE
));
715 uefi_call_wrapper(ST
->ConOut
->EnableCursor
, 2, ST
->ConOut
, FALSE
);
716 uefi_call_wrapper(ST
->ConOut
->SetAttribute
, 2, ST
->ConOut
,
717 EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
);
720 static void console_restore_mode (SIMPLE_TEXT_OUTPUT_MODE
*SavedMode
)
722 uefi_call_wrapper(ST
->ConOut
->EnableCursor
, 2, ST
->ConOut
,
723 SavedMode
->CursorVisible
);
724 uefi_call_wrapper(ST
->ConOut
->SetCursorPosition
, 3, ST
->ConOut
,
725 SavedMode
->CursorColumn
, SavedMode
->CursorRow
);
726 uefi_call_wrapper(ST
->ConOut
->SetAttribute
, 2, ST
->ConOut
,
727 SavedMode
->Attribute
);
730 static UINT32
get_password (CHAR16
*prompt
, CHAR16
*password
, UINT32 max
)
732 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
739 prompt
= L
"Password:";
741 console_save_and_set_mode(&SavedMode
);
743 str
= PoolPrint(L
"%s ", prompt
);
745 console_errorbox(L
"Failed to allocate prompt");
751 length
= StrLen(message
[0]);
752 console_print_box_at(message
, -1, -length
-4, -5, length
+4, 3, 0, 1);
753 get_line(&pw_length
, password
, max
, 0);
755 console_restore_mode(&SavedMode
);
762 static EFI_STATUS
match_password (PASSWORD_CRYPT
*pw_crypt
,
763 void *Data
, UINTN DataSize
,
764 UINT8
*auth
, CHAR16
*prompt
)
770 CHAR16 password
[PASSWORD_MAX
];
772 UINT8 fail_count
= 0;
776 auth_hash
= pw_crypt
->hash
;
777 auth_size
= get_hash_size (pw_crypt
->method
);
779 return EFI_INVALID_PARAMETER
;
782 auth_size
= SHA256_DIGEST_SIZE
;
784 return EFI_INVALID_PARAMETER
;
787 while (fail_count
< 3) {
788 pw_length
= get_password(prompt
, password
, PASSWORD_MAX
);
790 if (pw_length
< PASSWORD_MIN
|| pw_length
> PASSWORD_MAX
) {
791 console_errorbox(L
"Invalid password length");
797 * Compute password hash
800 char pw_ascii
[PASSWORD_MAX
+ 1];
801 for (i
= 0; i
< pw_length
; i
++)
802 pw_ascii
[i
] = (char)password
[i
];
803 pw_ascii
[pw_length
] = '\0';
805 status
= password_crypt(pw_ascii
, pw_length
, pw_crypt
, hash
);
808 * For backward compatibility
810 status
= compute_pw_hash(Data
, DataSize
, (UINT8
*)password
,
811 pw_length
* sizeof(CHAR16
), hash
);
813 if (status
!= EFI_SUCCESS
) {
814 console_errorbox(L
"Unable to generate password hash");
819 if (CompareMem(auth_hash
, hash
, auth_size
) != 0) {
820 console_errorbox(L
"Password doesn't match");
829 return EFI_ACCESS_DENIED
;
834 static EFI_STATUS
store_keys (void *MokNew
, UINTN MokNewSize
, int authenticate
,
837 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
838 EFI_STATUS efi_status
;
841 UINT8 auth
[PASSWORD_CRYPT_SIZE
];
842 UINTN auth_size
= PASSWORD_CRYPT_SIZE
;
846 db_name
= L
"MokListX";
847 auth_name
= L
"MokXAuth";
849 db_name
= L
"MokList";
850 auth_name
= L
"MokAuth";
854 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, auth_name
,
856 &attributes
, &auth_size
, auth
);
858 if (efi_status
!= EFI_SUCCESS
||
859 (auth_size
!= SHA256_DIGEST_SIZE
&&
860 auth_size
!= PASSWORD_CRYPT_SIZE
)) {
862 console_error(L
"Failed to get MokXAuth", efi_status
);
864 console_error(L
"Failed to get MokAuth", efi_status
);
868 if (auth_size
== PASSWORD_CRYPT_SIZE
) {
869 efi_status
= match_password((PASSWORD_CRYPT
*)auth
,
870 NULL
, 0, NULL
, NULL
);
872 efi_status
= match_password(NULL
, MokNew
, MokNewSize
,
875 if (efi_status
!= EFI_SUCCESS
)
876 return EFI_ACCESS_DENIED
;
881 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, db_name
,
883 EFI_VARIABLE_NON_VOLATILE
884 | EFI_VARIABLE_BOOTSERVICE_ACCESS
,
888 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, db_name
,
890 EFI_VARIABLE_NON_VOLATILE
891 | EFI_VARIABLE_BOOTSERVICE_ACCESS
892 | EFI_VARIABLE_APPEND_WRITE
,
896 if (efi_status
!= EFI_SUCCESS
) {
897 console_error(L
"Failed to set variable", efi_status
);
904 static UINTN
mok_enrollment_prompt (void *MokNew
, UINTN MokNewSize
, int auth
,
907 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
908 EFI_STATUS efi_status
;
912 title
= L
"[Enroll MOKX]";
914 title
= L
"[Enroll MOK]";
916 if (list_keys(MokNew
, MokNewSize
, title
) != EFI_SUCCESS
)
919 if (console_yes_no((CHAR16
*[]){L
"Enroll the key(s)?", NULL
}) == 0)
922 efi_status
= store_keys(MokNew
, MokNewSize
, auth
, MokX
);
924 if (efi_status
!= EFI_SUCCESS
) {
925 console_notify(L
"Failed to enroll keys\n");
931 LibDeleteVariable(L
"MokXNew", &shim_lock_guid
);
932 LibDeleteVariable(L
"MokXAuth", &shim_lock_guid
);
934 LibDeleteVariable(L
"MokNew", &shim_lock_guid
);
935 LibDeleteVariable(L
"MokAuth", &shim_lock_guid
);
938 console_notify(L
"The system must now be rebooted");
939 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
940 EFI_SUCCESS
, 0, NULL
);
941 console_notify(L
"Failed to reboot");
948 static INTN
mok_reset_prompt (BOOLEAN MokX
)
950 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
951 EFI_STATUS efi_status
;
954 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
957 prompt
= L
"Erase all stored keys in MokListX?";
959 prompt
= L
"Erase all stored keys in MokList?";
960 if (console_yes_no((CHAR16
*[]){prompt
, NULL
}) == 0)
963 efi_status
= store_keys(NULL
, 0, TRUE
, MokX
);
965 if (efi_status
!= EFI_SUCCESS
) {
966 console_notify(L
"Failed to erase keys\n");
971 LibDeleteVariable(L
"MokXNew", &shim_lock_guid
);
972 LibDeleteVariable(L
"MokXAuth", &shim_lock_guid
);
974 LibDeleteVariable(L
"MokNew", &shim_lock_guid
);
975 LibDeleteVariable(L
"MokAuth", &shim_lock_guid
);
978 console_notify(L
"The system must now be rebooted");
979 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
980 EFI_SUCCESS
, 0, NULL
);
981 console_notify(L
"Failed to reboot\n");
985 static EFI_STATUS
write_back_mok_list (MokListNode
*list
, INTN key_num
,
988 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
989 EFI_GUID CertType
= X509_GUID
;
990 EFI_STATUS efi_status
;
991 EFI_SIGNATURE_LIST
*CertList
;
992 EFI_SIGNATURE_DATA
*CertData
;
993 void *Data
= NULL
, *ptr
;
999 db_name
= L
"MokListX";
1001 db_name
= L
"MokList";
1003 for (i
= 0; i
< key_num
; i
++) {
1004 if (list
[i
].Mok
== NULL
)
1007 DataSize
+= sizeof(EFI_SIGNATURE_LIST
);
1008 if (CompareGuid(&(list
[i
].Type
), &CertType
) == 0)
1009 DataSize
+= sizeof(EFI_GUID
);
1010 DataSize
+= list
[i
].MokSize
;
1013 Data
= AllocatePool(DataSize
);
1014 if (Data
== NULL
&& DataSize
!= 0)
1015 return EFI_OUT_OF_RESOURCES
;
1019 for (i
= 0; i
< key_num
; i
++) {
1020 if (list
[i
].Mok
== NULL
)
1023 CertList
= (EFI_SIGNATURE_LIST
*)ptr
;
1024 CertData
= (EFI_SIGNATURE_DATA
*)(((uint8_t *)ptr
) +
1025 sizeof(EFI_SIGNATURE_LIST
));
1027 CertList
->SignatureType
= list
[i
].Type
;
1028 CertList
->SignatureHeaderSize
= 0;
1030 if (CompareGuid(&(list
[i
].Type
), &CertType
) == 0) {
1031 CertList
->SignatureListSize
= list
[i
].MokSize
+
1032 sizeof(EFI_SIGNATURE_LIST
) +
1034 CertList
->SignatureSize
= list
[i
].MokSize
+ sizeof(EFI_GUID
);
1036 CertData
->SignatureOwner
= shim_lock_guid
;
1037 CopyMem(CertData
->SignatureData
, list
[i
].Mok
, list
[i
].MokSize
);
1039 CertList
->SignatureListSize
= list
[i
].MokSize
+
1040 sizeof(EFI_SIGNATURE_LIST
);
1041 CertList
->SignatureSize
= sha_size(list
[i
].Type
) + sizeof(EFI_GUID
);
1043 CopyMem(CertData
, list
[i
].Mok
, list
[i
].MokSize
);
1045 ptr
= (uint8_t *)ptr
+ CertList
->SignatureListSize
;
1048 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, db_name
,
1050 EFI_VARIABLE_NON_VOLATILE
1051 | EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1056 if (efi_status
!= EFI_SUCCESS
) {
1057 console_error(L
"Failed to set variable", efi_status
);
1064 static void delete_cert (void *key
, UINT32 key_size
,
1065 MokListNode
*mok
, INTN mok_num
)
1067 EFI_GUID CertType
= X509_GUID
;
1070 for (i
= 0; i
< mok_num
; i
++) {
1071 if (CompareGuid(&(mok
[i
].Type
), &CertType
) != 0)
1074 if (mok
[i
].MokSize
== key_size
&&
1075 CompareMem(key
, mok
[i
].Mok
, key_size
) == 0) {
1076 /* Remove the key */
1083 static int match_hash (UINT8
*hash
, UINT32 hash_size
, int start
,
1084 void *hash_list
, UINT32 list_num
)
1089 ptr
= hash_list
+ sizeof(EFI_GUID
);
1090 for (i
= start
; i
< list_num
; i
++) {
1091 if (CompareMem(hash
, ptr
, hash_size
) == 0)
1093 ptr
+= hash_size
+ sizeof(EFI_GUID
);
1099 static void mem_move (void *dest
, void *src
, UINTN size
)
1106 for (i
= 0; i
< size
; i
++)
1110 static void delete_hash_in_list (UINT8
*hash
, UINT32 hash_size
,
1111 MokListNode
*mok
, INTN mok_num
)
1119 sig_size
= hash_size
+ sizeof(EFI_GUID
);
1121 for (i
= 0; i
< mok_num
; i
++) {
1122 if (!is_sha_hash(mok
[i
].Type
) || (mok
[i
].MokSize
< sig_size
))
1125 list_num
= mok
[i
].MokSize
/ sig_size
;
1127 del_ind
= match_hash(hash
, hash_size
, 0, mok
[i
].Mok
,
1129 while (del_ind
>= 0) {
1130 /* Remove the hash */
1131 if (sig_size
== mok
[i
].MokSize
) {
1137 start
= mok
[i
].Mok
+ del_ind
* sig_size
;
1138 end
= start
+ sig_size
;
1139 remain
= mok
[i
].MokSize
- (del_ind
+ 1)*sig_size
;
1141 mem_move(start
, end
, remain
);
1142 mok
[i
].MokSize
-= sig_size
;
1145 del_ind
= match_hash(hash
, hash_size
, del_ind
,
1146 mok
[i
].Mok
, list_num
);
1151 static void delete_hash_list (EFI_GUID Type
, void *hash_list
, UINT32 list_size
,
1152 MokListNode
*mok
, INTN mok_num
)
1160 hash_size
= sha_size (Type
);
1161 sig_size
= hash_size
+ sizeof(EFI_GUID
);
1162 if (list_size
< sig_size
)
1165 hash_num
= list_size
/ sig_size
;
1167 hash
= hash_list
+ sizeof(EFI_GUID
);
1169 for (i
= 0; i
< hash_num
; i
++) {
1170 delete_hash_in_list (hash
, hash_size
, mok
, mok_num
);
1175 static EFI_STATUS
delete_keys (void *MokDel
, UINTN MokDelSize
, BOOLEAN MokX
)
1177 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1178 EFI_GUID CertType
= X509_GUID
;
1179 EFI_STATUS efi_status
;
1184 UINT8 auth
[PASSWORD_CRYPT_SIZE
];
1185 UINTN auth_size
= PASSWORD_CRYPT_SIZE
;
1187 UINT8
*MokListData
= NULL
;
1188 UINTN MokListDataSize
= 0;
1189 MokListNode
*mok
, *del_key
;
1190 INTN mok_num
, del_num
;
1194 db_name
= L
"MokListX";
1195 auth_name
= L
"MokXDelAuth";
1197 db_name
= L
"MokList";
1198 auth_name
= L
"MokDelAuth";
1201 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, auth_name
,
1203 &attributes
, &auth_size
, auth
);
1205 if (efi_status
!= EFI_SUCCESS
||
1206 (auth_size
!= SHA256_DIGEST_SIZE
&& auth_size
!= PASSWORD_CRYPT_SIZE
)) {
1208 console_error(L
"Failed to get MokXDelAuth", efi_status
);
1210 console_error(L
"Failed to get MokDelAuth", efi_status
);
1214 if (auth_size
== PASSWORD_CRYPT_SIZE
) {
1215 efi_status
= match_password((PASSWORD_CRYPT
*)auth
, NULL
, 0,
1218 efi_status
= match_password(NULL
, MokDel
, MokDelSize
, auth
, NULL
);
1220 if (efi_status
!= EFI_SUCCESS
)
1221 return EFI_ACCESS_DENIED
;
1223 efi_status
= get_variable_attr (db_name
, &MokListData
, &MokListDataSize
,
1224 shim_lock_guid
, &attributes
);
1225 if (attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) {
1227 err_str1
= L
"MokListX is compromised!";
1228 err_str2
= L
"Erase all keys in MokListX!";
1230 err_str1
= L
"MokList is compromised!";
1231 err_str2
= L
"Erase all keys in MokList!";
1233 console_alertbox((CHAR16
*[]){err_str1
, err_str2
, NULL
});
1234 LibDeleteVariable(db_name
, &shim_lock_guid
);
1235 return EFI_ACCESS_DENIED
;
1239 if (!MokListData
|| MokListDataSize
== 0)
1242 /* Construct lists */
1243 mok_num
= count_keys(MokListData
, MokListDataSize
);
1244 mok
= build_mok_list(mok_num
, MokListData
, MokListDataSize
);
1245 del_num
= count_keys(MokDel
, MokDelSize
);
1246 del_key
= build_mok_list(del_num
, MokDel
, MokDelSize
);
1248 /* Search and destroy */
1249 for (i
= 0; i
< del_num
; i
++) {
1250 if (CompareGuid(&(del_key
[i
].Type
), &CertType
) == 0) {
1251 delete_cert(del_key
[i
].Mok
, del_key
[i
].MokSize
,
1253 } else if (is_sha_hash(del_key
[i
].Type
)) {
1254 delete_hash_list(del_key
[i
].Type
, del_key
[i
].Mok
,
1255 del_key
[i
].MokSize
, mok
, mok_num
);
1259 efi_status
= write_back_mok_list(mok
, mok_num
, MokX
);
1262 FreePool(MokListData
);
1271 static INTN
mok_deletion_prompt (void *MokDel
, UINTN MokDelSize
, BOOLEAN MokX
)
1273 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1274 EFI_STATUS efi_status
;
1278 title
= L
"[Delete MOKX]";
1280 title
= L
"[Delete MOK]";
1282 if (list_keys(MokDel
, MokDelSize
, title
) != EFI_SUCCESS
) {
1286 if (console_yes_no((CHAR16
*[]){L
"Delete the key(s)?", NULL
}) == 0)
1289 efi_status
= delete_keys(MokDel
, MokDelSize
, MokX
);
1291 if (efi_status
!= EFI_SUCCESS
) {
1292 console_notify(L
"Failed to delete keys");
1297 LibDeleteVariable(L
"MokXDel", &shim_lock_guid
);
1298 LibDeleteVariable(L
"MokXDelAuth", &shim_lock_guid
);
1300 LibDeleteVariable(L
"MokDel", &shim_lock_guid
);
1301 LibDeleteVariable(L
"MokDelAuth", &shim_lock_guid
);
1304 console_notify(L
"The system must now be rebooted");
1305 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
1306 EFI_SUCCESS
, 0, NULL
);
1307 console_notify(L
"Failed to reboot");
1311 static CHAR16
get_password_charater (CHAR16
*prompt
)
1313 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1321 prompt
= L
"Password charater: ";
1323 console_save_and_set_mode(&SavedMode
);
1325 message
[0] = prompt
;
1327 length
= StrLen(message
[0]);
1328 console_print_box_at(message
, -1, -length
-4, -5, length
+4, 3, 0, 1);
1329 status
= get_line(&pw_length
, &character
, 1, 0);
1330 if (EFI_ERROR(status
))
1333 console_restore_mode(&SavedMode
);
1338 static INTN
mok_sb_prompt (void *MokSB
, UINTN MokSBSize
) {
1339 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1340 EFI_STATUS efi_status
;
1341 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1342 MokSBvar
*var
= MokSB
;
1344 CHAR16 pass1
, pass2
, pass3
;
1346 UINT8 fail_count
= 0;
1348 UINT8 pos1
, pos2
, pos3
;
1351 if (MokSBSize
!= sizeof(MokSBvar
)) {
1352 console_notify(L
"Invalid MokSB variable contents");
1356 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1358 message
[0] = L
"Change Secure Boot state";
1361 console_save_and_set_mode(&SavedMode
);
1362 console_print_box_at(message
, -1, 0, 0, -1, -1, 1, 1);
1363 console_restore_mode(&SavedMode
);
1365 while (fail_count
< 3) {
1366 RandomBytes (&pos1
, sizeof(pos1
));
1367 pos1
= (pos1
% var
->PWLen
);
1370 RandomBytes (&pos2
, sizeof(pos2
));
1371 pos2
= (pos2
% var
->PWLen
);
1372 } while (pos2
== pos1
);
1375 RandomBytes (&pos3
, sizeof(pos3
));
1376 pos3
= (pos3
% var
->PWLen
) ;
1377 } while (pos3
== pos2
|| pos3
== pos1
);
1379 str
= PoolPrint(L
"Enter password character %d: ", pos1
+ 1);
1381 console_errorbox(L
"Failed to allocate buffer");
1384 pass1
= get_password_charater(str
);
1387 str
= PoolPrint(L
"Enter password character %d: ", pos2
+ 1);
1389 console_errorbox(L
"Failed to allocate buffer");
1392 pass2
= get_password_charater(str
);
1395 str
= PoolPrint(L
"Enter password character %d: ", pos3
+ 1);
1397 console_errorbox(L
"Failed to allocate buffer");
1400 pass3
= get_password_charater(str
);
1403 if (pass1
!= var
->Password
[pos1
] ||
1404 pass2
!= var
->Password
[pos2
] ||
1405 pass3
!= var
->Password
[pos3
]) {
1406 Print(L
"Invalid character\n");
1413 if (fail_count
>= 3) {
1414 console_notify(L
"Password limit reached");
1418 if (var
->MokSBState
== 0)
1419 ret
= console_yes_no((CHAR16
*[]){L
"Disable Secure Boot", NULL
});
1421 ret
= console_yes_no((CHAR16
*[]){L
"Enable Secure Boot", NULL
});
1424 LibDeleteVariable(L
"MokSB", &shim_lock_guid
);
1428 if (var
->MokSBState
== 0) {
1429 efi_status
= uefi_call_wrapper(RT
->SetVariable
,
1432 EFI_VARIABLE_NON_VOLATILE
|
1433 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1435 if (efi_status
!= EFI_SUCCESS
) {
1436 console_notify(L
"Failed to set Secure Boot state");
1440 efi_status
= uefi_call_wrapper(RT
->SetVariable
,
1443 EFI_VARIABLE_NON_VOLATILE
|
1444 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1446 if (efi_status
!= EFI_SUCCESS
) {
1447 console_notify(L
"Failed to delete Secure Boot state");
1452 console_notify(L
"The system must now be rebooted");
1453 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
1454 EFI_SUCCESS
, 0, NULL
);
1455 console_notify(L
"Failed to reboot");
1459 static INTN
mok_db_prompt (void *MokDB
, UINTN MokDBSize
) {
1460 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1461 EFI_STATUS efi_status
;
1462 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1463 MokDBvar
*var
= MokDB
;
1465 CHAR16 pass1
, pass2
, pass3
;
1467 UINT8 fail_count
= 0;
1469 UINT8 pos1
, pos2
, pos3
;
1472 if (MokDBSize
!= sizeof(MokDBvar
)) {
1473 console_notify(L
"Invalid MokDB variable contents");
1477 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1479 message
[0] = L
"Change DB state";
1482 console_save_and_set_mode(&SavedMode
);
1483 console_print_box_at(message
, -1, 0, 0, -1, -1, 1, 1);
1484 console_restore_mode(&SavedMode
);
1486 while (fail_count
< 3) {
1487 RandomBytes (&pos1
, sizeof(pos1
));
1488 pos1
= (pos1
% var
->PWLen
);
1491 RandomBytes (&pos2
, sizeof(pos2
));
1492 pos2
= (pos2
% var
->PWLen
);
1493 } while (pos2
== pos1
);
1496 RandomBytes (&pos3
, sizeof(pos3
));
1497 pos3
= (pos3
% var
->PWLen
) ;
1498 } while (pos3
== pos2
|| pos3
== pos1
);
1500 str
= PoolPrint(L
"Enter password character %d: ", pos1
+ 1);
1502 console_errorbox(L
"Failed to allocate buffer");
1505 pass1
= get_password_charater(str
);
1508 str
= PoolPrint(L
"Enter password character %d: ", pos2
+ 1);
1510 console_errorbox(L
"Failed to allocate buffer");
1513 pass2
= get_password_charater(str
);
1516 str
= PoolPrint(L
"Enter password character %d: ", pos3
+ 1);
1518 console_errorbox(L
"Failed to allocate buffer");
1521 pass3
= get_password_charater(str
);
1524 if (pass1
!= var
->Password
[pos1
] ||
1525 pass2
!= var
->Password
[pos2
] ||
1526 pass3
!= var
->Password
[pos3
]) {
1527 Print(L
"Invalid character\n");
1534 if (fail_count
>= 3) {
1535 console_notify(L
"Password limit reached");
1539 if (var
->MokDBState
== 0)
1540 ret
= console_yes_no((CHAR16
*[]){L
"Ignore DB certs/hashes", NULL
});
1542 ret
= console_yes_no((CHAR16
*[]){L
"Use DB certs/hashes", NULL
});
1545 LibDeleteVariable(L
"MokDB", &shim_lock_guid
);
1549 if (var
->MokDBState
== 0) {
1550 efi_status
= uefi_call_wrapper(RT
->SetVariable
,
1553 EFI_VARIABLE_NON_VOLATILE
|
1554 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1556 if (efi_status
!= EFI_SUCCESS
) {
1557 console_notify(L
"Failed to set DB state");
1561 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5,
1564 EFI_VARIABLE_NON_VOLATILE
|
1565 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1567 if (efi_status
!= EFI_SUCCESS
) {
1568 console_notify(L
"Failed to delete DB state");
1573 console_notify(L
"The system must now be rebooted");
1574 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
,
1575 EFI_SUCCESS
, 0, NULL
);
1576 console_notify(L
"Failed to reboot");
1580 static INTN
mok_pw_prompt (void *MokPW
, UINTN MokPWSize
) {
1581 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1582 EFI_STATUS efi_status
;
1583 UINT8 hash
[PASSWORD_CRYPT_SIZE
];
1586 if (MokPWSize
!= SHA256_DIGEST_SIZE
&& MokPWSize
!= PASSWORD_CRYPT_SIZE
) {
1587 console_notify(L
"Invalid MokPW variable contents");
1591 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1593 SetMem(hash
, PASSWORD_CRYPT_SIZE
, 0);
1595 if (MokPWSize
== PASSWORD_CRYPT_SIZE
) {
1596 if (CompareMem(MokPW
, hash
, PASSWORD_CRYPT_SIZE
) == 0)
1599 if (CompareMem(MokPW
, hash
, SHA256_DIGEST_SIZE
) == 0)
1604 if (console_yes_no((CHAR16
*[]){L
"Clear MOK password?", NULL
}) == 0)
1607 uefi_call_wrapper(RT
->SetVariable
, 5, L
"MokPWStore",
1609 EFI_VARIABLE_NON_VOLATILE
1610 | EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1612 LibDeleteVariable(L
"MokPW", &shim_lock_guid
);
1613 console_notify(L
"The system must now be rebooted");
1614 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
, EFI_SUCCESS
, 0,
1616 console_notify(L
"Failed to reboot");
1620 if (MokPWSize
== PASSWORD_CRYPT_SIZE
) {
1621 efi_status
= match_password((PASSWORD_CRYPT
*)MokPW
, NULL
, 0,
1622 NULL
, L
"Confirm MOK passphrase: ");
1624 efi_status
= match_password(NULL
, NULL
, 0, MokPW
,
1625 L
"Confirm MOK passphrase: ");
1628 if (efi_status
!= EFI_SUCCESS
) {
1629 console_notify(L
"Password limit reached");
1633 if (console_yes_no((CHAR16
*[]){L
"Set MOK password?", NULL
}) == 0)
1636 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5,
1639 EFI_VARIABLE_NON_VOLATILE
|
1640 EFI_VARIABLE_BOOTSERVICE_ACCESS
,
1642 if (efi_status
!= EFI_SUCCESS
) {
1643 console_notify(L
"Failed to set MOK password");
1647 LibDeleteVariable(L
"MokPW", &shim_lock_guid
);
1649 console_notify(L
"The system must now be rebooted");
1650 uefi_call_wrapper(RT
->ResetSystem
, 4, EfiResetWarm
, EFI_SUCCESS
, 0,
1652 console_notify(L
"Failed to reboot");
1656 static BOOLEAN
verify_certificate(UINT8
*cert
, UINTN size
)
1660 if (!cert
|| size
< 0)
1664 * A DER encoding x509 certificate starts with SEQUENCE(0x30),
1665 * the number of length bytes, and the number of value bytes.
1666 * The size of a x509 certificate is usually between 127 bytes
1667 * and 64KB. For convenience, assume the number of value bytes
1668 * is 2, i.e. the second byte is 0x82.
1670 if (cert
[0] != 0x30 || cert
[1] != 0x82) {
1671 console_notify(L
"Not a DER encoding X509 certificate");
1675 length
= (cert
[2]<<8 | cert
[3]);
1676 if (length
!= (size
- 4)) {
1677 console_notify(L
"Invalid X509 certificate: Inconsistent size");
1681 if (!(X509ConstructCertificate(cert
, size
, (UINT8
**) &X509Cert
)) ||
1683 console_notify(L
"Invalid X509 certificate");
1687 X509_free(X509Cert
);
1691 static EFI_STATUS
enroll_file (void *data
, UINTN datasize
, BOOLEAN hash
)
1693 EFI_STATUS status
= EFI_SUCCESS
;
1694 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1695 EFI_SIGNATURE_LIST
*CertList
;
1696 EFI_SIGNATURE_DATA
*CertData
;
1697 UINTN mokbuffersize
;
1698 void *mokbuffer
= NULL
;
1701 UINT8 sha256
[SHA256_DIGEST_SIZE
];
1702 UINT8 sha1
[SHA1_DIGEST_SIZE
];
1703 SHIM_LOCK
*shim_lock
;
1704 EFI_GUID shim_guid
= SHIM_LOCK_GUID
;
1705 PE_COFF_LOADER_IMAGE_CONTEXT context
;
1707 status
= LibLocateProtocol(&shim_guid
, (VOID
**)&shim_lock
);
1709 if (status
!= EFI_SUCCESS
)
1712 mokbuffersize
= sizeof(EFI_SIGNATURE_LIST
) + sizeof(EFI_GUID
) +
1715 mokbuffer
= AllocatePool(mokbuffersize
);
1720 status
= shim_lock
->Context(data
, datasize
, &context
);
1722 if (status
!= EFI_SUCCESS
)
1725 status
= shim_lock
->Hash(data
, datasize
, &context
, sha256
,
1728 if (status
!= EFI_SUCCESS
)
1731 CertList
= mokbuffer
;
1732 CertList
->SignatureType
= EFI_CERT_SHA256_GUID
;
1733 CertList
->SignatureSize
= 16 + SHA256_DIGEST_SIZE
;
1734 CertData
= (EFI_SIGNATURE_DATA
*)(((UINT8
*)mokbuffer
) +
1735 sizeof(EFI_SIGNATURE_LIST
));
1736 CopyMem(CertData
->SignatureData
, sha256
, SHA256_DIGEST_SIZE
);
1738 mokbuffersize
= datasize
+ sizeof(EFI_SIGNATURE_LIST
) +
1740 mokbuffer
= AllocatePool(mokbuffersize
);
1745 CertList
= mokbuffer
;
1746 CertList
->SignatureType
= X509_GUID
;
1747 CertList
->SignatureSize
= 16 + datasize
;
1749 memcpy(mokbuffer
+ sizeof(EFI_SIGNATURE_LIST
) + 16, data
,
1752 CertData
= (EFI_SIGNATURE_DATA
*)(((UINT8
*)mokbuffer
) +
1753 sizeof(EFI_SIGNATURE_LIST
));
1756 CertList
->SignatureListSize
= mokbuffersize
;
1757 CertList
->SignatureHeaderSize
= 0;
1758 CertData
->SignatureOwner
= shim_lock_guid
;
1761 if (!verify_certificate(CertData
->SignatureData
, datasize
))
1765 mok_enrollment_prompt(mokbuffer
, mokbuffersize
, FALSE
, FALSE
);
1768 FreePool(mokbuffer
);
1773 static void mok_hash_enroll(void)
1775 EFI_STATUS efi_status
;
1776 CHAR16
*file_name
= NULL
;
1777 EFI_HANDLE im
= NULL
;
1778 EFI_FILE
*file
= NULL
;
1782 simple_file_selector(&im
, (CHAR16
*[]){
1785 L
"The Selected Binary will have its hash Enrolled",
1786 L
"This means it will Subsequently Boot with no prompting",
1787 L
"Remember to make sure it is a genuine binary before Enroling its hash",
1789 }, L
"\\", L
"", &file_name
);
1794 efi_status
= simple_file_open(im
, file_name
, &file
, EFI_FILE_MODE_READ
);
1796 if (efi_status
!= EFI_SUCCESS
) {
1797 console_error(L
"Unable to open file", efi_status
);
1801 simple_file_read_all(file
, &filesize
, &data
);
1802 simple_file_close(file
);
1805 console_error(L
"Unable to read file", efi_status
);
1809 efi_status
= enroll_file(data
, filesize
, TRUE
);
1811 if (efi_status
!= EFI_SUCCESS
)
1812 console_error(L
"Hash failed (did you select a valid EFI binary?)", efi_status
);
1817 static CHAR16
*der_suffix
[] = {
1824 static BOOLEAN
check_der_suffix (CHAR16
*file_name
)
1829 if (!file_name
|| StrLen(file_name
) <= 4)
1833 StrCat(suffix
, file_name
+ StrLen(file_name
) - 4);
1836 for (i
= 0; der_suffix
[i
] != NULL
; i
++) {
1837 if (StrCmp(suffix
, der_suffix
[i
]) == 0) {
1845 static void mok_key_enroll(void)
1847 EFI_STATUS efi_status
;
1848 CHAR16
*file_name
= NULL
;
1849 EFI_HANDLE im
= NULL
;
1850 EFI_FILE
*file
= NULL
;
1854 simple_file_selector(&im
, (CHAR16
*[]){
1857 L
"The selected key will be enrolled into the MOK database",
1858 L
"This means any binaries signed with it will be run without prompting",
1859 L
"Remember to make sure it is a genuine key before Enroling it",
1861 }, L
"\\", L
"", &file_name
);
1866 if (!check_der_suffix(file_name
)) {
1867 console_alertbox((CHAR16
*[]){
1868 L
"Unsupported Format",
1870 L
"Only DER encoded certificate (*.cer/der/crt) is supported",
1875 efi_status
= simple_file_open(im
, file_name
, &file
, EFI_FILE_MODE_READ
);
1877 if (efi_status
!= EFI_SUCCESS
) {
1878 console_error(L
"Unable to open file", efi_status
);
1882 simple_file_read_all(file
, &filesize
, &data
);
1883 simple_file_close(file
);
1886 console_error(L
"Unable to read file", efi_status
);
1890 enroll_file(data
, filesize
, FALSE
);
1894 static BOOLEAN
verify_pw(BOOLEAN
*protected)
1896 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
1897 EFI_STATUS efi_status
;
1898 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1899 UINT8 pwhash
[PASSWORD_CRYPT_SIZE
];
1900 UINTN size
= PASSWORD_CRYPT_SIZE
;
1906 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokPWStore",
1907 &shim_lock_guid
, &attributes
, &size
,
1911 * If anything can attack the password it could just set it to a
1912 * known value, so there's no safety advantage in failing to validate
1913 * purely because of a failure to read the variable
1915 if (efi_status
!= EFI_SUCCESS
||
1916 (size
!= SHA256_DIGEST_SIZE
&& size
!= PASSWORD_CRYPT_SIZE
))
1919 if (attributes
& EFI_VARIABLE_RUNTIME_ACCESS
)
1922 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
1924 /* Draw the background */
1925 console_save_and_set_mode(&SavedMode
);
1926 message
[0] = PoolPrint (L
"%s UEFI key management", SHIM_VENDOR
);
1928 console_print_box_at(message
, -1, 0, 0, -1, -1, 1, 1);
1929 FreePool(message
[0]);
1930 console_restore_mode(&SavedMode
);
1932 if (size
== PASSWORD_CRYPT_SIZE
) {
1933 efi_status
= match_password((PASSWORD_CRYPT
*)pwhash
, NULL
, 0,
1934 NULL
, L
"Enter MOK password:");
1936 efi_status
= match_password(NULL
, NULL
, 0, pwhash
,
1937 L
"Enter MOK password:");
1939 if (efi_status
!= EFI_SUCCESS
) {
1940 console_notify(L
"Password limit reached");
1949 static int draw_countdown()
1951 SIMPLE_TEXT_OUTPUT_MODE SavedMode
;
1956 CHAR16
*message
= L
"Press any key to perform MOK management";
1957 int timeout
= 10, wait
= 10000000;
1959 console_save_and_set_mode (&SavedMode
);
1961 title
[0] = PoolPrint (L
"%s UEFI key management", SHIM_VENDOR
);
1964 console_print_box_at(title
, -1, 0, 0, -1, -1, 1, 1);
1966 uefi_call_wrapper(ST
->ConOut
->QueryMode
, 4, ST
->ConOut
,
1967 ST
->ConOut
->Mode
->Mode
, &cols
, &rows
);
1969 PrintAt((cols
- StrLen(message
))/2, rows
/2, message
);
1972 PrintAt(2, rows
- 3, L
"Booting in %d seconds ", timeout
);
1974 PrintAt(2, rows
- 3, L
"Booting in %d second ", timeout
);
1976 status
= WaitForSingleEvent(ST
->ConIn
->WaitForKey
, wait
);
1978 if (status
!= EFI_TIMEOUT
) {
1979 /* Clear the key in the queue */
1980 uefi_call_wrapper(ST
->ConIn
->ReadKeyStroke
, 2,
1992 console_restore_mode(&SavedMode
);
2012 static EFI_STATUS
enter_mok_menu(EFI_HANDLE image_handle
,
2013 void *MokNew
, UINTN MokNewSize
,
2014 void *MokDel
, UINTN MokDelSize
,
2015 void *MokSB
, UINTN MokSBSize
,
2016 void *MokPW
, UINTN MokPWSize
,
2017 void *MokDB
, UINTN MokDBSize
,
2018 void *MokXNew
, UINTN MokXNewSize
,
2019 void *MokXDel
, UINTN MokXDelSize
)
2021 CHAR16
**menu_strings
;
2022 mok_menu_item
*menu_item
;
2025 UINT32 MokDelAuth
= 0;
2026 UINT32 MokXAuth
= 0;
2027 UINT32 MokXDelAuth
= 0;
2028 UINTN menucount
= 3, i
= 0;
2029 EFI_STATUS efi_status
;
2030 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
2031 UINT8 auth
[PASSWORD_CRYPT_SIZE
];
2032 UINTN auth_size
= PASSWORD_CRYPT_SIZE
;
2035 EFI_STATUS ret
= EFI_SUCCESS
;
2037 if (verify_pw(&protected) == FALSE
)
2038 return EFI_ACCESS_DENIED
;
2040 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokAuth",
2042 &attributes
, &auth_size
, auth
);
2044 if ((efi_status
== EFI_SUCCESS
) &&
2045 (auth_size
== SHA256_DIGEST_SIZE
|| auth_size
== PASSWORD_CRYPT_SIZE
))
2048 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokDelAuth",
2050 &attributes
, &auth_size
, auth
);
2052 if ((efi_status
== EFI_SUCCESS
) &&
2053 (auth_size
== SHA256_DIGEST_SIZE
|| auth_size
== PASSWORD_CRYPT_SIZE
))
2056 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokXAuth",
2058 &attributes
, &auth_size
, auth
);
2060 if ((efi_status
== EFI_SUCCESS
) &&
2061 (auth_size
== SHA256_DIGEST_SIZE
|| auth_size
== PASSWORD_CRYPT_SIZE
))
2064 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokXDelAuth",
2066 &attributes
, &auth_size
, auth
);
2068 if ((efi_status
== EFI_SUCCESS
) &&
2069 (auth_size
== SHA256_DIGEST_SIZE
|| auth_size
== PASSWORD_CRYPT_SIZE
))
2072 if (MokNew
|| MokAuth
)
2075 if (MokDel
|| MokDelAuth
)
2078 if (MokXNew
|| MokXAuth
)
2081 if (MokXDel
|| MokXDelAuth
)
2093 menu_strings
= AllocateZeroPool(sizeof(CHAR16
*) * (menucount
+ 1));
2096 return EFI_OUT_OF_RESOURCES
;
2098 menu_item
= AllocateZeroPool(sizeof(mok_menu_item
) * menucount
);
2101 FreePool(menu_strings
);
2102 return EFI_OUT_OF_RESOURCES
;
2105 menu_strings
[i
] = L
"Continue boot";
2106 menu_item
[i
] = MOK_CONTINUE_BOOT
;
2110 if (MokNew
|| MokAuth
) {
2112 menu_strings
[i
] = L
"Reset MOK";
2113 menu_item
[i
] = MOK_RESET_MOK
;
2115 menu_strings
[i
] = L
"Enroll MOK";
2116 menu_item
[i
] = MOK_ENROLL_MOK
;
2121 if (MokDel
|| MokDelAuth
) {
2122 menu_strings
[i
] = L
"Delete MOK";
2123 menu_item
[i
] = MOK_DELETE_MOK
;
2127 if (MokXNew
|| MokXAuth
) {
2129 menu_strings
[i
] = L
"Reset MOKX";
2130 menu_item
[i
] = MOK_RESET_MOKX
;
2132 menu_strings
[i
] = L
"Enroll MOKX";
2133 menu_item
[i
] = MOK_ENROLL_MOKX
;
2138 if (MokXDel
|| MokXDelAuth
) {
2139 menu_strings
[i
] = L
"Delete MOKX";
2140 menu_item
[i
] = MOK_DELETE_MOKX
;
2145 menu_strings
[i
] = L
"Change Secure Boot state";
2146 menu_item
[i
] = MOK_CHANGE_SB
;
2151 menu_strings
[i
] = L
"Set MOK password";
2152 menu_item
[i
] = MOK_SET_PW
;
2157 menu_strings
[i
] = L
"Change DB state";
2158 menu_item
[i
] = MOK_CHANGE_DB
;
2162 menu_strings
[i
] = L
"Enroll key from disk";
2163 menu_item
[i
] = MOK_KEY_ENROLL
;
2166 menu_strings
[i
] = L
"Enroll hash from disk";
2167 menu_item
[i
] = MOK_HASH_ENROLL
;
2170 menu_strings
[i
] = NULL
;
2172 if (protected == FALSE
&& draw_countdown() == 0)
2175 while (choice
>= 0) {
2176 choice
= console_select((CHAR16
*[]){ L
"Perform MOK management", NULL
},
2182 switch (menu_item
[choice
]) {
2183 case MOK_CONTINUE_BOOT
:
2186 mok_reset_prompt(FALSE
);
2188 case MOK_ENROLL_MOK
:
2189 mok_enrollment_prompt(MokNew
, MokNewSize
, TRUE
, FALSE
);
2191 case MOK_DELETE_MOK
:
2192 mok_deletion_prompt(MokDel
, MokDelSize
, FALSE
);
2194 case MOK_RESET_MOKX
:
2195 mok_reset_prompt(TRUE
);
2197 case MOK_ENROLL_MOKX
:
2198 mok_enrollment_prompt(MokXNew
, MokXNewSize
, TRUE
, TRUE
);
2200 case MOK_DELETE_MOKX
:
2201 mok_deletion_prompt(MokXDel
, MokXDelSize
, TRUE
);
2204 mok_sb_prompt(MokSB
, MokSBSize
);
2207 mok_pw_prompt(MokPW
, MokPWSize
);
2210 mok_db_prompt(MokDB
, MokDBSize
);
2212 case MOK_KEY_ENROLL
:
2215 case MOK_HASH_ENROLL
:
2224 FreePool(menu_strings
);
2227 FreePool(menu_item
);
2232 static EFI_STATUS
check_mok_request(EFI_HANDLE image_handle
)
2234 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
2235 UINTN MokNewSize
= 0, MokDelSize
= 0, MokSBSize
= 0, MokPWSize
= 0;
2236 UINTN MokDBSize
= 0, MokXNewSize
= 0, MokXDelSize
= 0;
2237 void *MokNew
= NULL
;
2238 void *MokDel
= NULL
;
2242 void *MokXNew
= NULL
;
2243 void *MokXDel
= NULL
;
2246 status
= get_variable(L
"MokNew", (UINT8
**)&MokNew
, &MokNewSize
,
2248 if (status
== EFI_SUCCESS
) {
2249 if (LibDeleteVariable(L
"MokNew", &shim_lock_guid
) != EFI_SUCCESS
) {
2250 console_notify(L
"Failed to delete MokNew");
2252 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2253 console_error(L
"Could not retrieve MokNew", status
);
2256 status
= get_variable(L
"MokDel", (UINT8
**)&MokDel
, &MokDelSize
,
2258 if (status
== EFI_SUCCESS
) {
2259 if (LibDeleteVariable(L
"MokDel", &shim_lock_guid
) != EFI_SUCCESS
) {
2260 console_notify(L
"Failed to delete MokDel");
2262 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2263 console_error(L
"Could not retrieve MokDel", status
);
2266 status
= get_variable(L
"MokSB", (UINT8
**)&MokSB
, &MokSBSize
,
2268 if (status
== EFI_SUCCESS
) {
2269 if (LibDeleteVariable(L
"MokSB", &shim_lock_guid
) != EFI_SUCCESS
) {
2270 console_notify(L
"Failed to delete MokSB");
2272 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2273 console_error(L
"Could not retrieve MokSB", status
);
2276 status
= get_variable(L
"MokPW", (UINT8
**)&MokPW
, &MokPWSize
,
2278 if (status
== EFI_SUCCESS
) {
2279 if (LibDeleteVariable(L
"MokPW", &shim_lock_guid
) != EFI_SUCCESS
) {
2280 console_notify(L
"Failed to delete MokPW");
2282 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2283 console_error(L
"Could not retrieve MokPW", status
);
2286 status
= get_variable(L
"MokDB", (UINT8
**)&MokDB
, &MokDBSize
,
2288 if (status
== EFI_SUCCESS
) {
2289 if (LibDeleteVariable(L
"MokDB", &shim_lock_guid
) != EFI_SUCCESS
) {
2290 console_notify(L
"Failed to delete MokDB");
2292 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2293 console_error(L
"Could not retrieve MokDB", status
);
2296 status
= get_variable(L
"MokXNew", (UINT8
**)&MokXNew
, &MokXNewSize
,
2298 if (status
== EFI_SUCCESS
) {
2299 if (LibDeleteVariable(L
"MokXNew", &shim_lock_guid
) != EFI_SUCCESS
) {
2300 console_notify(L
"Failed to delete MokXNew");
2302 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2303 console_error(L
"Could not retrieve MokXNew", status
);
2306 status
= get_variable(L
"MokXDel", (UINT8
**)&MokXDel
, &MokXDelSize
,
2308 if (status
== EFI_SUCCESS
) {
2309 if (LibDeleteVariable(L
"MokXDel", &shim_lock_guid
) != EFI_SUCCESS
) {
2310 console_notify(L
"Failed to delete MokXDel");
2312 } else if (EFI_ERROR(status
) && status
!= EFI_NOT_FOUND
) {
2313 console_error(L
"Could not retrieve MokXDel", status
);
2316 enter_mok_menu(image_handle
, MokNew
, MokNewSize
, MokDel
, MokDelSize
,
2317 MokSB
, MokSBSize
, MokPW
, MokPWSize
, MokDB
, MokDBSize
,
2318 MokXNew
, MokXNewSize
, MokXDel
, MokXDelSize
);
2341 LibDeleteVariable(L
"MokAuth", &shim_lock_guid
);
2342 LibDeleteVariable(L
"MokDelAuth", &shim_lock_guid
);
2343 LibDeleteVariable(L
"MokXAuth", &shim_lock_guid
);
2344 LibDeleteVariable(L
"MokXDelAuth", &shim_lock_guid
);
2349 static EFI_STATUS
setup_rand (void)
2352 EFI_STATUS efi_status
;
2356 efi_status
= uefi_call_wrapper(RT
->GetTime
, 2, &time
, NULL
);
2358 if (efi_status
!= EFI_SUCCESS
)
2361 seed
= ((UINT64
)time
.Year
<< 48) | ((UINT64
)time
.Month
<< 40) |
2362 ((UINT64
)time
.Day
<< 32) | ((UINT64
)time
.Hour
<< 24) |
2363 ((UINT64
)time
.Minute
<< 16) | ((UINT64
)time
.Second
<< 8) |
2364 ((UINT64
)time
.Daylight
);
2366 status
= RandomSeed((UINT8
*)&seed
, sizeof(seed
));
2374 EFI_STATUS
efi_main (EFI_HANDLE image_handle
, EFI_SYSTEM_TABLE
*systab
)
2376 EFI_STATUS efi_status
;
2378 InitializeLib(image_handle
, systab
);
2384 efi_status
= check_mok_request(image_handle
);