Revision 0e61400c
b/hw/usb/ccid-card-passthru.c | ||
---|---|---|
138 | 138 |
ccid_card_vscard_send_init(card); |
139 | 139 |
} |
140 | 140 |
|
141 |
static int check_atr(PassthruState *card, uint8_t *data, int len) |
|
142 |
{ |
|
143 |
int historical_length, opt_bytes; |
|
144 |
int td_count = 0; |
|
145 |
int td; |
|
146 |
|
|
147 |
if (len < 2) { |
|
148 |
return 0; |
|
149 |
} |
|
150 |
historical_length = data[1] & 0xf; |
|
151 |
opt_bytes = 0; |
|
152 |
if (data[0] != 0x3b && data[0] != 0x3f) { |
|
153 |
DPRINTF(card, D_WARN, "atr's T0 is 0x%X, not in {0x3b, 0x3f}\n", |
|
154 |
data[0]); |
|
155 |
return 0; |
|
156 |
} |
|
157 |
td_count = 0; |
|
158 |
td = data[1] >> 4; |
|
159 |
while (td && td_count < 2 && opt_bytes + historical_length + 2 < len) { |
|
160 |
td_count++; |
|
161 |
if (td & 0x1) { |
|
162 |
opt_bytes++; |
|
163 |
} |
|
164 |
if (td & 0x2) { |
|
165 |
opt_bytes++; |
|
166 |
} |
|
167 |
if (td & 0x4) { |
|
168 |
opt_bytes++; |
|
169 |
} |
|
170 |
if (td & 0x8) { |
|
171 |
opt_bytes++; |
|
172 |
td = data[opt_bytes + 2] >> 4; |
|
173 |
} |
|
174 |
} |
|
175 |
if (len < 2 + historical_length + opt_bytes) { |
|
176 |
DPRINTF(card, D_WARN, |
|
177 |
"atr too short: len %d, but historical_len %d, T1 0x%X\n", |
|
178 |
len, historical_length, data[1]); |
|
179 |
return 0; |
|
180 |
} |
|
181 |
if (len > 2 + historical_length + opt_bytes) { |
|
182 |
DPRINTF(card, D_WARN, |
|
183 |
"atr too long: len %d, but hist/opt %d/%d, T1 0x%X\n", |
|
184 |
len, historical_length, opt_bytes, data[1]); |
|
185 |
/* let it through */ |
|
186 |
} |
|
187 |
DPRINTF(card, D_VERBOSE, |
|
188 |
"atr passes check: %d total length, %d historical, %d optional\n", |
|
189 |
len, historical_length, opt_bytes); |
|
190 |
|
|
191 |
return 1; |
|
192 |
} |
|
193 |
|
|
141 | 194 |
static void ccid_card_vscard_handle_message(PassthruState *card, |
142 | 195 |
VSCMsgHeader *scr_msg_header) |
143 | 196 |
{ |
... | ... | |
152 | 205 |
VSC_GENERAL_ERROR); |
153 | 206 |
break; |
154 | 207 |
} |
208 |
if (!check_atr(card, data, scr_msg_header->length)) { |
|
209 |
error_report("ATR is inconsistent, ignoring"); |
|
210 |
ccid_card_vscard_send_error(card, scr_msg_header->reader_id, |
|
211 |
VSC_GENERAL_ERROR); |
|
212 |
break; |
|
213 |
} |
|
155 | 214 |
memcpy(card->atr, data, scr_msg_header->length); |
156 | 215 |
card->atr_length = scr_msg_header->length; |
157 | 216 |
ccid_card_card_inserted(&card->base); |
Also available in: Unified diff