1/*
2    RSA_SecurID_getpasswd.c: get the one-use password from a RSA sid-800 token
3    Copyright (C) 2006   Ludovic Rousseau <ludovic.rousseau@free.fr>
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15	You should have received a copy of the GNU General Public License along
16	with this program; if not, write to the Free Software Foundation, Inc., 51
17	Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18*/
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <winscard.h>
24
25/* PCSC error message pretty print */
26#define PCSC_ERROR_EXIT(rv, text) \
27if (rv != SCARD_S_SUCCESS) \
28{ \
29	printf(text ": %s (0x%ulX)\n", pcsc_stringify_error(rv), rv); \
30	goto end; \
31}
32
33int main(void)
34{
35	unsigned char cmd1[] = { 0x00, 0xa4, 0x04, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x63, 0x86, 0x53, 0x49, 0x44, 0x01};
36	unsigned char cmd2[] = { 0x80, 0x56, 0x00, 0x00, 0x04 };
37	unsigned char cmd3[] = { 0x80, 0x48, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff };
38	unsigned char cmd4[] = { 0x80, 0x44, 0x00, 0x00, 0x05};
39	LONG rv;
40	SCARDCONTEXT hContext;
41	DWORD dwReaders;
42	LPSTR mszReaders = NULL;
43	char **readers = NULL;
44	SCARDHANDLE hCard;
45	DWORD dwActiveProtocol;
46	unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
47	DWORD length;
48	SCARD_IO_REQUEST pioRecvPci;
49 	SCARD_IO_REQUEST pioSendPci;
50
51	rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
52	if (rv != SCARD_S_SUCCESS)
53	{
54		printf("SCardEstablishContext: Cannot Connect to Resource Manager %ulX\n", rv);
55		return 1;
56	}
57
58	/* Retrieve the available readers list */
59	rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
60	PCSC_ERROR_EXIT(rv, "SCardListReader");
61
62	if (dwReaders < 4)
63	{
64		printf("No reader found!\n");
65		return -1;
66	}
67
68	mszReaders = malloc(sizeof(char)*dwReaders);
69	if (mszReaders == NULL)
70	{
71		printf("malloc: not enough memory\n");
72		goto end;
73	}
74
75	rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
76	PCSC_ERROR_EXIT(rv, "SCardListReader");
77
78	/* connect to the first reader */
79	dwActiveProtocol = -1;
80	rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_EXCLUSIVE,
81		SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
82	PCSC_ERROR_EXIT(rv, "SCardConnect")
83
84    switch(dwActiveProtocol)
85    {
86        case SCARD_PROTOCOL_T0:
87            pioSendPci = *SCARD_PCI_T0;
88            break;
89        case SCARD_PROTOCOL_T1:
90            pioSendPci = *SCARD_PCI_T1;
91            break;
92        default:
93            printf("Unknown protocol\n");
94            return -1;
95    }
96
97	/* APDU select applet */
98	length = sizeof(bRecvBuffer);
99	rv = SCardTransmit(hCard, &pioSendPci, cmd1, sizeof cmd1,
100		&pioRecvPci, bRecvBuffer, &length);
101	PCSC_ERROR_EXIT(rv, "SCardTransmit")
102	if ((length != 2) || (bRecvBuffer[0] != 0x90) || (bRecvBuffer[1] != 0x00))
103	{
104		printf("cmd1 failed (%uld): %02X%02X\n", length, bRecvBuffer[length-2],
105			bRecvBuffer[length-1]);
106		goto end;
107	}
108
109	/* non ISO APDU */
110	length = sizeof(bRecvBuffer);
111	rv = SCardTransmit(hCard, &pioSendPci, cmd2, sizeof cmd2,
112		&pioRecvPci, bRecvBuffer, &length);
113	PCSC_ERROR_EXIT(rv, "SCardTransmit")
114	if ((length != 6) || (bRecvBuffer[4] != 0x90) || (bRecvBuffer[5] != 0x00))
115	{
116		printf("cmd2 failed (%uld) : %02X%02X\n", length, bRecvBuffer[length-2],
117			bRecvBuffer[length-1]);
118		goto end;
119	}
120
121	/* get the argument for cmd3 from result of cmd2 */
122	memcpy(cmd3+5, bRecvBuffer, 4);
123
124	/* non ISO APDU */
125	length = sizeof(bRecvBuffer);
126	rv = SCardTransmit(hCard, &pioSendPci, cmd3, sizeof cmd3,
127		&pioRecvPci, bRecvBuffer, &length);
128	PCSC_ERROR_EXIT(rv, "SCardTransmit")
129	if ((length != 2) || (bRecvBuffer[0] != 0x90) || (bRecvBuffer[1] != 0x00))
130	{
131		printf("cmd3 failed (%uld): %02X%02X\n", length, bRecvBuffer[length-2],
132			bRecvBuffer[length-1]);
133		goto end;
134	}
135
136	/* non iSO APDU */
137	length = sizeof(bRecvBuffer);
138	rv = SCardTransmit(hCard, &pioSendPci, cmd4, sizeof cmd4,
139		&pioRecvPci, bRecvBuffer, &length);
140	PCSC_ERROR_EXIT(rv, "SCardTransmit")
141	if ((length != 7) || (bRecvBuffer[5] != 0x90) || (bRecvBuffer[6] != 0x00))
142	{
143		printf("cmd4 failed (%uld): %02X%02X\n", length, bRecvBuffer[length-2],
144			bRecvBuffer[length-1]);
145		goto end;
146	}
147
148	printf("%02X%02X%02X\n", bRecvBuffer[2], bRecvBuffer[3], bRecvBuffer[4]);
149
150end:
151	/* We try to leave things as clean as possible */
152    rv = SCardReleaseContext(hContext);
153    if (rv != SCARD_S_SUCCESS)
154        printf("SCardReleaseContext: %s (0x%ulX)\n", pcsc_stringify_error(rv),
155            rv);
156
157    /* free allocated memory */
158    free(mszReaders);
159    free(readers);
160
161	return 0;
162} /* main */
163
164