1/*
2    PCSCv2part10.c: helper functions for PC/SC v2 part 10 services
3    Copyright (C) 2012   Ludovic Rousseau
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    This library 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 GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18*/
19
20/*
21 * $Id: PCSCv2part10.c 6559 2013-03-06 14:18:24Z rousseau $
22 */
23
24#include <stdio.h>
25#include <arpa/inet.h>
26
27#ifdef __APPLE__
28#include <PCSC/winscard.h>
29#include <PCSC/wintypes.h>
30#else
31#include <winscard.h>
32#endif
33
34#include "PCSCv2part10.h"
35
36int PCSCv2Part10_find_TLV_property_by_tag_from_buffer(
37	unsigned char *buffer, int length, int property, int * value_int)
38{
39	unsigned char *p;
40	int found = 0, len;
41	int value = -1;
42	int ret = -1;	/* not found by default */
43
44	p = buffer;
45	while (p-buffer < length)
46	{
47		if (*p++ == property)
48		{
49			found = 1;
50			break;
51		}
52
53		/* go to next tag */
54		len = *p++;
55		p += len;
56	}
57
58	if (found)
59	{
60		len = *p++;
61		ret = 0;
62
63		switch(len)
64		{
65			case 1:
66				value = *p;
67				break;
68			case 2:
69				value = *p + (*(p+1)<<8);
70				break;
71			case 4:
72				value = *p + (*(p+1)<<8) + (*(p+2)<<16) + (*(p+3)<<24);
73				break;
74			default:
75				/* wrong length for an integer */
76				ret = -2;
77		}
78	}
79
80	if (value_int)
81		*value_int = value;
82
83	return ret;
84} /* PCSCv2Part10_find_TLV_property_by_tag_from_buffer */
85
86int PCSCv2Part10_find_TLV_property_by_tag_from_hcard(SCARDHANDLE hCard,
87	int property, int * value)
88{
89	unsigned char buffer[MAX_BUFFER_SIZE];
90	LONG rv;
91	DWORD length;
92	unsigned int i;
93	PCSC_TLV_STRUCTURE *pcsc_tlv;
94	DWORD properties_in_tlv_ioctl;
95	int found;
96
97	rv = SCardControl(hCard, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0,
98		buffer, sizeof buffer, &length);
99	if (rv != SCARD_S_SUCCESS)
100		return -1;
101
102	/* get the number of elements instead of the complete size */
103	length /= sizeof(PCSC_TLV_STRUCTURE);
104
105	pcsc_tlv = (PCSC_TLV_STRUCTURE *)buffer;
106	found = 0;
107	for (i = 0; i < length; i++)
108	{
109		if (FEATURE_GET_TLV_PROPERTIES == pcsc_tlv[i].tag)
110		{
111			properties_in_tlv_ioctl = ntohl(pcsc_tlv[i].value);
112			found = 1;
113		}
114	}
115
116	if (! found)
117		return -3;
118
119	rv= SCardControl(hCard, properties_in_tlv_ioctl, NULL, 0,
120		buffer, sizeof buffer, &length);
121	if (rv != SCARD_S_SUCCESS)
122		return -1;
123
124	return PCSCv2Part10_find_TLV_property_by_tag_from_buffer(buffer,
125		length, property, value);
126}
127
128