X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=SecurityPkg%2FVariableAuthenticated%2FSecureBootConfigDxe%2FSecureBootConfigImpl.c;h=0a08479b4b01a07ae60c70d9de843c05e1e4bef1;hp=c80c5eaface3db49074488dd48bf5e4aad7fcf8d;hb=de2447dd4ca93ca37ff067c325e478dc586235ca;hpb=4adc12bfc30e59c4592c0351e0d9d1a07ed0e357 diff --git a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c index c80c5eafac..0a08479b4b 100644 --- a/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c +++ b/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c @@ -108,6 +108,90 @@ SaveSecureBootVariable ( return Status; } +/** + Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2 + descriptor with the input data. NO authentication is required in this function. + + @param[in, out] DataSize On input, the size of Data buffer in bytes. + On output, the size of data returned in Data + buffer in bytes. + @param[in, out] Data On input, Pointer to data buffer to be wrapped or + pointer to NULL to wrap an empty payload. + On output, Pointer to the new payload date buffer allocated from pool, + it's caller's responsibility to free the memory when finish using it. + + @retval EFI_SUCCESS Create time based payload successfully. + @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload. + @retval EFI_INVALID_PARAMETER The parameter is invalid. + @retval Others Unexpected error happens. + +**/ +EFI_STATUS +CreateTimeBasedPayload ( + IN OUT UINTN *DataSize, + IN OUT UINT8 **Data + ) +{ + EFI_STATUS Status; + UINT8 *NewData; + UINT8 *Payload; + UINTN PayloadSize; + EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData; + UINTN DescriptorSize; + EFI_TIME Time; + + if (Data == NULL || DataSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // In Setup mode or Custom mode, the variable does not need to be signed but the + // parameters to the SetVariable() call still need to be prepared as authenticated + // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate + // data in it. + // + Payload = *Data; + PayloadSize = *DataSize; + + DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData); + NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize); + if (NewData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if ((Payload != NULL) && (PayloadSize != 0)) { + CopyMem (NewData + DescriptorSize, Payload, PayloadSize); + } + + DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData); + + ZeroMem (&Time, sizeof (EFI_TIME)); + Status = gRT->GetTime (&Time, NULL); + if (EFI_ERROR (Status)) { + FreePool(NewData); + return Status; + } + Time.Pad1 = 0; + Time.Nanosecond = 0; + Time.TimeZone = 0; + Time.Daylight = 0; + Time.Pad2 = 0; + CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME)); + + DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData); + DescriptorData->AuthInfo.Hdr.wRevision = 0x0200; + DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID; + CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid); + + if (Payload != NULL) { + FreePool(Payload); + } + + *DataSize = DescriptorSize + PayloadSize; + *Data = NewData; + return EFI_SUCCESS; +} + /** Internal helper function to delete a Variable given its name and GUID, NO authentication required. @@ -127,129 +211,36 @@ DeleteVariable ( { EFI_STATUS Status; VOID* Variable; + UINT8 *Data; + UINTN DataSize; + UINT32 Attr; - Variable = GetVariable (VariableName, VendorGuid); + GetVariable2 (VariableName, VendorGuid, &Variable, NULL); if (Variable == NULL) { return EFI_SUCCESS; } - Status = gRT->SetVariable ( - VariableName, - VendorGuid, - EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, - 0, - NULL - ); - return Status; -} - -/** - Generate a PK signature list from the public key storing file (*.pbk). - - @param[in] PkKeyFile FileHandle of the public key storing file. - @param[out] PkCert Point to the data buffer to store the signature list. - - @return EFI_UNSUPPORTED Unsupported Key Length. - @return EFI_OUT_OF_RESOURCES There are not enough memory resourses to form the signature list. - -**/ -EFI_STATUS -CreatePkRsaSignatureList ( - IN EFI_FILE_HANDLE PkKeyFile, - OUT EFI_SIGNATURE_LIST **PkCert - ) -{ - EFI_STATUS Status; - UINTN KeyBlobSize; - VOID *KeyBlob; - CPL_KEY_INFO *KeyInfo; - EFI_SIGNATURE_DATA *PkCertData; - VOID *KeyBuffer; - UINTN KeyLenInBytes; - - PkCertData = NULL; - KeyBlob = NULL; - KeyBuffer = NULL; - Status = EFI_SUCCESS; - - // - // Get key from PK key file - // - Status = ReadFileContent (PkKeyFile, &KeyBlob, &KeyBlobSize, 0); - if (EFI_ERROR(Status)) { - DEBUG ((EFI_D_ERROR, "Can't Open the file for PK enrolling.\n")); - goto ON_EXIT; - } - - KeyInfo = (CPL_KEY_INFO *)KeyBlob; - if (KeyInfo->KeyLengthInBits/8 != WIN_CERT_UEFI_RSA2048_SIZE) { - Status = EFI_UNSUPPORTED; - goto ON_EXIT; - } - - // - // Convert the Public key to fix octet string format represented in RSA PKCS#1. - // - KeyLenInBytes = KeyInfo->KeyLengthInBits / 8; - KeyBuffer = AllocateZeroPool(KeyLenInBytes); - if (KeyBuffer == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; - } - Status = Int2OctStr ( - (UINTN*) ((UINTN)KeyBlob + sizeof(CPL_KEY_INFO)), - KeyLenInBytes / sizeof (UINTN), - (UINT8*)KeyBuffer, - KeyLenInBytes - ); - if (EFI_ERROR(Status)) { - goto ON_EXIT; - } + Data = NULL; + DataSize = 0; + Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS + | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; - // Allocate space for PK certificate list and initialize the list. - // Create PK database entry with SignatureHeaderSize equals 0. - // - *PkCert = (EFI_SIGNATURE_LIST*)AllocateZeroPool( - sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 - + WIN_CERT_UEFI_RSA2048_SIZE - ); - - if (*PkCert == NULL) { - Status = EFI_OUT_OF_RESOURCES; - goto ON_EXIT; + Status = CreateTimeBasedPayload (&DataSize, &Data); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + return Status; } - (*PkCert)->SignatureListSize = sizeof(EFI_SIGNATURE_LIST) - + sizeof(EFI_SIGNATURE_DATA) - 1 - + WIN_CERT_UEFI_RSA2048_SIZE; - (*PkCert)->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + WIN_CERT_UEFI_RSA2048_SIZE; - (*PkCert)->SignatureHeaderSize = 0; - CopyGuid (&(*PkCert)->SignatureType, &gEfiCertRsa2048Guid); - - PkCertData = (EFI_SIGNATURE_DATA*)((UINTN)(*PkCert) - + sizeof(EFI_SIGNATURE_LIST) - + (*PkCert)->SignatureHeaderSize); - CopyGuid (&PkCertData->SignatureOwner, &gEfiGlobalVariableGuid); - // - // Fill the PK database with PKpub data from PKKeyFile. - // - CopyMem (&(PkCertData->SignatureData[0]), KeyBuffer, WIN_CERT_UEFI_RSA2048_SIZE); - -ON_EXIT: - - if (KeyBlob != NULL) { - FreePool (KeyBlob); - } - - if (EFI_ERROR(Status) && *PkCert != NULL) { - FreePool (*PkCert); - *PkCert = NULL; - } - - if (KeyBuffer != NULL) { - FreePool (KeyBuffer); + Status = gRT->SetVariable ( + VariableName, + VendorGuid, + Attr, + DataSize, + Data + ); + if (Data != NULL) { + FreePool (Data); } - return Status; } @@ -282,6 +273,7 @@ CreatePkX509SignatureList ( if (EFI_ERROR (Status)) { goto ON_EXIT; } + ASSERT (X509Data != NULL); // // Allocate space for PK certificate list and initialize it. @@ -355,11 +347,11 @@ EnrollPlatformKey ( PkCert = NULL; // - // Parse the file's postfix. Only support *.pbk(RSA2048) and *.cer(X509) files. + // Parse the file's postfix. Only support *.cer(X509) files. // FilePostFix = Private->FileContext->FileName + StrLen (Private->FileContext->FileName) - 4; - if (CompareMem (FilePostFix, L".pbk",4) && CompareMem (FilePostFix, L".cer",4)) { - DEBUG ((EFI_D_ERROR, "Don't support the file, only *.pbk or *.cer.\n is supported.")); + if (CompareMem (FilePostFix, L".cer",4)) { + DEBUG ((EFI_D_ERROR, "Don't support the file, only *.cer is supported.")); return EFI_INVALID_PARAMETER; } DEBUG ((EFI_D_INFO, "FileName= %s\n", Private->FileContext->FileName)); @@ -368,30 +360,27 @@ EnrollPlatformKey ( // // Prase the selected PK file and generature PK certificate list. // - if (!CompareMem (FilePostFix, L".pbk",4)) { - Status = CreatePkRsaSignatureList ( - Private->FileContext->FHandle, - &PkCert - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - } else if (!CompareMem (FilePostFix, L".cer",4)) { - Status = CreatePkX509SignatureList ( - Private->FileContext->FHandle, - &PkCert - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } + Status = CreatePkX509SignatureList ( + Private->FileContext->FHandle, + &PkCert + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; } + ASSERT (PkCert != NULL); // // Set Platform Key variable. // Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS - | EFI_VARIABLE_BOOTSERVICE_ACCESS; + | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; DataSize = PkCert->SignatureListSize; + Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &PkCert); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + Status = gRT->SetVariable( EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, @@ -434,8 +423,10 @@ DeletePlatformKey ( { EFI_STATUS Status; - Status = DeleteVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid); - + Status = DeleteVariable ( + EFI_PLATFORM_KEY_NAME, + &gEfiGlobalVariableGuid + ); return Status; } @@ -490,6 +481,7 @@ EnrollRsa2048ToKek ( if (EFI_ERROR (Status)) { goto ON_EXIT; } + ASSERT (KeyBlob != NULL); KeyInfo = (CPL_KEY_INFO *) KeyBlob; if (KeyInfo->KeyLengthInBits / 8 != WIN_CERT_UEFI_RSA2048_SIZE) { DEBUG ((DEBUG_ERROR, "Unsupported key length, Only RSA2048 is supported.\n")); @@ -547,8 +539,14 @@ EnrollRsa2048ToKek ( // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the // new KEK to original variable. // - Attr |= EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS; - DataSize = 0; + Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + Status = gRT->GetVariable( EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, @@ -641,6 +639,7 @@ EnrollX509ToKek ( if (EFI_ERROR (Status)) { goto ON_EXIT; } + ASSERT (X509Data != NULL); KekSigListSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize; KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize); @@ -667,8 +666,13 @@ EnrollX509ToKek ( // new kek to original variable // Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS - | EFI_VARIABLE_BOOTSERVICE_ACCESS; - + | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + Status = gRT->GetVariable( EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, @@ -792,6 +796,7 @@ EnrollX509toSigDB ( if (EFI_ERROR (Status)) { goto ON_EXIT; } + ASSERT (X509Data != NULL); SigDBSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize; @@ -820,7 +825,12 @@ EnrollX509toSigDB ( // new signature data to original variable // Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS - | EFI_VARIABLE_BOOTSERVICE_ACCESS; + | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } Status = gRT->GetVariable( VariableName, @@ -1006,7 +1016,21 @@ HashPeImage ( // Measuring PE/COFF Image Header; // But CheckSum field and SECURITY data directory (certificate) are excluded // - Magic = mNtHeader.Pe32->OptionalHeader.Magic; + if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value + // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the + // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC + // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + } else { + // + // Get the magic value from the PE/COFF Optional Header + // + Magic = mNtHeader.Pe32->OptionalHeader.Magic; + } + // // 3. Calculate the distance from the base of the image header to the image checksum address. // 4. Hash the image header from its base to beginning of the image checksum. @@ -1275,8 +1299,6 @@ EnrollImageSignatureToSigDB ( Data = NULL; GuidCertData = NULL; - Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS - | EFI_VARIABLE_BOOTSERVICE_ACCESS; // // Form the SigDB certificate list. @@ -1299,6 +1321,7 @@ EnrollImageSignatureToSigDB ( if (EFI_ERROR (Status)) { goto ON_EXIT; } + ASSERT (mImageBase != NULL); Status = LoadPeImage (); if (EFI_ERROR (Status)) { @@ -1367,6 +1390,14 @@ EnrollImageSignatureToSigDB ( CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID); CopyMem (SigDBCertData->SignatureData, mImageDigest, mImageDigestSize); + Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS + | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; + Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + // // Check if SigDB variable has been already existed. // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the @@ -1792,8 +1823,14 @@ DeleteKeyExchangeKey ( CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); } - CertList = (EFI_SIGNATURE_LIST*) OldData; DataSize = Offset; + if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) { + Status = CreateTimeBasedPayload (&DataSize, &OldData); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + } Status = gRT->SetVariable( EFI_KEY_EXCHANGE_KEY_NAME, @@ -1979,8 +2016,14 @@ DeleteSignature ( CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); } - CertList = (EFI_SIGNATURE_LIST*) OldData; DataSize = Offset; + if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) { + Status = CreateTimeBasedPayload (&DataSize, &OldData); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status)); + goto ON_EXIT; + } + } Status = gRT->SetVariable( VariableName, @@ -2035,7 +2078,7 @@ SecureBootExtractConfigFromVariable ( // // Get the SecureBootEnable Variable // - SecureBootEnable = GetVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid); + GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL); // // If the SecureBootEnable Variable doesn't exist, hide the SecureBoot Enable/Disable @@ -2059,7 +2102,7 @@ SecureBootExtractConfigFromVariable ( // // If there is no PK then the Delete Pk button will be gray. // - SetupMode = GetVariable (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid); + GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL); if (SetupMode == NULL || (*SetupMode) == 1) { ConfigData->HasPk = FALSE; } else { @@ -2069,7 +2112,7 @@ SecureBootExtractConfigFromVariable ( // // Get the SecureBootMode from CustomMode variable. // - SecureBootMode = GetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid); + GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL); if (SecureBootMode == NULL) { ConfigData->SecureBootMode = STANDARD_SECURE_BOOT_MODE; } else { @@ -2269,6 +2312,9 @@ SecureBootCallback ( UINTN BufferSize; SECUREBOOT_CONFIGURATION *IfrNvData; UINT16 LabelId; + UINT8 *SecureBootEnable; + + SecureBootEnable = NULL; if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) { return EFI_INVALID_PARAMETER; @@ -2297,7 +2343,8 @@ SecureBootCallback ( switch (QuestionId) { case KEY_SECURE_BOOT_ENABLE: - if (NULL != GetVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid)) { + GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL); + if (NULL != SecureBootEnable) { if (EFI_ERROR (SaveSecureBootVariable (Value->u8))) { CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, @@ -2458,7 +2505,7 @@ SecureBootCallback ( CreatePopUp ( EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, - L"ERROR: The File Type is neither *.cer nor *.pbk!", + L"ERROR: Unsupported file type, only *.cer is supported!", NULL ); } else { @@ -2484,7 +2531,8 @@ SecureBootCallback ( break; case KEY_SECURE_BOOT_MODE: - if (NULL != GetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid)) { + GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootEnable, NULL); + if (NULL != SecureBootEnable) { Status = gRT->SetVariable ( EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid,