VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/Library/CommonLib/EfiUsb.c
blob: f885cc6aff9ad7cb55209947a7d95a21b5432950 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/** @file
EFI USB helpers

Copyright (c) 2016. Disk Cryptography Services for EFI (DCS), Alex Kolotnikov
Copyright (c) 2016. VeraCrypt, Mounir IDRASSI 

This program and the accompanying materials are licensed and made available
under the terms and conditions of the GNU Lesser General Public License, version 3.0 (LGPL-3.0).

The full text of the license may be found at
https://opensource.org/licenses/LGPL-3.0
**/

#include <Library/CommonLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/DevicePathLib.h>
#include <Library/PrintLib.h>
#include <Protocol/UsbIo.h>
#include <Library/BaseMemoryLib.h>

EFI_HANDLE* gUSBHandles = NULL;
UINTN       gUSBCount = 0;
UINTN       gUSBSelect = 0;

EFI_STATUS
InitUsb() {
	EFI_STATUS res;
	res = EfiGetHandles(ByProtocol, &gEfiUsbIoProtocolGuid, 0, &gUSBHandles, &gUSBCount);
	return res;
}

EFI_STATUS
UsbGetIO(
	IN    EFI_HANDLE					Handle,
	OUT   EFI_USB_IO_PROTOCOL**	UsbIo
	) {
	if (!UsbIo) {
		return EFI_INVALID_PARAMETER;
	}
	return gBS->HandleProtocol(Handle, &gEfiUsbIoProtocolGuid, (VOID**)UsbIo);
}

EFI_STATUS
UsbGetIOwithDescriptor(
	IN    EFI_HANDLE					Handle,
	OUT   EFI_USB_IO_PROTOCOL**	UsbIo,
	OUT   EFI_USB_DEVICE_DESCRIPTOR* UsbDescriptor
	) {
	EFI_STATUS                    res;
	if (!UsbIo || !UsbDescriptor) {
		return EFI_INVALID_PARAMETER;
	}
	res = UsbGetIO(Handle, UsbIo);
	if (EFI_ERROR(res)) {
		return res;
	}
	return (*UsbIo)->UsbGetDeviceDescriptor(*UsbIo, UsbDescriptor);
}

EFI_STATUS
UsbGetId(
	IN    EFI_HANDLE		Handle,
	OUT   CHAR8**			id
	)
{
	EFI_STATUS                    res;
	EFI_USB_IO_PROTOCOL           *usbIO = NULL;
	EFI_USB_DEVICE_DESCRIPTOR     usbDescriptor;
	CHAR16*                       serial = NULL;
	CHAR8*                        buff;
	UINTN                         len;
	res = UsbGetIOwithDescriptor(Handle, &usbIO, &usbDescriptor);
	if (EFI_ERROR(res)) {
		return res;
	}
//	Print(L" %02x ", (UINTN)usbDescriptor.StrSerialNumber);
	res = usbIO->UsbGetStringDescriptor(usbIO, 0x409, usbDescriptor.StrSerialNumber, &serial);
	if (!EFI_ERROR(res)) {
		len = 11 + StrLen(serial);
		buff = (CHAR8*)MEM_ALLOC(len);
		AsciiSPrint(buff, len, "%04x_%04x_%s", usbDescriptor.IdVendor, usbDescriptor.IdProduct, serial);
	}	else {
//		Print(L" %04x %r ", res, res);
		len = 10;
		buff = (CHAR8*)MEM_ALLOC(len);
		AsciiSPrint(buff, len, "%04x_%04x", usbDescriptor.IdVendor, usbDescriptor.IdProduct);
	}
	*id = buff;
	return EFI_SUCCESS;
}

//////////////////////////////////////////////////////////////////////////
// Smart card over usb
//////////////////////////////////////////////////////////////////////////

/**
* Send APDU to smart card
* @param[IN] cmd command to send
* @param[IN] cmdLen size of Apdu command
* @param[OUT] resp smart card response
* @param[OUT] respLen smart card response length
* @param[OUT] statusSc smart card status (0x9000 - OK)
* @return  EFI_SUCCESS if send success. Or platform dependent error
*/
EFI_STATUS
UsbScTransmit(
	IN    EFI_USB_IO_PROTOCOL    *UsbIO,
	IN    UINT8*                 cmd,
	IN    UINTN                  cmdLen,
	OUT   UINT8*                 resp,
	OUT   UINTN*                 respLen,
	OUT   UINT16*                statusSc
	) {
	CCID_HEADER_OUT*   oheader = (CCID_HEADER_OUT*)cmd;
	CCID_HEADER_IN*    iheader = (CCID_HEADER_IN*)resp;
	EFI_STATUS         status;
	UINT32             usbres;
	UINTN              len;
	UINTN              resplen;
	// Init CCID HEADER
	SetMem(cmd,sizeof(CCID_HEADER_OUT), 0);
	oheader->bMessageType = PC_to_RDR_XfrBlock_Message;
	oheader->bSeq = 0x99;
	oheader->dwLength = (UINT32)(cmdLen - sizeof(CCID_HEADER_OUT));
	len = cmdLen;
	// Send APDU
	PrintBytes(cmd, len);
	OUT_PRINT(L"\n");
	status = UsbIO->UsbBulkTransfer(UsbIO, 2,cmd, &len, 5000, &usbres);
	if (EFI_ERROR(status)) {
		ERR_PRINT(L"SC send: %r\n", status);
		return status;
	}
	len = *respLen;
	SetMem(resp, len, 0);
	do {
		status = UsbIO->UsbBulkTransfer(UsbIO, 0x81, resp, &len, 5000, &usbres);
	} while ((status == EFI_SUCCESS) && ((iheader->bStatus & 0xC0) == 0x80)); // Timeout? => retry
	if (EFI_ERROR(status)) {
		ERR_PRINT(L"SC resp: %r\n", status);
		return status;
	}
	// Parse response
	resplen = iheader->dwLength;
	*respLen = iheader->dwLength + sizeof(CCID_HEADER_IN);
	*statusSc = (UINT16)(resp[sizeof(CCID_HEADER_IN) + resplen - 1]) | (((UINT16)resp[sizeof(CCID_HEADER_IN) + resplen - 2]) << 8);
	return EFI_SUCCESS;
}