如何在UEFI应用程序中获取USB Token(飞天汽车ePass 2003 FIPS USB Token)序列号?

How to get USB Token (Feitian Auto ePass 2003 FIPS USB Token) serial number in UEFI Application?

开发基于 UEFI 的应用程序以使用 飞天汽车 ePass 2003 FIPS USB 令牌。我还处于开发过程的初始阶段。

现在我可以使用 UsbIo->UsbGetDeviceDescriptor 协议获取令牌的制造商和产品代码。但是,当我尝试查找序列号时,出现错误。

有没有其他方法可以找到USB Token的序列号?请帮我解决这个问题..

这是我查找序列号的示例代码

EFI_USB_DEVICE_DESCRIPTOR DevDesc;
EFI_USB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
EFI_USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
EFI_USB_CONFIG_DESCRIPTOR     ConfigDescriptor;
EFI_USB_IO_PROTOCOL *UsbIo;

EFI_STATUS Status;
EFI_HANDLE *HandleBuffer = NULL;

BOOLEAN    LangFound;
UINTN      HandleCount;
UINT8      EndpointNumber;

CHAR16* ManufacturerString = NULL;
CHAR16* ProductString = NULL;
CHAR16* SerialNumber = NULL;
UINT16* LangIDTable;
UINT16 TableSize;
INTN Index;

int index;


unsigned char* device_descriptor, * ccid_descriptor;

EFI_USB_DEVICE_REQUEST  DevReq;
UINT32 Status_uint;
 
Status = gBS->LocateHandleBuffer( ByProtocol,
                                  &gEfiUsbIoProtocolGuid,
                                  NULL,
                                  &HandleCount,
                                  &HandleBuffer );
if (EFI_ERROR(Status)) {
    Print(L"ERROR: LocateHandleBuffer.\n");
    goto ErrorExit;
}

UINT8 usbIndex;

for (usbIndex = 0; usbIndex < HandleCount; usbIndex++) {
    Status = gBS->HandleProtocol( HandleBuffer[usbIndex],
                                    &gEfiUsbIoProtocolGuid,
                                    (VOID**)&UsbIo );
    if (EFI_ERROR(Status)) {
        Print(L"ERROR: Open UsbIo.\n");
        goto ErrorExit;
    }
 
    Status = UsbIo->UsbGetDeviceDescriptor( UsbIo, &DevDesc );
    if (EFI_ERROR(Status)) {
        Print(L"ERROR: UsbGetDeviceDescriptor.\n");
        goto ErrorExit;
    }


    Status = UsbIo->UsbGetConfigDescriptor( UsbIo, &ConfigDescriptor );
    if (EFI_ERROR (Status))
    {
        Print(L"UsbGetConfigDescriptor %d", Status);
        goto ErrorExit;
    }

        
    Status = UsbIo->UsbGetInterfaceDescriptor( UsbIo, &InterfaceDescriptor );
    if (EFI_ERROR (Status)) {
        Print(L"ERROR: UsbGetInterfaceDescriptor.\n");
        goto ErrorExit;
    }

    if (InterfaceDescriptor.InterfaceClass != CLASS_CCID) {
        continue;            
    }

    Print(L":::::::::::::::::::::: CCID ::::::::::::::::::::::\n");

    //
    // Get all supported languages.
    //
    TableSize = 0;
    LangIDTable = NULL;
    Status = UsbIo->UsbGetSupportedLanguages(UsbIo, &LangIDTable, &TableSize);
    if (EFI_ERROR(Status)) {
        Print(L"ERROR: UsbGetSupportedLanguages.\n");
        return Status;
    }

    /* Get Manufacturer string */
    for (Index = 0; Index < TableSize / sizeof(LangIDTable[0]); Index++) {
        ManufacturerString = NULL;
        Status = UsbIo->UsbGetStringDescriptor(UsbIo,
            LangIDTable[Index],
            DevDesc.StrManufacturer,
            &ManufacturerString);

        if (EFI_ERROR(Status) || (ManufacturerString == NULL)) {
            continue;
        }
        Print(L"StrManufacturer ::%s\n", ManufacturerString);
        FreePool(ManufacturerString);
        break;
    }

    /* Get Product string */
    for (Index = 0; Index < TableSize / sizeof(LangIDTable[0]); Index++) {
        ProductString = NULL;
        Status = UsbIo->UsbGetStringDescriptor(UsbIo,
            LangIDTable[Index],
            DevDesc.StrProduct,
            &ProductString);

        if (EFI_ERROR(Status) || (ProductString == NULL)) {
            continue;
        }
        Print(L"StrProduct ::%s\n", ProductString);
        FreePool(ProductString);
        break;
    }

    /* Get Serial string */
    for (Index = 0; Index < TableSize / sizeof(LangIDTable[0]); Index++) {
        SerialNumber = NULL;
        Status = UsbIo->UsbGetStringDescriptor(UsbIo,
            LangIDTable[Index],
            DevDesc.StrSerialNumber,
            &SerialNumber);

        if (EFI_ERROR(Status) || (SerialNumber == NULL)) {
            Print(L"Error in finding SerialNumber \n");
            continue;
        }

        Print(L"SerialNumber :: %s\n", SerialNumber);

        FreePool(SerialNumber);
        break;
    }

    Print(L"usbIndex ::%d\n", usbIndex);
    Print(L"IdVendor ::%d\n", DevDesc.IdVendor);
    Print(L"IdProduct ::%d\n", DevDesc.IdProduct);    
}

