3 #include <Library/BaseCryptLib.h>
4 #include <openssl/x509.h>
7 #define PASSWORD_LENGTH 16
14 static EFI_STATUS
get_variable (CHAR16
*name
, EFI_GUID guid
, UINT32
*attributes
,
15 UINTN
*size
, void **buffer
)
17 EFI_STATUS efi_status
;
18 char allocate
= !(*size
);
20 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, name
, &guid
,
21 attributes
, size
, buffer
);
23 if (efi_status
!= EFI_BUFFER_TOO_SMALL
|| !allocate
) {
28 *buffer
= AllocatePool(*size
);
31 Print(L
"Unable to allocate variable buffer\n");
32 return EFI_OUT_OF_RESOURCES
;
35 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, name
, &guid
,
36 attributes
, size
, *buffer
);
41 static EFI_STATUS
delete_variable (CHAR16
*name
, EFI_GUID guid
)
43 EFI_STATUS efi_status
;
45 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, name
, &guid
,
51 static EFI_INPUT_KEY
get_keystroke (void)
56 uefi_call_wrapper(BS
->WaitForEvent
, 3, 1, &ST
->ConIn
->WaitForKey
,
58 uefi_call_wrapper(ST
->ConIn
->ReadKeyStroke
, 2, ST
->ConIn
, &key
);
63 static EFI_STATUS
get_sha256sum (void *Data
, int DataSize
, UINT8
*hash
)
69 ctxsize
= Sha256GetContextSize();
70 ctx
= AllocatePool(ctxsize
);
73 Print(L
"Unable to allocate memory for hash context\n");
74 return EFI_OUT_OF_RESOURCES
;
77 if (!Sha256Init(ctx
)) {
78 Print(L
"Unable to initialise hash\n");
79 status
= EFI_OUT_OF_RESOURCES
;
83 if (!(Sha256Update(ctx
, Data
, DataSize
))) {
84 Print(L
"Unable to generate hash\n");
85 status
= EFI_OUT_OF_RESOURCES
;
89 if (!(Sha256Final(ctx
, hash
))) {
90 Print(L
"Unable to finalise hash\n");
91 status
= EFI_OUT_OF_RESOURCES
;
100 static MokListNode
*build_mok_list(UINT32 num
, void *Data
, UINTN DataSize
) {
102 INT64 remain
= DataSize
;
106 if (DataSize
< sizeof(UINT32
))
109 list
= AllocatePool(sizeof(MokListNode
) * num
);
112 Print(L
"Unable to allocate MOK list\n");
117 for (i
= 0; i
< num
; i
++) {
118 CopyMem(&list
[i
].MokSize
, ptr
, sizeof(UINT32
));
119 remain
-= sizeof(UINT32
) + list
[i
].MokSize
;
122 Print(L
"the list was corrupted\n");
127 ptr
+= sizeof(UINT32
);
129 ptr
+= list
[i
].MokSize
;
135 static void print_x509_name (X509_NAME
*X509Name
, CHAR16
*name
)
139 str
= X509_NAME_oneline(X509Name
, NULL
, 0);
141 Print(L
" %s:\n %a\n", name
, str
);
146 static const char *mon
[12]= {
147 "Jan","Feb","Mar","Apr","May","Jun",
148 "Jul","Aug","Sep","Oct","Nov","Dec"
151 static void print_x509_GENERALIZEDTIME_time (ASN1_TIME
*time
, CHAR16
*time_string
)
156 int y
= 0,M
= 0,d
= 0,h
= 0,m
= 0,s
= 0;
161 v
=(char *)time
->data
;
169 for (i
=0; i
<12; i
++) {
170 if ((v
[i
] > '9') || (v
[i
] < '0'))
174 y
= (v
[0]-'0')*1000+(v
[1]-'0')*100 + (v
[2]-'0')*10+(v
[3]-'0');
175 M
= (v
[4]-'0')*10+(v
[5]-'0');
177 if ((M
> 12) || (M
< 1))
180 d
= (v
[6]-'0')*10+(v
[7]-'0');
181 h
= (v
[8]-'0')*10+(v
[9]-'0');
182 m
= (v
[10]-'0')*10+(v
[11]-'0');
184 if (time
->length
>= 14 &&
185 (v
[12] >= '0') && (v
[12] <= '9') &&
186 (v
[13] >= '0') && (v
[13] <= '9')) {
187 s
= (v
[12]-'0')*10+(v
[13]-'0');
188 /* Check for fractions of seconds. */
189 if (time
->length
>= 15 && v
[14] == '.') {
190 int l
= time
->length
;
191 f
= &v
[14]; /* The decimal point. */
193 while (14 + f_len
< l
&& f
[f_len
] >= '0' &&
199 SPrint(time_string
, 0, L
"%a %2d %02d:%02d:%02d%.*a %d%a",
200 mon
[M
-1], d
, h
, m
, s
, f_len
, f
, y
, (gmt
)?" GMT":"");
205 static void print_x509_UTCTIME_time (ASN1_TIME
*time
, CHAR16
*time_string
)
210 int y
= 0,M
= 0,d
= 0,h
= 0,m
= 0,s
= 0;
213 v
=(char *)time
->data
;
222 if ((v
[i
] > '9') || (v
[i
] < '0'))
225 y
= (v
[0]-'0')*10+(v
[1]-'0');
230 M
= (v
[2]-'0')*10+(v
[3]-'0');
232 if ((M
> 12) || (M
< 1))
235 d
= (v
[4]-'0')*10+(v
[5]-'0');
236 h
= (v
[6]-'0')*10+(v
[7]-'0');
237 m
= (v
[8]-'0')*10+(v
[9]-'0');
239 if (time
->length
>=12 &&
240 (v
[10] >= '0') && (v
[10] <= '9') &&
241 (v
[11] >= '0') && (v
[11] <= '9'))
242 s
= (v
[10]-'0')*10+(v
[11]-'0');
244 SPrint(time_string
, 0, L
"%a %2d %02d:%02d:%02d %d%a",
245 mon
[M
-1], d
, h
, m
, s
, y
+1900, (gmt
)?" GMT":"");
250 static void print_x509_time (ASN1_TIME
*time
, CHAR16
*name
)
252 CHAR16 time_string
[30];
254 if (time
->type
== V_ASN1_UTCTIME
) {
255 print_x509_UTCTIME_time(time
, time_string
);
256 } else if (time
->type
== V_ASN1_GENERALIZEDTIME
) {
257 print_x509_GENERALIZEDTIME_time(time
, time_string
);
259 time_string
[0] = '\0';
262 Print(L
" %s:\n %s\n", name
, time_string
);
265 static void show_x509_info (X509
*X509Cert
)
267 ASN1_INTEGER
*serial
;
269 unsigned char hexbuf
[30];
273 serial
= X509_get_serialNumber(X509Cert
);
276 bnser
= ASN1_INTEGER_to_BN(serial
, NULL
);
277 n
= BN_bn2bin(bnser
, hexbuf
);
278 Print(L
" Serial Number:\n ");
279 for (i
= 0; i
< n
-1; i
++) {
280 Print(L
"%02x:", hexbuf
[i
]);
282 Print(L
"%02x\n", hexbuf
[n
-1]);
285 X509Name
= X509_get_issuer_name(X509Cert
);
287 print_x509_name(X509Name
, L
"Issuer");
290 X509Name
= X509_get_subject_name(X509Cert
);
292 print_x509_name(X509Name
, L
"Subject");
295 time
= X509_get_notBefore(X509Cert
);
297 print_x509_time(time
, L
"Validity from");
300 time
= X509_get_notAfter(X509Cert
);
302 print_x509_time(time
, L
"Validity till");
306 static void show_mok_info (void *Mok
, UINTN MokSize
)
308 EFI_STATUS efi_status
;
309 UINT8 hash
[SHA256_DIGEST_SIZE
];
313 if (!Mok
|| MokSize
== 0)
316 if (X509ConstructCertificate(Mok
, MokSize
, (UINT8
**) &X509Cert
) &&
318 show_x509_info(X509Cert
);
321 Print(L
" Not a valid X509 certificate\n\n");
325 efi_status
= get_sha256sum(Mok
, MokSize
, hash
);
327 if (efi_status
!= EFI_SUCCESS
) {
328 Print(L
"Failed to compute MOK fingerprint\n");
332 Print(L
" Fingerprint (SHA256):\n ");
333 for (i
= 0; i
< SHA256_DIGEST_SIZE
; i
++) {
334 Print(L
" %02x", hash
[i
]);
341 static INTN
get_number ()
343 EFI_INPUT_KEY input_key
;
348 input_key
= get_keystroke();
350 if ((input_key
.UnicodeChar
< '0' ||
351 input_key
.UnicodeChar
> '9' ||
353 input_key
.UnicodeChar
!= CHAR_BACKSPACE
) {
357 if (count
== 0 && input_key
.UnicodeChar
== CHAR_BACKSPACE
)
360 Print(L
"%c", input_key
.UnicodeChar
);
362 if (input_key
.UnicodeChar
== CHAR_BACKSPACE
) {
363 input
[--count
] = '\0';
367 input
[count
++] = input_key
.UnicodeChar
;
368 } while (input_key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
375 return (INTN
)Atoi(input
);
378 static UINT8
list_keys (void *MokNew
, UINTN MokNewSize
)
381 MokListNode
*keys
= NULL
;
385 CopyMem(&MokNum
, MokNew
, sizeof(UINT32
));
387 Print(L
"No key exists\n");
391 keys
= build_mok_list(MokNum
,
392 (void *)MokNew
+ sizeof(UINT32
),
393 MokNewSize
- sizeof(UINT32
));
396 Print(L
"Failed to construct key list in MokNew\n");
401 uefi_call_wrapper(ST
->ConOut
->ClearScreen
, 1, ST
->ConOut
);
402 Print(L
"Input the key number to show the details of the key or\n"
403 L
"type \'0\' to continue\n\n");
404 Print(L
"%d key(s) in the new key list\n\n", MokNum
);
406 if (key_num
> MokNum
) {
407 Print(L
"No such key\n\n");
408 } else if (initial
!= 1){
409 Print(L
"[Key %d]\n", key_num
);
410 show_mok_info(keys
[key_num
-1].Mok
, keys
[key_num
-1].MokSize
);
413 Print(L
"Key Number: ");
415 key_num
= get_number();
423 } while (key_num
!= 0);
430 static UINT8
mok_enrollment_prompt (void *MokNew
, UINTN MokNewSize
)
435 if (!list_keys(MokNew
, MokNewSize
)) {
439 Print(L
"Enroll the key(s) or list the key(s) again? (y/n/l): ");
441 key
= get_keystroke();
442 Print(L
"%c\n", key
.UnicodeChar
);
444 if (key
.UnicodeChar
== 'Y' || key
.UnicodeChar
== 'y') {
447 } while (key
.UnicodeChar
== 'L' || key
.UnicodeChar
== 'l');
454 static UINT8
mok_deletion_prompt () {
457 Print(L
"Erase all stored keys? (y/N): ");
459 key
= get_keystroke();
460 Print(L
"%c\n", key
.UnicodeChar
);
462 if (key
.UnicodeChar
== 'Y' || key
.UnicodeChar
== 'y') {
471 static UINT8
get_password (UINT32
*length
, CHAR16
*password
)
474 CHAR16 input
[PASSWORD_LENGTH
];
478 key
= get_keystroke();
480 if ((count
>= PASSWORD_LENGTH
&&
481 key
.UnicodeChar
!= CHAR_BACKSPACE
) ||
482 key
.UnicodeChar
== CHAR_NULL
||
483 key
.UnicodeChar
== CHAR_TAB
||
484 key
.UnicodeChar
== CHAR_LINEFEED
||
485 key
.UnicodeChar
== CHAR_CARRIAGE_RETURN
) {
489 if (count
== 0 && key
.UnicodeChar
== CHAR_BACKSPACE
) {
491 } else if (key
.UnicodeChar
== CHAR_BACKSPACE
) {
492 Print(L
"%c", CHAR_BACKSPACE
);
493 input
[--count
] = '\0';
497 input
[count
++] = key
.UnicodeChar
;
498 } while (key
.UnicodeChar
!= CHAR_CARRIAGE_RETURN
);
502 CopyMem(password
, input
, count
* sizeof(CHAR16
));
507 static EFI_STATUS
compute_pw_hash (void *MokNew
, UINTN MokNewSize
, CHAR16
*password
,
508 UINT32 pw_length
, UINT8
*hash
)
511 unsigned int ctxsize
;
514 ctxsize
= Sha256GetContextSize();
515 ctx
= AllocatePool(ctxsize
);
518 Print(L
"Unable to allocate memory for hash context\n");
519 return EFI_OUT_OF_RESOURCES
;
522 if (!Sha256Init(ctx
)) {
523 Print(L
"Unable to initialise hash\n");
524 status
= EFI_OUT_OF_RESOURCES
;
528 if (!(Sha256Update(ctx
, MokNew
, MokNewSize
))) {
529 Print(L
"Unable to generate hash\n");
530 status
= EFI_OUT_OF_RESOURCES
;
534 if (!(Sha256Update(ctx
, password
, pw_length
* sizeof(CHAR16
)))) {
535 Print(L
"Unable to generate hash\n");
536 status
= EFI_OUT_OF_RESOURCES
;
540 if (!(Sha256Final(ctx
, hash
))) {
541 Print(L
"Unable to finalise hash\n");
542 status
= EFI_OUT_OF_RESOURCES
;
546 status
= EFI_SUCCESS
;
551 static UINT8
compare_hash (UINT8
*hash1
, UINT8
*hash2
, UINT32 size
)
555 for (i
= 0; i
< size
; i
++) {
556 if (hash1
[i
] != hash2
[i
]) {
564 static EFI_STATUS
store_keys (void *MokNew
, UINTN MokNewSize
)
566 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
567 EFI_STATUS efi_status
;
568 UINT8 hash
[SHA256_DIGEST_SIZE
];
569 UINT8 auth
[SHA256_DIGEST_SIZE
];
572 CHAR16 password
[PASSWORD_LENGTH
];
574 UINT8 fail_count
= 0;
576 auth_size
= SHA256_DIGEST_SIZE
;
577 efi_status
= uefi_call_wrapper(RT
->GetVariable
, 5, L
"MokAuth",
579 &attributes
, &auth_size
, auth
);
582 if (efi_status
!= EFI_SUCCESS
|| auth_size
!= SHA256_DIGEST_SIZE
) {
583 Print(L
"Failed to get MokAuth %d\n", efi_status
);
587 while (fail_count
< 3) {
588 Print(L
"Password: ");
589 get_password(&pw_length
, password
);
592 Print(L
"At least 8 characters for the password\n");
595 efi_status
= compute_pw_hash(MokNew
, MokNewSize
, password
,
598 if (efi_status
!= EFI_SUCCESS
) {
602 if (!compare_hash(auth
, hash
, SHA256_DIGEST_SIZE
)) {
610 return EFI_ACCESS_DENIED
;
613 efi_status
= uefi_call_wrapper(RT
->SetVariable
, 5, L
"MokList",
615 EFI_VARIABLE_NON_VOLATILE
616 | EFI_VARIABLE_BOOTSERVICE_ACCESS
,
618 if (efi_status
!= EFI_SUCCESS
) {
619 Print(L
"Failed to set variable %d\n", efi_status
);
626 static EFI_STATUS
check_mok_request(EFI_HANDLE image_handle
)
628 EFI_GUID shim_lock_guid
= SHIM_LOCK_GUID
;
629 EFI_STATUS efi_status
;
630 UINTN MokNewSize
= 0;
632 UINT32 attributes
, MokNum
;
635 efi_status
= get_variable(L
"MokNew", shim_lock_guid
, &attributes
,
636 &MokNewSize
, &MokNew
);
638 if (efi_status
!= EFI_SUCCESS
|| MokNewSize
< sizeof(UINT32
)) {
642 CopyMem(&MokNum
, MokNew
, sizeof(UINT32
));
644 confirmed
= mok_deletion_prompt();
649 efi_status
= store_keys(MokNew
, sizeof(UINT32
));
651 if (efi_status
!= EFI_SUCCESS
) {
652 Print(L
"Failed to erase keys\n");
656 confirmed
= mok_enrollment_prompt(MokNew
, MokNewSize
);
661 efi_status
= store_keys(MokNew
, MokNewSize
);
663 if (efi_status
!= EFI_SUCCESS
) {
664 Print(L
"Failed to enroll MOK\n");
670 if (delete_variable(L
"MokNew", shim_lock_guid
) != EFI_SUCCESS
) {
671 Print(L
"Failed to delete MokNew\n");
675 delete_variable(L
"MokAuth", shim_lock_guid
);
680 EFI_STATUS
efi_main (EFI_HANDLE image_handle
, EFI_SYSTEM_TABLE
*systab
)
682 EFI_STATUS efi_status
;
684 InitializeLib(image_handle
, systab
);
686 efi_status
= check_mok_request(image_handle
);