~vorlon/ubuntu/yakkety/shim/trunk

41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
1
#include <efi.h>
2
#include <efilib.h>
3
#include <Library/BaseCryptLib.h>
4
#include <openssl/x509.h>
5
#include "shim.h"
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
6
#include "PeImage.h"
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
7
#include "PasswordCrypt.h"
0.1.5 by Steve Langasek
Import upstream version 0.7
8
41.2.152 by Gary Ching-Pang Lin
Merge signature.h into efiauthenticated.h and guid.h
9
#include "guid.h"
10
#include "console.h"
41.2.153 by Gary Ching-Pang Lin
Merge variable retrieving functions
11
#include "variables.h"
41.2.152 by Gary Ching-Pang Lin
Merge signature.h into efiauthenticated.h and guid.h
12
#include "simple_file.h"
13
#include "efiauthenticated.h"
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
14
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
15
#define PASSWORD_MAX 256
16
#define PASSWORD_MIN 1
17
#define SB_PASSWORD_LEN 16
0.1.5 by Steve Langasek
Import upstream version 0.7
18
41.2.146 by Gary Ching-Pang Lin
MokManager: fetch more info from X509 name
19
#define NAME_LINE_MAX 70
20
41.2.52 by Matthew Garrett
Add menu header
21
#ifndef SHIM_VENDOR
22
#define SHIM_VENDOR L"Shim"
23
#endif
24
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
25
#define EFI_VARIABLE_APPEND_WRITE 0x00000040
26
41.2.121 by Peter Jones
We have to declare SHIM_LOCK_GUID here as well.
27
EFI_GUID SHIM_LOCK_GUID = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} };
28
41.3.1 by Matthew Garrett
Add section headers
29
#define CERT_STRING L"Select an X509 certificate to enroll:\n\n"
30
#define HASH_STRING L"Select a file to trust:\n\n"
31
41.2.34 by Matthew Garrett
Add filesystem browsing and enrollment
32
struct menu_item {
33
	CHAR16 *text;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
34
	INTN (* callback)(void *data, void *data2, void *data3);
41.2.34 by Matthew Garrett
Add filesystem browsing and enrollment
35
	void *data;
36
	void *data2;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
37
	void *data3;
41.2.34 by Matthew Garrett
Add filesystem browsing and enrollment
38
	UINTN colour;
39
};
40
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
41
typedef struct {
42
	UINT32 MokSize;
43
	UINT8 *Mok;
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
44
	EFI_GUID Type;
41.2.41 by Matthew Garrett
Add __attribute__ ((packed)) to MokListNode definition
45
} __attribute__ ((packed)) MokListNode;
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
46
41.3.2 by Matthew Garrett
Add support for disabling signature verification
47
typedef struct {
48
	UINT32 MokSBState;
41.3.12 by Matthew Garrett
Update image validation enable/disable
49
	UINT32 PWLen;
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
50
	CHAR16 Password[SB_PASSWORD_LEN];
41.3.2 by Matthew Garrett
Add support for disabling signature verification
51
} __attribute__ ((packed)) MokSBvar;
52
41.2.171 by Josh Boyer
Add support for disabling db for verification
53
typedef struct {
54
	UINT32 MokDBState;
55
	UINT32 PWLen;
56
	CHAR16 Password[SB_PASSWORD_LEN];
57
} __attribute__ ((packed)) MokDBvar;
58
41.2.29 by Gary Ching-Pang Lin
Calculate SHA1 fingerprint
59
static EFI_STATUS get_sha1sum (void *Data, int DataSize, UINT8 *hash)
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
60
{
61
	EFI_STATUS status;
62
	unsigned int ctxsize;
63
	void *ctx = NULL;
64
41.2.29 by Gary Ching-Pang Lin
Calculate SHA1 fingerprint
65
	ctxsize = Sha1GetContextSize();
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
66
	ctx = AllocatePool(ctxsize);
67
68
	if (!ctx) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
69
		console_notify(L"Unable to allocate memory for hash context");
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
70
		return EFI_OUT_OF_RESOURCES;
71
	}
72
41.2.29 by Gary Ching-Pang Lin
Calculate SHA1 fingerprint
73
	if (!Sha1Init(ctx)) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
74
		console_notify(L"Unable to initialise hash");
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
75
		status = EFI_OUT_OF_RESOURCES;
76
		goto done;
77
	}
78
41.2.29 by Gary Ching-Pang Lin
Calculate SHA1 fingerprint
79
	if (!(Sha1Update(ctx, Data, DataSize))) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
80
		console_notify(L"Unable to generate hash");
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
81
		status = EFI_OUT_OF_RESOURCES;
82
		goto done;
83
	}
84
41.2.29 by Gary Ching-Pang Lin
Calculate SHA1 fingerprint
85
	if (!(Sha1Final(ctx, hash))) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
86
		console_notify(L"Unable to finalise hash");
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
87
		status = EFI_OUT_OF_RESOURCES;
88
		goto done;
89
	}
90
91
	status = EFI_SUCCESS;
92
done:
93
	return status;
94
}
95
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
96
static UINT32 count_keys(void *Data, UINTN DataSize)
97
{
98
	EFI_SIGNATURE_LIST *CertList = Data;
41.2.152 by Gary Ching-Pang Lin
Merge signature.h into efiauthenticated.h and guid.h
99
	EFI_GUID CertType = X509_GUID;
100
	EFI_GUID HashType = EFI_CERT_SHA256_GUID;
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
101
	UINTN dbsize = DataSize;
102
	UINT32 MokNum = 0;
41.2.262 by Sebastian Krahmer
OOB access when parsing MOK List/Certificates on MOK enrollment
103
	void *end = Data + DataSize;
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
104
105
	while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
41.2.262 by Sebastian Krahmer
OOB access when parsing MOK List/Certificates on MOK enrollment
106
107
		/* Use ptr arithmetics to ensure bounded access. Do not allow 0
108
		 * SignatureListSize that will cause endless loop.
109
		 */
110
		if ((void *)(CertList + 1) > end || CertList->SignatureListSize == 0) {
111
			console_notify(L"Invalid MOK detected! Ignoring MOK List.");
112
			return 0;
113
		}
114
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
115
		if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
116
		    (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
117
			console_notify(L"Doesn't look like a key or hash");
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
118
			dbsize -= CertList->SignatureListSize;
119
			CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
120
						  CertList->SignatureListSize);
121
			continue;
122
		}
123
124
		if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
125
		    (CertList->SignatureSize != 48)) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
126
			console_notify(L"Doesn't look like a valid hash");
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
127
			dbsize -= CertList->SignatureListSize;
128
			CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
129
						  CertList->SignatureListSize);
130
			continue;
131
		}
132
133
		MokNum++;
134
		dbsize -= CertList->SignatureListSize;
135
		CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
136
						  CertList->SignatureListSize);
137
	}
138
139
	return MokNum;
140
}
141
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
142
static MokListNode *build_mok_list(UINT32 num, void *Data, UINTN DataSize) {
143
	MokListNode *list;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
144
	EFI_SIGNATURE_LIST *CertList = Data;
145
	EFI_SIGNATURE_DATA *Cert;
41.2.152 by Gary Ching-Pang Lin
Merge signature.h into efiauthenticated.h and guid.h
146
	EFI_GUID CertType = X509_GUID;
147
	EFI_GUID HashType = EFI_CERT_SHA256_GUID;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
148
	UINTN dbsize = DataSize;
149
	UINTN count = 0;
41.2.262 by Sebastian Krahmer
OOB access when parsing MOK List/Certificates on MOK enrollment
150
	void *end = Data + DataSize;
41.2.19 by Gary Ching-Pang Lin
Make sure the variables are not broken
151
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
152
	list = AllocatePool(sizeof(MokListNode) * num);
153
154
	if (!list) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
155
		console_notify(L"Unable to allocate MOK list");
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
156
		return NULL;
157
	}
158
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
159
	while ((dbsize > 0) && (dbsize >= CertList->SignatureListSize)) {
41.2.262 by Sebastian Krahmer
OOB access when parsing MOK List/Certificates on MOK enrollment
160
		/* CertList out of bounds? */
161
		if ((void *)(CertList + 1) > end || CertList->SignatureListSize == 0) {
162
			FreePool(list);
163
			return NULL;
164
		}
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
165
		if ((CompareGuid (&CertList->SignatureType, &CertType) != 0) &&
166
		    (CompareGuid (&CertList->SignatureType, &HashType) != 0)) {
167
			dbsize -= CertList->SignatureListSize;
168
			CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList +
41.3.9 by Matthew Garrett
Fix key database parsing
169
						  CertList->SignatureListSize);
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
170
			continue;
171
		}
172
173
		if ((CompareGuid (&CertList->SignatureType, &HashType) == 0) &&
174
		    (CertList->SignatureSize != 48)) {
175
			dbsize -= CertList->SignatureListSize;
176
			CertList = (EFI_SIGNATURE_LIST *)((UINT8 *) CertList +
41.3.9 by Matthew Garrett
Fix key database parsing
177
						  CertList->SignatureListSize);
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
178
			continue;
179
		}
180
181
		Cert = (EFI_SIGNATURE_DATA *) (((UINT8 *) CertList) +
182
		  sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
183
41.2.262 by Sebastian Krahmer
OOB access when parsing MOK List/Certificates on MOK enrollment
184
		/* Cert out of bounds? */
185
		if ((void *)(Cert + 1) > end || CertList->SignatureSize <= sizeof(EFI_GUID)) {
186
			FreePool(list);
187
			return NULL;
188
		}
189
41.2.70 by Gary Ching-Pang Lin
MOK doesn't include the signature owner
190
		list[count].MokSize = CertList->SignatureSize - sizeof(EFI_GUID);
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
191
		list[count].Mok = (void *)Cert->SignatureData;
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
192
		list[count].Type = CertList->SignatureType;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
193
41.2.262 by Sebastian Krahmer
OOB access when parsing MOK List/Certificates on MOK enrollment
194
		/* MOK out of bounds? */
41.2.263 by Peter Jones
Make another integer compare be signed/unsigned safe as well.
195
		if (list[count].MokSize > (unsigned long)end -
196
					  (unsigned long)list[count].Mok) {
41.2.262 by Sebastian Krahmer
OOB access when parsing MOK List/Certificates on MOK enrollment
197
			FreePool(list);
198
			return NULL;
199
		}
200
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
201
		count++;
202
		dbsize -= CertList->SignatureListSize;
203
		CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList +
41.3.9 by Matthew Garrett
Fix key database parsing
204
						  CertList->SignatureListSize);
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
205
	}
206
207
	return list;
