问题描述
开发基于 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/),因为他还提供了有用的示例应用程序。