diff options
Diffstat (limited to 'src/VBox/Runtime/common/efi/efisignaturedb.cpp')
-rw-r--r-- | src/VBox/Runtime/common/efi/efisignaturedb.cpp | 587 |
1 files changed, 587 insertions, 0 deletions
diff --git a/src/VBox/Runtime/common/efi/efisignaturedb.cpp b/src/VBox/Runtime/common/efi/efisignaturedb.cpp new file mode 100644 index 00000000..6f9c3436 --- /dev/null +++ b/src/VBox/Runtime/common/efi/efisignaturedb.cpp @@ -0,0 +1,587 @@ +/* $Id: efisignaturedb.cpp $ */ +/** @file + * IPRT - EFI signature database helpers. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP RTLOGGROUP_DEFAULT +#include <iprt/efi.h> + +#include <iprt/cdefs.h> +#include <iprt/asm.h> +#include <iprt/string.h> +#include <iprt/list.h> +#include <iprt/mem.h> +#include <iprt/sg.h> + +#include <iprt/formats/efi-signature.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ + +/** + * EFI signature entry. + */ +typedef struct RTEFISIGNATURE +{ + /** List node. */ + RTLISTNODE NdLst; + /** The signature owner. */ + RTUUID UuidOwner; + /** Size of the signature data in bytes. */ + uint32_t cbSignature; + /** The signature data (variable in size). */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abSignature[RT_FLEXIBLE_ARRAY]; +} RTEFISIGNATURE; +/** Pointer to a EFI signature entry. */ +typedef RTEFISIGNATURE *PRTEFISIGNATURE; +/** Pointer to a const EFI signature entry. */ +typedef const RTEFISIGNATURE *PCRTEFISIGNATURE; + + +/** + * The EFI signature database instance data. + */ +typedef struct RTEFISIGDBINT +{ + /** List head of the various signature types. */ + RTLISTANCHOR aLstSigTypes[RTEFISIGTYPE_FIRST_INVALID]; +} RTEFISIGDBINT; +/** Pointer to the EFI signature database instance data. */ +typedef RTEFISIGDBINT *PRTEFISIGDBINT; + + +/** + * Signature type descriptor. + */ +typedef struct RTEFISIGDBDESC +{ + /** The EFI GUID identifying the signature type. */ + EFI_GUID GuidSignatureType; + /** The additional signature header for this signature type. */ + uint32_t cbSigHdr; + /** Size of the signature data (including EFI_SIGNATURE_DATA), + * can be 0 size varies with each signature (X.509 for example). */ + uint32_t cbSig; + /** The internal signature type enum. */ + RTEFISIGTYPE enmSigType; + /** Human readable string of the signature type. */ + const char *pszName; +} RTEFISIGDBDESC; +/** Pointer to a signature type descriptor. */ +typedef RTEFISIGDBDESC *PRTEFISIGDBDESC; +/** Pointer to a const signature type descriptor. */ +typedef const RTEFISIGDBDESC *PCRTEFISIGDBDESC; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ + +/** + * Mapping of EFI signature GUIDs to their IPRT signature type equivalent. + */ +static const RTEFISIGDBDESC g_aGuid2SigTypeMapping[] = +{ + { EFI_NULL_GUID, 0, 0, RTEFISIGTYPE_INVALID, "INVALID" }, + { EFI_SIGNATURE_TYPE_GUID_SHA256, 0, EFI_SIGNATURE_TYPE_SZ_SHA256, RTEFISIGTYPE_SHA256, "SHA-256" }, + { EFI_SIGNATURE_TYPE_GUID_RSA2048, 0, EFI_SIGNATURE_TYPE_SZ_RSA2048, RTEFISIGTYPE_RSA2048, "RSA-2048" }, + { EFI_SIGNATURE_TYPE_GUID_RSA2048_SHA256, 0, EFI_SIGNATURE_TYPE_SZ_RSA2048_SHA256, RTEFISIGTYPE_RSA2048_SHA256, "RSA-2048/SHA-256" }, + { EFI_SIGNATURE_TYPE_GUID_SHA1, 0, EFI_SIGNATURE_TYPE_SZ_SHA1, RTEFISIGTYPE_SHA1, "SHA-1" }, + { EFI_SIGNATURE_TYPE_GUID_RSA2048_SHA1, 0, EFI_SIGNATURE_TYPE_SZ_RSA2048_SHA1, RTEFISIGTYPE_RSA2048_SHA1, "RSA-2048/SHA-1" }, + { EFI_SIGNATURE_TYPE_GUID_X509, 0, 0, RTEFISIGTYPE_X509, "X.509" } +}; + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ + + +/** + * Returns the internal siganture type descriptor for the given EFI GUID. + * + * @returns Pointer to the descriptor if found or NULL if not. + * @param pGuid The EFI signature type GUID to look for. + */ +static PCRTEFISIGDBDESC rtEfiSigDbGetDescByGuid(PCEFI_GUID pGuid) +{ + for (uint32_t i = 0; i < RT_ELEMENTS(g_aGuid2SigTypeMapping); i++) + if (!RTEfiGuidCompare(&g_aGuid2SigTypeMapping[i].GuidSignatureType, pGuid)) + return &g_aGuid2SigTypeMapping[i]; + + return NULL; +} + + +/** + * Validates the given signature lsit header. + * + * @returns Flag whether the list header is considered valid. + * @param pLstHdr The list header to validate. + * @param pDesc The descriptor for the signature type of the given list. + */ +static bool rtEfiSigDbSigHdrValidate(PCEFI_SIGNATURE_LIST pLstHdr, PCRTEFISIGDBDESC pDesc) +{ + uint32_t cbSigLst = RT_LE2H_U32(pLstHdr->cbSigLst); + uint32_t cbSigHdr = RT_LE2H_U32(pLstHdr->cbSigHdr); + uint32_t cbSig = RT_LE2H_U32(pLstHdr->cbSig); + + if (cbSigHdr != pDesc->cbSigHdr) + return false; + if (cbSig < sizeof(EFI_SIGNATURE_DATA)) + return false; + if ( pDesc->cbSig + && pLstHdr->cbSig != pDesc->cbSig) + return false; + if ( cbSigLst <= sizeof(*pLstHdr) + || cbSigLst <= cbSigHdr + || cbSigLst <= cbSig) + return false; + if ((cbSigLst - sizeof(*pLstHdr) - cbSigHdr) % cbSig) + return false; + + return true; +} + + +/** + * Loads a single signature list into the given signature database from the given file. + * + * @returns IPRT status code. + * @param pThis The signature database instance. + * @param hVfsFileIn The file to load the signature list from. + * @param pcbConsumed Where to store the number of bytes consumed for this signature list on success. + */ +static int rtEfiSigDbLoadSigList(PRTEFISIGDBINT pThis, RTVFSFILE hVfsFileIn, uint64_t *pcbConsumed) +{ + EFI_SIGNATURE_LIST LstHdr; + int rc = RTVfsFileRead(hVfsFileIn, &LstHdr, sizeof(LstHdr), NULL /*pcbRead*/); + if (RT_SUCCESS(rc)) + { + PCRTEFISIGDBDESC pDesc = rtEfiSigDbGetDescByGuid(&LstHdr.GuidSigType); + if (pDesc) + { + if (rtEfiSigDbSigHdrValidate(&LstHdr, pDesc)) + { + RTLISTANCHOR LstTmp; + uint32_t cbSig = RT_LE2H_U32(LstHdr.cbSig); + uint32_t cbSigData = cbSig - sizeof(EFI_SIGNATURE_DATA); + uint32_t cSigs = (RT_LE2H_U32(LstHdr.cbSigLst) - RT_LE2H_U32(LstHdr.cbSigHdr)) / cbSig; + + /** @todo Skip/parse signature header if we have to add a type which has this != 0. */ + RTListInit(&LstTmp); + for (uint32_t i = 0; i < cSigs && RT_SUCCESS(rc); i++) + { + PRTEFISIGNATURE pSig = (PRTEFISIGNATURE)RTMemAllocZ(RT_UOFFSETOF_DYN(RTEFISIGNATURE, abSignature[cbSigData])); + if (pSig) + { + EFI_SIGNATURE_DATA SigData; + rc = RTVfsFileRead(hVfsFileIn, &SigData, sizeof(SigData), NULL /*pcbRead*/); + if (RT_SUCCESS(rc)) + rc = RTVfsFileRead(hVfsFileIn, &pSig->abSignature[0], cbSigData, NULL /*pcbRead*/); + if (RT_SUCCESS(rc)) + { + RTEfiGuidToUuid(&pSig->UuidOwner, &SigData.GuidOwner); + pSig->cbSignature = cbSigData; + RTListAppend(&LstTmp, &pSig->NdLst); + } + else + RTMemFree(pSig); + } + else + rc = VERR_NO_MEMORY; + } + + if (RT_SUCCESS(rc)) + { + /* Add the signatures to the list. */ + RTListConcatenate(&pThis->aLstSigTypes[pDesc->enmSigType], &LstTmp); + *pcbConsumed = sizeof(LstHdr) + RT_LE2H_U32(LstHdr.cbSigHdr) + cSigs * cbSig; + } + else + { + /* Destroy the temporary list. */ + PRTEFISIGNATURE pIt, pItNext; + + RTListForEachSafe(&LstTmp, pIt, pItNext, RTEFISIGNATURE, NdLst) + { + RTListNodeRemove(&pIt->NdLst); + RTMemFree(pIt); + } + } + } + else + rc = VERR_NOT_SUPPORTED; + } + else + rc = VERR_NOT_SUPPORTED; + } + + return rc; +} + + +/** + * Variant for written a list of signatures where each signature gets its own signature list header + * (for types where each signature can differ in size like X.509). + * + * @returns IPRT status code. + * @param pLst The list of signatures to write. + * @param pDesc The signature type descriptor. + * @param hVfsFileOut The file to write the database to. + * @param pcbThisWritten Where to store the number of bytes written for the given signature list. + */ +static int rtEfiSigDbWriteListSingle(PRTLISTANCHOR pLst, PCRTEFISIGDBDESC pDesc, RTVFSFILE hVfsFileOut, size_t *pcbThisWritten) +{ + int rc = VINF_SUCCESS; + size_t cbWritten = 0; + PRTEFISIGNATURE pIt; + + RTListForEach(pLst, pIt, RTEFISIGNATURE, NdLst) + { + EFI_SIGNATURE_LIST LstHdr; + EFI_SIGNATURE_DATA SigData; + LstHdr.GuidSigType = pDesc->GuidSignatureType; + LstHdr.cbSigLst = RT_H2LE_U32(sizeof(LstHdr) + sizeof(SigData) + pDesc->cbSigHdr + pIt->cbSignature); + LstHdr.cbSigHdr = RT_H2LE_U32(pDesc->cbSigHdr); + LstHdr.cbSig = RT_H2LE_U32(pIt->cbSignature + sizeof(SigData)); + RTEfiGuidFromUuid(&SigData.GuidOwner, &pIt->UuidOwner); + + RTSGSEG aSegs[3]; + RTSGBUF SgBuf; + + Assert(!pDesc->cbSigHdr); + aSegs[0].pvSeg = &LstHdr; + aSegs[0].cbSeg = sizeof(LstHdr); + aSegs[1].pvSeg = &SigData; + aSegs[1].cbSeg = sizeof(SigData); + aSegs[2].pvSeg = &pIt->abSignature[0]; + aSegs[2].cbSeg = pIt->cbSignature; + RTSgBufInit(&SgBuf, &aSegs[0], RT_ELEMENTS(aSegs)); + rc = RTVfsFileSgWrite(hVfsFileOut, -1, &SgBuf, true /*fBlocking*/, NULL /*pcbWritten*/); + if (RT_FAILURE(rc)) + break; + + cbWritten += sizeof(LstHdr) + sizeof(SigData) + pDesc->cbSigHdr + pIt->cbSignature; + } + + if (RT_SUCCESS(rc)) + *pcbThisWritten = cbWritten; + + return rc; +} + + +/** + * Writes the given signature list to the database in the given file. + * + * @returns IPRT status code. + * @param pLst The list of signatures to write. + * @param pDesc The signature type descriptor. + * @param hVfsFileOut The file to write the database to. + * @param pcbThisWritten Where to store the number of bytes written for the given signature list. + */ +static int rtEfiSigDbWriteList(PRTLISTANCHOR pLst, PCRTEFISIGDBDESC pDesc, RTVFSFILE hVfsFileOut, size_t *pcbThisWritten) +{ + /* + * For signature lists where each signature can have a different size (X.509 for example) + * writing a new list for each signature is required which is done by a dedicated method. + */ + if (!pDesc->cbSig) + return rtEfiSigDbWriteListSingle(pLst, pDesc, hVfsFileOut, pcbThisWritten); + + + /* Count the number of signatures first. */ + uint32_t cSigs = 0; + PRTEFISIGNATURE pIt; + + RTListForEach(pLst, pIt, RTEFISIGNATURE, NdLst) + { + cSigs++; + } + + EFI_SIGNATURE_LIST LstHdr; + LstHdr.GuidSigType = pDesc->GuidSignatureType; + LstHdr.cbSigLst = RT_H2LE_U32(sizeof(LstHdr) + pDesc->cbSigHdr + cSigs * pDesc->cbSig); + LstHdr.cbSigHdr = RT_H2LE_U32(pDesc->cbSigHdr); + LstHdr.cbSig = RT_H2LE_U32(pDesc->cbSig); + + int rc = RTVfsFileWrite(hVfsFileOut, &LstHdr, sizeof(LstHdr), NULL /*pcbWritten*/); + if (RT_SUCCESS(rc)) + { + RTListForEach(pLst, pIt, RTEFISIGNATURE, NdLst) + { + RTSGSEG aSegs[2]; + RTSGBUF SgBuf; + EFI_SIGNATURE_DATA SigData; + RTEfiGuidFromUuid(&SigData.GuidOwner, &pIt->UuidOwner); + + Assert(pDesc->cbSig == pIt->cbSignature); + aSegs[0].pvSeg = &SigData; + aSegs[0].cbSeg = sizeof(SigData); + aSegs[1].pvSeg = &pIt->abSignature[0]; + aSegs[1].cbSeg = pIt->cbSignature; + RTSgBufInit(&SgBuf, &aSegs[0], RT_ELEMENTS(aSegs)); + rc = RTVfsFileSgWrite(hVfsFileOut, -1, &SgBuf, true /*fBlocking*/, NULL /*pcbWritten*/); + if (RT_FAILURE(rc)) + break; + } + } + + if (RT_SUCCESS(rc)) + *pcbThisWritten = sizeof(LstHdr) + pDesc->cbSigHdr + cSigs * pDesc->cbSig; + + return rc; +} + + +/** + * Allocate a new signature of the given size. + * + * @returns Pointer to the new signature or NULL if out of memory. + * @param pUuidOwner The UUID of the signature owner. + * @param cbSig Size of the signature data in bytes. + */ +static PRTEFISIGNATURE rtEfiSigDbAllocSignature(PCRTUUID pUuidOwner, uint32_t cbSig) +{ + PRTEFISIGNATURE pSig = (PRTEFISIGNATURE)RTMemAllocZ(RT_UOFFSETOF_DYN(RTEFISIGNATURE, abSignature[cbSig])); + if (pSig) + { + pSig->UuidOwner = *pUuidOwner; + pSig->cbSignature = cbSig; + } + + return pSig; +} + + +RTDECL(int) RTEfiSigDbCreate(PRTEFISIGDB phEfiSigDb) +{ + AssertPtrReturn(phEfiSigDb, VERR_INVALID_POINTER); + + PRTEFISIGDBINT pThis = (PRTEFISIGDBINT)RTMemAllocZ(sizeof(*pThis)); + if (RT_LIKELY(pThis)) + { + for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aLstSigTypes); i++) + RTListInit(&pThis->aLstSigTypes[i]); + *phEfiSigDb = pThis; + return VINF_SUCCESS; + } + + return VERR_NO_MEMORY; +} + + +RTDECL(int) RTEfiSigDbDestroy(RTEFISIGDB hEfiSigDb) +{ + PRTEFISIGDBINT pThis = hEfiSigDb; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aLstSigTypes); i++) + { + PRTEFISIGNATURE pIt, pItNext; + + RTListForEachSafe(&pThis->aLstSigTypes[i], pIt, pItNext, RTEFISIGNATURE, NdLst) + { + RTListNodeRemove(&pIt->NdLst); + RTMemFree(pIt); + } + } + + RTMemFree(pThis); + return VINF_SUCCESS; +} + + +RTDECL(int) RTEfiSigDbAddFromExistingDb(RTEFISIGDB hEfiSigDb, RTVFSFILE hVfsFileIn) +{ + PRTEFISIGDBINT pThis = hEfiSigDb; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + uint64_t cbFile; + int rc = RTVfsFileQuerySize(hVfsFileIn, &cbFile); + if ( RT_SUCCESS(rc) + && cbFile) + { + do + { + uint64_t cbConsumed = 0; + rc = rtEfiSigDbLoadSigList(pThis, hVfsFileIn, &cbConsumed); + cbFile -= cbConsumed; + } while ( RT_SUCCESS(rc) + && cbFile); + } + + return rc; +} + + +RTDECL(int) RTEfiSigDbAddSignatureFromFile(RTEFISIGDB hEfiSigDb, RTEFISIGTYPE enmSigType, PCRTUUID pUuidOwner, RTVFSFILE hVfsFileIn) +{ + PRTEFISIGDBINT pThis = hEfiSigDb; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(enmSigType >= RTEFISIGTYPE_FIRST_VALID && enmSigType < RTEFISIGTYPE_FIRST_INVALID, VERR_INVALID_PARAMETER); + AssertPtrReturn(pUuidOwner, VERR_INVALID_POINTER); + + PCRTEFISIGDBDESC pDesc = &g_aGuid2SigTypeMapping[enmSigType]; + uint64_t cbSig = 0; + int rc = RTVfsFileQuerySize(hVfsFileIn, &cbSig); + if (RT_SUCCESS(rc)) + { + if ( ( !pDesc->cbSig + || pDesc->cbSig - sizeof(EFI_SIGNATURE_DATA) == cbSig) + && cbSig < UINT32_MAX) + { + PRTEFISIGNATURE pSig = rtEfiSigDbAllocSignature(pUuidOwner, (uint32_t)cbSig); + if (pSig) + { + rc = RTVfsFileRead(hVfsFileIn, &pSig->abSignature[0], (size_t)cbSig, NULL /*pcbRead*/); + if (RT_SUCCESS(rc)) + RTListAppend(&pThis->aLstSigTypes[enmSigType], &pSig->NdLst); + else + RTMemFree(pSig); + } + else + rc = VERR_NO_MEMORY; + } + else + rc = VERR_INVALID_PARAMETER; + } + + return rc; +} + + +RTDECL(int) RTEfiSigDbAddSignatureFromBuf(RTEFISIGDB hEfiSigDb, RTEFISIGTYPE enmSigType, PCRTUUID pUuidOwner, + const void *pvBuf, size_t cbBuf) +{ + PRTEFISIGDBINT pThis = hEfiSigDb; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + AssertReturn(enmSigType >= RTEFISIGTYPE_FIRST_VALID && enmSigType < RTEFISIGTYPE_FIRST_INVALID, VERR_INVALID_PARAMETER); + AssertPtrReturn(pUuidOwner, VERR_INVALID_POINTER); + AssertPtrReturn(pvBuf, VERR_INVALID_POINTER); + AssertReturn(cbBuf && cbBuf < UINT32_MAX, VERR_INVALID_PARAMETER); + + int rc = VINF_SUCCESS; + PCRTEFISIGDBDESC pDesc = &g_aGuid2SigTypeMapping[enmSigType]; + if ( !pDesc->cbSig + || pDesc->cbSig - sizeof(EFI_SIGNATURE_DATA) == cbBuf) + { + PRTEFISIGNATURE pSig = rtEfiSigDbAllocSignature(pUuidOwner, (uint32_t)cbBuf); + if (pSig) + { + memcpy(&pSig->abSignature[0], pvBuf, cbBuf); + RTListAppend(&pThis->aLstSigTypes[enmSigType], &pSig->NdLst); + } + else + rc = VERR_NO_MEMORY; + } + else + rc = VERR_INVALID_PARAMETER; + + return rc; +} + + +RTDECL(int) RTEfiSigDbWriteToFile(RTEFISIGDB hEfiSigDb, RTVFSFILE hVfsFileOut) +{ + PRTEFISIGDBINT pThis = hEfiSigDb; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + int rc = VINF_SUCCESS; + size_t cbSigDb = 0; + for (uint32_t i = RTEFISIGTYPE_FIRST_VALID; i < RT_ELEMENTS(pThis->aLstSigTypes) && RT_SUCCESS(rc); i++) + { + if (!RTListIsEmpty(&pThis->aLstSigTypes[i])) + { + size_t cbThisWritten = 0; + rc = rtEfiSigDbWriteList(&pThis->aLstSigTypes[i], &g_aGuid2SigTypeMapping[i], hVfsFileOut, &cbThisWritten); + if (RT_SUCCESS(rc)) + cbSigDb += cbThisWritten; + } + } + + if (RT_SUCCESS(rc)) + rc = RTVfsFileSetSize(hVfsFileOut, cbSigDb, RTVFSFILE_SIZE_F_NORMAL); + + return rc; +} + + +RTDECL(int) RTEfiSigDbEnum(RTEFISIGDB hEfiSigDb, PFNRTEFISIGDBENUMSIG pfnEnumSig, void *pvUser) +{ + PRTEFISIGDBINT pThis = hEfiSigDb; + AssertPtrReturn(pThis, VERR_INVALID_HANDLE); + + for (uint32_t i = RTEFISIGTYPE_FIRST_VALID; i < RT_ELEMENTS(pThis->aLstSigTypes); i++) + { + PRTEFISIGNATURE pIt; + + RTListForEach(&pThis->aLstSigTypes[i], pIt, RTEFISIGNATURE, NdLst) + { + int rc = pfnEnumSig(pThis, (RTEFISIGTYPE)i, &pIt->UuidOwner, &pIt->abSignature[0], pIt->cbSignature, pvUser); + if (rc != VINF_SUCCESS) + return rc; + } + } + + return VINF_SUCCESS; +} + + +RTDECL(const char *) RTEfiSigDbTypeStringify(RTEFISIGTYPE enmSigType) +{ + AssertReturn(enmSigType < RTEFISIGTYPE_FIRST_INVALID, NULL); + return g_aGuid2SigTypeMapping[enmSigType].pszName; +} + + +RTDECL(PCEFI_GUID) RTEfiSigDbTypeGetGuid(RTEFISIGTYPE enmSigType) +{ + AssertReturn(enmSigType < RTEFISIGTYPE_FIRST_INVALID, NULL); + return &g_aGuid2SigTypeMapping[enmSigType].GuidSignatureType; +} + |