26#include 27
28#include "internal.h"
29#include "asn1.h"
30#include "iso7816.h"
31
32static const struct sc_card_error iso7816_errors[] = {
33 { 0x6200, SC_ERROR_MEMORY_FAILURE, "State of non-volatile memory unchanged" },
34 { 0x6281, SC_ERROR_MEMORY_FAILURE, "Part of returned data may be corrupted" },
35 { 0x6282, SC_ERROR_CARD_CMD_FAILED, "End of file/record reached before reading Le bytes" },
36 { 0x6283, SC_ERROR_CARD_CMD_FAILED, "Selected file invalidated" },
37 { 0x6284, SC_ERROR_CARD_CMD_FAILED, "FCI not formatted according to ISO 7816-4" },
38
39 { 0x6300, SC_ERROR_MEMORY_FAILURE, "State of non-volatile memory changed" },
40 { 0x6381, SC_ERROR_CARD_CMD_FAILED, "File filled up by last write" },
41
42 { 0x6581, SC_ERROR_MEMORY_FAILURE, "Memory failure" },
43
44 { 0x6700, SC_ERROR_WRONG_LENGTH, "Wrong length" },
45
46 { 0x6800, SC_ERROR_NO_CARD_SUPPORT, "Functions in CLA not supported" },
47 { 0x6881, SC_ERROR_NO_CARD_SUPPORT, "Logical channel not supported" },
48 { 0x6882, SC_ERROR_NO_CARD_SUPPORT, "Secure messaging not supported" },
49
50 { 0x6900, SC_ERROR_NOT_ALLOWED, "Command not allowed" },
51 { 0x6981, SC_ERROR_CARD_CMD_FAILED, "Command incompatible with file structure" },
52 { 0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Security status not satisfied" },
53 { 0x6983, SC_ERROR_AUTH_METHOD_BLOCKED, "Authentication method blocked" },
54 { 0x6984, SC_ERROR_CARD_CMD_FAILED, "Referenced data invalidated" },
55 { 0x6985, SC_ERROR_NOT_ALLOWED, "Conditions of use not satisfied" },
56 { 0x6986, SC_ERROR_NOT_ALLOWED, "Command not allowed (no current EF)" },
57 { 0x6987, SC_ERROR_INCORRECT_PARAMETERS,"Expected SM data objects missing" },
58 { 0x6988, SC_ERROR_INCORRECT_PARAMETERS,"SM data objects incorrect" },
59
60 { 0x6A00, SC_ERROR_INCORRECT_PARAMETERS,"Wrong parameter(s) P1-P2" },
61 { 0x6A80, SC_ERROR_INCORRECT_PARAMETERS,"Incorrect parameters in the data field" },
62 { 0x6A81, SC_ERROR_NO_CARD_SUPPORT, "Function not supported" },
63 { 0x6A82, SC_ERROR_FILE_NOT_FOUND, "File not found" },
64 { 0x6A83, SC_ERROR_RECORD_NOT_FOUND, "Record not found" },
65 { 0x6A84, SC_ERROR_NOT_ENOUGH_MEMORY, "Not enough memory space in the file" },
66 { 0x6A85, SC_ERROR_INCORRECT_PARAMETERS,"Lc inconsistent with TLV structure" },
67 { 0x6A86, SC_ERROR_INCORRECT_PARAMETERS,"Incorrect parameters P1-P2" },
68 { 0x6A87, SC_ERROR_INCORRECT_PARAMETERS,"Lc inconsistent with P1-P2" },
69 { 0x6A88, SC_ERROR_DATA_OBJECT_NOT_FOUND,"Referenced data not found" },
70
71 { 0x6B00, SC_ERROR_INCORRECT_PARAMETERS,"Wrong parameter(s) P1-P2" },
72 { 0x6D00, SC_ERROR_INS_NOT_SUPPORTED, "Instruction code not supported or invalid" },
73 { 0x6E00, SC_ERROR_CLASS_NOT_SUPPORTED, "Class not supported" },
74 { 0x6F00, SC_ERROR_CARD_CMD_FAILED, "No precise diagnosis" },
75
76 /* Possibly TCOS / Micardo specific errors */
77 { 0x6600, SC_ERROR_INCORRECT_PARAMETERS, "Error setting the security env"},
78 { 0x66F0, SC_ERROR_INCORRECT_PARAMETERS, "No space left for padding"},
79 { 0x69F0, SC_ERROR_NOT_ALLOWED, "Command not allowed"},
80 { 0x6A89, SC_ERROR_FILE_ALREADY_EXISTS, "Files exists"},
81 { 0x6A8A, SC_ERROR_FILE_ALREADY_EXISTS, "Application exists"},
82};
83
84static int iso7816_check_sw(sc_card_t *card, unsigned int sw1, unsigned int sw2)
85{
86 const int err_count = sizeof(iso7816_errors)/sizeof(iso7816_errors[0]);
87 int i;
88
89 /* Handle special cases here */
90 if (sw1 == 0x6C) {
91 sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Wrong length; correct length is %d", sw2);
92 return SC_ERROR_WRONG_LENGTH;
93 }
94 if (sw1 == 0x90)
95 return SC_SUCCESS;
96 if (sw1 == 0x63U && (sw2 & ~0x0fU) == 0xc0U ) {
97 sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Verification failed (remaining tries: %d)",
98 (sw2 & 0x0f));
99 return SC_ERROR_PIN_CODE_INCORRECT;
100 }
101 for (i = 0; i < err_count; i++)
102 if (iso7816_errors[i].SWs == ((sw1 << 8) | sw2)) {
103 sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s", iso7816_errors[i].errorstr);
104 return iso7816_errors[i].errorno;
105 }
106 sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unknown SWs; SW1=%02X, SW2=%02X", sw1, sw2);
107 return SC_ERROR_CARD_CMD_FAILED;
108}
109
110static int iso7816_read_binary(sc_card_t *card,
111 unsigned int idx, u8 *buf, size_t count,
112 unsigned long flags)
113{
114 sc_apdu_t apdu;
115 u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE];
116 int r;
117
118 if (idx > 0x7fff) {
119 sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "invalid EF offset: 0x%X > 0x7FFF", idx);
120 return SC_ERROR_OFFSET_TOO_LARGE;
121 }
122
123 assert(count <= (card->max_recv_size > 0 ? card->max_recv_size : 256));
124 sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB0,
125 (idx >> 8) & 0x7F, idx & 0xFF);
126 apdu.le = count;
127 apdu.resplen = count;
128 apdu.resp = recvbuf;
129
130 r = sc_transmit_apdu(card, &apdu);
131 SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
132 if (apdu.resplen == 0)
133 SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
134 memcpy(buf, recvbuf, apdu.resplen);
135
136 SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, apdu.resplen);
137}
138
139static int iso7816_read_record(sc_card_t *card,
140 unsigned int rec_nr, u8 *buf, size_t count,
141 unsigned long flags)
142{
143 sc_apdu_t apdu;
144 u8 recvbuf[SC_MAX_APDU_BUFFER_SIZE];
145 int r;
146
147 sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xB2, rec_nr, 0);
148 apdu.p2 = (flags & SC_RECORD_EF_ID_MASK) << 3;
149 if (flags & SC_RECORD_BY_REC_NR)
150 apdu.p2 |= 0x04;
151
152 apdu.le = count;
153 apdu.resplen = count;
154 apdu.resp = recvbuf;
155
156 r = sc_transmit_apdu(card, &apdu);
157 SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
158 if (apdu.resplen == 0)
159 SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
160 memcpy(buf, recvbuf, apdu.resplen);
161
162 SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, apdu.resplen);
163}
164
165static int iso7816_write_record(sc_card_t *card, unsigned int rec_nr,
166 const u8 *buf, size_t count,
167 unsigned long flags)
168{
169 sc_apdu_t apdu;
170 int r;
171
172 if (count > 256) {
173 sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Trying to send too many bytes");
174 return SC_ERROR_INVALID_ARGUMENTS;
175 }
176 sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xD2, rec_nr, 0);
177 apdu.p2 = (flags & SC_RECORD_EF_ID_MASK) << 3;
178 if (flags & SC_RECORD_BY_REC_NR)
179 apdu.p2 |= 0x04;
180
181 apdu.lc = count;
182 apdu.datalen = count;
183 apdu.data = buf;
184
185 r = sc_transmit_apdu(card, &apdu);
186 SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
187 SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, sc_check_sw(card, apdu.sw1, apdu.sw2),
188 "Card returned error");
189 SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, count);
190}
191
192static int iso7816_append_record(sc_card_t *card,
193 const u8 *buf, size_t count,
194 unsigned long flags)
195{
196 sc_apdu_t apdu;
197 int r;
198
199 if (count > 256) {
200 sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Trying to send too many bytes");
201 return SC_ERROR_INVALID_ARGUMENTS;
202 }
203 sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE2, 0, 0);
204 apdu.p2 = (flags & SC_RECORD_EF_ID_MASK) << 3;
205
206 apdu.lc = count;
207 apdu.datalen = count;
208 apdu.data = buf;