208
}
209
41.2.146 by Gary Ching-Pang Lin
MokManager: fetch more info from X509 name
210
typedef struct {
211
	int nid;
212
	CHAR16 *name;
213
} NidName;
214
215
static NidName nidname[] = {
216
	{NID_commonName, L"CN"},
217
	{NID_organizationName, L"O"},
218
	{NID_countryName, L"C"},
219
	{NID_stateOrProvinceName, L"ST"},
220
	{NID_localityName, L"L"},
221
	{-1, NULL}
222
};
223
224
static CHAR16* get_x509_name (X509_NAME *X509Name)
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
225
{
41.2.146 by Gary Ching-Pang Lin
MokManager: fetch more info from X509 name
226
	CHAR16 name[NAME_LINE_MAX+1];
227
	CHAR16 part[NAME_LINE_MAX+1];
228
	char str[NAME_LINE_MAX];
229
	int i, len, rest, first;
230
231
	name[0] = '\0';
232
	rest = NAME_LINE_MAX;
233
	first = 1;
234
	for (i = 0; nidname[i].name != NULL; i++) {
235
		int add;
236
		len = X509_NAME_get_text_by_NID (X509Name, nidname[i].nid,
237
						 str, NAME_LINE_MAX);
238
		if (len <= 0)
239
			continue;
240
241
		if (first)
242
			add = len + (int)StrLen(nidname[i].name) + 1;
243
		else
244
			add = len + (int)StrLen(nidname[i].name) + 3;
245
246
		if (add > rest)
247
			continue;
248
249
		if (first) {
250
			SPrint(part, NAME_LINE_MAX * sizeof(CHAR16), L"%s=%a",
251
			       nidname[i].name, str);
252
		} else {
253
			SPrint(part, NAME_LINE_MAX * sizeof(CHAR16), L", %s=%a",
254
			       nidname[i].name, str);
255
		}
256
		StrCat(name, part);
257
		rest -= add;
258
		first = 0;
259
	}
260
261
	if (rest >= 0 && rest < NAME_LINE_MAX)
262
		return PoolPrint(L"%s", name);
263
264
	return NULL;
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
265
}
266
267
static CHAR16* get_x509_time (ASN1_TIME *time)
268
{
269
	BIO *bio = BIO_new (BIO_s_mem());
270
	char str[30];
271
	int len;
272
273
	ASN1_TIME_print (bio, time);
274
	len = BIO_read(bio, str, 29);
275
	if (len < 0)
276
		len = 0;
277
	str[len] = '\0';
278
	BIO_free (bio);
279
280
	return PoolPrint(L"%a", str);
0.1.5 by Steve Langasek
Import upstream version 0.7
281
}
282
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
283
static void show_x509_info (X509 *X509Cert, UINT8 *hash)
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
284
{
41.2.14 by Gary Ching-Pang Lin
Improve the layout of the key info
285
	ASN1_INTEGER *serial;
286
	BIGNUM *bnser;
287
	unsigned char hexbuf[30];
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
288
	X509_NAME *X509Name;
289
	ASN1_TIME *time;
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
290
	CHAR16 *issuer = NULL;
291
	CHAR16 *subject = NULL;
292
	CHAR16 *from = NULL;
293
	CHAR16 *until = NULL;
294
	POOL_PRINT hash_string1;
295
	POOL_PRINT hash_string2;
296
	POOL_PRINT serial_string;
297
	int fields = 0;
298
	CHAR16 **text;
299
	int i = 0;
300
301
	ZeroMem(&hash_string1, sizeof(hash_string1));
302
	ZeroMem(&hash_string2, sizeof(hash_string2));
303
	ZeroMem(&serial_string, sizeof(serial_string));
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
304
41.2.14 by Gary Ching-Pang Lin
Improve the layout of the key info
305
	serial = X509_get_serialNumber(X509Cert);
306
	if (serial) {
307
		int i, n;
308
		bnser = ASN1_INTEGER_to_BN(serial, NULL);
309
		n = BN_bn2bin(bnser, hexbuf);
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
310
		for (i = 0; i < n; i++) {
311
			CatPrint(&serial_string, L"%02x:", hexbuf[i]);
41.2.14 by Gary Ching-Pang Lin
Improve the layout of the key info
312
		}
313
	}
314
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
315
	if (serial_string.str)
316
		fields++;
317
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
318
	X509Name = X509_get_issuer_name(X509Cert);
319
	if (X509Name) {
41.2.146 by Gary Ching-Pang Lin
MokManager: fetch more info from X509 name
320
		issuer = get_x509_name(X509Name);
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
321
		if (issuer)
322
			fields++;
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
323
	}
324
325
	X509Name = X509_get_subject_name(X509Cert);
326
	if (X509Name) {
41.2.146 by Gary Ching-Pang Lin
MokManager: fetch more info from X509 name
327
		subject = get_x509_name(X509Name);
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
328
		if (subject)
329
			fields++;
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
330
	}
331
332
	time = X509_get_notBefore(X509Cert);
333
	if (time) {
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
334
		from = get_x509_time(time);
335
		if (from)
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
336
			fields++;
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
337
	}
338
339
	time = X509_get_notAfter(X509Cert);
340
	if (time) {
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
341
		until = get_x509_time(time);
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
342
		if (until)
343
			fields++;
344
	}
345
346
	for (i=0; i<10; i++)
347
		CatPrint(&hash_string1, L"%02x ", hash[i]);
348
	for (i=10; i<20; i++)
349
		CatPrint(&hash_string2, L"%02x ", hash[i]);
350
351
	if (hash_string1.str)
352
		fields++;
353
354
	if (hash_string2.str)
355
		fields++;
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
356
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
357
	if (!fields)
358
		return;
359
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
360
	i = 0;
361
	text = AllocateZeroPool(sizeof(CHAR16 *) * (fields*3 + 1));
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
362
	if (serial_string.str) {
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
363
		text[i++] = StrDuplicate(L"[Serial Number]");
364
		text[i++] = serial_string.str;
365
		text[i++] = StrDuplicate(L"");
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
366
	}
367
	if (issuer) {
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
368
		text[i++] = StrDuplicate(L"[Issuer]");
369
		text[i++] = issuer;
370
		text[i++] = StrDuplicate(L"");
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
371
	}
372
	if (subject) {
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
373
		text[i++] = StrDuplicate(L"[Subject]");
374
		text[i++] = subject;
375
		text[i++] = StrDuplicate(L"");
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
376
	}
377
	if (from) {
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
378
		text[i++] = StrDuplicate(L"[Valid Not Before]");
379
		text[i++] = from;
380
		text[i++] = StrDuplicate(L"");
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
381
	}
382
	if (until) {
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
383
		text[i++] = StrDuplicate(L"[Valid Not After]");
384
		text[i++] = until;
385
		text[i++] = StrDuplicate(L"");
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
386
	}
387
	if (hash_string1.str) {
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
388
		text[i++] = StrDuplicate(L"[Fingerprint]");
389
		text[i++] = hash_string1.str;
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
390
	}
391
	if (hash_string2.str) {
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
392
		text[i++] = hash_string2.str;
393
		text[i++] = StrDuplicate(L"");
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
394
	}
395
	text[i] = NULL;
396
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
397
	console_print_box(text, -1);
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
398
399
	for (i=0; text[i] != NULL; i++)
400
		FreePool(text[i]);
401
402
	FreePool(text);
0.1.5 by Steve Langasek
Import upstream version 0.7
403
}
404
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
405
static void show_efi_hash (UINT8 *hash)
406
{
407
	CHAR16 *text[5];
408
	POOL_PRINT hash_string1;
409
	POOL_PRINT hash_string2;
410
	int i;
411
412
	ZeroMem(&hash_string1, sizeof(hash_string1));
413
	ZeroMem(&hash_string2, sizeof(hash_string2));
414
415
	text[0] = L"SHA256 hash";
416
	text[1] = L"";
417
418
	for (i=0; i<16; i++)
419
		CatPrint(&hash_string1, L"%02x ", hash[i]);
420
	for (i=16; i<32; i++)
421
		CatPrint(&hash_string2, L"%02x ", hash[i]);
422
423
	text[2] = hash_string1.str;
424
	text[3] = hash_string2.str;
425
	text[4] = NULL;
426
427
	console_print_box(text, -1);
428
429
	if (hash_string1.str)
430
		FreePool(hash_string1.str);
431
432
	if (hash_string2.str)
433
		FreePool(hash_string2.str);
434
}
435
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
436
static void show_mok_info (void *Mok, UINTN MokSize)
437
{
438
	EFI_STATUS efi_status;
41.2.29 by Gary Ching-Pang Lin
Calculate SHA1 fingerprint
439
	UINT8 hash[SHA1_DIGEST_SIZE];
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
440
	X509 *X509Cert;
441
442
	if (!Mok || MokSize == 0)
443
		return;
444
41.2.70 by Gary Ching-Pang Lin
MOK doesn't include the signature owner
445
	if (MokSize != SHA256_DIGEST_SIZE) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
446
		efi_status = get_sha1sum(Mok, MokSize, hash);
447
448
		if (efi_status != EFI_SUCCESS) {
449
			console_notify(L"Failed to compute MOK fingerprint");
450
			return;
451
		}
452
41.3.7 by Matthew Garrett
Don't print SHA1 sum when calculating file fingerprints
453
		if (X509ConstructCertificate(Mok, MokSize,
454
				 (UINT8 **) &X509Cert) && X509Cert != NULL) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
455
			show_x509_info(X509Cert, hash);
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
456
			X509_free(X509Cert);
457
		} else {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
458
			console_notify(L"Not a valid X509 certificate");
459
			return;
41.3.7 by Matthew Garrett
Don't print SHA1 sum when calculating file fingerprints
460
		}
41.2.14 by Gary Ching-Pang Lin
Improve the layout of the key info
461
	} else {
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
462
		show_efi_hash(Mok);
41.2.14 by Gary Ching-Pang Lin
Improve the layout of the key info
463
	}
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
464
}
465
466
static EFI_STATUS list_keys (void *KeyList, UINTN KeyListSize, CHAR16 *title)
41.2.11 by Gary Ching-Pang Lin
Simplify the key management
467
{
41.2.253 by Peter Jones
Make list_keys() index variables all be signed.
468
	INTN MokNum = 0;
41.2.11 by Gary Ching-Pang Lin
Simplify the key management
469
	MokListNode *keys = NULL;
41.2.16 by Gary Ching-Pang Lin
Make the key list interactive
470
	INTN key_num = 0;
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
471
	CHAR16 **menu_strings;
41.2.253 by Peter Jones
Make list_keys() index variables all be signed.
472
	int i;
41.2.11 by Gary Ching-Pang Lin
Simplify the key management
473
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
474
	if (KeyListSize < (sizeof(EFI_SIGNATURE_LIST) +
475
			   sizeof(EFI_SIGNATURE_DATA))) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
476
		console_notify(L"No MOK keys found");
41.2.18 by Gary Ching-Pang Lin
Allow the new keys to be listed again
477
		return 0;
41.2.11 by Gary Ching-Pang Lin
Simplify the key management
478
	}
479
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
480
	MokNum = count_keys(KeyList, KeyListSize);
41.2.262 by Sebastian Krahmer
OOB access when parsing MOK List/Certificates on MOK enrollment
481
	if (MokNum == 0)
482
		return 0;
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
483
	keys = build_mok_list(MokNum, KeyList, KeyListSize);
41.2.11 by Gary Ching-Pang Lin
Simplify the key management
484
485
	if (!keys) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
486
		console_notify(L"Failed to construct key list");
41.2.18 by Gary Ching-Pang Lin
Allow the new keys to be listed again
487
		return 0;
41.2.11 by Gary Ching-Pang Lin
Simplify the key management
488
	}
489
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
490
	menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (MokNum + 2));
491
492
	if (!menu_strings)
493
		return EFI_OUT_OF_RESOURCES;
494
495
	for (i=0; i<MokNum; i++) {
496
		menu_strings[i] = PoolPrint(L"View key %d", i);
497
	}
498
	menu_strings[i] = StrDuplicate(L"Continue");
499
500
	menu_strings[i+1] = NULL;
501
502
	while (key_num < MokNum) {
503
		key_num = console_select((CHAR16 *[]){ title, NULL },
504
					 menu_strings, 0);
505
41.2.143 by Gary Ching-Pang Lin
MokManager: rearrange the output of MOK info
506
		if (key_num < 0)
507
			break;
508
		else if (key_num < MokNum)
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
509
			show_mok_info(keys[key_num].Mok, keys[key_num].MokSize);
510
	}
