blob: 52cf18e92f31614537b922dcfa459ce3f4ac856e [file] [log] [blame]
Harald Welted54c2ee2012-01-17 18:25:50 +01001#include <errno.h>
2#include <stdint.h>
3#include <stdlib.h>
4#include <string.h>
5#include <stdio.h>
6
7#include <osmocom/sim/sim.h>
8
9
10#include "sim_int.h"
11
12static int get_sw(struct msgb *resp)
13{
14 int ret;
15
16 if (!msgb_apdu_de(resp) || msgb_apdu_le(resp) < 2)
17 return -EIO;
18
19 ret = resp->data[resp->len-2] << 8;
20 ret |= resp->data[resp->len-1];
21
22 return ret;
23}
24
25/* According to ISO7816-4 Annex A */
26static int transceive_apdu_t0(struct osim_card_hdl *st, struct msgb *amsg)
27{
28 struct osim_reader_hdl *rh = st->reader;
29 struct msgb *tmsg = msgb_alloc(1024, "TPDU");
30 struct osim_apdu_cmd_hdr *tpduh;
31 uint8_t *cur;
32 uint16_t sw;
33 int rc, num_resp = 0;
34
35 /* create TPDU header from APDU header */
36 tpduh = (struct osim_apdu_cmd_hdr *) msgb_put(tmsg, sizeof(*tpduh));
37 memcpy(tpduh, msgb_apdu_h(amsg), sizeof(*tpduh));
38
39 switch (msgb_apdu_case(amsg)) {
40 case APDU_CASE_1:
41 tpduh->p3 = 0x00;
42 break;
43 case APDU_CASE_2:
44 tpduh->p3 = msgb_apdu_le(amsg);
45 break;
46 case APDU_CASE_2_EXT:
47 if (msgb_apdu_le(amsg) <= 256) {
48 /* case 2E.1 */
49 tpduh->p3 = msgb_apdu_le(amsg) & 0xff;
50 } else {
51 /* case 2E.2 */
52 tpduh->p3 = 0;
53 msgb_put_u16(tmsg, msgb_apdu_le(amsg));
54 }
55 break;
56 case APDU_CASE_3:
57 case APDU_CASE_4:
58 tpduh->p3 = msgb_apdu_lc(amsg);
59 cur = msgb_put(tmsg, tpduh->p3);
60 memcpy(cur, msgb_apdu_dc(amsg), tpduh->p3);
61 break;
62 case APDU_CASE_3_EXT:
63 case APDU_CASE_4_EXT:
64 if (msgb_apdu_lc(amsg) < 256) {
65 /* Case 3E.1 */
66 tpduh->p3 = msgb_apdu_lc(amsg);
67 } else {
68 /* Case 3E.2 */
69 /* FXIME: Split using ENVELOPE! */
70 return -1;
71 }
72 break;
73 }
74
75transceive_again:
76
77 /* store pointer to start of response */
78 tmsg->l3h = tmsg->tail;
79
80 /* transceive */
81 rc = rh->ops->transceive(st->reader, tmsg);
82 if (rc < 0) {
83 msgb_free(tmsg);
84 return rc;
85 }
86 msgb_apdu_sw(tmsg) = get_sw(tmsg);
87
88 /* increase number of responsese received */
89 num_resp++;
90
91 /* save SW */
92 sw = msgb_apdu_sw(tmsg);
93 printf("sw = 0x%04x\n", sw);
94 msgb_apdu_sw(amsg) = sw;
95
96 switch (msgb_apdu_case(amsg)) {
97 case APDU_CASE_1:
98 case APDU_CASE_3:
99 /* just copy SW */
100 break;
101 case APDU_CASE_2:
102case_2s:
103 switch (sw >> 8) {
104 case 0x67: /* Case 2S.2: Le definitely not accepted */
105 break;
106 case 0x6c: /* Case 2S.3: Le not accepted, La indicated */
107 tpduh->p3 = sw & 0xff;
108 /* re-issue the command with La as */
109 goto transceive_again;
110 break;
111 case 0x90:
112 /* Case 2S.1, fall-through */
113 case 0x91: case 0x92: case 0x93: case 0x94: case 0x95:
114 case 0x96: case 0x97: case 0x98: case 0x99: case 0x9a:
115 case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
116 /* Case 2S.4 */
117 /* copy response data over */
118 cur = msgb_put(amsg, msgb_l3len(tmsg));
119 memcpy(cur, tmsg->l3h, msgb_l3len(tmsg));
120 }
121 break;
122 case APDU_CASE_4:
123 /* FIXME: this is 4S.2 only for 2nd... response: */
124 if (num_resp >= 2)
125 goto case_2s;
126
127 switch (sw >> 8) {
128 case 0x60: case 0x62: case 0x63: case 0x64: case 0x65:
129 case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a:
130 case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
131 /* Case 4S.1: Command not accepted: just copy SW */
132 break;
133 case 0x90:
134 /* case 4S.2: Command accepted */
135 tpduh->ins = 0xC0;
136 tpduh->p1 = tpduh->p2 = 0;
137 tpduh->p3 = msgb_apdu_le(amsg);
138 /* strip off current result */
139 msgb_get(tmsg, msgb_length(tmsg)-sizeof(*tpduh));
140 goto transceive_again;
141 break;
142 case 0x61: /* Case 4S.3: command accepted with info added */
143 tpduh->ins = 0xC0;
144 tpduh->p1 = tpduh->p2 = 0;
145 tpduh->p3 = OSMO_MIN(msgb_apdu_le(amsg), sw & 0xff);
146 /* strip off current result */
147 msgb_get(tmsg, msgb_length(tmsg)-sizeof(*tpduh));
148 goto transceive_again;
149 break;
150 }
151 /* Case 4S.2: Command accepted: just copy SW */
152 /* Case 4S.4: Just copy SW */
153 break;
154 case APDU_CASE_2_EXT:
155 if (msgb_apdu_le(amsg) <= 256) {
156 /* Case 2E.1: Le <= 256 */
157 goto case_2s;
158 }
159 switch (sw >> 8) {
160 case 0x67:
161 /* Case 2E.2a: wrong length, abort */
162 break;
163 case 0x6c:
164 /* Case 2E.2b: wrong length, La given */
165 tpduh->p3 = sw & 0xff;
166 /* re-issue the command with La as given */
167 goto transceive_again;
168 break;
169 case 0x90:
170 /* Case 2E.2c: */
171 break;
172 case 0x61:
173 /* Case 2E.2d: more data available */
174 /* FIXME: issue yet another GET RESPONSE */
175 break;
176 }
177 break;
178 case APDU_CASE_3_EXT:
179 /* FIXME: handling for ENVELOPE splitting */
180 break;
181 case APDU_CASE_4_EXT:
182 break;
183 }
184
185 msgb_free(tmsg);
186
187 /* compute total length of response data */
188 msgb_apdu_le(amsg) = amsg->tail - msgb_apdu_de(amsg);
189
190 return sw;
191}
192
193/* According to ISO7816-4 Annex B */
194static int transceive_apdu_t1(struct osim_card_hdl *st, struct msgb *amsg)
195{
196 return -1;
197}
198
199int osim_transceive_apdu(struct osim_chan_hdl *st, struct msgb *amsg)
200{
201 /* FIXME: check for protocol */
202 return transceive_apdu_t0(st->card, amsg);
203}
204
205
206
207struct osim_reader_hdl *osim_reader_open(int idx, const char *name)
208{
209 /* FIXME: support multiple drivers */
210 const struct osim_reader_ops *ops = &pcsc_reader_ops;
211 struct osim_reader_hdl *rh;
212
213 rh = ops->reader_open(idx, name);
214 if (!rh)
215 return NULL;
216 rh->ops = ops;
217
218 return rh;
219}
220
221struct osim_card_hdl *osim_card_open(struct osim_reader_hdl *rh)
222{
223 return rh->ops->card_open(rh);
224}