| 1 | /* |
|---|
| 2 | * OMNIKEY CardMan 2020/6020/6120 driver |
|---|
| 3 | * This driver is not yet complete, but at least it |
|---|
| 4 | * spits out the ATR already. |
|---|
| 5 | * Needs a recentish Linux Kernel (2.4.5 does NOT work) |
|---|
| 6 | * |
|---|
| 7 | * Copyright (C) 2003, Olaf Kirch <okir@suse.de> |
|---|
| 8 | * |
|---|
| 9 | * Based on information from the cm2020 driver by |
|---|
| 10 | * Omnikey AG. |
|---|
| 11 | */ |
|---|
| 12 | |
|---|
| 13 | #include "internal.h" |
|---|
| 14 | #include <stdlib.h> |
|---|
| 15 | #include <string.h> |
|---|
| 16 | |
|---|
| 17 | typedef struct cm_priv { |
|---|
| 18 | int icc_proto; |
|---|
| 19 | unsigned char rbuf[64]; |
|---|
| 20 | unsigned int head, tail; |
|---|
| 21 | } cm_priv_t; |
|---|
| 22 | |
|---|
| 23 | typedef int complete_fn_t(const void *, size_t); |
|---|
| 24 | static int cm_set_card_parameters(ifd_device_t *, unsigned int baudRate); |
|---|
| 25 | static int cm_transceive_t0(ifd_reader_t * reader, |
|---|
| 26 | const void *sbuf, size_t slen, |
|---|
| 27 | void *rbuf, size_t rlen); |
|---|
| 28 | static int cm_usb_int(ifd_device_t * dev, int requesttype, int request, |
|---|
| 29 | int value, int idx, |
|---|
| 30 | const void *sbuf, size_t slen, |
|---|
| 31 | void *rbuf, size_t rlen, |
|---|
| 32 | complete_fn_t check, long timeout); |
|---|
| 33 | static int cm_anyreply(const void *, size_t); |
|---|
| 34 | |
|---|
| 35 | /* |
|---|
| 36 | * Initialize the device |
|---|
| 37 | */ |
|---|
| 38 | static int cm_open(ifd_reader_t * reader, const char *device_name) |
|---|
| 39 | { |
|---|
| 40 | ifd_device_t *dev; |
|---|
| 41 | cm_priv_t *priv; |
|---|
| 42 | ifd_device_params_t params; |
|---|
| 43 | |
|---|
| 44 | reader->name = "OMNIKEY CardMan 2020/6020/6120"; |
|---|
| 45 | reader->nslots = 1; |
|---|
| 46 | if (!(dev = ifd_device_open(device_name))) |
|---|
| 47 | return -1; |
|---|
| 48 | if (ifd_device_type(dev) != IFD_DEVICE_TYPE_USB) { |
|---|
| 49 | ct_error("cardman: device %s is not a USB device", device_name); |
|---|
| 50 | ifd_device_close(dev); |
|---|
| 51 | return -1; |
|---|
| 52 | } |
|---|
| 53 | |
|---|
| 54 | params = dev->settings; |
|---|
| 55 | params.usb.interface = 0; |
|---|
| 56 | if (ifd_device_set_parameters(dev, ¶ms) < 0) { |
|---|
| 57 | ifd_device_close(dev); |
|---|
| 58 | return -1; |
|---|
| 59 | } |
|---|
| 60 | priv = (cm_priv_t *) calloc(1, sizeof(cm_priv_t)); |
|---|
| 61 | if (!priv) { |
|---|
| 62 | ct_error("out of memory"); |
|---|
| 63 | return IFD_ERROR_NO_MEMORY; |
|---|
| 64 | } |
|---|
| 65 | |
|---|
| 66 | reader->driver_data = priv; |
|---|
| 67 | reader->device = dev; |
|---|
| 68 | dev->timeout = 2000; |
|---|
| 69 | |
|---|
| 70 | return 0; |
|---|
| 71 | } |
|---|
| 72 | |
|---|
| 73 | /* |
|---|
| 74 | * Power up the card slot |
|---|
| 75 | */ |
|---|
| 76 | static int cm_activate(ifd_reader_t * reader) |
|---|
| 77 | { |
|---|
| 78 | ifd_device_t *dev = reader->device; |
|---|
| 79 | int rc; |
|---|
| 80 | |
|---|
| 81 | ifd_debug(1, "called."); |
|---|
| 82 | /* Set async card @9600 bps, 2 stop bits, even parity */ |
|---|
| 83 | if ((rc = cm_set_card_parameters(dev, 0x01)) < 0) { |
|---|
| 84 | ct_error("cardman: failed to set card parameters 9600/8E2"); |
|---|
| 85 | return rc; |
|---|
| 86 | } |
|---|
| 87 | return 0; |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | static int cm_deactivate(ifd_reader_t * reader) |
|---|
| 91 | { |
|---|
| 92 | ifd_device_t *dev = reader->device; |
|---|
| 93 | int rc; |
|---|
| 94 | |
|---|
| 95 | ifd_debug(1, "called."); |
|---|
| 96 | if ((rc = ifd_usb_control(dev, 0x42, 0x11, 0, 0, NULL, 0, -1)) < 0) { |
|---|
| 97 | ct_error("cardman: failed to deactivate card"); |
|---|
| 98 | return rc; |
|---|
| 99 | } |
|---|
| 100 | return 0; |
|---|
| 101 | } |
|---|
| 102 | |
|---|
| 103 | /* |
|---|
| 104 | * Card status - always present |
|---|
| 105 | */ |
|---|
| 106 | static int cm_card_status(ifd_reader_t * reader, int slot, int *status) |
|---|
| 107 | { |
|---|
| 108 | ifd_device_t *dev = reader->device; |
|---|
| 109 | unsigned char cm_status = 0; |
|---|
| 110 | int rc; |
|---|
| 111 | |
|---|
| 112 | *status = 0; |
|---|
| 113 | |
|---|
| 114 | if ((rc = |
|---|
| 115 | cm_usb_int(dev, 0x42, 0x20, 0, 0, NULL, 0, &cm_status, 1, NULL, |
|---|
| 116 | -1)) < 0) { |
|---|
| 117 | ct_error("cardman: failed to get card status"); |
|---|
| 118 | return -1; |
|---|
| 119 | } |
|---|
| 120 | if (rc == 1 && (cm_status & 0x42)) |
|---|
| 121 | *status = IFD_CARD_PRESENT; |
|---|
| 122 | ifd_debug(1, "card %spresent", *status ? "" : "not "); |
|---|
| 123 | return 0; |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | /* |
|---|
| 127 | * Reset |
|---|
| 128 | */ |
|---|
| 129 | static int cm_card_reset(ifd_reader_t * reader, int slot, void *atr, |
|---|
| 130 | size_t size) |
|---|
| 131 | { |
|---|
| 132 | ifd_device_t *dev = reader->device; |
|---|
| 133 | unsigned char buffer[IFD_MAX_ATR_LEN]; |
|---|
| 134 | int n; |
|---|
| 135 | |
|---|
| 136 | /* Request the ATR */ |
|---|
| 137 | if ((n = cm_usb_int(dev, 0x42, 0x10, 1, 0, NULL, 0, |
|---|
| 138 | buffer, sizeof(buffer), |
|---|
| 139 | (complete_fn_t *) ifd_atr_complete, -1)) < 0) { |
|---|
| 140 | ct_error("cardman: failed to reset card"); |
|---|
| 141 | return n; |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | /* XXX Handle inverse convention, odd parity, etc */ |
|---|
| 145 | |
|---|
| 146 | if ((size_t) n > size) |
|---|
| 147 | n = size; |
|---|
| 148 | memcpy(atr, buffer, n); |
|---|
| 149 | return n; |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | /* |
|---|
| 153 | * Select a protocol for communication with the ICC. |
|---|
| 154 | */ |
|---|
| 155 | static int cm_set_protocol(ifd_reader_t * reader, int nslot, int proto) |
|---|
| 156 | { |
|---|
| 157 | ifd_device_t *dev = reader->device; |
|---|
| 158 | ifd_slot_t *slot; |
|---|
| 159 | cm_priv_t *priv; |
|---|
| 160 | unsigned char pts[4], reply[4]; |
|---|
| 161 | unsigned int baudRate; |
|---|
| 162 | int n; |
|---|
| 163 | |
|---|
| 164 | ifd_debug(1, "called, proto=%d", proto); |
|---|
| 165 | |
|---|
| 166 | pts[0] = 0xFF; |
|---|
| 167 | switch (proto) { |
|---|
| 168 | case IFD_PROTOCOL_T0: |
|---|
| 169 | pts[1] = 0x10; |
|---|
| 170 | pts[2] = 0x11; |
|---|
| 171 | break; |
|---|
| 172 | case IFD_PROTOCOL_T1: |
|---|
| 173 | pts[1] = 0x11; |
|---|
| 174 | /* XXX select Fi/Di according to TA1 */ |
|---|
| 175 | pts[2] = 0x11; |
|---|
| 176 | break; |
|---|
| 177 | default: |
|---|
| 178 | return IFD_ERROR_NOT_SUPPORTED; |
|---|
| 179 | } |
|---|
| 180 | pts[3] = pts[0] ^ pts[1] ^ pts[2]; |
|---|
| 181 | |
|---|
| 182 | /* Send the PTS bytes */ |
|---|
| 183 | if ((n = |
|---|
| 184 | cm_usb_int(dev, 0x42, 1, 0, 0, pts, 4, reply, 2, NULL, -1)) < 0) { |
|---|
| 185 | ct_error("cardman: failed to send PTS"); |
|---|
| 186 | return n; |
|---|
| 187 | } |
|---|
| 188 | if (reply[0] != 4) { |
|---|
| 189 | ct_error("cardman: card refused PTS"); |
|---|
| 190 | return IFD_ERROR_COMM_ERROR; |
|---|
| 191 | } |
|---|
| 192 | #ifdef notyet |
|---|
| 193 | /* Receive PTS response */ |
|---|
| 194 | if ((n = ifd_usb_control(dev, 0xC2, 0, 0, 0, reply, 4, -1)) < 0) { |
|---|
| 195 | ct_error("cardman: failed to receive PTS response"); |
|---|
| 196 | return n; |
|---|
| 197 | } |
|---|
| 198 | if (n != 4) { |
|---|
| 199 | ct_error("cardman: received short PTS response (%u bytes)", n); |
|---|
| 200 | return IFD_ERROR_COMM_ERROR; |
|---|
| 201 | } |
|---|
| 202 | if (memcmp(pts, reply, 4)) { |
|---|
| 203 | ct_error("cardman: PTS reply does not match request", n); |
|---|
| 204 | return IFD_ERROR_COMM_ERROR; |
|---|
| 205 | } |
|---|
| 206 | #endif |
|---|
| 207 | |
|---|
| 208 | baudRate = pts[2] & 0xf; |
|---|
| 209 | /* Select f=5.12 MHz */ |
|---|
| 210 | if ((pts[2] & 0xF0) == 0x90) |
|---|
| 211 | baudRate |= 0x10; |
|---|
| 212 | if ((n = cm_set_card_parameters(dev, baudRate)) < 0) { |
|---|
| 213 | ct_error |
|---|
| 214 | ("cardman: failed to set card communication parameters"); |
|---|
| 215 | return n; |
|---|
| 216 | } |
|---|
| 217 | |
|---|
| 218 | /* T=0 goes through send/receive functions, but |
|---|
| 219 | * T=1 needs special massaging */ |
|---|
| 220 | slot = &reader->slot[nslot]; |
|---|
| 221 | if (proto == IFD_PROTOCOL_T0) { |
|---|
| 222 | slot->proto = ifd_protocol_new(proto, reader, slot->dad); |
|---|
| 223 | } else { |
|---|
| 224 | slot->proto = ifd_protocol_new(IFD_PROTOCOL_TRANSPARENT, |
|---|
| 225 | reader, slot->dad); |
|---|
| 226 | } |
|---|
| 227 | if (slot->proto == NULL) { |
|---|
| 228 | ct_error("cardman: internal error"); |
|---|
| 229 | return -1; |
|---|
| 230 | } |
|---|
| 231 | |
|---|
| 232 | priv = (cm_priv_t *) reader->driver_data; |
|---|
| 233 | priv->icc_proto = proto; |
|---|
| 234 | |
|---|
| 235 | return 0; |
|---|
| 236 | } |
|---|
| 237 | |
|---|
| 238 | /* |
|---|
| 239 | * Send/receive using the underlying protocol. |
|---|
| 240 | */ |
|---|
| 241 | static int cm_transparent(ifd_reader_t * reader, int dad, |
|---|
| 242 | const void *sbuf, size_t slen, void *rbuf, |
|---|
| 243 | size_t rlen) |
|---|
| 244 | { |
|---|
| 245 | cm_priv_t *priv = (cm_priv_t *) reader->driver_data; |
|---|
| 246 | |
|---|
| 247 | switch (priv->icc_proto) { |
|---|
| 248 | case IFD_PROTOCOL_T0: |
|---|
| 249 | return cm_transceive_t0(reader, sbuf, slen, rbuf, rlen); |
|---|
| 250 | case IFD_PROTOCOL_T1: |
|---|
| 251 | return IFD_ERROR_NOT_SUPPORTED; /* not yet */ |
|---|
| 252 | } |
|---|
| 253 | |
|---|
| 254 | return IFD_ERROR_NOT_SUPPORTED; |
|---|
| 255 | } |
|---|
| 256 | |
|---|
| 257 | static int cm_transceive_t0(ifd_reader_t * reader, |
|---|
| 258 | const void *sbuf, size_t slen, void *rbuf, |
|---|
| 259 | size_t rlen) |
|---|
| 260 | { |
|---|
| 261 | #if 0 |
|---|
| 262 | ifd_device_t *dev = reader->device; |
|---|
| 263 | int rc; |
|---|
| 264 | |
|---|
| 265 | if (len > 5) { |
|---|
| 266 | rc = ifd_usb_control(dev, 0x42, 2, 0, 0, rbuf, rlen); |
|---|
| 267 | } else { |
|---|
| 268 | unsigned char temp[5]; |
|---|
| 269 | |
|---|
| 270 | if (len < 4) |
|---|
| 271 | return IFD_ERROR_INVALID_ARG; |
|---|
| 272 | temp[4] = 0; |
|---|
| 273 | memcpy(temp, sbuf, slen); |
|---|
| 274 | rc = ifd_usb_control(dev, 0x42, 3, 8, (temp[1] << 8) | temp[4], |
|---|
| 275 | temp, 5); |
|---|
| 276 | } |
|---|
| 277 | #endif |
|---|
| 278 | return IFD_ERROR_NOT_SUPPORTED; |
|---|
| 279 | } |
|---|
| 280 | |
|---|
| 281 | /* |
|---|
| 282 | * Send/receive routines |
|---|
| 283 | */ |
|---|
| 284 | static int cm_send_t0(ifd_reader_t * reader, unsigned int dad, |
|---|
| 285 | const unsigned char *sbuf, size_t slen) |
|---|
| 286 | { |
|---|
| 287 | cm_priv_t *priv = (cm_priv_t *) reader->driver_data; |
|---|
| 288 | ifd_device_t *dev = reader->device; |
|---|
| 289 | int rc; |
|---|
| 290 | |
|---|
| 291 | /* XXX how can we know if this is a CASE 1 or CASE 2 APDU? */ |
|---|
| 292 | priv->head = priv->tail = 0; |
|---|
| 293 | rc = cm_usb_int(dev, 0x42, 2, 0, 0, sbuf, slen, |
|---|
| 294 | priv->rbuf, sizeof(priv->rbuf), cm_anyreply, -1); |
|---|
| 295 | if (rc >= 0) { |
|---|
| 296 | priv->tail = rc; |
|---|
| 297 | rc = slen; |
|---|
| 298 | } |
|---|
| 299 | return rc; |
|---|
| 300 | } |
|---|
| 301 | |
|---|
| 302 | static int cm_send(ifd_reader_t * reader, unsigned int dad, |
|---|
| 303 | const unsigned char *buffer, size_t len) |
|---|
| 304 | { |
|---|
| 305 | cm_priv_t *priv = (cm_priv_t *) reader->driver_data; |
|---|
| 306 | |
|---|
| 307 | switch (priv->icc_proto) { |
|---|
| 308 | case IFD_PROTOCOL_T0: |
|---|
| 309 | return cm_send_t0(reader, dad, buffer, len); |
|---|
| 310 | } |
|---|
| 311 | |
|---|
| 312 | return IFD_ERROR_NOT_SUPPORTED; |
|---|
| 313 | } |
|---|
| 314 | |
|---|
| 315 | static int cm_recv(ifd_reader_t * reader, unsigned int dad, |
|---|
| 316 | unsigned char *buffer, size_t len, long timeout) |
|---|
| 317 | { |
|---|
| 318 | cm_priv_t *priv = (cm_priv_t *) reader->driver_data; |
|---|
| 319 | |
|---|
| 320 | switch (priv->icc_proto) { |
|---|
| 321 | case IFD_PROTOCOL_T0: |
|---|
| 322 | if (priv->tail - priv->head < len) |
|---|
| 323 | len = priv->tail - priv->head; |
|---|
| 324 | memcpy(buffer, priv->rbuf + priv->head, len); |
|---|
| 325 | priv->head += len; |
|---|
| 326 | return len; |
|---|
| 327 | } |
|---|
| 328 | return IFD_ERROR_NOT_SUPPORTED; /* not yet */ |
|---|
| 329 | } |
|---|
| 330 | |
|---|
| 331 | /* |
|---|
| 332 | * Set the card's baud rate etc |
|---|
| 333 | */ |
|---|
| 334 | static int cm_set_card_parameters(ifd_device_t * dev, unsigned int baudrate) |
|---|
| 335 | { |
|---|
| 336 | return ifd_usb_control(dev, 0x42, 0x30, baudrate << 8, 2, NULL, 0, -1); |
|---|
| 337 | } |
|---|
| 338 | |
|---|
| 339 | /* |
|---|
| 340 | * Send USB control message, and receive data via |
|---|
| 341 | * Interrupt URBs. |
|---|
| 342 | */ |
|---|
| 343 | static int cm_usb_int(ifd_device_t * dev, int requesttype, int request, |
|---|
| 344 | int value, int idx, const void *sbuf, size_t slen, |
|---|
| 345 | void *rbuf, size_t rlen, complete_fn_t complete, |
|---|
| 346 | long timeout) |
|---|
| 347 | { |
|---|
| 348 | ifd_usb_capture_t *cap; |
|---|
| 349 | struct timeval begin; |
|---|
| 350 | unsigned int total = 0; |
|---|
| 351 | int rc; |
|---|
| 352 | |
|---|
| 353 | if (timeout < 0) |
|---|
| 354 | timeout = dev->timeout; |
|---|
| 355 | |
|---|
| 356 | rc = ifd_usb_begin_capture(dev, |
|---|
| 357 | IFD_USB_URB_TYPE_INTERRUPT, 0x81, 8, &cap); |
|---|
| 358 | if (rc < 0) |
|---|
| 359 | return rc; |
|---|
| 360 | |
|---|
| 361 | gettimeofday(&begin, NULL); |
|---|
| 362 | rc = ifd_usb_control(dev, requesttype, request, |
|---|
| 363 | value, idx, (void *)sbuf, slen, timeout); |
|---|
| 364 | if (rc < 0) |
|---|
| 365 | goto out; |
|---|
| 366 | |
|---|
| 367 | /* Capture URBs until we have a complete answer */ |
|---|
| 368 | while (rc >= 0 && total < rlen) { |
|---|
| 369 | unsigned char temp[8]; |
|---|
| 370 | long wait; |
|---|
| 371 | |
|---|
| 372 | wait = timeout - ifd_time_elapsed(&begin); |
|---|
| 373 | if (wait <= 0) |
|---|
| 374 | return IFD_ERROR_TIMEOUT; |
|---|
| 375 | rc = ifd_usb_capture(dev, cap, temp, sizeof(temp), wait); |
|---|
| 376 | if (rc > 0) { |
|---|
| 377 | if (rc > (int)(rlen - total)) |
|---|
| 378 | rc = rlen - total; |
|---|
| 379 | memcpy((caddr_t) rbuf + total, temp, rc); |
|---|
| 380 | total += rc; |
|---|
| 381 | |
|---|
| 382 | if (complete && complete(rbuf, total)) |
|---|
| 383 | break; |
|---|
| 384 | } |
|---|
| 385 | } |
|---|
| 386 | |
|---|
| 387 | if (rc >= 0) { |
|---|
| 388 | ifd_debug(3, "received %u bytes:%s", total, |
|---|
| 389 | ct_hexdump(rbuf, total)); |
|---|
| 390 | rc = total; |
|---|
| 391 | } |
|---|
| 392 | |
|---|
| 393 | out: |
|---|
| 394 | ifd_usb_end_capture(dev, cap); |
|---|
| 395 | return rc; |
|---|
| 396 | } |
|---|
| 397 | |
|---|
| 398 | static int cm_anyreply(const void *ptr, size_t len) |
|---|
| 399 | { |
|---|
| 400 | return 1; |
|---|
| 401 | } |
|---|
| 402 | |
|---|
| 403 | /* |
|---|
| 404 | * Driver operations |
|---|
| 405 | */ |
|---|
| 406 | static struct ifd_driver_ops cardman_driver; |
|---|
| 407 | |
|---|
| 408 | /* |
|---|
| 409 | * Initialize this module |
|---|
| 410 | */ |
|---|
| 411 | void ifd_cardman_register(void) |
|---|
| 412 | { |
|---|
| 413 | cardman_driver.open = cm_open; |
|---|
| 414 | cardman_driver.activate = cm_activate; |
|---|
| 415 | cardman_driver.deactivate = cm_deactivate; |
|---|
| 416 | cardman_driver.card_status = cm_card_status; |
|---|
| 417 | cardman_driver.card_reset = cm_card_reset; |
|---|
| 418 | cardman_driver.send = cm_send; |
|---|
| 419 | cardman_driver.recv = cm_recv; |
|---|
| 420 | cardman_driver.set_protocol = cm_set_protocol; |
|---|
| 421 | cardman_driver.transparent = cm_transparent; |
|---|
| 422 | |
|---|
| 423 | ifd_driver_register("cardman", &cardman_driver); |
|---|
| 424 | } |
|---|