511
512
	for (i=0; menu_strings[i] != NULL; i++)
513
		FreePool(menu_strings[i]);
514
515
	FreePool(menu_strings);
41.2.11 by Gary Ching-Pang Lin
Simplify the key management
516
41.2.18 by Gary Ching-Pang Lin
Allow the new keys to be listed again
517
	FreePool(keys);
41.2.11 by Gary Ching-Pang Lin
Simplify the key management
518
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
519
	return EFI_SUCCESS;
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
520
}
521
41.2.224 by Gary Ching-Pang Lin
MokManager: handle the error status from ReadKeyStroke
522
static EFI_STATUS get_line (UINT32 *length, CHAR16 *line, UINT32 line_max, UINT8 show)
41.2.32 by Gary Ching-Pang Lin
Use the same function to get commands and password
523
{
524
	EFI_INPUT_KEY key;
41.2.224 by Gary Ching-Pang Lin
MokManager: handle the error status from ReadKeyStroke
525
	EFI_STATUS status;
41.2.214 by Kees Cook
additional bounds-checking on section sizes
526
	unsigned int count = 0;
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
527
528
	do {
41.2.224 by Gary Ching-Pang Lin
MokManager: handle the error status from ReadKeyStroke
529
		status = console_get_keystroke(&key);
530
		if (EFI_ERROR (status)) {
531
			console_error(L"Failed to read the keystroke", status);
532
			*length = 0;
533
			return status;
534
		}
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
535
41.2.32 by Gary Ching-Pang Lin
Use the same function to get commands and password
536
		if ((count >= line_max &&
41.2.22 by Gary Ching-Pang Lin
Define the max length of password
537
		     key.UnicodeChar != CHAR_BACKSPACE) ||
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
538
		    key.UnicodeChar == CHAR_NULL ||
539
		    key.UnicodeChar == CHAR_TAB  ||
41.2.25 by Gary Ching-Pang Lin
Filter out newline from the password array
540
		    key.UnicodeChar == CHAR_LINEFEED ||
541
		    key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
542
			continue;
543
		}
544
545
		if (count == 0 && key.UnicodeChar == CHAR_BACKSPACE) {
546
			continue;
547
		} else if (key.UnicodeChar == CHAR_BACKSPACE) {
41.2.32 by Gary Ching-Pang Lin
Use the same function to get commands and password
548
			if (show) {
549
				Print(L"\b");
550
			}
551
			line[--count] = '\0';
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
552
			continue;
553
		}
554
41.2.32 by Gary Ching-Pang Lin
Use the same function to get commands and password
555
		if (show) {
556
			Print(L"%c", key.UnicodeChar);
557
		}
558
559
		line[count++] = key.UnicodeChar;
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
560
	} while (key.UnicodeChar != CHAR_CARRIAGE_RETURN);
561
	Print(L"\n");
562
563
	*length = count;
564
41.2.224 by Gary Ching-Pang Lin
MokManager: handle the error status from ReadKeyStroke
565
	return EFI_SUCCESS;
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
566
}
567
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
568
static EFI_STATUS compute_pw_hash (void *Data, UINTN DataSize, UINT8 *password,
569
				   UINT32 pw_length, UINT8 *hash)
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
570
{
571
	EFI_STATUS status;
572
	unsigned int ctxsize;
573
	void *ctx = NULL;
574
575
	ctxsize = Sha256GetContextSize();
576
	ctx = AllocatePool(ctxsize);
577
578
	if (!ctx) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
579
		console_notify(L"Unable to allocate memory for hash context");
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
580
		return EFI_OUT_OF_RESOURCES;
581
	}
582
583
	if (!Sha256Init(ctx)) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
584
		console_notify(L"Unable to initialise hash");
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
585
		status = EFI_OUT_OF_RESOURCES;
586
		goto done;
587
	}
588
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
589
	if (Data && DataSize) {
590
		if (!(Sha256Update(ctx, Data, DataSize))) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
591
			console_notify(L"Unable to generate hash");
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
592
			status = EFI_OUT_OF_RESOURCES;
593
			goto done;
594
		}
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
595
	}
596
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
597
	if (!(Sha256Update(ctx, password, pw_length))) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
598
		console_notify(L"Unable to generate hash");
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
599
		status = EFI_OUT_OF_RESOURCES;
600
		goto done;
601
	}
602
603
	if (!(Sha256Final(ctx, hash))) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
604
		console_notify(L"Unable to finalise hash");
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
605
		status = EFI_OUT_OF_RESOURCES;
606
		goto done;
607
	}
608
609
	status = EFI_SUCCESS;
610
done:
611
	return status;
612
}
613
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
614
static void console_save_and_set_mode (SIMPLE_TEXT_OUTPUT_MODE *SavedMode)
615
{
616
	if (!SavedMode) {
617
		Print(L"Invalid parameter: SavedMode\n");
618
		return;
619
	}
620
621
	CopyMem(SavedMode, ST->ConOut->Mode, sizeof(SIMPLE_TEXT_OUTPUT_MODE));
622
	uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut, FALSE);
623
	uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
624
			  EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE);
625
}
626
627
static void console_restore_mode (SIMPLE_TEXT_OUTPUT_MODE *SavedMode)
628
{
629
	uefi_call_wrapper(ST->ConOut->EnableCursor, 2, ST->ConOut,
630
			  SavedMode->CursorVisible);
631
	uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut,
632
			  SavedMode->CursorColumn, SavedMode->CursorRow);
633
	uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut,
634
			  SavedMode->Attribute);
635
}
636
637
static UINT32 get_password (CHAR16 *prompt, CHAR16 *password, UINT32 max)
638
{
639
	SIMPLE_TEXT_OUTPUT_MODE SavedMode;
640
	CHAR16 *str;
641
	CHAR16 *message[2];
642
	UINTN length;
643
	UINT32 pw_length;
644
645
	if (!prompt)
646
		prompt = L"Password:";
647
648
	console_save_and_set_mode(&SavedMode);
649
650
	str = PoolPrint(L"%s            ", prompt);
651
	if (!str) {
652
		console_errorbox(L"Failed to allocate prompt");
653
		return 0;
654
	}
655
656
	message[0] = str;
657
	message[1] = NULL;
658
	length = StrLen(message[0]);
659
	console_print_box_at(message, -1, -length-4, -5, length+4, 3, 0, 1);
660
	get_line(&pw_length, password, max, 0);
661
662
	console_restore_mode(&SavedMode);
663
664
	FreePool(str);
665
666
	return pw_length;
667
}
668
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
669
static EFI_STATUS match_password (PASSWORD_CRYPT *pw_crypt,
670
				  void *Data, UINTN DataSize,
671
				  UINT8 *auth, CHAR16 *prompt)
0.1.5 by Steve Langasek
Import upstream version 0.7
672
{
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
673
	EFI_STATUS status;
41.2.128 by Gary Ching-Pang Lin
MokManager: support SHA512-based crypt() hash
674
	UINT8 hash[128];
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
675
	UINT8 *auth_hash;
676
	UINT32 auth_size;
41.2.69 by Gary Ching-Pang Lin
Add a general function for password matching
677
	CHAR16 password[PASSWORD_MAX];
678
	UINT32 pw_length;
679
	UINT8 fail_count = 0;
41.2.214 by Kees Cook
additional bounds-checking on section sizes
680
	unsigned int i;
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
681
682
	if (pw_crypt) {
41.2.128 by Gary Ching-Pang Lin
MokManager: support SHA512-based crypt() hash
683
		auth_hash = pw_crypt->hash;
684
		auth_size = get_hash_size (pw_crypt->method);
685
		if (auth_size == 0)
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
686
			return EFI_INVALID_PARAMETER;
687
	} else if (auth) {
688
		auth_hash = auth;
689
		auth_size = SHA256_DIGEST_SIZE;
690
	} else {
691
		return EFI_INVALID_PARAMETER;
692
	}
41.2.69 by Gary Ching-Pang Lin
Add a general function for password matching
693
694
	while (fail_count < 3) {
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
695
		pw_length = get_password(prompt, password, PASSWORD_MAX);
41.2.69 by Gary Ching-Pang Lin
Add a general function for password matching
696
697
		if (pw_length < PASSWORD_MIN || pw_length > PASSWORD_MAX) {
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
698
			console_errorbox(L"Invalid password length");
0.1.5 by Steve Langasek
Import upstream version 0.7
699
			fail_count++;
700
			continue;
701
		}
702
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
703
		/*
704
		 * Compute password hash
705
		 */
706
		if (pw_crypt) {
707
			char pw_ascii[PASSWORD_MAX + 1];
708
			for (i = 0; i < pw_length; i++)
709
				pw_ascii[i] = (char)password[i];
710
			pw_ascii[pw_length] = '\0';
0.1.5 by Steve Langasek
Import upstream version 0.7
711
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
712
			status = password_crypt(pw_ascii, pw_length, pw_crypt, hash);
713
		} else {
714
			/*
715
			 * For backward compatibility
716
			 */
717
			status = compute_pw_hash(Data, DataSize, (UINT8 *)password,
718
						 pw_length * sizeof(CHAR16), hash);
719
		}
720
		if (status != EFI_SUCCESS) {
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
721
			console_errorbox(L"Unable to generate password hash");
0.1.5 by Steve Langasek
Import upstream version 0.7
722
			fail_count++;
723
			continue;
724
		}
725
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
726
		if (CompareMem(auth_hash, hash, auth_size) != 0) {
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
727
			console_errorbox(L"Password doesn't match");
41.2.69 by Gary Ching-Pang Lin
Add a general function for password matching
728
			fail_count++;
729
			continue;
730
		}
731
732
		break;
733
	}
734
735
	if (fail_count >= 3)
736
		return EFI_ACCESS_DENIED;
737
738
	return EFI_SUCCESS;
739
}
740
41.2.42 by Matthew Garrett
Add an auth argument to store_keys()
741
static EFI_STATUS store_keys (void *MokNew, UINTN MokNewSize, int authenticate)
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
742
{
743
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
744
	EFI_STATUS efi_status;
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
745
	UINT8 auth[PASSWORD_CRYPT_SIZE];
746
	UINTN auth_size = PASSWORD_CRYPT_SIZE;
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
747
	UINT32 attributes;
748
41.2.42 by Matthew Garrett
Add an auth argument to store_keys()
749
	if (authenticate) {
750
		efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
751
					       &shim_lock_guid,
752
					       &attributes, &auth_size, auth);
753
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
754
		if (efi_status != EFI_SUCCESS ||
755
		    (auth_size != SHA256_DIGEST_SIZE &&
756
		     auth_size != PASSWORD_CRYPT_SIZE)) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
757
			console_error(L"Failed to get MokAuth", efi_status);
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
758
			return efi_status;
759
		}
760
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
761
		if (auth_size == PASSWORD_CRYPT_SIZE) {
762
			efi_status = match_password((PASSWORD_CRYPT *)auth,
763
						    NULL, 0, NULL, NULL);
764
		} else {
765
			efi_status = match_password(NULL, MokNew, MokNewSize,
766
						    auth, NULL);
767
		}
41.2.69 by Gary Ching-Pang Lin
Add a general function for password matching
768
		if (efi_status != EFI_SUCCESS)
41.2.42 by Matthew Garrett
Add an auth argument to store_keys()
769
			return EFI_ACCESS_DENIED;
41.2.21 by Gary Ching-Pang Lin
Request a password to verify the key list
770
	}
771
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
772
	if (!MokNewSize) {
773
		/* Delete MOK */
774
		efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
775
					       &shim_lock_guid,
776
					       EFI_VARIABLE_NON_VOLATILE
41.3.11 by Matthew Garrett
Delete MokList properly
777
					       | EFI_VARIABLE_BOOTSERVICE_ACCESS,
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
778
					       0, NULL);