Print(L"\n");
FreePool(HandleBuffer);
return Status;

据我了解,飞天科技 ePass2003 使用英飞凌 M7893 或 SLE 78CUFX5000PH (M7893-B) 安全芯片。

如您所知,ePass2003 的序列号不存储在 USB 设备描述符中,而是存储在安全芯片中。

要获取芯片全局数据,如OEM信息、算法支持、FIPS模式指示符、RAM大小和序列号,使用GetData原语。请参阅 M7893 编程指南。如果您可以访问它。

OpenSC中ePass2003的driver称为“epass2003”。源代码目前可在 https://github.com/OpenSC/OpenSC/blob/master/src/libopensc/card-epass2003.c 获得。它依赖于 OpenSSL 和 ASN.1 以及一些非 EDK2 headers,但这些很容易解决。

如果您要查找的只是序列号,那么通过研究 OpenSC ePass2003 driver 的实现方式,编写 UEFI 应用程序(或 driver)来获取该信息应该相当容易是吗(提示 - 查看 epass2003_get_serialnr 或研究可从 Feitain 和其他地方免费获得的 ePass2003 SDK。

2015 年 4 月发布的 UEFI 2.5 规范详细介绍了与智能卡相关的 2 个协议,即 Smart Card Reader 和 Smart Card Edge。

typedef struct _EFI_SMART_CARD_READER_PROTOCOL {
  EFI_SMART_CARD_READER_CONNECT    SCardConnect;
  EFI_SMART_CARD_READER_DISCONNECT SCardDisconnect;
  EFI_SMART_CARD_READER_STATUS     SCardStatus;
  EFI_SMART_CARD_READER_TRANSMIT   SCardTransmit;
  EFI_SMART_CARD_READER_CONTROL    SCardControl;
  EFI_SMART_CARD_READER_GET_ATTRIB SCardGetAttrib;
} EFI_SMART_CARD_READER_PROTOCOL;

typedef struct _EFI_SMART_CARD_EDGE_PROTOCOL {
  EFI_SMART_CARD_EDGE_GET_CONTEXT        GetContext;
  EFI_SMART_CARD_EDGE_CONNECT            Connect;
  EFI_SMART_CARD_EDGE_DISCONNECT         Disconnect;
  EFI_SMART_CARD_EDGE_GET_CSN            GetCsn;
  EFI_SMART_CARD_EDGE_GET_READER_NAME    GetReaderName;
  EFI_SMART_CARD_EDGE_VERIFY_PIN         VerifyPin;
  EFI_SMART_CARD_EDGE_GET_PIN_REMAINING  GetPinRemaining;
  EFI_SMART_CARD_EDGE_GET_DATA           GetData;
  EFI_SMART_CARD_EDGE_GET_CREDENTIAL     GetCredential;
  EFI_SMART_CARD_EDGE_SIGN_DATA          SignData;
  EFI_SMART_CARD_EDGE_DECRYPT_DATA       DecryptData;
  EFI_SMART_CARD_EDGE_BUILD_DH_AGREEMENT BuildDHAgreement;
} EFI_SMART_CARD_EDGE_PROTOCOL;

EDK2 目前不包含示例实现。但是,您可能对 Ludovic Rousseau 的 GPL2 许可示例实现感兴趣,可在 https://github.com/LudovicRousseau/edk2/tree/SmartCard 获得。实施代码大约有 5 年历史,我还没有测试过,位于 MdeModulePkg/Library/SmartCardReader。还请阅读他的博客 (https://ludovicrousseau.blogspot.com/),因为他还提供了有用的示例应用程序。