1From 19e79008e0fa3193b54bf6499516dc75cb10f6ec Mon Sep 17 00:00:00 2001 2From: Gabor Toth <gabor.toth2@arm.com> 3Date: Thu, 11 Apr 2024 13:42:03 +0200 4Subject: [PATCH 2/3] Isolate common uefi variable authentication steps 5 6Currently all auth variables are authenticated with the secure boot 7keys. To introduce corrent check for Private Authenticated Variables 8first separate the common steps from the secure boot related steps. 9 10Signed-off-by: Gabor Toth <gabor.toth2@arm.com> 11Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TS/trusted-services/+/27956] 12--- 13 .../backend/uefi_variable_store.c | 191 ++++++++++-------- 14 1 file changed, 103 insertions(+), 88 deletions(-) 15 16diff --git a/components/service/uefi/smm_variable/backend/uefi_variable_store.c b/components/service/uefi/smm_variable/backend/uefi_variable_store.c 17index 1b624f0c9..1384d0def 100644 18--- a/components/service/uefi/smm_variable/backend/uefi_variable_store.c 19+++ b/components/service/uefi/smm_variable/backend/uefi_variable_store.c 20@@ -78,6 +78,12 @@ static efi_status_t verify_var_by_key_var(const efi_data_map *new_var, 21 static efi_status_t authenticate_variable(const struct uefi_variable_store *context, 22 EFI_TIME *timestamp, 23 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *var); 24+ 25+static efi_status_t authenticate_secure_boot_variable(const struct uefi_variable_store *context, 26+ efi_data_map* var_map, 27+ uint8_t* hash_buffer, 28+ size_t hash_len, 29+ uint64_t max_variable_size); 30 #endif 31 32 static efi_status_t store_variable_data(const struct uefi_variable_store *context, 33@@ -1118,30 +1124,109 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont 34 { 35 efi_status_t status = EFI_SUCCESS; 36 EFI_GUID pkcs7_guid = EFI_CERT_TYPE_PKCS7_GUID; 37- EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE; 38- EFI_GUID security_database_guid = EFI_IMAGE_SECURITY_DATABASE_GUID; 39 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO variable_info = { 0, 0, 0, 0 }; 40- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *pk_variable = NULL; 41- size_t pk_payload_size = 0; 42 efi_data_map var_map = { NULL, NULL, NULL, 0, 0, NULL, 0, NULL }; 43 uint8_t hash_buffer[PSA_HASH_MAX_SIZE]; 44 size_t hash_len = 0; 45- bool hash_result = false; 46 47 /* Create a map of the fields of the new variable including the auth header */ 48 if (!init_efi_data_map(var, true, &var_map)) 49 return EFI_SECURITY_VIOLATION; 50 51- /* database variables can be verified by either PK or KEK while images 52- * should be checked by db and dbx so the length of two will be enough. 53- */ 54- SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *allowed_key_store_variables[] = { NULL, NULL }; 55- 56 /* Find the maximal size of variables for the GetVariable operation */ 57 status = uefi_variable_store_query_variable_info(context, &variable_info); 58 if (status != EFI_SUCCESS) 59 return EFI_SECURITY_VIOLATION; 60 61+ /** 62+ * UEFI: Page 246 63+ * If the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set in a 64+ * SetVariable() call, and firmware does not support signature type of the certificate 65+ * included in the EFI_VARIABLE_AUTHENTICATION_2 descriptor, then the SetVariable() call 66+ * shall return EFI_INVALID_PARAMETER. The list of signature types supported by the 67+ * firmware is defined by the SignatureSupport variable. Signature type of the certificate 68+ * is defined by its digest and encryption algorithms. 69+ */ 70+ /* TODO: Should support WIN_CERT_TYPE_PKCS_SIGNED_DATA and WIN_CERT_TYPE_EFI_PKCS115 */ 71+ if (var_map.efi_auth_descriptor->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) 72+ return EFI_INVALID_PARAMETER; 73+ 74+ /* Only a CertType of EFI_CERT_TYPE_PKCS7_GUID is accepted */ 75+ if (!compare_guid(&var_map.efi_auth_descriptor->AuthInfo.CertType, &pkcs7_guid)) 76+ return EFI_SECURITY_VIOLATION; 77+ 78+ /** 79+ * Time associated with the authentication descriptor. For the TimeStamp value, 80+ * components Pad1, Nanosecond, TimeZone, Daylight and Pad2 shall be set to 0. 81+ * This means that the time shall always be expressed in GMT. 82+ * 83+ * UEFI: Page 253 84+ * 2. Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components 85+ * of the TimeStamp value are set to zero. 86+ */ 87+ if ((var_map.efi_auth_descriptor->TimeStamp.Pad1 != 0) || 88+ (var_map.efi_auth_descriptor->TimeStamp.Pad2 != 0) || 89+ (var_map.efi_auth_descriptor->TimeStamp.Nanosecond != 0) || 90+ (var_map.efi_auth_descriptor->TimeStamp.TimeZone != 0) || 91+ (var_map.efi_auth_descriptor->TimeStamp.Daylight != 0)) { 92+ return EFI_SECURITY_VIOLATION; 93+ } 94+ 95+ /** 96+ * UEFI: Page 253 97+ * Unless the EFI_VARIABLE_APPEND_WRITE attribute is set, verify 98+ * that the TimeStamp value is later than the current 99+ * timestamp value associated with the variable 100+ */ 101+ if (!(var->Attributes & EFI_VARIABLE_APPEND_WRITE)) { 102+ if (memcmp(&var_map.efi_auth_descriptor->TimeStamp, timestamp, sizeof(EFI_GUID)) <= 0) { 103+ EMSG("Timestamp violation"); 104+ return EFI_SECURITY_VIOLATION; 105+ } 106+ 107+ /* Save new timestamp */ 108+ memcpy(timestamp, &var_map.efi_auth_descriptor->TimeStamp, sizeof(EFI_TIME)); 109+ } 110+ /* Calculate hash for the variable only once */ 111+ if (calc_variable_hash(&var_map, (uint8_t *)&hash_buffer, sizeof(hash_buffer), &hash_len) == 0) { 112+ status = EFI_SECURITY_VIOLATION; 113+ } 114+ 115+ /* Run Secure Boot related authentication steps */ 116+ status = authenticate_secure_boot_variable(context, &var_map, (uint8_t*) &hash_buffer, hash_len, variable_info.MaximumVariableSize); 117+ 118+ /* Remove the authentication header from the variable if the authentication is successful */ 119+ if (status == EFI_SUCCESS) { 120+ uint8_t *smm_payload = 121+ (uint8_t *)var + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var); 122+ 123+ memmove(smm_payload, var_map.payload, var_map.payload_len); 124+ memset((uint8_t *)smm_payload + var_map.payload_len, 0, 125+ var_map.efi_auth_descriptor_len); 126+ 127+ var->DataSize -= var_map.efi_auth_descriptor_len; 128+ } 129+ 130+ return status; 131+} 132+ 133+static efi_status_t authenticate_secure_boot_variable(const struct uefi_variable_store *context, 134+ efi_data_map* var_map, 135+ uint8_t* hash_buffer, 136+ size_t hash_len, 137+ uint64_t max_variable_size) 138+{ 139+ efi_status_t status = EFI_SUCCESS; 140+ EFI_GUID global_variable_guid = EFI_GLOBAL_VARIABLE; 141+ EFI_GUID security_database_guid = EFI_IMAGE_SECURITY_DATABASE_GUID; 142+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *pk_variable = NULL; 143+ size_t pk_payload_size = 0; 144+ 145+ /* database variables can be verified by either PK or KEK while images 146+ * should be checked by db and dbx so the length of two will be enough. 147+ */ 148+ SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *allowed_key_store_variables[] = { NULL, NULL }; 149+ 150 /** 151 * UEFI: Page 253 152 * 3. If the variable SetupMode==1, and the variable is a secure 153@@ -1166,14 +1251,14 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont 154 * Platform Key is checked to enable or disable authentication. 155 */ 156 create_smm_variable(&pk_variable, sizeof(EFI_PLATFORM_KEY_NAME), 157- variable_info.MaximumVariableSize, (uint8_t *)EFI_PLATFORM_KEY_NAME, 158+ max_variable_size, (uint8_t *)EFI_PLATFORM_KEY_NAME, 159 &global_variable_guid); 160 161 if (!pk_variable) 162 return EFI_OUT_OF_RESOURCES; 163 164 status = uefi_variable_store_get_variable( 165- context, pk_variable, variable_info.MaximumVariableSize, &pk_payload_size); 166+ context, pk_variable, max_variable_size, &pk_payload_size); 167 168 /* If PK does not exist authentication is disabled */ 169 if (status != EFI_SUCCESS) { 170@@ -1207,66 +1292,8 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont 171 goto end; 172 } 173 174- /** 175- * UEFI: Page 246 176- * If the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set in a 177- * SetVariable() call, and firmware does not support signature type of the certificate 178- * included in the EFI_VARIABLE_AUTHENTICATION_2 descriptor, then the SetVariable() call 179- * shall return EFI_INVALID_PARAMETER. The list of signature types supported by the 180- * firmware is defined by the SignatureSupport variable. Signature type of the certificate 181- * is defined by its digest and encryption algorithms. 182- */ 183- /* TODO: Should support WIN_CERT_TYPE_PKCS_SIGNED_DATA and WIN_CERT_TYPE_EFI_PKCS115 */ 184- if (var_map.efi_auth_descriptor->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) 185- return EFI_INVALID_PARAMETER; 186- 187- /* Only a CertType of EFI_CERT_TYPE_PKCS7_GUID is accepted */ 188- if (!compare_guid(&var_map.efi_auth_descriptor->AuthInfo.CertType, &pkcs7_guid)) 189- return EFI_SECURITY_VIOLATION; 190- 191- /** 192- * Time associated with the authentication descriptor. For the TimeStamp value, 193- * components Pad1, Nanosecond, TimeZone, Daylight and Pad2 shall be set to 0. 194- * This means that the time shall always be expressed in GMT. 195- * 196- * UEFI: Page 253 197- * 2. Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components 198- * of the TimeStamp value are set to zero. 199- */ 200- if ((var_map.efi_auth_descriptor->TimeStamp.Pad1 != 0) || 201- (var_map.efi_auth_descriptor->TimeStamp.Pad2 != 0) || 202- (var_map.efi_auth_descriptor->TimeStamp.Nanosecond != 0) || 203- (var_map.efi_auth_descriptor->TimeStamp.TimeZone != 0) || 204- (var_map.efi_auth_descriptor->TimeStamp.Daylight != 0)) { 205- return EFI_SECURITY_VIOLATION; 206- } 207- 208- /** 209- * UEFI: Page 253 210- * Unless the EFI_VARIABLE_APPEND_WRITE attribute is set, verify 211- * that the TimeStamp value is later than the current 212- * timestamp value associated with the variable 213- */ 214- if (!(var->Attributes & EFI_VARIABLE_APPEND_WRITE)) { 215- if (memcmp(&var_map.efi_auth_descriptor->TimeStamp, timestamp, sizeof(EFI_GUID)) <= 0) { 216- EMSG("Timestamp violation"); 217- return EFI_SECURITY_VIOLATION; 218- } 219- 220- /* Save new timestamp */ 221- memcpy(timestamp, &var_map.efi_auth_descriptor->TimeStamp, sizeof(EFI_TIME)); 222- } 223- /* Calculate hash for the variable only once */ 224- hash_result = calc_variable_hash(&var_map, (uint8_t *)&hash_buffer, sizeof(hash_buffer), 225- &hash_len); 226- 227- if (!hash_result) { 228- status = EFI_SECURITY_VIOLATION; 229- goto end; 230- } 231- 232- status = select_verification_keys(var_map, global_variable_guid, security_database_guid, 233- variable_info.MaximumVariableSize, 234+ status = select_verification_keys(*var_map, global_variable_guid, security_database_guid, 235+ max_variable_size, 236 &allowed_key_store_variables[0]); 237 238 if (status != EFI_SUCCESS) 239@@ -1280,8 +1307,8 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont 240 continue; 241 242 status = uefi_variable_store_get_variable(context, allowed_key_store_variables[i], 243- variable_info.MaximumVariableSize, 244- &actual_variable_length); 245+ max_variable_size, 246+ &actual_variable_length); 247 248 if (status) { 249 /* When the parent does not exist it is considered verification failure */ 250@@ -1297,8 +1324,8 @@ static efi_status_t authenticate_variable(const struct uefi_variable_store *cont 251 goto end; 252 } 253 254- status = verify_var_by_key_var(&var_map, &allowed_key_store_var_map, 255- (uint8_t *)&hash_buffer, hash_len); 256+ status = verify_var_by_key_var(var_map, &allowed_key_store_var_map, 257+ hash_buffer, hash_len); 258 259 if (status == EFI_SUCCESS) 260 goto end; 261@@ -1311,18 +1338,6 @@ end: 262 free(allowed_key_store_variables[i]); 263 } 264 265- /* Remove the authentication header from the variable if the authentication is successful */ 266- if (status == EFI_SUCCESS) { 267- uint8_t *smm_payload = 268- (uint8_t *)var + SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE_DATA_OFFSET(var); 269- 270- memmove(smm_payload, var_map.payload, var_map.payload_len); 271- memset((uint8_t *)smm_payload + var_map.payload_len, 0, 272- var_map.efi_auth_descriptor_len); 273- 274- var->DataSize -= var_map.efi_auth_descriptor_len; 275- } 276- 277 return status; 278 } 279 #endif 280-- 2812.25.1 282 283