779
	} else {
780
		/* Write new MOK */
781
		efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
782
					       &shim_lock_guid,
783
					       EFI_VARIABLE_NON_VOLATILE
784
					       | EFI_VARIABLE_BOOTSERVICE_ACCESS
785
					       | EFI_VARIABLE_APPEND_WRITE,
786
					       MokNewSize, MokNew);
787
	}
788
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
789
	if (efi_status != EFI_SUCCESS) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
790
		console_error(L"Failed to set variable", efi_status);
41.2.20 by Gary Ching-Pang Lin
Erase stored keys when there is no key in the new key list
791
		return efi_status;
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
792
	}
793
41.2.20 by Gary Ching-Pang Lin
Erase stored keys when there is no key in the new key list
794
	return EFI_SUCCESS;
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
795
}
796
41.2.42 by Matthew Garrett
Add an auth argument to store_keys()
797
static UINTN mok_enrollment_prompt (void *MokNew, UINTN MokNewSize, int auth) {
41.2.68 by Gary Ching-Pang Lin
Reboot the system after enrolling/erasing keys
798
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
799
	EFI_STATUS efi_status;
800
801
	if (list_keys(MokNew, MokNewSize, L"[Enroll MOK]") != EFI_SUCCESS)
802
		return 0;
803
804
	if (console_yes_no((CHAR16 *[]){L"Enroll the key(s)?", NULL}) == 0)
805
		return 0;
806
807
	efi_status = store_keys(MokNew, MokNewSize, auth);
808
809
	if (efi_status != EFI_SUCCESS) {
810
		console_notify(L"Failed to enroll keys\n");
811
		return -1;
812
	}
813
814
	if (auth) {
41.2.68 by Gary Ching-Pang Lin
Reboot the system after enrolling/erasing keys
815
		LibDeleteVariable(L"MokNew", &shim_lock_guid);
816
		LibDeleteVariable(L"MokAuth", &shim_lock_guid);
817
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
818
		console_notify(L"The system must now be rebooted");
41.2.68 by Gary Ching-Pang Lin
Reboot the system after enrolling/erasing keys
819
		uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
820
				  EFI_SUCCESS, 0, NULL);
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
821
		console_notify(L"Failed to reboot");
41.2.68 by Gary Ching-Pang Lin
Reboot the system after enrolling/erasing keys
822
		return -1;
41.2.34 by Matthew Garrett
Add filesystem browsing and enrollment
823
	}
824
825
	return 0;
826
}
827
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
828
static INTN mok_reset_prompt ()
829
{
830
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
831
	EFI_STATUS efi_status;
832
833
	uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
834
835
	if (console_yes_no((CHAR16 *[]){L"Erase all stored keys?", NULL }) == 0)
836
		return 0;
837
838
	efi_status = store_keys(NULL, 0, TRUE);
839
840
	if (efi_status != EFI_SUCCESS) {
841
		console_notify(L"Failed to erase keys\n");
842
		return -1;
843
	}
844
845
	LibDeleteVariable(L"MokNew", &shim_lock_guid);
846
	LibDeleteVariable(L"MokAuth", &shim_lock_guid);
847
848
	console_notify(L"The system must now be rebooted");
849
	uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
850
			  EFI_SUCCESS, 0, NULL);
851
	console_notify(L"Failed to reboot\n");
852
	return -1;
853
}
854
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
855
static EFI_STATUS write_back_mok_list (MokListNode *list, INTN key_num)
856
{
857
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
858
	EFI_STATUS efi_status;
859
	EFI_SIGNATURE_LIST *CertList;
860
	EFI_SIGNATURE_DATA *CertData;
861
	void *Data = NULL, *ptr;
862
	INTN DataSize = 0;
863
	int i;
864
865
	for (i = 0; i < key_num; i++) {
866
		if (list[i].Mok == NULL)
867
			continue;
868
869
		DataSize += sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID);
870
		DataSize += list[i].MokSize;
871
	}
872
873
	Data = AllocatePool(DataSize);
874
	if (Data == NULL && DataSize != 0)
875
		return EFI_OUT_OF_RESOURCES;
876
877
	ptr = Data;
878
879
	for (i = 0; i < key_num; i++) {
880
		if (list[i].Mok == NULL)
881
			continue;
882
883
		CertList = (EFI_SIGNATURE_LIST *)ptr;
884
		CertData = (EFI_SIGNATURE_DATA *)(((uint8_t *)ptr) +
885
			   sizeof(EFI_SIGNATURE_LIST));
886
887
		CertList->SignatureType = list[i].Type;
888
		CertList->SignatureListSize = list[i].MokSize +
889
					      sizeof(EFI_SIGNATURE_LIST) +
890
					      sizeof(EFI_SIGNATURE_DATA) - 1;
891
		CertList->SignatureHeaderSize = 0;
892
		CertList->SignatureSize = list[i].MokSize + sizeof(EFI_GUID);
893
894
		CertData->SignatureOwner = shim_lock_guid;
895
		CopyMem(CertData->SignatureData, list[i].Mok, list[i].MokSize);
896
897
		ptr = (uint8_t *)ptr + sizeof(EFI_SIGNATURE_LIST) +
898
		      sizeof(EFI_GUID) + list[i].MokSize;
899
	}
900
901
	efi_status = uefi_call_wrapper(RT->SetVariable, 5, L"MokList",
902
				       &shim_lock_guid,
903
				       EFI_VARIABLE_NON_VOLATILE
904
				       | EFI_VARIABLE_BOOTSERVICE_ACCESS,
905
				       DataSize, Data);
906
	if (Data)
907
		FreePool(Data);
908
909
	if (efi_status != EFI_SUCCESS) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
910
		console_error(L"Failed to set variable", efi_status);
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
911
		return efi_status;
912
	}
913
914
	return EFI_SUCCESS;
915
}
916
917
static EFI_STATUS delete_keys (void *MokDel, UINTN MokDelSize)
918
{
919
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
920
	EFI_STATUS efi_status;
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
921
	UINT8 auth[PASSWORD_CRYPT_SIZE];
922
	UINTN auth_size = PASSWORD_CRYPT_SIZE;
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
923
	UINT32 attributes;
41.2.153 by Gary Ching-Pang Lin
Merge variable retrieving functions
924
	UINT8 *MokListData = NULL;
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
925
	UINTN MokListDataSize = 0;
926
	MokListNode *mok, *del_key;
927
	INTN mok_num, del_num;
928
	int i, j;
929
930
	efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth",
931
				       &shim_lock_guid,
932
				       &attributes, &auth_size, auth);
933
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
934
	if (efi_status != EFI_SUCCESS ||
935
	    (auth_size != SHA256_DIGEST_SIZE && auth_size != PASSWORD_CRYPT_SIZE)) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
936
		console_error(L"Failed to get MokDelAuth", efi_status);
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
937
		return efi_status;
938
	}
939
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
940
	if (auth_size == PASSWORD_CRYPT_SIZE) {
941
		efi_status = match_password((PASSWORD_CRYPT *)auth, NULL, 0,
942
					    NULL, NULL);
943
	} else {
944
		efi_status = match_password(NULL, MokDel, MokDelSize, auth, NULL);
945
	}
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
946
	if (efi_status != EFI_SUCCESS)
947
		return EFI_ACCESS_DENIED;
948
41.2.153 by Gary Ching-Pang Lin
Merge variable retrieving functions
949
	efi_status = get_variable_attr (L"MokList", &MokListData, &MokListDataSize,
950
				        shim_lock_guid, &attributes);
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
951
	if (attributes & EFI_VARIABLE_RUNTIME_ACCESS) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
952
		console_alertbox((CHAR16 *[]){L"MokList is compromised!",
953
					L"Erase all keys in MokList!",
954
					NULL});
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
955
		if (LibDeleteVariable(L"MokList", &shim_lock_guid) != EFI_SUCCESS) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
956
			console_notify(L"Failed to erase MokList");
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
957
		}
958
		return EFI_ACCESS_DENIED;
959
	}
960
961
	/* Nothing to do */
962
	if (!MokListData || MokListDataSize == 0)
963
		return EFI_SUCCESS;
964
965
	/* Construct lists */
966
	mok_num = count_keys(MokListData, MokListDataSize);
967
	mok = build_mok_list(mok_num, MokListData, MokListDataSize);
968
	del_num = count_keys(MokDel, MokDelSize);
969
	del_key = build_mok_list(del_num, MokDel, MokDelSize);
970
971
	/* Search and destroy */
972
	for (i = 0; i < del_num; i++) {
973
		UINT32 key_size = del_key[i].MokSize;
974
		void *key = del_key[i].Mok;
975
		for (j = 0; j < mok_num; j++) {
976
			if (mok[j].MokSize == key_size &&
977
			    CompareMem(key, mok[j].Mok, key_size) == 0) {
978
				/* Remove the key */
979
				mok[j].Mok = NULL;
980
				mok[j].MokSize = 0;
981
			}
982
		}
983
	}
984
985
	efi_status = write_back_mok_list(mok, mok_num);
986
987
	if (MokListData)
988
		FreePool(MokListData);
989
	if (mok)
990
		FreePool(mok);
991
	if (del_key)
992
		FreePool(del_key);
993
994
	return efi_status;
995
}
996
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
997
static INTN mok_deletion_prompt (void *MokDel, UINTN MokDelSize)
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
998
{
999
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1000
	EFI_STATUS efi_status;
1001
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1002
	if (list_keys(MokDel, MokDelSize, L"[Delete MOK]") != EFI_SUCCESS) {
1003
		return 0;
1004
	}
1005
1006
        if (console_yes_no((CHAR16 *[]){L"Delete the key(s)?", NULL}) == 0)
1007
                return 0;
1008
1009
	efi_status = delete_keys(MokDel, MokDelSize);
1010
1011
	if (efi_status != EFI_SUCCESS) {
1012
		console_notify(L"Failed to delete keys");
1013
		return -1;
1014
	}
1015
1016
	LibDeleteVariable(L"MokDel", &shim_lock_guid);
1017
	LibDeleteVariable(L"MokDelAuth", &shim_lock_guid);
1018
1019
	console_notify(L"The system must now be rebooted");
1020
	uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
1021
			  EFI_SUCCESS, 0, NULL);
1022
	console_notify(L"Failed to reboot");
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1023
	return -1;
