]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/AmdSev/BlobVerifierLibSevHashes/BlobVerifierSevHashes.c
OvmfPkg/AmdSev: add BlobVerifierLibSevHashes
[mirror_edk2.git] / OvmfPkg / AmdSev / BlobVerifierLibSevHashes / BlobVerifierSevHashes.c
1 /** @file
2
3 Blob verifier library that uses SEV hashes table. The hashes table holds the
4 allowed hashes of the kernel, initrd, and cmdline blobs.
5
6 Copyright (C) 2021, IBM Corporation
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9 **/
10
11 #include <Library/BaseCryptLib.h>
12 #include <Library/BaseLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <Library/DebugLib.h>
15 #include <Library/BlobVerifierLib.h>
16
17 /**
18 The SEV Hashes table must be in encrypted memory and has the table
19 and its entries described by
20
21 <GUID>|UINT16 <len>|<data>
22
23 With the whole table GUID being 9438d606-4f22-4cc9-b479-a793d411fd21
24
25 The current possible table entries are for the kernel, the initrd
26 and the cmdline:
27
28 4de79437-abd2-427f-b835-d5b172d2045b kernel
29 44baf731-3a2f-4bd7-9af1-41e29169781d initrd
30 97d02dd8-bd20-4c94-aa78-e7714d36ab2a cmdline
31
32 The size of the entry is used to identify the hash, but the
33 expectation is that it will be 32 bytes of SHA-256.
34 **/
35
36 #define SEV_HASH_TABLE_GUID \
37 (GUID) { 0x9438d606, 0x4f22, 0x4cc9, { 0xb4, 0x79, 0xa7, 0x93, 0xd4, 0x11, 0xfd, 0x21 } }
38 #define SEV_KERNEL_HASH_GUID \
39 (GUID) { 0x4de79437, 0xabd2, 0x427f, { 0xb8, 0x35, 0xd5, 0xb1, 0x72, 0xd2, 0x04, 0x5b } }
40 #define SEV_INITRD_HASH_GUID \
41 (GUID) { 0x44baf731, 0x3a2f, 0x4bd7, { 0x9a, 0xf1, 0x41, 0xe2, 0x91, 0x69, 0x78, 0x1d } }
42 #define SEV_CMDLINE_HASH_GUID \
43 (GUID) { 0x97d02dd8, 0xbd20, 0x4c94, { 0xaa, 0x78, 0xe7, 0x71, 0x4d, 0x36, 0xab, 0x2a } }
44
45 STATIC CONST EFI_GUID mSevKernelHashGuid = SEV_KERNEL_HASH_GUID;
46 STATIC CONST EFI_GUID mSevInitrdHashGuid = SEV_INITRD_HASH_GUID;
47 STATIC CONST EFI_GUID mSevCmdlineHashGuid = SEV_CMDLINE_HASH_GUID;
48
49 #pragma pack (1)
50 typedef struct {
51 GUID Guid;
52 UINT16 Len;
53 UINT8 Data[];
54 } HASH_TABLE;
55 #pragma pack ()
56
57 STATIC HASH_TABLE *mHashesTable;
58 STATIC UINT16 mHashesTableSize;
59
60 STATIC
61 CONST GUID*
62 FindBlobEntryGuid (
63 IN CONST CHAR16 *BlobName
64 )
65 {
66 if (StrCmp (BlobName, L"kernel") == 0) {
67 return &mSevKernelHashGuid;
68 } else if (StrCmp (BlobName, L"initrd") == 0) {
69 return &mSevInitrdHashGuid;
70 } else if (StrCmp (BlobName, L"cmdline") == 0) {
71 return &mSevCmdlineHashGuid;
72 } else {
73 return NULL;
74 }
75 }
76
77 /**
78 Verify blob from an external source.
79
80 @param[in] BlobName The name of the blob
81 @param[in] Buf The data of the blob
82 @param[in] BufSize The size of the blob in bytes
83
84 @retval EFI_SUCCESS The blob was verified successfully.
85 @retval EFI_ACCESS_DENIED The blob could not be verified, and therefore
86 should be considered non-secure.
87 **/
88 EFI_STATUS
89 EFIAPI
90 VerifyBlob (
91 IN CONST CHAR16 *BlobName,
92 IN CONST VOID *Buf,
93 IN UINT32 BufSize
94 )
95 {
96 CONST GUID *Guid;
97 INT32 Remaining;
98 HASH_TABLE *Entry;
99
100 if (mHashesTable == NULL || mHashesTableSize == 0) {
101 DEBUG ((DEBUG_ERROR,
102 "%a: Verifier called but no hashes table discoverd in MEMFD\n",
103 __FUNCTION__));
104 return EFI_ACCESS_DENIED;
105 }
106
107 Guid = FindBlobEntryGuid (BlobName);
108 if (Guid == NULL) {
109 DEBUG ((DEBUG_ERROR, "%a: Unknown blob name \"%s\"\n", __FUNCTION__,
110 BlobName));
111 return EFI_ACCESS_DENIED;
112 }
113
114 //
115 // Remaining is INT32 to catch underflow in case Entry->Len has a
116 // very high UINT16 value
117 //
118 for (Entry = mHashesTable, Remaining = mHashesTableSize;
119 Remaining >= sizeof *Entry && Remaining >= Entry->Len;
120 Remaining -= Entry->Len,
121 Entry = (HASH_TABLE *)((UINT8 *)Entry + Entry->Len)) {
122 UINTN EntrySize;
123 EFI_STATUS Status;
124 UINT8 Hash[SHA256_DIGEST_SIZE];
125
126 if (!CompareGuid (&Entry->Guid, Guid)) {
127 continue;
128 }
129
130 DEBUG ((DEBUG_INFO, "%a: Found GUID %g in table\n", __FUNCTION__, Guid));
131
132 EntrySize = Entry->Len - sizeof Entry->Guid - sizeof Entry->Len;
133 if (EntrySize != SHA256_DIGEST_SIZE) {
134 DEBUG ((DEBUG_ERROR, "%a: Hash has the wrong size %d != %d\n",
135 __FUNCTION__, EntrySize, SHA256_DIGEST_SIZE));
136 return EFI_ACCESS_DENIED;
137 }
138
139 //
140 // Calculate the buffer's hash and verify that it is identical to the
141 // expected hash table entry
142 //
143 Sha256HashAll (Buf, BufSize, Hash);
144
145 if (CompareMem (Entry->Data, Hash, EntrySize) == 0) {
146 Status = EFI_SUCCESS;
147 DEBUG ((DEBUG_INFO, "%a: Hash comparison succeeded for \"%s\"\n",
148 __FUNCTION__, BlobName));
149 } else {
150 Status = EFI_ACCESS_DENIED;
151 DEBUG ((DEBUG_ERROR, "%a: Hash comparison failed for \"%s\"\n",
152 __FUNCTION__, BlobName));
153 }
154 return Status;
155 }
156
157 DEBUG ((DEBUG_ERROR, "%a: Hash GUID %g not found in table\n", __FUNCTION__,
158 Guid));
159 return EFI_ACCESS_DENIED;
160 }
161
162 /**
163 Locate the SEV hashes table.
164
165 This function always returns success, even if the table can't be found. The
166 subsequent VerifyBlob calls will fail if no table was found.
167
168 @retval RETURN_SUCCESS The hashes table is set up correctly, or there is no
169 hashes table
170 **/
171 RETURN_STATUS
172 EFIAPI
173 BlobVerifierLibSevHashesConstructor (
174 VOID
175 )
176 {
177 HASH_TABLE *Ptr;
178 UINT32 Size;
179
180 mHashesTable = NULL;
181 mHashesTableSize = 0;
182
183 Ptr = (void *)(UINTN)FixedPcdGet64 (PcdQemuHashTableBase);
184 Size = FixedPcdGet32 (PcdQemuHashTableSize);
185
186 if (Ptr == NULL || Size < sizeof *Ptr ||
187 !CompareGuid (&Ptr->Guid, &SEV_HASH_TABLE_GUID) ||
188 Ptr->Len < sizeof *Ptr || Ptr->Len > Size) {
189 return RETURN_SUCCESS;
190 }
191
192 DEBUG ((DEBUG_INFO, "%a: Found injected hashes table in secure location\n",
193 __FUNCTION__));
194
195 mHashesTable = (HASH_TABLE *)Ptr->Data;
196 mHashesTableSize = Ptr->Len - sizeof Ptr->Guid - sizeof Ptr->Len;
197
198 DEBUG ((DEBUG_VERBOSE, "%a: mHashesTable=0x%p, Size=%u\n", __FUNCTION__,
199 mHashesTable, mHashesTableSize));
200
201 return RETURN_SUCCESS;
202 }