1

Developing UEFI Based application for enabling pre-boot authentication using Feitian Auto ePass 2003 FIPS USB Token. I'm still in the initial stage of the development process.

Now I'm able to fetch Manufacturer, Product Code of the token by using UsbIo->UsbGetDeviceDescriptor protocol. But when I try to find serial number it's throwing an error.

Is there any other way to find the serial number of the USB Token? Please help me on this..

This is my sample code for finding serial number

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;
Selva
  • 13
  • 4
  • What error is it throwing? Is the serial number visible from within a running operating system - e.g. by using lsusb in Linux or device manager in windows? – unixsmurf Jan 28 '21 at 12:27
  • Getting EFI_NOT_FOUND error. Yes able to access from windows device manager. – Selva Jan 28 '21 at 12:58
  • Where exactly are you getting EFI_NOT_FOUND? Retrieving serial number? Why are you looping through all the languages? Try hardcoding the language to 0x409 - which is English - and skip the looping. – fpmurphy Jan 31 '21 at 11:34
  • Hi @fpmurphy, Thanks for your reply. Yes.. While retrieving serial number only getting error. I tried hardcoding the 0x409 value. Still facing the same issue. Is it possible to get the PKI token's serial number in UEFI layer? – Selva Feb 01 '21 at 13:09
  • Hi @fpmurphy, These are the values that i am getting after UsbGetDeviceDescriptor call Length: 12 DescriptorType: 1 BcdUSB: 110 DeviceClass: 0 DeviceSubClass: 0 DeviceProtocol: 0 MaxPacketSize: 40 IdVendor: 96E IdProduct: 80A BcdDevice: 1004 StrManufacturer: 1 StrProduct: 2 StrSerialNumber: 0 NumConfigurations: 1 – Selva Feb 04 '21 at 05:19
  • @fpmurphy In user space I use OpenSC - epass2003 driver approach. But I have no idea that how we can implement the same into UEFI environment. If you have any suggestion please provide. – Selva Feb 05 '21 at 07:15

1 Answers1

1

From what I have read, the Feitian Technologies ePass2003 uses an Infineon M7893 or SLE 78CUFX5000PH (M7893-B) security chip.

As you have found out, the serial number for the ePass2003 is not stored in the USB device descriptor but in the security chip.

To obtain chip global data such as OEM information, algorithm support, FIPS mode indicator, RAM size and serial number, the GetData primitive is used. See the M7893 programming guide. if you can obtain access to it.

The driver for ePass2003 in OpenSC is called “epass2003”. The source code is currently available at https://github.com/OpenSC/OpenSC/blob/master/src/libopensc/card-epass2003.c. It has dependencies on OpenSSL and ASN.1 and some non-EDK2 headers, but these are easily worked around.

If all you are looking for is the serial number, it should be fairly easy to write a UEFI application (or driver) to get that information either by studying how the OpenSC ePass2003 driver does it (hint - look at epass2003_get_serialnr or studying the ePass2003 SDK which is available for free from Feitain and elsewhere.

The UEFI 2.5 specification released in April 2015 detailed 2 protocols relating to smart cards, i.e. Smart Card Reader and 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 does not contain a sample implementation at present. However, you may be interested in the GPL2-licensed sample implementation by Ludovic Rousseau which is available at https://github.com/LudovicRousseau/edk2/tree/SmartCard. The implementation code, which is circa 5 years old and which I have not tested, is at MdeModulePkg/Library/SmartCardReader. Read his blog (https://ludovicrousseau.blogspot.com/) also as he provides useful sample applications also.

fpmurphy
  • 2,464
  • 1
  • 18
  • 22
  • Thank you!!! OpenSC uses winscard.dll for transmitting data in user space. What should I use to transfer APDU data to USB FIPS Token? I referred CCID driver and UsbIo->BulkTransfer operations. Is it right way to proceed further? I'm very new to UEFI development and I've been referring EDK2 Lab Materials in order to create Driver / Application. – Selva Feb 06 '21 at 06:02
  • @Selva. Added information about UEFI smart card support. – fpmurphy Feb 07 '21 at 08:09