1024
}
1025
41.2.144 by Gary Ching-Pang Lin
MokManager: enhance the password prompt for SB state
1026
static CHAR16 get_password_charater (CHAR16 *prompt)
1027
{
1028
	SIMPLE_TEXT_OUTPUT_MODE SavedMode;
41.2.224 by Gary Ching-Pang Lin
MokManager: handle the error status from ReadKeyStroke
1029
	EFI_STATUS status;
41.2.144 by Gary Ching-Pang Lin
MokManager: enhance the password prompt for SB state
1030
	CHAR16 *message[2];
1031
	CHAR16 character;
1032
	UINTN length;
1033
	UINT32 pw_length;
1034
1035
	if (!prompt)
1036
		prompt = L"Password charater: ";
1037
1038
	console_save_and_set_mode(&SavedMode);
1039
1040
	message[0] = prompt;
1041
	message[1] = NULL;
1042
	length = StrLen(message[0]);
1043
	console_print_box_at(message, -1, -length-4, -5, length+4, 3, 0, 1);
41.2.224 by Gary Ching-Pang Lin
MokManager: handle the error status from ReadKeyStroke
1044
	status = get_line(&pw_length, &character, 1, 0);
1045
	if (EFI_ERROR(status))
1046
		character = 0;
41.2.144 by Gary Ching-Pang Lin
MokManager: enhance the password prompt for SB state
1047
1048
	console_restore_mode(&SavedMode);
1049
1050
	return character;
1051
}
1052
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1053
static INTN mok_sb_prompt (void *MokSB, UINTN MokSBSize) {
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1054
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1055
	EFI_STATUS efi_status;
41.2.144 by Gary Ching-Pang Lin
MokManager: enhance the password prompt for SB state
1056
	SIMPLE_TEXT_OUTPUT_MODE SavedMode;
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1057
	MokSBvar *var = MokSB;
41.2.144 by Gary Ching-Pang Lin
MokManager: enhance the password prompt for SB state
1058
	CHAR16 *message[4];
41.3.18 by Matthew Garrett
Improve signature validation enable/disable
1059
	CHAR16 pass1, pass2, pass3;
41.2.144 by Gary Ching-Pang Lin
MokManager: enhance the password prompt for SB state
1060
	CHAR16 *str;
41.3.18 by Matthew Garrett
Improve signature validation enable/disable
1061
	UINT8 fail_count = 0;
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1062
	UINT8 sbval = 1;
41.3.18 by Matthew Garrett
Improve signature validation enable/disable
1063
	UINT8 pos1, pos2, pos3;
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1064
	int ret;
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1065
1066
	if (MokSBSize != sizeof(MokSBvar)) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1067
		console_notify(L"Invalid MokSB variable contents");
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1068
		return -1;
1069
	}
1070
41.3.8 by Matthew Garrett
Clear screen before prompting
1071
	uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
1072
41.2.144 by Gary Ching-Pang Lin
MokManager: enhance the password prompt for SB state
1073
	message[0] = L"Change Secure Boot state";
1074
	message[1] = NULL;
1075
1076
	console_save_and_set_mode(&SavedMode);
1077
	console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
1078
	console_restore_mode(&SavedMode);
1079
41.3.18 by Matthew Garrett
Improve signature validation enable/disable
1080
	while (fail_count < 3) {
1081
		RandomBytes (&pos1, sizeof(pos1));
1082
		pos1 = (pos1 % var->PWLen);
1083
1084
		do {
1085
			RandomBytes (&pos2, sizeof(pos2));
1086
			pos2 = (pos2 % var->PWLen);
1087
		} while (pos2 == pos1);
1088
1089
		do {
1090
			RandomBytes (&pos3, sizeof(pos3));
1091
			pos3 = (pos3 % var->PWLen) ;
1092
		} while (pos3 == pos2 || pos3 == pos1);
1093
41.2.144 by Gary Ching-Pang Lin
MokManager: enhance the password prompt for SB state
1094
		str = PoolPrint(L"Enter password character %d: ", pos1 + 1);
1095
		if (!str) {
1096
			console_errorbox(L"Failed to allocate buffer");
1097
			return -1;
1098
		}
1099
		pass1 = get_password_charater(str);
1100
		FreePool(str);
1101
1102
		str = PoolPrint(L"Enter password character %d: ", pos2 + 1);
1103
		if (!str) {
1104
			console_errorbox(L"Failed to allocate buffer");
1105
			return -1;
1106
		}
1107
		pass2 = get_password_charater(str);
1108
		FreePool(str);
1109
1110
		str = PoolPrint(L"Enter password character %d: ", pos3 + 1);
1111
		if (!str) {
1112
			console_errorbox(L"Failed to allocate buffer");
1113
			return -1;
1114
		}
1115
		pass3 = get_password_charater(str);
1116
		FreePool(str);
41.3.18 by Matthew Garrett
Improve signature validation enable/disable
1117
1118
		if (pass1 != var->Password[pos1] ||
1119
		    pass2 != var->Password[pos2] ||
1120
		    pass3 != var->Password[pos3]) {
41.3.12 by Matthew Garrett
Update image validation enable/disable
1121
			Print(L"Invalid character\n");
1122
			fail_count++;
1123
		} else {
41.3.18 by Matthew Garrett
Improve signature validation enable/disable
1124
			break;
41.3.12 by Matthew Garrett
Update image validation enable/disable
1125
		}
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1126
	}
1127
1128
	if (fail_count >= 3) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1129
		console_notify(L"Password limit reached");
1130
		return -1;
1131
	}
1132
1133
	if (var->MokSBState == 0)
1134
		ret = console_yes_no((CHAR16 *[]){L"Disable Secure Boot", NULL});
1135
	else
1136
		ret = console_yes_no((CHAR16 *[]){L"Enable Secure Boot", NULL});
1137
1138
	if (ret == 0) {
1139
		LibDeleteVariable(L"MokSB", &shim_lock_guid);
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1140
		return -1;
1141
	}
1142
1143
	if (var->MokSBState == 0) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1144
		efi_status = uefi_call_wrapper(RT->SetVariable,
1145
					       5, L"MokSBState",
1146
					       &shim_lock_guid,
0.1.5 by Steve Langasek
Import upstream version 0.7
1147
					       EFI_VARIABLE_NON_VOLATILE |
1148
					       EFI_VARIABLE_BOOTSERVICE_ACCESS,
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1149
					       1, &sbval);
1150
		if (efi_status != EFI_SUCCESS) {
1151
			console_notify(L"Failed to set Secure Boot state");
0.1.5 by Steve Langasek
Import upstream version 0.7
1152
			return -1;
1153
		}
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1154
	} else {
41.2.223 by Gary Ching-Pang Lin
MokManager: delete the BS+NV variables the right way
1155
		efi_status = uefi_call_wrapper(RT->SetVariable,
1156
					       5, L"MokSBState",
1157
					       &shim_lock_guid,
1158
					       EFI_VARIABLE_NON_VOLATILE |
1159
					       EFI_VARIABLE_BOOTSERVICE_ACCESS,
1160
					       0, NULL);
1161
		if (efi_status != EFI_SUCCESS) {
1162
			console_notify(L"Failed to delete Secure Boot state");
1163
			return -1;
1164
		}
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1165
	}
0.1.5 by Steve Langasek
Import upstream version 0.7
1166
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1167
	console_notify(L"The system must now be rebooted");
1168
	uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
1169
			  EFI_SUCCESS, 0, NULL);
1170
	console_notify(L"Failed to reboot");
0.1.5 by Steve Langasek
Import upstream version 0.7
1171
	return -1;
1172
}
1173
41.2.171 by Josh Boyer
Add support for disabling db for verification
1174
static INTN mok_db_prompt (void *MokDB, UINTN MokDBSize) {
1175
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1176
	EFI_STATUS efi_status;
1177
	SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1178
	MokDBvar *var = MokDB;
1179
	CHAR16 *message[4];
1180
	CHAR16 pass1, pass2, pass3;
1181
	CHAR16 *str;
1182
	UINT8 fail_count = 0;
1183
	UINT8 dbval = 1;
1184
	UINT8 pos1, pos2, pos3;
1185
	int ret;
1186
1187
	if (MokDBSize != sizeof(MokDBvar)) {
1188
		console_notify(L"Invalid MokDB variable contents");
1189
		return -1;
1190
	}
1191
1192
	uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
1193
1194
	message[0] = L"Change DB state";
1195
	message[1] = NULL;
1196
1197
	console_save_and_set_mode(&SavedMode);
1198
	console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
1199
	console_restore_mode(&SavedMode);
1200
1201
	while (fail_count < 3) {
1202
		RandomBytes (&pos1, sizeof(pos1));
1203
		pos1 = (pos1 % var->PWLen);
1204
1205
		do {
1206
			RandomBytes (&pos2, sizeof(pos2));
1207
			pos2 = (pos2 % var->PWLen);
1208
		} while (pos2 == pos1);
1209
1210
		do {
1211
			RandomBytes (&pos3, sizeof(pos3));
1212
			pos3 = (pos3 % var->PWLen) ;
1213
		} while (pos3 == pos2 || pos3 == pos1);
1214
1215
		str = PoolPrint(L"Enter password character %d: ", pos1 + 1);
1216
		if (!str) {
1217
			console_errorbox(L"Failed to allocate buffer");
1218
			return -1;
1219
		}
1220
		pass1 = get_password_charater(str);
1221
		FreePool(str);
1222
1223
		str = PoolPrint(L"Enter password character %d: ", pos2 + 1);
1224
		if (!str) {
1225
			console_errorbox(L"Failed to allocate buffer");
1226
			return -1;
1227
		}
1228
		pass2 = get_password_charater(str);
1229
		FreePool(str);
1230
1231
		str = PoolPrint(L"Enter password character %d: ", pos3 + 1);
1232
		if (!str) {
1233
			console_errorbox(L"Failed to allocate buffer");
1234
			return -1;
1235
		}
1236
		pass3 = get_password_charater(str);
1237
		FreePool(str);
1238
1239
		if (pass1 != var->Password[pos1] ||
1240
		    pass2 != var->Password[pos2] ||
1241
		    pass3 != var->Password[pos3]) {
1242
			Print(L"Invalid character\n");
1243
			fail_count++;
1244
		} else {
1245
			break;
1246
		}
1247
	}
1248
1249
	if (fail_count >= 3) {
1250
		console_notify(L"Password limit reached");
1251
		return -1;
1252
	}
1253
1254
	if (var->MokDBState == 0)
1255
		ret = console_yes_no((CHAR16 *[]){L"Ignore DB certs/hashes", NULL});
1256
	else
1257
		ret = console_yes_no((CHAR16 *[]){L"Use DB certs/hashes", NULL});
1258
1259
	if (ret == 0) {
1260
		LibDeleteVariable(L"MokDB", &shim_lock_guid);
1261
		return -1;
1262
	}
1263
1264
	if (var->MokDBState == 0) {
1265
		efi_status = uefi_call_wrapper(RT->SetVariable,
1266
					       5, L"MokDBState",
1267
					       &shim_lock_guid,
1268
					       EFI_VARIABLE_NON_VOLATILE |
1269
					       EFI_VARIABLE_BOOTSERVICE_ACCESS,
1270
					       1, &dbval);
1271
		if (efi_status != EFI_SUCCESS) {
1272
			console_notify(L"Failed to set DB state");
1273
			return -1;
1274
		}
1275
	} else {
41.2.223 by Gary Ching-Pang Lin
MokManager: delete the BS+NV variables the right way
1276
		efi_status = uefi_call_wrapper(RT->SetVariable, 5,
1277
					       L"MokDBState",
1278
					       &shim_lock_guid,
1279
					       EFI_VARIABLE_NON_VOLATILE |
1280
					       EFI_VARIABLE_BOOTSERVICE_ACCESS,
1281
					       0, NULL);
1282
		if (efi_status != EFI_SUCCESS) {
1283
			console_notify(L"Failed to delete DB state");
1284
			return -1;
1285
		}
41.2.171 by Josh Boyer
Add support for disabling db for verification
1286
	}
1287
1288
	console_notify(L"The system must now be rebooted");
1289
	uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm,
1290
			  EFI_SUCCESS, 0, NULL);
1291
	console_notify(L"Failed to reboot");
1292
	return -1;
1293
}
1294
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1295
static INTN mok_pw_prompt (void *MokPW, UINTN MokPWSize) {
0.1.5 by Steve Langasek
Import upstream version 0.7
1296
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1297
	EFI_STATUS efi_status;
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1298
	UINT8 hash[PASSWORD_CRYPT_SIZE];
1299
	UINT8 clear = 0;
0.1.5 by Steve Langasek
Import upstream version 0.7
1300
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1301
	if (MokPWSize != SHA256_DIGEST_SIZE && MokPWSize != PASSWORD_CRYPT_SIZE) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1302
		console_notify(L"Invalid MokPW variable contents");
0.1.5 by Steve Langasek
Import upstream version 0.7
1303
		return -1;
1304
	}
