1 /* 2 * CCID Passthru Card Device emulation 3 * 4 * Copyright (c) 2011 Red Hat. 5 * Written by Alon Levy. 6 * 7 * This work is licensed under the terms of the GNU GPL, version 2.1 or later. 8 * See the COPYING file in the top-level directory. 9 */ 10 11 #include "sysemu/char.h" 12 #include "qemu/sockets.h" 13 #include "monitor/monitor.h" 14 #include "ccid.h" 15 #include "libcacard/vscard_common.h" 16 17 #define DPRINTF(card, lvl, fmt, ...) \ 18 do { \ 19 if (lvl <= card->debug) { \ 20 printf("ccid-card-passthru: " fmt , ## __VA_ARGS__); \ 21 } \ 22 } while (0) 23 24 #define D_WARN 1 25 #define D_INFO 2 26 #define D_MORE_INFO 3 27 #define D_VERBOSE 4 28 29 /* TODO: do we still need this? */ 30 uint8_t DEFAULT_ATR[] = { 31 /* 32 * From some example somewhere 33 * 0x3B, 0xB0, 0x18, 0x00, 0xD1, 0x81, 0x05, 0xB1, 0x40, 0x38, 0x1F, 0x03, 0x28 34 */ 35 36 /* From an Athena smart card */ 37 0x3B, 0xD5, 0x18, 0xFF, 0x80, 0x91, 0xFE, 0x1F, 0xC3, 0x80, 0x73, 0xC8, 0x21, 38 0x13, 0x08 39 }; 40 41 42 #define PASSTHRU_DEV_NAME "ccid-card-passthru" 43 #define VSCARD_IN_SIZE 65536 44 45 /* maximum size of ATR - from 7816-3 */ 46 #define MAX_ATR_SIZE 40 47 48 typedef struct PassthruState PassthruState; 49 50 struct PassthruState { 51 CCIDCardState base; 52 CharDriverState *cs; 53 uint8_t vscard_in_data[VSCARD_IN_SIZE]; 54 uint32_t vscard_in_pos; 55 uint32_t vscard_in_hdr; 56 uint8_t atr[MAX_ATR_SIZE]; 57 uint8_t atr_length; 58 uint8_t debug; 59 }; 60 61 /* 62 * VSCard protocol over chardev 63 * This code should not depend on the card type. 64 */ 65 66 static void ccid_card_vscard_send_msg(PassthruState *s, 67 VSCMsgType type, uint32_t reader_id, 68 const uint8_t *payload, uint32_t length) 69 { 70 VSCMsgHeader scr_msg_header; 71 72 scr_msg_header.type = htonl(type); 73 scr_msg_header.reader_id = htonl(reader_id); 74 scr_msg_header.length = htonl(length); 75 qemu_chr_fe_write(s->cs, (uint8_t *)&scr_msg_header, sizeof(VSCMsgHeader)); 76 qemu_chr_fe_write(s->cs, payload, length); 77 } 78 79 static void ccid_card_vscard_send_apdu(PassthruState *s, 80 const uint8_t *apdu, uint32_t length) 81 { 82 ccid_card_vscard_send_msg( 83 s, VSC_APDU, VSCARD_MINIMAL_READER_ID, apdu, length); 84 } 85 86 static void ccid_card_vscard_send_error(PassthruState *s, 87 uint32_t reader_id, VSCErrorCode code) 88 { 89 VSCMsgError msg = {.code = htonl(code)}; 90 91 ccid_card_vscard_send_msg( 92 s, VSC_Error, reader_id, (uint8_t *)&msg, sizeof(msg)); 93 } 94 95 static void ccid_card_vscard_send_init(PassthruState *s) 96 { 97 VSCMsgInit msg = { 98 .version = htonl(VSCARD_VERSION), 99 .magic = VSCARD_MAGIC, 100 .capabilities = {0} 101 }; 102 103 ccid_card_vscard_send_msg(s, VSC_Init, VSCARD_UNDEFINED_READER_ID, 104 (uint8_t *)&msg, sizeof(msg)); 105 } 106 107 static int ccid_card_vscard_can_read(void *opaque) 108 { 109 PassthruState *card = opaque; 110 111 return VSCARD_IN_SIZE >= card->vscard_in_pos ? 112 VSCARD_IN_SIZE - card->vscard_in_pos : 0; 113 } 114 115 static void ccid_card_vscard_handle_init( 116 PassthruState *card, VSCMsgHeader *hdr, VSCMsgInit *init) 117 { 118 uint32_t *capabilities; 119 int num_capabilities; 120 int i; 121 122 capabilities = init->capabilities; 123 num_capabilities = 124 1 + ((hdr->length - sizeof(VSCMsgInit)) / sizeof(uint32_t)); 125 init->version = ntohl(init->version); 126 for (i = 0 ; i < num_capabilities; ++i) { 127 capabilities[i] = ntohl(capabilities[i]); 128 } 129 if (init->magic != VSCARD_MAGIC) { 130 error_report("wrong magic"); 131 /* we can't disconnect the chardev */ 132 } 133 if (init->version != VSCARD_VERSION) { 134 DPRINTF(card, D_WARN, 135 "got version %d, have %d", init->version, VSCARD_VERSION); 136 } 137 /* future handling of capabilities, none exist atm */ 138 ccid_card_vscard_send_init(card); 139 } 140 141 static void ccid_card_vscard_handle_message(PassthruState *card, 142 VSCMsgHeader *scr_msg_header) 143 { 144 uint8_t *data = (uint8_t *)&scr_msg_header[1]; 145 146 switch (scr_msg_header->type) { 147 case VSC_ATR: 148 DPRINTF(card, D_INFO, "VSC_ATR %d\n", scr_msg_header->length); 149 if (scr_msg_header->length > MAX_ATR_SIZE) { 150 error_report("ATR size exceeds spec, ignoring"); 151 ccid_card_vscard_send_error(card, scr_msg_header->reader_id, 152 VSC_GENERAL_ERROR); 153 break; 154 } 155 memcpy(card->atr, data, scr_msg_header->length); 156 card->atr_length = scr_msg_header->length; 157 ccid_card_card_inserted(&card->base); 158 ccid_card_vscard_send_error(card, scr_msg_header->reader_id, 159 VSC_SUCCESS); 160 break; 161 case VSC_APDU: 162 ccid_card_send_apdu_to_guest( 163 &card->base, data, scr_msg_header->length); 164 break; 165 case VSC_CardRemove: 166 DPRINTF(card, D_INFO, "VSC_CardRemove\n"); 167 ccid_card_card_removed(&card->base); 168 ccid_card_vscard_send_error(card, 169 scr_msg_header->reader_id, VSC_SUCCESS); 170 break; 171 case VSC_Init: 172 ccid_card_vscard_handle_init( 173 card, scr_msg_header, (VSCMsgInit *)data); 174 break; 175 case VSC_Error: 176 ccid_card_card_error(&card->base, *(uint32_t *)data); 177 break; 178 case VSC_ReaderAdd: 179 if (ccid_card_ccid_attach(&card->base) < 0) { 180 ccid_card_vscard_send_error(card, VSCARD_UNDEFINED_READER_ID, 181 VSC_CANNOT_ADD_MORE_READERS); 182 } else { 183 ccid_card_vscard_send_error(card, VSCARD_MINIMAL_READER_ID, 184 VSC_SUCCESS); 185 } 186 break; 187 case VSC_ReaderRemove: 188 ccid_card_ccid_detach(&card->base); 189 ccid_card_vscard_send_error(card, 190 scr_msg_header->reader_id, VSC_SUCCESS); 191 break; 192 default: 193 printf("usb-ccid: chardev: unexpected message of type %X\n", 194 scr_msg_header->type); 195 ccid_card_vscard_send_error(card, scr_msg_header->reader_id, 196 VSC_GENERAL_ERROR); 197 } 198 } 199 200 static void ccid_card_vscard_drop_connection(PassthruState *card) 201 { 202 qemu_chr_delete(card->cs); 203 card->vscard_in_pos = card->vscard_in_hdr = 0; 204 } 205 206 static void ccid_card_vscard_read(void *opaque, const uint8_t *buf, int size) 207 { 208 PassthruState *card = opaque; 209 VSCMsgHeader *hdr; 210 211 if (card->vscard_in_pos + size > VSCARD_IN_SIZE) { 212 error_report( 213 "no room for data: pos %d + size %d > %d. dropping connection.", 214 card->vscard_in_pos, size, VSCARD_IN_SIZE); 215 ccid_card_vscard_drop_connection(card); 216 return; 217 } 218 assert(card->vscard_in_pos < VSCARD_IN_SIZE); 219 assert(card->vscard_in_hdr < VSCARD_IN_SIZE); 220 memcpy(card->vscard_in_data + card->vscard_in_pos, buf, size); 221 card->vscard_in_pos += size; 222 hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr); 223 224 while ((card->vscard_in_pos - card->vscard_in_hdr >= sizeof(VSCMsgHeader)) 225 &&(card->vscard_in_pos - card->vscard_in_hdr >= 226 sizeof(VSCMsgHeader) + ntohl(hdr->length))) { 227 hdr->reader_id = ntohl(hdr->reader_id); 228 hdr->length = ntohl(hdr->length); 229 hdr->type = ntohl(hdr->type); 230 ccid_card_vscard_handle_message(card, hdr); 231 card->vscard_in_hdr += hdr->length + sizeof(VSCMsgHeader); 232 hdr = (VSCMsgHeader *)(card->vscard_in_data + card->vscard_in_hdr); 233 } 234 if (card->vscard_in_hdr == card->vscard_in_pos) { 235 card->vscard_in_pos = card->vscard_in_hdr = 0; 236 } 237 } 238 239 static void ccid_card_vscard_event(void *opaque, int event) 240 { 241 PassthruState *card = opaque; 242 243 switch (event) { 244 case CHR_EVENT_BREAK: 245 card->vscard_in_pos = card->vscard_in_hdr = 0; 246 break; 247 case CHR_EVENT_FOCUS: 248 break; 249 case CHR_EVENT_OPENED: 250 DPRINTF(card, D_INFO, "%s: CHR_EVENT_OPENED\n", __func__); 251 break; 252 } 253 } 254 255 /* End VSCard handling */ 256 257 static void passthru_apdu_from_guest( 258 CCIDCardState *base, const uint8_t *apdu, uint32_t len) 259 { 260 PassthruState *card = DO_UPCAST(PassthruState, base, base); 261 262 if (!card->cs) { 263 printf("ccid-passthru: no chardev, discarding apdu length %d\n", len); 264 return; 265 } 266 ccid_card_vscard_send_apdu(card, apdu, len); 267 } 268 269 static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len) 270 { 271 PassthruState *card = DO_UPCAST(PassthruState, base, base); 272 273 *len = card->atr_length; 274 return card->atr; 275 } 276 277 static int passthru_initfn(CCIDCardState *base) 278 { 279 PassthruState *card = DO_UPCAST(PassthruState, base, base); 280 281 card->vscard_in_pos = 0; 282 card->vscard_in_hdr = 0; 283 if (card->cs) { 284 DPRINTF(card, D_INFO, "initing chardev\n"); 285 qemu_chr_add_handlers(card->cs, 286 ccid_card_vscard_can_read, 287 ccid_card_vscard_read, 288 ccid_card_vscard_event, card); 289 ccid_card_vscard_send_init(card); 290 } else { 291 error_report("missing chardev"); 292 return -1; 293 } 294 assert(sizeof(DEFAULT_ATR) <= MAX_ATR_SIZE); 295 memcpy(card->atr, DEFAULT_ATR, sizeof(DEFAULT_ATR)); 296 card->atr_length = sizeof(DEFAULT_ATR); 297 return 0; 298 } 299 300 static int passthru_exitfn(CCIDCardState *base) 301 { 302 return 0; 303 } 304 305 static VMStateDescription passthru_vmstate = { 306 .name = PASSTHRU_DEV_NAME, 307 .version_id = 1, 308 .minimum_version_id = 1, 309 .fields = (VMStateField[]) { 310 VMSTATE_BUFFER(vscard_in_data, PassthruState), 311 VMSTATE_UINT32(vscard_in_pos, PassthruState), 312 VMSTATE_UINT32(vscard_in_hdr, PassthruState), 313 VMSTATE_BUFFER(atr, PassthruState), 314 VMSTATE_UINT8(atr_length, PassthruState), 315 VMSTATE_END_OF_LIST() 316 } 317 }; 318 319 static Property passthru_card_properties[] = { 320 DEFINE_PROP_CHR("chardev", PassthruState, cs), 321 DEFINE_PROP_UINT8("debug", PassthruState, debug, 0), 322 DEFINE_PROP_END_OF_LIST(), 323 }; 324 325 static void passthru_class_initfn(ObjectClass *klass, void *data) 326 { 327 DeviceClass *dc = DEVICE_CLASS(klass); 328 CCIDCardClass *cc = CCID_CARD_CLASS(klass); 329 330 cc->initfn = passthru_initfn; 331 cc->exitfn = passthru_exitfn; 332 cc->get_atr = passthru_get_atr; 333 cc->apdu_from_guest = passthru_apdu_from_guest; 334 dc->desc = "passthrough smartcard"; 335 dc->vmsd = &passthru_vmstate; 336 dc->props = passthru_card_properties; 337 } 338 339 static const TypeInfo passthru_card_info = { 340 .name = PASSTHRU_DEV_NAME, 341 .parent = TYPE_CCID_CARD, 342 .instance_size = sizeof(PassthruState), 343 .class_init = passthru_class_initfn, 344 }; 345 346 static void ccid_card_passthru_register_types(void) 347 { 348 type_register_static(&passthru_card_info); 349 } 350 351 type_init(ccid_card_passthru_register_types) 352