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

问题描述

开发基于 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],(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,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,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 的驱动程序称为“epass2003”。源代码目前可在 https://github.com/OpenSC/OpenSC/blob/master/src/libopensc/card-epass2003.c 获得。它依赖于 OpenSSL 和 ASN.1 以及一些非 EDK2 标头,但这些很容易解决。

如果您只需要序列号,那么通过研究 OpenSC ePass2003 驱动程序的工作原理,编写 UEFI 应用程序(或驱动程序)来获取该信息应该相当容易(提示 - 查看 {{1 }} 或者学习ePass2003 SDK,它可以从飞坦和其他地方免费获得。

2015 年 4 月发布的 UEFI 2.5 规范详细介绍了与智能卡相关的 2 个协议,即智能卡读卡器和智能卡边缘。

epass2003_get_serialnr

EDK2 目前不包含示例实现。但是,您可能对 Ludovic Rousseau 提供的 GPL2 许可示例实现感兴趣,该实现可在 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; 获得。大约有 5 年历史且我尚未测试过的实现代码位于 https://github.com/LudovicRousseau/edk2/tree/SmartCard。也请阅读他的博客 (https://ludovicrousseau.blogspot.com/),因为他还提供了有用的示例应用程序。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...