1305
1306
	uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
1307
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1308
	SetMem(hash, PASSWORD_CRYPT_SIZE, 0);
1309
1310
	if (MokPWSize == PASSWORD_CRYPT_SIZE) {
1311
		if (CompareMem(MokPW, hash, PASSWORD_CRYPT_SIZE) == 0)
1312
			clear = 1;
1313
	} else {
1314
		if (CompareMem(MokPW, hash, SHA256_DIGEST_SIZE) == 0)
1315
			clear = 1;
1316
	}
1317
1318
	if (clear) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1319
		if (console_yes_no((CHAR16 *[]){L"Clear MOK password?", NULL}) == 0)
1320
			return 0;
1321
41.2.223 by Gary Ching-Pang Lin
MokManager: delete the BS+NV variables the right way
1322
		uefi_call_wrapper(RT->SetVariable, 5, L"MokPWStore",
1323
				  &shim_lock_guid,
1324
				  EFI_VARIABLE_NON_VOLATILE
1325
				  | EFI_VARIABLE_BOOTSERVICE_ACCESS,
1326
				  0, NULL);
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1327
		LibDeleteVariable(L"MokPW", &shim_lock_guid);
41.2.145 by Gary Ching-Pang Lin
MokManager: reboot the system after clearing MOK password
1328
		console_notify(L"The system must now be rebooted");
1329
		uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0,
1330
				  NULL);
1331
		console_notify(L"Failed to reboot");
1332
		return -1;
0.1.5 by Steve Langasek
Import upstream version 0.7
1333
	}
1334
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1335
	if (MokPWSize == PASSWORD_CRYPT_SIZE) {
1336
		efi_status = match_password((PASSWORD_CRYPT *)MokPW, NULL, 0,
1337
					    NULL, L"Confirm MOK passphrase: ");
1338
	} else {
1339
		efi_status = match_password(NULL, NULL, 0, MokPW,
1340
					    L"Confirm MOK passphrase: ");
1341
	}
1342
0.1.5 by Steve Langasek
Import upstream version 0.7
1343
	if (efi_status != EFI_SUCCESS) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1344
		console_notify(L"Password limit reached");
1345
		return -1;
1346
	}
1347
1348
	if (console_yes_no((CHAR16 *[]){L"Set MOK password?", NULL}) == 0)
1349
		return 0;
1350
1351
	efi_status = uefi_call_wrapper(RT->SetVariable, 5,
1352
				       L"MokPWStore",
1353
				       &shim_lock_guid,
1354
				       EFI_VARIABLE_NON_VOLATILE |
1355
				       EFI_VARIABLE_BOOTSERVICE_ACCESS,
1356
				       MokPWSize, MokPW);
1357
	if (efi_status != EFI_SUCCESS) {
1358
		console_notify(L"Failed to set MOK password");
1359
		return -1;
1360
	}
1361
1362
	LibDeleteVariable(L"MokPW", &shim_lock_guid);
1363
1364
	console_notify(L"The system must now be rebooted");
1365
	uefi_call_wrapper(RT->ResetSystem, 4, EfiResetWarm, EFI_SUCCESS, 0,
1366
			  NULL);
1367
	console_notify(L"Failed to reboot");
1368
	return -1;
0.1.5 by Steve Langasek
Import upstream version 0.7
1369
}
1370
41.2.221 by Gary Ching-Pang Lin
Check the first 4 bytes of the certificate
1371
static BOOLEAN verify_certificate(UINT8 *cert, UINTN size)
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1372
{
1373
	X509 *X509Cert;
41.2.221 by Gary Ching-Pang Lin
Check the first 4 bytes of the certificate
1374
	UINTN length;
1375
	if (!cert || size < 0)
1376
		return FALSE;
1377
1378
	/*
1379
	 * A DER encoding x509 certificate starts with SEQUENCE(0x30),
1380
	 * the number of length bytes, and the number of value bytes.
1381
	 * The size of a x509 certificate is usually between 127 bytes
1382
	 * and 64KB. For convenience, assume the number of value bytes
1383
	 * is 2, i.e. the second byte is 0x82.
1384
	 */
1385
	if (cert[0] != 0x30 || cert[1] != 0x82) {
1386
		console_notify(L"Not a DER encoding X509 certificate");
1387
		return FALSE;
1388
	}
1389
1390
	length = (cert[2]<<8 | cert[3]);
1391
	if (length != (size - 4)) {
1392
		console_notify(L"Invalid X509 certificate: Inconsistent size");
1393
		return FALSE;
1394
	}
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1395
1396
	if (!(X509ConstructCertificate(cert, size, (UINT8 **) &X509Cert)) ||
1397
	    X509Cert == NULL) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1398
		console_notify(L"Invalid X509 certificate");
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1399
		return FALSE;
1400
	}
1401
1402
	X509_free(X509Cert);
1403
	return TRUE;
1404
}
1405
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1406
static EFI_STATUS enroll_file (void *data, UINTN datasize, BOOLEAN hash)
1407
{
1408
	EFI_STATUS status = EFI_SUCCESS;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1409
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1410
	EFI_SIGNATURE_LIST *CertList;
1411
	EFI_SIGNATURE_DATA *CertData;
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1412
	UINTN mokbuffersize;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1413
	void *mokbuffer = NULL;
41.2.34 by Matthew Garrett
Add filesystem browsing and enrollment
1414
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1415
	if (hash) {
1416
		UINT8 sha256[SHA256_DIGEST_SIZE];
1417
		UINT8 sha1[SHA1_DIGEST_SIZE];
1418
		SHIM_LOCK *shim_lock;
1419
		EFI_GUID shim_guid = SHIM_LOCK_GUID;
1420
		PE_COFF_LOADER_IMAGE_CONTEXT context;
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1421
	
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1422
		status = LibLocateProtocol(&shim_guid, (VOID **)&shim_lock);
1423
1424
		if (status != EFI_SUCCESS)
1425
			goto out;
1426
1427
		mokbuffersize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_GUID) +
1428
			SHA256_DIGEST_SIZE;
1429
1430
		mokbuffer = AllocatePool(mokbuffersize);
41.2.43 by Matthew Garrett
Fix filesystem enrollment
1431
1432
		if (!mokbuffer)
1433
			goto out;
1434
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1435
		status = shim_lock->Context(data, datasize, &context);
1436
1437
		if (status != EFI_SUCCESS)
1438
			goto out;
1439
	
1440
		status = shim_lock->Hash(data, datasize, &context, sha256,
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1441
					 sha1);
1442
1443
		if (status != EFI_SUCCESS)
1444
			goto out;
1445
1446
		CertList = mokbuffer;
41.2.152 by Gary Ching-Pang Lin
Merge signature.h into efiauthenticated.h and guid.h
1447
		CertList->SignatureType = EFI_CERT_SHA256_GUID;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1448
		CertList->SignatureSize = 16 + SHA256_DIGEST_SIZE;
1449
		CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) +
1450
						  sizeof(EFI_SIGNATURE_LIST));
1451
		CopyMem(CertData->SignatureData, sha256, SHA256_DIGEST_SIZE);
41.2.43 by Matthew Garrett
Fix filesystem enrollment
1452
	} else {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1453
		mokbuffersize = datasize + sizeof(EFI_SIGNATURE_LIST) +
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1454
			sizeof(EFI_GUID);
1455
		mokbuffer = AllocatePool(mokbuffersize);
41.2.43 by Matthew Garrett
Fix filesystem enrollment
1456
1457
		if (!mokbuffer)
1458
			goto out;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1459
1460
		CertList = mokbuffer;
41.2.152 by Gary Ching-Pang Lin
Merge signature.h into efiauthenticated.h and guid.h
1461
		CertList->SignatureType = X509_GUID;
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1462
		CertList->SignatureSize = 16 + datasize;
1463
1464
		memcpy(mokbuffer + sizeof(EFI_SIGNATURE_LIST) + 16, data,
1465
		       datasize);
1466
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1467
		CertData = (EFI_SIGNATURE_DATA *)(((UINT8 *)mokbuffer) +
1468
						  sizeof(EFI_SIGNATURE_LIST));
1469
	}
1470
1471
	CertList->SignatureListSize = mokbuffersize;
1472
	CertList->SignatureHeaderSize = 0;
1473
	CertData->SignatureOwner = shim_lock_guid;
1474
1475
	if (!hash) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1476
		if (!verify_certificate(CertData->SignatureData, datasize))
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1477
			goto out;
1478
	}
1479
1480
	mok_enrollment_prompt(mokbuffer, mokbuffersize, FALSE);
41.2.34 by Matthew Garrett
Add filesystem browsing and enrollment
1481
out:
1482
	if (mokbuffer)
1483
		FreePool(mokbuffer);
1484
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1485
	return status;
1486
}
1487
1488
static void mok_hash_enroll(void)
1489
{
1490
	EFI_STATUS efi_status;
1491
        CHAR16 *file_name = NULL;
1492
	EFI_HANDLE im = NULL;
1493
	EFI_FILE *file = NULL;
1494
	UINTN filesize;
1495
	void *data;
1496
1497
	simple_file_selector(&im, (CHAR16 *[]){
1498
      L"Select Binary",
1499
      L"",
1500
      L"The Selected Binary will have its hash Enrolled",
1501
      L"This means it will Subsequently Boot with no prompting",
1502
      L"Remember to make sure it is a genuine binary before Enroling its hash",
1503
      NULL
1504
	      }, L"\\", L"", &file_name);
1505
1506
	if (!file_name)
1507
		return;
1508
1509
	efi_status = simple_file_open(im, file_name, &file, EFI_FILE_MODE_READ);
1510
1511
	if (efi_status != EFI_SUCCESS) {
1512
		console_error(L"Unable to open file", efi_status);
1513
		return;
1514
	}
1515
1516
	simple_file_read_all(file, &filesize, &data);
1517
	simple_file_close(file);
1518
1519
	if (!filesize) {
1520
		console_error(L"Unable to read file", efi_status);
1521
		return;
1522
	}
1523
1524
	efi_status = enroll_file(data, filesize, TRUE);
1525
1526
	if (efi_status != EFI_SUCCESS)
1527
		console_error(L"Hash failed (did you select a valid EFI binary?)", efi_status);
1528
1529
	FreePool(data);
1530
}
1531
41.2.147 by Gary Ching-Pang Lin
MokManager: check the suffix of the key file
1532
static CHAR16 *der_suffix[] = {
1533
	L".cer",
1534
	L".der",
1535
	L".crt",
1536
	NULL
1537
};
1538
1539
static BOOLEAN check_der_suffix (CHAR16 *file_name)
1540
{
1541
	CHAR16 suffix[5];
1542
	int i;
1543
1544
	if (!file_name || StrLen(file_name) <= 4)
1545
		return FALSE;
1546
1547
	suffix[0] = '\0';
1548
	StrCat(suffix, file_name + StrLen(file_name) - 4);
1549
1550
	StrLwr (suffix);
1551
	for (i = 0; der_suffix[i] != NULL; i++) {
1552
		if (StrCmp(suffix, der_suffix[i]) == 0) {
1553
			return TRUE;
1554
		}
1555
	}
1556
1557
	return FALSE;
1558
}
1559
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1560
static void mok_key_enroll(void)
1561
{
1562
	EFI_STATUS efi_status;
1563
        CHAR16 *file_name = NULL;
1564
	EFI_HANDLE im = NULL;
1565
	EFI_FILE *file = NULL;
1566
	UINTN filesize;
1567
	void *data;
1568
1569
	simple_file_selector(&im, (CHAR16 *[]){
1570
      L"Select Key",
1571
      L"",
1572
      L"The selected key will be enrolled into the MOK database",
1573
      L"This means any binaries signed with it will be run without prompting",
1574
      L"Remember to make sure it is a genuine key before Enroling it",
1575
      NULL
1576
	      }, L"\\", L"", &file_name);
1577
1578
	if (!file_name)
1579
		return;
1580
41.2.147 by Gary Ching-Pang Lin
MokManager: check the suffix of the key file
1581
	if (!check_der_suffix(file_name)) {
1582
		console_alertbox((CHAR16 *[]){
1583
			L"Unsupported Format",
1584
			L"",
1585
			L"Only DER encoded certificate (*.cer/der/crt) is supported",
1586
			NULL});
1587
		return;
1588
	}
1589
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1590
	efi_status = simple_file_open(im, file_name, &file, EFI_FILE_MODE_READ);
1591
1592
	if (efi_status != EFI_SUCCESS) {
1593
		console_error(L"Unable to open file", efi_status);
1594
		return;
1595
	}
1596
1597
	simple_file_read_all(file, &filesize, &data);
1598
	simple_file_close(file);
1599
1600
	if (!filesize) {
1601
		console_error(L"Unable to read file", efi_status);
1602
		return;
1603
	}
1604
1605
	enroll_file(data, filesize, FALSE);
1606
	FreePool(data);
0.1.5 by Steve Langasek
Import upstream version 0.7
1607
}
1608
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1609
static BOOLEAN verify_pw(BOOLEAN *protected)
41.3.5 by Matthew Garrett
Add MOK password auth
1610
{
1611
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
1612
	EFI_STATUS efi_status;
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1613
	SIMPLE_TEXT_OUTPUT_MODE SavedMode;
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1614
	UINT8 pwhash[PASSWORD_CRYPT_SIZE];
1615
	UINTN size = PASSWORD_CRYPT_SIZE;
41.3.5 by Matthew Garrett
Add MOK password auth
1616
	UINT32 attributes;
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1617
	CHAR16 *message[2];
1618
1619
	*protected = FALSE;
41.3.5 by Matthew Garrett
Add MOK password auth
1620
1621
	efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokPWStore",
1622
				       &shim_lock_guid, &attributes, &size,
1623
				       pwhash);
