399 lines
13 KiB
C
399 lines
13 KiB
C
//
|
|
// This file contains a 'Sample Driver' and is licensed as such
|
|
// under the terms of your license agreement with Intel or your
|
|
// vendor. This file may be modified by the user, subject to
|
|
// the additional terms of the license agreement
|
|
//
|
|
/**
|
|
Manage trusted certificate database in KeyEnroll tool.
|
|
|
|
Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
|
|
This software and associated documentation (if any) is furnished
|
|
under a license and may only be used or copied in accordance
|
|
with the terms of the license. Except as permitted by such
|
|
license, no part of this software or documentation may be
|
|
reproduced, stored in a retrieval system, or transmitted in any
|
|
form or by any means without the express written consent of
|
|
Intel Corporation.
|
|
|
|
**/
|
|
|
|
#include "AuthVarCertDB.h"
|
|
|
|
extern LIST_ENTRY mVarListEntry;
|
|
EFI_GUID gEfiCertDbGuid = { 0xd9bee56e, 0x75dc, 0x49d9, { 0xb4, 0xd7, 0xb5, 0x34, 0x21, 0xf, 0x63, 0x7a } };
|
|
CONST UINT32 gEfiCertDBAttr = EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS |
|
|
EFI_VARIABLE_NON_VOLATILE |
|
|
EFI_VARIABLE_RUNTIME_ACCESS |
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS;
|
|
|
|
/*
|
|
Function to get "certdb" variable according to Attributes parameter.
|
|
|
|
@param[in] Attributes Attributes of authenticated variable.
|
|
@param[out] CertDBPtr Point to "certdb" variable buffer.
|
|
|
|
@retval EFI_SUCCESS Find matching certs and output parameters.
|
|
@retval EFI_INVALID_PARAMETER CertDBPtr is NULL or Attributes is invalid.
|
|
@retval EFI_SECURITY_VIOLATION CertDB structure has been corrupted.
|
|
@retval EFI_NOT_FOUND Fail to find matching certs.
|
|
*/
|
|
EFI_STATUS
|
|
GetCertDB (
|
|
IN UINT32 Attributes,
|
|
OUT VOID **CertDBPtr
|
|
)
|
|
{
|
|
CHAR16 *CertDBName;
|
|
VARIABLE_INFO_PRIVATE *VariableInfo;
|
|
|
|
if (CertDBPtr == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
|
|
CertDBName = EFI_CERT_DB;
|
|
} else {
|
|
Error (NULL, 0, 0, "Just support EFI_VARIABLE_NON_VOLATILE attribute.", NULL);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
VariableInfo = FindVariableInfoPtr (CertDBName, &gEfiCertDbGuid);
|
|
if (VariableInfo == NULL || VariableInfo->Size == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (*(UINT32 *)(VariableInfo->Buffer) != VariableInfo->Size) {
|
|
Error (NULL, 0, 0, "CertDB corrupt.", NULL);
|
|
return EFI_SECURITY_VIOLATION;
|
|
}
|
|
|
|
*CertDBPtr = VariableInfo;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Find matching signer's certificates for common authenticated variable
|
|
by corresponding VariableName and VendorGuid from "certdb".
|
|
|
|
@param[in] VariableName Name of authenticated Variable.
|
|
@param[in] VendorGuid Vendor GUID of authenticated Variable.
|
|
@param[in] Data Pointer to variable "certdb".
|
|
@param[in] DataSize Size of variable "certdb".
|
|
@param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA, from starting of Data.
|
|
@param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.
|
|
@param[out] CertDataPtr Pointer to the matching CertData.
|
|
@param[out] CertDataSize Lenght of CertData in bytes.
|
|
|
|
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
|
@retval EFI_NOT_FOUND Fail to find matching certs.
|
|
@retval EFI_SUCCESS Find matching certs and output parameters.
|
|
**/
|
|
EFI_STATUS
|
|
FindCertsFromDb (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN UINT32 Attributes,
|
|
OUT UINT32 *CertNodeOffset OPTIONAL,
|
|
OUT UINT32 *CertNodeSize OPTIONAL,
|
|
OUT UINT8 **CertDataPtr OPTIONAL,
|
|
OUT UINT32 *CertDataSize OPTIONAL
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VARIABLE_INFO_PRIVATE *VariableInfo;
|
|
AUTH_CERT_DB_DATA *Ptr;
|
|
UINT32 CertDBListSize;
|
|
UINT32 Offset;
|
|
UINT32 NodeSize;
|
|
UINT32 NameSize;
|
|
UINT32 DataSize;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
if ((VariableName == NULL) || (VendorGuid == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = GetCertDB (Attributes, (VOID **)&VariableInfo);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (VariableInfo->Buffer == NULL || VariableInfo->Size == 0) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
if (VariableInfo->Size != *((UINT32 *)VariableInfo->Buffer)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
CertDBListSize = VariableInfo->Size;
|
|
Offset = sizeof (UINT32);
|
|
|
|
//
|
|
// Traverse CertDB and try to matching certs.
|
|
//
|
|
while (Offset < CertDBListSize) {
|
|
Ptr = (AUTH_CERT_DB_DATA *) ((UINT8 *)VariableInfo->Buffer + Offset);
|
|
|
|
NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
|
|
NameSize = ReadUnaligned32 (&Ptr->NameSize);
|
|
DataSize = ReadUnaligned32 (&Ptr->CertDataSize);
|
|
|
|
if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + DataSize + NameSize * sizeof (CHAR16)) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;
|
|
if ((CompareGuid (&Ptr->VendorGuid, VendorGuid) == 0) &&
|
|
(NameSize == KeyEnrollStrLen (VariableName)) &&
|
|
(CompareMem (VariableName, VariableInfo->Buffer + Offset, NameSize * sizeof (CHAR16)) == 0)
|
|
) {
|
|
if (CertNodeOffset != NULL) {
|
|
*CertNodeOffset = (UINT32) ((UINT8 *)Ptr - VariableInfo->Buffer);
|
|
}
|
|
if (CertNodeSize != NULL) {
|
|
*CertNodeSize = NodeSize;
|
|
}
|
|
if (CertDataPtr != NULL) {
|
|
*CertDataPtr = (UINT8 *)Ptr + sizeof (EFI_GUID) + sizeof (UINT32) * 3 + NameSize * sizeof (CHAR16);
|
|
}
|
|
if (CertDataSize != NULL) {
|
|
*CertDataSize = DataSize;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
Offset = Offset + NameSize * sizeof (CHAR16) + DataSize;
|
|
}
|
|
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
/**
|
|
Delete matching signer's certificates when deleting common authenticated
|
|
variable by corresponding VariableName and VendorGuid from "certdb".
|
|
|
|
@param[in] VariableName Name of authenticated Variable.
|
|
@param[in] VendorGuid Vendor GUID of authenticated Variable.
|
|
@param[in] Attributes Attributes of authenticated variable.
|
|
|
|
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
|
@retval EFI_NOT_FOUND Fail to find "certdb" or matching certs.
|
|
@retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
|
|
@retval EFI_SUCCESS The operation is completed successfully.
|
|
**/
|
|
EFI_STATUS
|
|
DeleteCertsFromDb (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN UINT32 Attributes
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VARIABLE_INFO_PRIVATE *VariableInfo;
|
|
UINT32 CertNodeOffset;
|
|
UINT32 CertNodeSize;
|
|
UINT8 *NewBuffer;
|
|
UINTN NewBufferSize;
|
|
|
|
Status = EFI_SUCCESS;
|
|
VariableInfo = NULL;
|
|
NewBuffer = NULL;
|
|
CertNodeOffset = 0;
|
|
CertNodeSize = 0;
|
|
|
|
if (VariableName == NULL || VendorGuid == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = GetCertDB (Attributes, (VOID **)&VariableInfo);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = FindCertsFromDb (
|
|
VariableName,
|
|
VendorGuid,
|
|
Attributes,
|
|
&CertNodeOffset,
|
|
&CertNodeSize,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
NewBufferSize = VariableInfo->Size - CertNodeSize;
|
|
|
|
//
|
|
// If the NewBufferSize == 4, it means no AUTH_CERT_DB_DATA in "certDB".
|
|
//
|
|
if (NewBufferSize == 4) {
|
|
return DeleteVariableList (&mVarListEntry, VariableInfo->Name, &gEfiCertDbGuid);
|
|
}
|
|
|
|
NewBuffer = (UINT8 *)malloc (NewBufferSize);
|
|
if (NewBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Copy first-part from old buffer to new buffer.
|
|
//
|
|
CopyMem (NewBuffer, VariableInfo->Buffer, CertNodeOffset);
|
|
//
|
|
// Copy second-part to new buffer.
|
|
//
|
|
CopyMem (
|
|
NewBuffer + CertNodeOffset,
|
|
VariableInfo->Buffer + CertNodeOffset + CertNodeSize,
|
|
VariableInfo->Size - CertNodeOffset - CertNodeSize
|
|
);
|
|
|
|
Status = CreateVariableList (
|
|
&mVarListEntry,
|
|
VariableInfo->Name,
|
|
&gEfiCertDbGuid,
|
|
gEfiCertDBAttr,
|
|
NULL,
|
|
NewBufferSize,
|
|
NewBuffer,
|
|
FALSE
|
|
);
|
|
|
|
FREE_NON_NULL_PTR (NewBuffer);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Insert signer's certificates for common authenticated variable
|
|
with VariableName and VendorGuid in AUTH_CERT_DB_DATA to "certdb".
|
|
|
|
@param[in] VariableName Name of authenticated Variable.
|
|
@param[in] VendorGuid Vendor GUID of authenticated Variable.
|
|
@param[in] Attributes Attributes of authenticated variable.
|
|
@param[in] SignerCert Signer certificate data.
|
|
@param[in] SignerCertSize Length of signer certificate.
|
|
@param[in] TopLevelCert Top-level certificate data.
|
|
@param[in] TopLevelCertSize Length of top-level certificate.
|
|
|
|
|
|
@retval EFI_INVALID_PARAMETER Any input parameter is invalid.
|
|
@retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName
|
|
and VendorGuid already exists.
|
|
@retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
|
|
@retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb" or "certdbv"
|
|
**/
|
|
EFI_STATUS
|
|
InsertCertsToDb (
|
|
IN CHAR16 *VariableName,
|
|
IN EFI_GUID *VendorGuid,
|
|
IN UINT32 Attributes,
|
|
IN UINT8 *SignerCert,
|
|
IN UINTN SignerCertSize,
|
|
IN UINT8 *TopLevelCert,
|
|
IN UINTN TopLevelCertSize
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Sha256Digest[SHA256_DIGEST_SIZE];
|
|
UINT8 *NewBuffer;
|
|
UINTN NewBufferSize;
|
|
UINT32 NameSize;
|
|
UINT32 NodeSize;
|
|
UINT32 DataSize;
|
|
UINT32 Offset;
|
|
CHAR16 *CertDBName;
|
|
|
|
Status = EFI_SUCCESS;
|
|
NewBuffer = NULL;
|
|
|
|
if (VariableName == NULL || VendorGuid == NULL || SignerCert == NULL || TopLevelCert == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
|
|
CertDBName = EFI_CERT_DB;
|
|
} else {
|
|
Error (NULL, 0, 0, "Just support EFI_VARIABLE_NON_VOLATILE attribute.", NULL);
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = FindCertsFromDb (VariableName, VendorGuid, Attributes, NULL, NULL, NULL, NULL);
|
|
if (Status == EFI_SUCCESS) {
|
|
return EFI_SECURITY_VIOLATION;
|
|
} else if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
|
|
return Status;
|
|
}
|
|
|
|
Status = CalculatePrivAuthVarSignChainSHA256Digest (
|
|
SignerCert,
|
|
SignerCertSize,
|
|
TopLevelCert,
|
|
TopLevelCertSize,
|
|
Sha256Digest
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
///
|
|
/// AUTH_CERT_DB_DATA format:
|
|
///
|
|
/// EFI_GUID VendorGuid;
|
|
/// UINT32 CertNodeSize;
|
|
/// UINT32 NameSize;
|
|
/// UINT32 CertDataSize;
|
|
/// CHAR16 VariableName[NameSize];
|
|
/// UINT8 CertData[CertDataSize];
|
|
///
|
|
|
|
NameSize = (UINT32)(KeyEnrollStrLen (VariableName));
|
|
DataSize = SHA256_DIGEST_SIZE;
|
|
NodeSize = sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16) + DataSize;
|
|
|
|
NewBufferSize = sizeof (UINT32) + NodeSize;
|
|
|
|
NewBuffer = (UINT8 *)malloc (NewBufferSize);
|
|
if (NewBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
Offset = 0;
|
|
CopyMem (NewBuffer + Offset, &NewBufferSize, sizeof (UINT32));
|
|
Offset = Offset + sizeof (UINT32);
|
|
|
|
CopyMem (NewBuffer + Offset, VendorGuid, sizeof (EFI_GUID));
|
|
Offset = Offset + sizeof (EFI_GUID);
|
|
|
|
CopyMem (NewBuffer + Offset, &NodeSize, sizeof (UINT32));
|
|
Offset = Offset + sizeof (UINT32);
|
|
|
|
CopyMem (NewBuffer + Offset, &NameSize, sizeof (UINT32));
|
|
Offset = Offset + sizeof (UINT32);
|
|
|
|
CopyMem (NewBuffer + Offset, &DataSize, sizeof (UINT32));
|
|
Offset = Offset + sizeof (UINT32);
|
|
|
|
CopyMem (NewBuffer + Offset, VariableName, NameSize * sizeof (CHAR16));
|
|
Offset = Offset + NameSize * sizeof (CHAR16);
|
|
|
|
CopyMem (NewBuffer + Offset, Sha256Digest, DataSize);
|
|
|
|
Status = CreateVariableList (
|
|
&mVarListEntry,
|
|
CertDBName,
|
|
&gEfiCertDbGuid,
|
|
gEfiCertDBAttr,
|
|
NULL,
|
|
NewBufferSize,
|
|
NewBuffer,
|
|
FALSE
|
|
);
|
|
|
|
FREE_NON_NULL_PTR (NewBuffer);
|
|
return Status;
|
|
}
|