1624
1625
	/*
1626
	 * If anything can attack the password it could just set it to a
1627
	 * known value, so there's no safety advantage in failing to validate
1628
	 * purely because of a failure to read the variable
1629
	 */
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1630
	if (efi_status != EFI_SUCCESS ||
1631
	    (size != SHA256_DIGEST_SIZE && size != PASSWORD_CRYPT_SIZE))
41.3.5 by Matthew Garrett
Add MOK password auth
1632
		return TRUE;
1633
1634
	if (attributes & EFI_VARIABLE_RUNTIME_ACCESS)
1635
		return TRUE;
1636
41.3.8 by Matthew Garrett
Clear screen before prompting
1637
	uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut);
1638
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1639
	/* Draw the background */
1640
	console_save_and_set_mode(&SavedMode);
1641
	message[0] = PoolPrint (L"%s UEFI key management", SHIM_VENDOR);
1642
	message[1] = NULL;
1643
	console_print_box_at(message, -1, 0, 0, -1, -1, 1, 1);
1644
	FreePool(message[0]);
1645
	console_restore_mode(&SavedMode);
1646
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1647
	if (size == PASSWORD_CRYPT_SIZE) {
1648
		efi_status = match_password((PASSWORD_CRYPT *)pwhash, NULL, 0,
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1649
					    NULL, L"Enter MOK password:");
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1650
	} else {
1651
		efi_status = match_password(NULL, NULL, 0, pwhash,
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1652
					    L"Enter MOK password:");
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1653
	}
41.2.69 by Gary Ching-Pang Lin
Add a general function for password matching
1654
	if (efi_status != EFI_SUCCESS) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1655
		console_notify(L"Password limit reached");
41.2.69 by Gary Ching-Pang Lin
Add a general function for password matching
1656
		return FALSE;
41.3.5 by Matthew Garrett
Add MOK password auth
1657
	}
1658
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1659
	*protected = TRUE;
1660
41.2.69 by Gary Ching-Pang Lin
Add a general function for password matching
1661
	return TRUE;
41.3.5 by Matthew Garrett
Add MOK password auth
1662
}
1663
41.2.138 by Gary Ching-Pang Lin
MokManager: draw the countdown screen
1664
static int draw_countdown()
1665
{
1666
	SIMPLE_TEXT_OUTPUT_MODE SavedMode;
1667
	EFI_INPUT_KEY key;
1668
	EFI_STATUS status;
1669
	UINTN cols, rows;
1670
	CHAR16 *title[2];
1671
	CHAR16 *message =  L"Press any key to perform MOK management";
1672
	int timeout = 10, wait = 10000000;
1673
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1674
	console_save_and_set_mode (&SavedMode);
41.2.138 by Gary Ching-Pang Lin
MokManager: draw the countdown screen
1675
1676
	title[0] = PoolPrint (L"%s UEFI key management", SHIM_VENDOR);
1677
	title[1] = NULL;
1678
1679
	console_print_box_at(title, -1, 0, 0, -1, -1, 1, 1);
1680
1681
	uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut,
1682
			  ST->ConOut->Mode->Mode, &cols, &rows);
1683
1684
	PrintAt((cols - StrLen(message))/2, rows/2, message);
1685
	while (1) {
1686
		if (timeout > 1)
1687
			PrintAt(2, rows - 3, L"Booting in %d seconds  ", timeout);
1688
		else if (timeout)
1689
			PrintAt(2, rows - 3, L"Booting in %d second   ", timeout);
1690
1691
		status = WaitForSingleEvent(ST->ConIn->WaitForKey, wait);
1692
1693
		if (status != EFI_TIMEOUT) {
1694
			/* Clear the key in the queue */
1695
			uefi_call_wrapper(ST->ConIn->ReadKeyStroke, 2,
1696
					  ST->ConIn, &key);
1697
			break;
1698
		}
1699
1700
		timeout--;
1701
		if (!timeout)
1702
			break;
1703
	}
1704
1705
	FreePool(title[0]);
1706
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1707
	console_restore_mode(&SavedMode);
41.2.138 by Gary Ching-Pang Lin
MokManager: draw the countdown screen
1708
1709
	return timeout;
1710
}
1711
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1712
typedef enum {
1713
	MOK_CONTINUE_BOOT,
1714
	MOK_RESET_MOK,
1715
	MOK_ENROLL_MOK,
1716
	MOK_DELETE_MOK,
1717
	MOK_CHANGE_SB,
1718
	MOK_SET_PW,
41.2.171 by Josh Boyer
Add support for disabling db for verification
1719
	MOK_CHANGE_DB,
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1720
	MOK_KEY_ENROLL,
1721
	MOK_HASH_ENROLL
1722
} mok_menu_item;
1723
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1724
static EFI_STATUS enter_mok_menu(EFI_HANDLE image_handle,
1725
				 void *MokNew, UINTN MokNewSize,
1726
				 void *MokDel, UINTN MokDelSize,
1727
				 void *MokSB, UINTN MokSBSize,
41.2.171 by Josh Boyer
Add support for disabling db for verification
1728
				 void *MokPW, UINTN MokPWSize,
1729
				 void *MokDB, UINTN MokDBSize)
41.2.34 by Matthew Garrett
Add filesystem browsing and enrollment
1730
{
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1731
	CHAR16 **menu_strings;
1732
	mok_menu_item *menu_item;
1733
	int choice = 0;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1734
	UINT32 MokAuth = 0;
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1735
	UINT32 MokDelAuth = 0;
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1736
	UINTN menucount = 3, i = 0;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1737
	EFI_STATUS efi_status;
1738
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1739
	UINT8 auth[PASSWORD_CRYPT_SIZE];
1740
	UINTN auth_size = PASSWORD_CRYPT_SIZE;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1741
	UINT32 attributes;
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1742
	BOOLEAN protected;
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1743
	EFI_STATUS ret = EFI_SUCCESS;
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1744
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1745
	if (verify_pw(&protected) == FALSE)
41.3.5 by Matthew Garrett
Add MOK password auth
1746
		return EFI_ACCESS_DENIED;
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1747
	
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1748
	efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokAuth",
1749
					       &shim_lock_guid,
1750
					       &attributes, &auth_size, auth);
1751
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1752
	if ((efi_status == EFI_SUCCESS) &&
1753
	    (auth_size == SHA256_DIGEST_SIZE || auth_size == PASSWORD_CRYPT_SIZE))
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1754
		MokAuth = 1;
1755
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1756
	efi_status = uefi_call_wrapper(RT->GetVariable, 5, L"MokDelAuth",
1757
					       &shim_lock_guid,
1758
					       &attributes, &auth_size, auth);
1759
41.2.127 by Gary Ching-Pang Lin
MokManager: support crypt() password hash
1760
	if ((efi_status == EFI_SUCCESS) &&
1761
	   (auth_size == SHA256_DIGEST_SIZE || auth_size == PASSWORD_CRYPT_SIZE))
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1762
		MokDelAuth = 1;
1763
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1764
	if (MokNew || MokAuth)
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1765
		menucount++;
1766
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1767
	if (MokDel || MokDelAuth)
1768
		menucount++;
1769
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1770
	if (MokSB)
1771
		menucount++;
1772
41.3.5 by Matthew Garrett
Add MOK password auth
1773
	if (MokPW)
1774
		menucount++;
1775
41.2.171 by Josh Boyer
Add support for disabling db for verification
1776
	if (MokDB)
1777
		menucount++;
1778
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1779
	menu_strings = AllocateZeroPool(sizeof(CHAR16 *) * (menucount + 1));
1780
1781
	if (!menu_strings)
1782
		return EFI_OUT_OF_RESOURCES;
1783
1784
	menu_item = AllocateZeroPool(sizeof(mok_menu_item) * menucount);
1785
1786
	if (!menu_item) {
1787
		FreePool(menu_strings);
1788
		return EFI_OUT_OF_RESOURCES;
1789
	}
1790
41.2.137 by Gary Ching-Pang Lin
MokManager: Remove the unnecessary string duplication
1791
	menu_strings[i] = L"Continue boot";
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1792
	menu_item[i] = MOK_CONTINUE_BOOT;
41.2.34 by Matthew Garrett
Add filesystem browsing and enrollment
1793
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1794
	i++;
41.2.37 by Matthew Garrett
Fix menu items
1795
41.2.56 by Matthew Garrett
Switch to using db format for MokList and MokNew
1796
	if (MokNew || MokAuth) {
1797
		if (!MokNew) {
41.2.137 by Gary Ching-Pang Lin
MokManager: Remove the unnecessary string duplication
1798
			menu_strings[i] = L"Reset MOK";
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1799
			menu_item[i] = MOK_RESET_MOK;
41.2.37 by Matthew Garrett
Fix menu items
1800
		} else {
41.2.137 by Gary Ching-Pang Lin
MokManager: Remove the unnecessary string duplication
1801
			menu_strings[i] = L"Enroll MOK";
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1802
			menu_item[i] = MOK_ENROLL_MOK;
41.2.37 by Matthew Garrett
Fix menu items
1803
		}
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1804
		i++;
1805
	}
1806
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1807
	if (MokDel || MokDelAuth) {		
41.2.137 by Gary Ching-Pang Lin
MokManager: Remove the unnecessary string duplication
1808
		menu_strings[i] = L"Delete MOK";
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1809
		menu_item[i] = MOK_DELETE_MOK;
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1810
		i++;
1811
	}
1812
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1813
	if (MokSB) {
41.2.137 by Gary Ching-Pang Lin
MokManager: Remove the unnecessary string duplication
1814
		menu_strings[i] = L"Change Secure Boot state";
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1815
		menu_item[i] = MOK_CHANGE_SB;
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1816
		i++;
1817
	}
1818
41.3.5 by Matthew Garrett
Add MOK password auth
1819
	if (MokPW) {
41.2.137 by Gary Ching-Pang Lin
MokManager: Remove the unnecessary string duplication
1820
		menu_strings[i] = L"Set MOK password";
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1821
		menu_item[i] = MOK_SET_PW;
0.1.5 by Steve Langasek
Import upstream version 0.7
1822
		i++;
1823
	}
1824
41.2.171 by Josh Boyer
Add support for disabling db for verification
1825
	if (MokDB) {
1826
		menu_strings[i] = L"Change DB state";
1827
		menu_item[i] = MOK_CHANGE_DB;
1828
		i++;
1829
	}
1830
41.2.137 by Gary Ching-Pang Lin
MokManager: Remove the unnecessary string duplication
1831
	menu_strings[i] = L"Enroll key from disk";
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1832
	menu_item[i] = MOK_KEY_ENROLL;
1833
	i++;
1834
41.2.137 by Gary Ching-Pang Lin
MokManager: Remove the unnecessary string duplication
1835
	menu_strings[i] = L"Enroll hash from disk";
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1836
	menu_item[i] = MOK_HASH_ENROLL;
1837
	i++;
1838
1839
	menu_strings[i] = NULL;
1840
41.2.140 by Gary Ching-Pang Lin
MokManager: enhance the password prompt
1841
	if (protected == FALSE && draw_countdown() == 0)
41.2.138 by Gary Ching-Pang Lin
MokManager: draw the countdown screen
1842
		goto out;
1843
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1844
	while (choice >= 0) {
1845
		choice = console_select((CHAR16 *[]){ L"Perform MOK management", NULL },
1846
					menu_strings, 0);
1847
1848
		if (choice < 0)
1849
			goto out;
1850
1851
		switch (menu_item[choice]) {
1852
		case MOK_CONTINUE_BOOT:
1853
			goto out;
1854
		case MOK_RESET_MOK:
1855
			mok_reset_prompt();
1856
			break;
1857
		case MOK_ENROLL_MOK:
1858
			mok_enrollment_prompt(MokNew, MokNewSize, TRUE);
1859
			break;
1860
		case MOK_DELETE_MOK:
1861
			mok_deletion_prompt(MokDel, MokDelSize);
1862
			break;
1863
		case MOK_CHANGE_SB:
1864
			mok_sb_prompt(MokSB, MokSBSize);
1865
			break;
1866
		case MOK_SET_PW:
1867
			mok_pw_prompt(MokPW, MokPWSize);
1868
			break;
41.2.171 by Josh Boyer
Add support for disabling db for verification
1869
		case MOK_CHANGE_DB:
1870
			mok_db_prompt(MokDB, MokDBSize);
1871
			break;
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1872
		case MOK_KEY_ENROLL:
1873
			mok_key_enroll();
1874
			break;
1875
		case MOK_HASH_ENROLL:
1876
			mok_hash_enroll();
1877
			break;
1878
		}
1879
	}
1880
1881
out:
1882
	console_reset();
1883
1884
	FreePool(menu_strings);
1885
1886
	if (menu_item)
1887
		FreePool(menu_item);
1888
1889
	return ret;
41.2.34 by Matthew Garrett
Add filesystem browsing and enrollment
1890
}
1891
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
1892
static EFI_STATUS check_mok_request(EFI_HANDLE image_handle)
1893
{
1894
	EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
41.2.171 by Josh Boyer
Add support for disabling db for verification
1895
	UINTN MokNewSize = 0, MokDelSize = 0, MokSBSize = 0, MokPWSize = 0,
1896
		  MokDBSize = 0;
41.2.11 by Gary Ching-Pang Lin
Simplify the key management
1897
	void *MokNew = NULL;
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1898
	void *MokDel = NULL;
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1899
	void *MokSB = NULL;
41.3.5 by Matthew Garrett
Add MOK password auth
1900
	void *MokPW = NULL;
41.2.171 by Josh Boyer
Add support for disabling db for verification
1901
	void *MokDB = NULL;
41.2.156 by Peter Jones
Don't use LibGetVariable(), since it doesn't give us real error codes.
1902
	EFI_STATUS status;
1903
1904
	status = get_variable(L"MokNew", (UINT8 **)&MokNew, &MokNewSize,
1905
				shim_lock_guid);
1906
	if (status == EFI_SUCCESS) {
41.2.27 by Gary Ching-Pang Lin
Use LibDeleteVariable in gnu-efi
1907
		if (LibDeleteVariable(L"MokNew", &shim_lock_guid) != EFI_SUCCESS) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1908
			console_notify(L"Failed to delete MokNew");
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
1909
		}
41.2.156 by Peter Jones
Don't use LibGetVariable(), since it doesn't give us real error codes.
1910
	} else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
1911
		console_error(L"Could not retrieve MokNew", status);
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
1912
	}
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1913
41.2.156 by Peter Jones
Don't use LibGetVariable(), since it doesn't give us real error codes.
1914
	status = get_variable(L"MokDel", (UINT8 **)&MokDel, &MokDelSize,
1915
				shim_lock_guid);
1916
	if (status == EFI_SUCCESS) {
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1917
		if (LibDeleteVariable(L"MokDel", &shim_lock_guid) != EFI_SUCCESS) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1918
			console_notify(L"Failed to delete MokDel");
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1919
		}
41.2.156 by Peter Jones
Don't use LibGetVariable(), since it doesn't give us real error codes.
1920
	} else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
1921
		console_error(L"Could not retrieve MokDel", status);
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1922
	}
1923
41.2.156 by Peter Jones
Don't use LibGetVariable(), since it doesn't give us real error codes.
1924
	status = get_variable(L"MokSB", (UINT8 **)&MokSB, &MokSBSize,
1925
				shim_lock_guid);
1926
	if (status == EFI_SUCCESS) {
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1927
		if (LibDeleteVariable(L"MokSB", &shim_lock_guid) != EFI_SUCCESS) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1928
			console_notify(L"Failed to delete MokSB");
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1929
		}
41.2.156 by Peter Jones
Don't use LibGetVariable(), since it doesn't give us real error codes.
1930
	} else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
1931
		console_error(L"Could not retrieve MokSB", status);
41.3.2 by Matthew Garrett
Add support for disabling signature verification
1932
	}
41.3.5 by Matthew Garrett
Add MOK password auth
1933
41.2.156 by Peter Jones
Don't use LibGetVariable(), since it doesn't give us real error codes.
1934
	status = get_variable(L"MokPW", (UINT8 **)&MokPW, &MokPWSize,
1935
				shim_lock_guid);
1936
	if (status == EFI_SUCCESS) {
41.3.5 by Matthew Garrett
Add MOK password auth
1937
		if (LibDeleteVariable(L"MokPW", &shim_lock_guid) != EFI_SUCCESS) {
41.2.122 by Peter Jones
Port MokManager to Linux Foundation loader UI code
1938
			console_notify(L"Failed to delete MokPW");
0.1.5 by Steve Langasek
Import upstream version 0.7
1939
		}
41.2.156 by Peter Jones
Don't use LibGetVariable(), since it doesn't give us real error codes.
1940
	} else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
1941
		console_error(L"Could not retrieve MokPW", status);
1942
	}
1943
41.2.171 by Josh Boyer
Add support for disabling db for verification
1944
	status = get_variable(L"MokDB", (UINT8 **)&MokDB, &MokDBSize,
1945
				shim_lock_guid);
1946
	if (status == EFI_SUCCESS) {
1947
		if (LibDeleteVariable(L"MokDB", &shim_lock_guid) != EFI_SUCCESS) {
1948
			console_notify(L"Failed to delete MokDB");
1949
		}
1950
	} else if (EFI_ERROR(status) && status != EFI_NOT_FOUND) {
1951
		console_error(L"Could not retrieve MokDB", status);
1952
	}
1953
41.2.156 by Peter Jones
Don't use LibGetVariable(), since it doesn't give us real error codes.
1954
	enter_mok_menu(image_handle, MokNew, MokNewSize, MokDel, MokDelSize,
41.2.171 by Josh Boyer
Add support for disabling db for verification
1955
		       MokSB, MokSBSize, MokPW, MokPWSize, MokDB, MokDBSize);
41.2.156 by Peter Jones
Don't use LibGetVariable(), since it doesn't give us real error codes.
1956
1957
	if (MokNew)
41.3.5 by Matthew Garrett
Add MOK password auth
1958
		FreePool (MokNew);
41.2.156 by Peter Jones
Don't use LibGetVariable(), since it doesn't give us real error codes.
1959
1960
	if (MokDel)
1961
		FreePool (MokDel);
1962
1963
	if (MokSB)
1964
		FreePool (MokSB);
1965
1966
	if (MokPW)
1967
		FreePool (MokPW);
0.1.5 by Steve Langasek
Import upstream version 0.7
1968
41.2.171 by Josh Boyer
Add support for disabling db for verification
1969
	if (MokDB)
1970
		FreePool (MokDB);
1971
41.2.27 by Gary Ching-Pang Lin
Use LibDeleteVariable in gnu-efi
1972
	LibDeleteVariable(L"MokAuth", &shim_lock_guid);
41.2.71 by Gary Ching-Pang Lin
Add support for deleting specific keys
1973
	LibDeleteVariable(L"MokDelAuth", &shim_lock_guid);
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
1974
1975
	return EFI_SUCCESS;
1976
}
1977
41.3.12 by Matthew Garrett
Update image validation enable/disable
1978
static EFI_STATUS setup_rand (void)
1979
{
1980
	EFI_TIME time;
1981
	EFI_STATUS efi_status;
1982
	UINT64 seed;
1983
	BOOLEAN status;
1984
1985
	efi_status = uefi_call_wrapper(RT->GetTime, 2, &time, NULL);
1986
1987
	if (efi_status != EFI_SUCCESS)
1988
		return efi_status;
1989
1990
	seed = ((UINT64)time.Year << 48) | ((UINT64)time.Month << 40) |
1991
		((UINT64)time.Day << 32) | ((UINT64)time.Hour << 24) |
1992
		((UINT64)time.Minute << 16) | ((UINT64)time.Second << 8) |
1993
		((UINT64)time.Daylight);
1994
1995
	status = RandomSeed((UINT8 *)&seed, sizeof(seed));
1996
1997
	if (!status)
1998
		return EFI_ABORTED;
1999
2000
	return EFI_SUCCESS;
2001
}
2002
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
2003
EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab)
2004
{
2005
	EFI_STATUS efi_status;
2006
2007
	InitializeLib(image_handle, systab);
2008
41.2.119 by Peter Jones
MokManager needs to disable the graphics console.
2009
	setup_console(1);
2010
41.3.12 by Matthew Garrett
Update image validation enable/disable
2011
	setup_rand();
2012
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
2013
	efi_status = check_mok_request(image_handle);
2014
41.2.119 by Peter Jones
MokManager needs to disable the graphics console.
2015
	setup_console(0);
41.2.7 by Gary Ching-Pang Lin
Add a separate efi application to manage MOKs
2016
	return efi_status;
2017
}