Coverage Report

Created: 2026-08-31 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensc/src/libopensc/muscle.c
Line
Count
Source
1
/*
2
 * muscle.c: Support for MuscleCard Applet from musclecard.com
3
 *
4
 * Copyright (C) 2006, Identity Alliance, Thomas Harning <support@identityalliance.com>
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
#ifdef HAVE_CONFIG_H
22
#include "config.h"
23
#endif
24
25
#include <string.h>
26
27
#include "internal.h"
28
#include "muscle.h"
29
30
0
#define MSC_RSA_PUBLIC    0x01
31
#define MSC_RSA_PRIVATE   0x02
32
#define MSC_RSA_PRIVATE_CRT 0x03
33
34
static msc_id inputId = { { 0xFF, 0xFF, 0xFF, 0xFF } };
35
static msc_id outputId = { { 0xFF, 0xFF, 0xFF, 0xFE } };
36
37
32.6k
int msc_list_objects(sc_card_t* card, u8 next, mscfs_file_t* file) {
38
32.6k
  sc_apdu_t apdu;
39
32.6k
  u8 fileData[14];
40
32.6k
  int r;
41
42
32.6k
  sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x58, next, 0x00);
43
32.6k
  apdu.le = 14;
44
32.6k
  apdu.resplen = 14;
45
32.6k
  apdu.resp = fileData;
46
32.6k
  r = sc_transmit_apdu(card, &apdu);
47
32.6k
  if (r)
48
39
    return r;
49
50
32.5k
  if(apdu.sw1 == 0x9C && apdu.sw2 == 0x12) {
51
30
    return 0;
52
30
  }
53
32.5k
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
54
32.5k
  if (r)
55
2.25k
    return r;
56
30.2k
  if(apdu.resplen == 0) /* No more left */
57
222
    return 0;
58
30.0k
  if (apdu.resplen != 14) {
59
15
    sc_log(card->ctx, "expected 14 bytes, got %zu.\n", apdu.resplen);
60
15
    return SC_ERROR_UNKNOWN_DATA_RECEIVED;
61
15
  }
62
30.0k
  memcpy(file->objectId.id, fileData, 4);
63
30.0k
  file->size = bebytes2ulong(fileData + 4);
64
30.0k
  file->read = bebytes2ushort(fileData + 8);
65
30.0k
  file->write = bebytes2ushort(fileData + 10);
66
30.0k
  file->delete = bebytes2ushort(fileData + 12);
67
68
30.0k
  return 1;
69
30.0k
}
70
71
int msc_partial_read_object(sc_card_t *card, msc_id objectId, int offset, u8 *data, size_t dataLength)
72
244
{
73
244
  u8 buffer[9];
74
244
  sc_apdu_t apdu;
75
244
  int r;
76
77
244
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x56, 0x00, 0x00);
78
79
244
  sc_log(card->ctx, "READ: Offset: %x\tLength: %zu\n", offset, dataLength);
80
244
  memcpy(buffer, objectId.id, 4);
81
244
  ulong2bebytes(buffer + 4, offset);
82
244
  buffer[8] = (u8)dataLength;
83
244
  apdu.data = buffer;
84
244
  apdu.datalen = 9;
85
244
  apdu.lc = 9;
86
244
  apdu.le = dataLength;
87
244
  apdu.resplen = dataLength;
88
244
  apdu.resp = data;
89
244
  r = sc_transmit_apdu(card, &apdu);
90
244
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
91
241
  if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00 && dataLength <= apdu.resplen)
92
201
    return (int)dataLength;
93
40
  if (apdu.sw1 == 0x9C) {
94
3
    if (apdu.sw2 == 0x07) {
95
1
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_FILE_NOT_FOUND);
96
2
    } else if (apdu.sw2 == 0x06) {
97
1
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_ALLOWED);
98
1
    } else if (apdu.sw2 == 0x0F) {
99
      /* GUESSED */
100
1
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
101
1
    }
102
3
  }
103
37
  sc_log(card->ctx,
104
37
    "got strange SWs: 0x%02X 0x%02X\n", apdu.sw1, apdu.sw2);
105
37
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED);
106
37
}
107
108
int msc_read_object(sc_card_t *card, msc_id objectId, int offset, u8 *data, size_t dataLength)
109
244
{
110
244
  int r = 0;
111
244
  unsigned int i;
112
244
  size_t max_read_unit = MSC_MAX_READ;
113
114
445
  for (i = 0; i < dataLength; i += r) {
115
244
    r = msc_partial_read_object(card, objectId, offset + i, data + i, MIN(dataLength - i, max_read_unit));
116
244
    LOG_TEST_RET(card->ctx, r, "Error in partial object read");
117
201
    if (r == 0)
118
0
      break;
119
201
  }
120
201
  return (int)dataLength;
121
244
}
122
123
int msc_zero_object(sc_card_t *card, msc_id objectId, size_t dataLength)
124
0
{
125
0
  u8 zeroBuffer[MSC_MAX_APDU];
126
0
  size_t i;
127
0
  size_t max_write_unit = MIN(MSC_MAX_APDU, MSC_MAX_SEND - 9); /* - 9 for object ID+length */
128
129
0
  memset(zeroBuffer, 0, max_write_unit);
130
0
  for(i = 0; i < dataLength; i += max_write_unit) {
131
0
    int r = msc_partial_update_object(card, objectId, i, zeroBuffer, MIN(dataLength - i, max_write_unit));
132
0
    LOG_TEST_RET(card->ctx, r, "Error in zeroing file update");
133
0
  }
134
0
  return 0;
135
0
}
136
137
int msc_create_object(sc_card_t *card, msc_id objectId, size_t objectSize, unsigned short readAcl, unsigned short writeAcl, unsigned short deleteAcl)
138
0
{
139
0
  u8 buffer[14];
140
0
  sc_apdu_t apdu;
141
0
  int r;
142
143
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x5A, 0x00, 0x00);
144
0
  apdu.lc = 14;
145
0
  apdu.data = buffer,
146
0
  apdu.datalen = 14;
147
148
0
  memcpy(buffer, objectId.id, 4);
149
0
  ulong2bebytes(buffer + 4, objectSize);
150
0
  ushort2bebytes(buffer + 8, readAcl);
151
0
  ushort2bebytes(buffer + 10, writeAcl);
152
0
  ushort2bebytes(buffer + 12, deleteAcl);
153
0
  r = sc_transmit_apdu(card, &apdu);
154
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
155
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
156
0
    return (int)objectSize;
157
0
  if(apdu.sw1 == 0x9C) {
158
0
    if(apdu.sw2 == 0x01) {
159
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_MEMORY_FAILURE);
160
0
    } else if(apdu.sw2 == 0x08) {
161
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_FILE_ALREADY_EXISTS);
162
0
    } else if(apdu.sw2 == 0x06) {
163
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_ALLOWED);
164
0
    }
165
0
  }
166
0
  if (card->ctx->debug >= 2) {
167
0
    sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
168
0
         apdu.sw1, apdu.sw2);
169
0
  }
170
0
  msc_zero_object(card, objectId, objectSize);
171
0
  return (int)objectSize;
172
0
}
173
174
/* Update up to MSC_MAX_READ - 9 bytes */
175
int msc_partial_update_object(sc_card_t *card, msc_id objectId, size_t offset, const u8 *data, size_t dataLength)
176
0
{
177
0
  u8 buffer[MSC_MAX_APDU];
178
0
  sc_apdu_t apdu;
179
0
  int r;
180
181
0
  if (dataLength + 9 > MSC_MAX_APDU)
182
0
    return SC_ERROR_INVALID_ARGUMENTS;
183
184
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x54, 0x00, 0x00);
185
0
  apdu.lc = dataLength + 9;
186
0
  if (card->ctx->debug >= 2)
187
0
    sc_log(card->ctx, "WRITE: Offset: %zx\tLength: %zu\n", offset, dataLength);
188
189
0
  memcpy(buffer, objectId.id, 4);
190
0
  ulong2bebytes(buffer + 4, offset);
191
0
  buffer[8] = (u8)dataLength;
192
0
  memcpy(buffer + 9, data, dataLength);
193
0
  apdu.data = buffer;
194
0
  apdu.datalen = apdu.lc;
195
0
  r = sc_transmit_apdu(card, &apdu);
196
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
197
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
198
0
    return (int)dataLength;
199
0
  if(apdu.sw1 == 0x9C) {
200
0
    if(apdu.sw2 == 0x07) {
201
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_FILE_NOT_FOUND);
202
0
    } else if(apdu.sw2 == 0x06) {
203
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_ALLOWED);
204
0
    } else if(apdu.sw2 == 0x0F) {
205
      /* GUESSED */
206
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
207
0
    }
208
0
  }
209
0
  if (card->ctx->debug >= 2) {
210
0
    sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
211
0
         apdu.sw1, apdu.sw2);
212
0
  }
213
0
  return (int)dataLength;
214
0
}
215
216
int msc_update_object(sc_card_t *card, msc_id objectId, int offset, const u8 *data, size_t dataLength)
217
0
{
218
0
  int r;
219
0
  size_t i;
220
0
  size_t max_write_unit = MSC_MAX_SEND - 9;
221
0
  for(i = 0; i < dataLength; i += max_write_unit) {
222
0
    r = msc_partial_update_object(card, objectId, offset + i, data + i, MIN(dataLength - i, max_write_unit));
223
0
    LOG_TEST_RET(card->ctx, r, "Error in partial object update");
224
0
  }
225
0
  return (int)dataLength;
226
0
}
227
228
int msc_delete_object(sc_card_t *card, msc_id objectId, int zero)
229
0
{
230
0
  sc_apdu_t apdu;
231
0
  int r;
232
233
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x52, 0x00, zero ? 0x01 : 0x00);
234
0
  apdu.lc = 4;
235
0
  apdu.data = objectId.id;
236
0
  apdu.datalen = 4;
237
0
  r = sc_transmit_apdu(card, &apdu);
238
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
239
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
240
0
    return 0;
241
0
  if(apdu.sw1 == 0x9C) {
242
0
    if(apdu.sw2 == 0x07) {
243
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_FILE_NOT_FOUND);
244
0
    } else if(apdu.sw2 == 0x06) {
245
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_ALLOWED);
246
0
    }
247
0
  }
248
0
  if (card->ctx->debug >= 2) {
249
0
    sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
250
0
         apdu.sw1, apdu.sw2);
251
0
  }
252
0
  return 0;
253
0
}
254
255
int msc_select_applet(sc_card_t *card, u8 *appletId, size_t appletIdLength)
256
7.03k
{
257
7.03k
  sc_apdu_t apdu;
258
7.03k
  int r;
259
260
7.03k
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 4, 0);
261
7.03k
  apdu.lc = appletIdLength;
262
7.03k
  apdu.data = appletId;
263
7.03k
  apdu.datalen = appletIdLength;
264
7.03k
  apdu.resplen = 0;
265
7.03k
  apdu.le = 0;
266
267
7.03k
  r = sc_transmit_apdu(card, &apdu);
268
7.03k
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
269
7.00k
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
270
748
    return 1;
271
272
6.25k
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,  SC_ERROR_CARD_CMD_FAILED);
273
6.25k
}
274
275
/* Truncate the nulls at the end of a PIN, useful in padding is unnecessarily added */
276
0
static void truncatePinNulls(const u8* pin, size_t *pinLength) {
277
0
  for(; *pinLength > 0; (*pinLength)--) {
278
0
    if(pin[*pinLength - 1]) break;
279
0
  }
280
0
}
281
282
int msc_verify_pin(sc_card_t *card, int pinNumber, const u8 *pinValue, int pinLength, int *tries)
283
0
{
284
0
  sc_apdu_t apdu;
285
0
  int r;
286
287
0
  const int bufferLength = MSC_MAX_PIN_LENGTH;
288
0
  u8 buffer[MSC_MAX_PIN_LENGTH];
289
290
0
  if (pinLength > MSC_MAX_PIN_LENGTH)
291
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
292
293
0
  r = msc_verify_pin_apdu(card, &apdu, buffer, bufferLength, pinNumber, pinValue, pinLength);
294
0
  LOG_TEST_RET(card->ctx, r, "APDU verification failed");
295
296
0
  if(tries)
297
0
    *tries = -1;
298
0
  r = sc_transmit_apdu(card, &apdu);
299
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
300
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
301
0
    return 0;
302
0
  } else if(apdu.sw1 == 0x63) { /* Invalid auth */
303
0
    if(tries)
304
0
      *tries = apdu.sw2 & 0x0F;
305
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
306
0
  } else if(apdu.sw1 == 0x9C && apdu.sw2 == 0x02) {
307
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
308
0
  } else if(apdu.sw1 == 0x69 && apdu.sw2 == 0x83) {
309
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_AUTH_METHOD_BLOCKED);
310
0
  }
311
312
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,  SC_ERROR_PIN_CODE_INCORRECT);
313
0
}
314
315
/* USE ISO_VERIFY due to tries return */
316
int msc_verify_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pinValue, size_t pinLength)
317
0
{
318
0
  if (!buffer || bufferLength < (size_t)pinLength || pinLength > MSC_MAX_PIN_LENGTH)
319
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
320
321
0
  truncatePinNulls(pinValue, &pinLength);
322
323
0
  memcpy(buffer, pinValue, pinLength);
324
0
  sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, 0x42, pinNumber, 0);
325
0
  apdu->lc = pinLength;
326
0
  apdu->data = buffer;
327
0
  apdu->datalen = pinLength;
328
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
329
0
}
330
331
int msc_unblock_pin(sc_card_t *card, int pinNumber, const u8 *pukValue, int pukLength, int *tries)
332
0
{
333
0
  sc_apdu_t apdu;
334
0
  int r;
335
0
  const int bufferLength = MSC_MAX_PIN_LENGTH;
336
0
  u8 buffer[MSC_MAX_PIN_LENGTH];
337
338
0
  if (pukLength > MSC_MAX_PIN_LENGTH)
339
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
340
341
0
  r = msc_unblock_pin_apdu(card, &apdu, buffer, bufferLength, pinNumber, pukValue, pukLength);
342
0
  LOG_TEST_RET(card->ctx, r, "APDU unblock failed");
343
344
0
  if(tries)
345
0
    *tries = -1;
346
0
  r = sc_transmit_apdu(card, &apdu);
347
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
348
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
349
0
    return 0;
350
0
  } else if(apdu.sw1 == 0x63) { /* Invalid auth */
351
0
    if(tries)
352
0
      *tries = apdu.sw2 & 0x0F;
353
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
354
0
  } else if(apdu.sw1 == 0x9C && apdu.sw2 == 0x02) {
355
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
356
0
  } else if(apdu.sw1 == 0x69 && apdu.sw2 == 0x83) {
357
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_AUTH_METHOD_BLOCKED);
358
0
  }
359
360
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,  SC_ERROR_PIN_CODE_INCORRECT);
361
0
}
362
363
int msc_unblock_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pukValue, size_t pukLength)
364
0
{
365
0
  if (!buffer || bufferLength < (size_t)pukLength || pukLength > MSC_MAX_PIN_LENGTH)
366
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
367
368
0
  truncatePinNulls(pukValue, &pukLength);
369
370
0
  memcpy(buffer, pukValue, pukLength);
371
0
  sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, 0x46, pinNumber, 0);
372
0
  apdu->lc = pukLength;
373
0
  apdu->data = buffer;
374
0
  apdu->datalen = pukLength;
375
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
376
0
}
377
378
int msc_change_pin(sc_card_t *card, int pinNumber, const u8 *pinValue, int pinLength, const u8 *newPin, int newPinLength, int *tries)
379
0
{
380
0
  sc_apdu_t apdu;
381
0
  int r;
382
0
  const int bufferLength = (MSC_MAX_PIN_LENGTH + 1) * 2;
383
0
  u8 buffer[(MSC_MAX_PIN_LENGTH + 1) * 2];
384
385
0
  r = msc_change_pin_apdu(card, &apdu, buffer, bufferLength, pinNumber, pinValue, pinLength, newPin, newPinLength);
386
0
  LOG_TEST_RET(card->ctx, r, "APDU change failed");
387
0
  if(tries)
388
0
    *tries = -1;
389
0
  r = sc_transmit_apdu(card, &apdu);
390
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
391
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
392
0
    return 0;
393
0
  } else if(apdu.sw1 == 0x63) { /* Invalid auth */
394
0
    if(tries)
395
0
      *tries = apdu.sw2 & 0x0F;
396
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
397
0
  } else if(apdu.sw1 == 0x9C && apdu.sw2 == 0x02) {
398
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
399
0
  } else if(apdu.sw1 == 0x69 && apdu.sw2 == 0x83) {
400
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_AUTH_METHOD_BLOCKED);
401
0
  }
402
403
0
  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,  SC_ERROR_PIN_CODE_INCORRECT);
404
0
}
405
406
/* USE ISO_VERIFY due to tries return */
407
int msc_change_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pinValue, size_t pinLength, const u8 *newPin, size_t newPinLength)
408
0
{
409
0
  u8 *ptr;
410
0
  if (pinLength > MSC_MAX_PIN_LENGTH || newPinLength > MSC_MAX_PIN_LENGTH
411
0
    || !buffer || bufferLength < pinLength + newPinLength + 2UL)
412
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
413
414
0
  truncatePinNulls(pinValue, &pinLength);
415
0
  truncatePinNulls(newPin, &newPinLength);
416
417
0
  ptr = buffer;
418
419
0
  sc_format_apdu(card, apdu, SC_APDU_CASE_3_SHORT, 0x44, pinNumber, 0);
420
0
  *ptr = pinLength;
421
0
  ptr++;
422
0
  memcpy(ptr, pinValue, pinLength);
423
0
  ptr += pinLength;
424
0
  *ptr = newPinLength;
425
0
  ptr++;
426
0
  memcpy(ptr, newPin, newPinLength);
427
0
  apdu->lc = pinLength + newPinLength + 2;
428
0
  apdu->datalen = apdu->lc;
429
0
  apdu->data = buffer;
430
0
  LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
431
0
}
432
433
int msc_get_challenge(sc_card_t *card, unsigned short dataLength, unsigned short seedLength, u8 *seedData, u8 *outputData)
434
36
{
435
36
  sc_apdu_t apdu;
436
36
  int r, location, cse;
437
36
  size_t len;
438
36
  u8 *buffer, *ptr;
439
440
36
  location = (dataLength < MSC_MAX_READ) ? 1 : 2; /* 1 == APDU, 2 == (seed in 0xFFFFFFFE, out in 0xFFFFFFFF) */
441
36
  cse = (location == 1) ? SC_APDU_CASE_4_SHORT : SC_APDU_CASE_3_SHORT;
442
36
  len = seedLength + 4;
443
444
36
  if (seedLength >= MSC_MAX_SEND - 4 || dataLength >= MSC_MAX_READ - 9)/* Output buffer doesn't seem to operate as desired.... nobody can read/delete */
445
36
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
446
447
31
  buffer = malloc(len);
448
31
  if(!buffer) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
449
31
  ptr = buffer;
450
31
  ushort2bebytes(ptr, dataLength);
451
31
  ptr+=2;
452
31
  ushort2bebytes(ptr, seedLength);
453
31
  ptr+=2;
454
31
  if(seedLength > 0) {
455
0
    memcpy(ptr, seedData, seedLength);
456
0
  }
457
31
  sc_format_apdu(card, &apdu, cse, 0x62, 0x00, location);
458
31
  apdu.data = buffer;
459
31
  apdu.datalen = len;
460
31
  apdu.lc = len;
461
462
31
  if(location == 1) {
463
31
    u8* outputBuffer = malloc(dataLength + 2);
464
31
    if(outputBuffer == NULL) {
465
0
      free(buffer);
466
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
467
31
    };
468
31
    apdu.le = dataLength + 2;
469
31
    apdu.resp = outputBuffer;
470
31
    apdu.resplen = dataLength + 2;
471
31
  }
472
31
  r = sc_transmit_apdu(card, &apdu);
473
31
  if(location == 1) {
474
31
    memcpy(outputData, apdu.resp + 2, dataLength);
475
31
    free(apdu.resp);
476
31
  }
477
31
  free(buffer);
478
31
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
479
30
  if(location == 1) {
480
30
    if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
481
1
      return SC_SUCCESS;
482
29
    } else {
483
29
      r = sc_check_sw(card, apdu.sw1, apdu.sw2);
484
29
      if (r) {
485
29
        if (card->ctx->debug >= 2) {
486
0
          sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
487
0
               apdu.sw1, apdu.sw2);
488
0
        }
489
29
        LOG_FUNC_RETURN(card->ctx, r);
490
29
      }
491
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
492
0
    }
493
30
  } else {
494
0
    if(apdu.sw1 != 0x90 || apdu.sw2 != 0x00) {
495
0
      r = sc_check_sw(card, apdu.sw1, apdu.sw2);
496
0
      if (r) {
497
0
        if (card->ctx->debug >= 2) {
498
0
          sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
499
0
               apdu.sw1, apdu.sw2);
500
0
        }
501
0
        LOG_FUNC_RETURN(card->ctx, r);
502
0
      }
503
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
504
0
    }
505
0
    r = msc_read_object(card, inputId, 2, outputData, dataLength);
506
0
    if(r < 0)
507
0
      LOG_FUNC_RETURN(card->ctx, r);
508
0
    msc_delete_object(card, inputId,0);
509
0
    LOG_FUNC_RETURN(card->ctx, r);
510
0
  }
511
30
}
512
513
int msc_generate_keypair(sc_card_t *card, int privateKey, int publicKey, int algorithm, size_t keySize, int options)
514
0
{
515
0
  sc_apdu_t apdu;
516
0
  u8 buffer[16]; /* Key pair payload length */
517
0
  u8 *ptr = buffer;
518
0
  int r;
519
0
  unsigned short prRead = 0xFFFF, prWrite = 0x0002, prCompute = 0x0002,
520
0
    puRead = 0x0000, puWrite = 0x0002, puCompute = 0x0000;
521
522
0
  if (privateKey > 0x0F || publicKey > 0x0F)
523
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
524
525
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x30, privateKey, publicKey);
526
527
0
  *ptr = algorithm; ptr++;
528
529
0
  ushort2bebytes(ptr, keySize);
530
0
  ptr+=2;
531
532
0
  ushort2bebytes(ptr, prRead);
533
0
  ptr+=2;
534
0
  ushort2bebytes(ptr, prWrite);
535
0
  ptr+=2;
536
0
  ushort2bebytes(ptr, prCompute);
537
0
  ptr+=2;
538
539
0
  ushort2bebytes(ptr, puRead);
540
0
  ptr+=2;
541
0
  ushort2bebytes(ptr, puWrite);
542
0
  ptr+=2;
543
0
  ushort2bebytes(ptr, puCompute);
544
0
  ptr+=2;
545
546
0
  *ptr = 0; /* options; -- no options for now, they need extra data */
547
548
0
  apdu.data = buffer;
549
0
  apdu.datalen = 16;
550
0
  apdu.lc = 16;
551
552
0
  r = sc_transmit_apdu(card, &apdu);
553
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
554
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
555
0
    return 0;
556
0
  }
557
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
558
0
  if (r) {
559
0
    if (card->ctx->debug >= 2) {
560
0
      sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
561
0
           apdu.sw1, apdu.sw2);
562
0
    }
563
0
    LOG_FUNC_RETURN(card->ctx, r);
564
0
  }
565
0
  LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
566
0
}
567
568
int msc_extract_key(sc_card_t *card,
569
      int keyLocation)
570
0
{
571
0
  sc_apdu_t apdu;
572
0
  u8 encoding = 0;
573
0
  int r;
574
575
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x34, keyLocation, 0x00);
576
0
  apdu.data = &encoding;
577
0
  apdu.datalen = 1;
578
0
  apdu.lc = 1;
579
0
  r = sc_transmit_apdu(card, &apdu);
580
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
581
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
582
0
    return 0;
583
0
  }
584
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
585
0
  if (r) {
586
0
    if (card->ctx->debug >= 2) {
587
0
      sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
588
0
           apdu.sw1, apdu.sw2);
589
0
    }
590
0
    LOG_FUNC_RETURN(card->ctx, r);
591
0
  }
592
0
  LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
593
0
}
594
595
int msc_extract_rsa_public_key(sc_card_t *card,
596
      int keyLocation,
597
      size_t* modLength,
598
      u8** modulus,
599
      size_t* expLength,
600
      u8** exponent)
601
0
{
602
0
  int r;
603
0
  u8 buffer[1024]; /* Should be plenty... */
604
0
  int fileLocation = 1;
605
606
0
  r = msc_extract_key(card, keyLocation);
607
0
  if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
608
609
  /* Read keyType, keySize, and what should be the modulus size */
610
0
  r = msc_read_object(card, inputId, fileLocation, buffer, 5);
611
0
  fileLocation += 5;
612
0
  if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
613
614
0
  if(buffer[0] != MSC_RSA_PUBLIC) LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
615
0
  *modLength = (buffer[3] << 8) | buffer[4];
616
  /* Read the modulus and the exponent length */
617
618
0
  if (*modLength + 2 > sizeof buffer)
619
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
620
0
  r = msc_read_object(card, inputId, fileLocation, buffer, *modLength + 2);
621
0
  fileLocation += *modLength + 2;
622
0
  if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
623
624
0
  *modulus = malloc(*modLength);
625
0
  if(!*modulus) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
626
0
  memcpy(*modulus, buffer, *modLength);
627
0
  *expLength = (buffer[*modLength] << 8) | buffer[*modLength + 1];
628
0
  if (*expLength > sizeof buffer) {
629
0
    free(*modulus); *modulus = NULL;
630
0
    return SC_ERROR_OUT_OF_MEMORY;
631
0
  }
632
0
  r = msc_read_object(card, inputId, fileLocation, buffer, *expLength);
633
0
  if(r < 0) {
634
0
    free(*modulus); *modulus = NULL;
635
0
    LOG_FUNC_RETURN(card->ctx, r);
636
0
  }
637
0
  *exponent = malloc(*expLength);
638
0
  if(!*exponent) {
639
0
    free(*modulus);
640
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
641
0
  }
642
0
  memcpy(*exponent, buffer, *expLength);
643
0
  return 0;
644
0
}
645
646
647
648
/* For the moment, only support streaming data to the card
649
  in blocks, not through file IO */
650
int msc_compute_crypt_init(sc_card_t *card,
651
      int keyLocation,
652
      int cipherMode,
653
      int cipherDirection,
654
      const u8* initData,
655
      u8* outputData,
656
      size_t dataLength,
657
      size_t* outputDataLength)
658
0
{
659
0
  sc_apdu_t apdu;
660
0
  u8 buffer[MSC_MAX_APDU];
661
0
  u8 *ptr;
662
0
  int r;
663
664
0
  u8 outputBuffer[MSC_MAX_APDU + 2];
665
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x36, keyLocation, 0x01); /* Init */
666
0
  apdu.data = buffer;
667
0
  apdu.datalen = dataLength + 5;
668
0
  apdu.lc = dataLength + 5;
669
670
0
  memset(outputBuffer, 0, sizeof(outputBuffer));
671
0
  apdu.resp = outputBuffer;
672
0
  apdu.resplen = dataLength + 2;
673
0
  apdu.le = dataLength + 2;
674
0
  ptr = buffer;
675
0
  *ptr = cipherMode; ptr++;
676
0
  *ptr = cipherDirection; ptr++;
677
0
  *ptr = 0x01; ptr++; /* DATA LOCATION: APDU */
678
0
  *ptr = (dataLength >> 8) & 0xFF; ptr++;
679
0
  *ptr = dataLength & 0xFF; ptr++;
680
0
  memcpy(ptr, initData, dataLength);
681
682
0
  r = sc_transmit_apdu(card, &apdu);
683
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
684
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
685
0
    size_t receivedData = outputBuffer[0] << 8 | outputBuffer[1];
686
0
    if (receivedData > MSC_MAX_APDU)
687
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
688
0
    if (receivedData > *outputDataLength) {
689
0
      *outputDataLength = receivedData;
690
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL);
691
0
    }
692
0
    *outputDataLength = receivedData;
693
694
0
    memcpy(outputData, outputBuffer + 2, receivedData);
695
0
    return 0;
696
0
  }
697
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
698
0
  if (r) {
699
0
    if (card->ctx->debug >= 2) {
700
0
      sc_log(card->ctx,  "init: got strange SWs: 0x%02X 0x%02X\n",
701
0
           apdu.sw1, apdu.sw2);
702
0
    }
703
0
    LOG_FUNC_RETURN(card->ctx, r);
704
0
  }
705
0
  LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
706
0
}
707
708
int msc_compute_crypt_final(
709
      sc_card_t *card,
710
      int keyLocation,
711
      const u8* inputData,
712
      u8* outputData,
713
      size_t dataLength,
714
      size_t* outputDataLength)
715
0
{
716
0
  sc_apdu_t apdu;
717
0
  u8 buffer[MSC_MAX_APDU];
718
0
  u8 outputBuffer[MSC_MAX_APDU + 2];
719
0
  u8 *ptr;
720
0
  int r;
721
722
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x36, keyLocation, 0x03); /* Final */
723
724
0
  apdu.data = buffer;
725
0
  apdu.datalen = dataLength + 3;
726
0
  apdu.lc = dataLength + 3;
727
728
0
  memset(outputBuffer, 0, sizeof(outputBuffer));
729
0
  apdu.resp = outputBuffer;
730
0
  apdu.resplen = dataLength + 2;
731
0
  apdu.le = dataLength +2;
732
0
  ptr = buffer;
733
0
  *ptr = 0x01; ptr++; /* DATA LOCATION: APDU */
734
0
  *ptr = (dataLength >> 8) & 0xFF; ptr++;
735
0
  *ptr = dataLength & 0xFF; ptr++;
736
0
  memcpy(ptr, inputData, dataLength);
737
738
0
  r = sc_transmit_apdu(card, &apdu);
739
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
740
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
741
0
    size_t receivedData = outputBuffer[0] << 8 | outputBuffer[1];
742
0
    if (receivedData > MSC_MAX_APDU)
743
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
744
0
    if (receivedData > *outputDataLength) {
745
0
      *outputDataLength = receivedData;
746
0
      LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL);
747
0
    }
748
0
    *outputDataLength = receivedData;
749
750
0
    memcpy(outputData, outputBuffer + 2, receivedData);
751
0
    return 0;
752
0
  }
753
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
754
0
  if (r) {
755
0
    if (card->ctx->debug >= 2) {
756
0
      sc_log(card->ctx,  "final: got strange SWs: 0x%02X 0x%02X\n",
757
0
           apdu.sw1, apdu.sw2);
758
0
    }
759
0
    LOG_FUNC_RETURN(card->ctx, r);
760
0
  }
761
0
  LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
762
0
}
763
764
/* Stream data to the card through file IO */
765
static int msc_compute_crypt_final_object(
766
      sc_card_t *card,
767
      int keyLocation,
768
      const u8* inputData,
769
      u8* outputData,
770
      size_t dataLength,
771
      size_t* outputDataLength)
772
0
{
773
0
  sc_apdu_t apdu;
774
0
  u8 buffer[MSC_MAX_APDU];
775
0
  u8 *ptr;
776
0
  int r;
777
778
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x36, keyLocation, 0x03); /* Final */
779
780
0
  apdu.data = buffer;
781
0
  apdu.datalen = 1;
782
0
  apdu.lc = 1;
783
784
0
  ptr = buffer;
785
0
  *ptr = 0x02;
786
0
  ptr++; /* DATA LOCATION: OBJECT */
787
0
  *ptr = (dataLength >> 8) & 0xFF;
788
0
  ptr++;
789
0
  *ptr = dataLength & 0xFF;
790
0
  ptr++;
791
0
  memcpy(ptr, inputData, dataLength);
792
793
0
  r = msc_create_object(card, outputId, dataLength + 2, 0x02, 0x02, 0x02);
794
0
  if(r < 0) {
795
0
    if(r == SC_ERROR_FILE_ALREADY_EXISTS) {
796
0
      r = msc_delete_object(card, outputId, 0);
797
0
      if(r < 0) {
798
0
        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
799
0
      }
800
0
      r = msc_create_object(card, outputId, dataLength + 2, 0x02, 0x02, 0x02);
801
0
      if(r < 0) {
802
0
        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
803
0
      }
804
0
    }
805
0
  }
806
807
0
  r = msc_update_object(card, outputId, 0, buffer + 1, dataLength + 2);
808
0
  if(r < 0) return r;
809
810
0
  r = sc_transmit_apdu(card, &apdu);
811
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
812
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
813
0
    r = msc_read_object(card, inputId, 2, outputData, dataLength);
814
0
    if (r >= 0)
815
0
      *outputDataLength = r;
816
0
    msc_delete_object(card, outputId, 0);
817
0
    msc_delete_object(card, inputId, 0);
818
0
    return r;
819
0
  }
820
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
821
0
  if (r) {
822
0
    if (card->ctx->debug >= 2) {
823
0
      sc_log(card->ctx,  "final: got strange SWs: 0x%02X 0x%02X\n",
824
0
           apdu.sw1, apdu.sw2);
825
0
    }
826
0
  } else {
827
0
    r = SC_ERROR_CARD_CMD_FAILED;
828
0
  }
829
  /* this is last ditch cleanup */
830
0
  msc_delete_object(card, outputId, 0);
831
832
0
  LOG_FUNC_RETURN(card->ctx, r);
833
0
}
834
835
int msc_compute_crypt(sc_card_t *card,
836
      int keyLocation,
837
      int cipherMode,
838
      int cipherDirection,
839
      const u8* data,
840
      u8* outputData,
841
      size_t dataLength,
842
      size_t outputDataLength)
843
0
{
844
0
  size_t left = dataLength, outLeft = outputDataLength;
845
0
  const u8* inPtr = data;
846
0
  u8* outPtr = outputData;
847
0
  int toSend;
848
0
  int r;
849
850
0
  size_t received = outputDataLength;
851
852
0
  if (outputDataLength < dataLength)
853
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
854
855
  /* Don't send data during init... apparently current version does not support it */
856
0
  toSend = 0;
857
0
  r = msc_compute_crypt_init(card,
858
0
    keyLocation,
859
0
    cipherMode,
860
0
    cipherDirection,
861
0
    inPtr,
862
0
    outPtr,
863
0
    toSend,
864
0
    &received);
865
0
  if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
866
0
  left -= toSend;
867
0
  inPtr += toSend;
868
0
  outLeft -= received;
869
0
  outPtr += received;
870
871
0
  toSend = MIN((int)left, MSC_MAX_APDU - 5);
872
  /* If the card supports extended APDUs, or the data fits in
873
           one normal APDU, use it for the data exchange */
874
0
  if (left < (MSC_MAX_SEND - 4) || (card->caps & SC_CARD_CAP_APDU_EXT) != 0) {
875
0
    r = msc_compute_crypt_final(card,
876
0
      keyLocation,
877
0
      inPtr,
878
0
      outPtr,
879
0
      toSend,
880
0
      &outLeft);
881
0
    if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
882
0
  } else { /* Data is too big: use objects */
883
0
    r = msc_compute_crypt_final_object(card,
884
0
      keyLocation,
885
0
      inPtr,
886
0
      outPtr,
887
0
      toSend,
888
0
      &outLeft);
889
0
    if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
890
0
  }
891
0
  outPtr += outLeft;
892
893
0
  return (int)(outPtr - outputData); /* Amt received */
894
0
}
895
896
/* USED IN KEY ITEM WRITING */
897
#define CPYVAL(valName) \
898
0
  ushort2bebytes(p, data->valName ## Length); p+= 2; \
899
0
  memcpy(p, data->valName ## Value, data->valName ## Length); p+= data->valName ## Length
900
901
int msc_import_key(sc_card_t *card,
902
  int keyLocation,
903
  sc_cardctl_muscle_key_info_t *data)
904
0
{
905
0
  unsigned short readAcl = 0xFFFF,
906
0
    writeAcl = 0x0002,
907
0
    use = 0x0002,
908
0
    keySize = data->keySize;
909
0
  size_t bufferSize = 0;
910
0
  u8 *buffer, *p;
911
0
  u8 apduBuffer[6];
912
0
  sc_apdu_t apdu;
913
0
  int r;
914
915
0
  if (data->keyType != 0x02 && data->keyType != 0x03)
916
0
    LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
917
918
0
  if(data->keyType == 0x02) {
919
0
    if( (data->pLength == 0 || !data->pValue)
920
0
    || (data->modLength == 0 || !data->modValue))
921
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
922
0
  } else if(data->keyType == 0x03) {
923
0
    if( (data->pLength == 0 || !data->pValue)
924
0
    || (data->qLength == 0 || !data->qValue)
925
0
    || (data->pqLength == 0 || !data->pqValue)
926
0
    || (data->dp1Length == 0 || !data->dp1Value)
927
0
    || (data->dq1Length == 0 || !data->dq1Value))
928
0
      SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
929
0
  } else {
930
0
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
931
0
  }
932
933
0
  if(data->keyType == 0x02) {
934
0
    bufferSize = 4 + 4 + data->pLength + data->modLength;
935
0
  } else if(data->keyType == 0x03) {
936
0
    bufferSize = 4 + 10
937
0
      + data->pLength + data->qLength + data->pqLength
938
0
      + data->dp1Length + data->dq1Length;
939
0
  }
940
0
  buffer = malloc(bufferSize);
941
0
  if(!buffer) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
942
0
  p = buffer;
943
0
  *p = 0x00; p++; /* Encoding plain */
944
0
  *p = data->keyType; p++; /* RSA_PRIVATE */
945
0
  ushort2bebytes(p, keySize); p+=2; /* key size */
946
947
0
  if(data->keyType == 0x02) {
948
0
    CPYVAL(mod);
949
0
    CPYVAL(p);
950
0
  } else if(data->keyType == 0x03) {
951
0
    CPYVAL(p);
952
0
    CPYVAL(q);
953
0
    CPYVAL(pq);
954
0
    CPYVAL(dp1);
955
0
    CPYVAL(dq1);
956
0
  }
957
958
0
  r = msc_create_object(card, outputId, bufferSize, 0x02, 0x02, 0x02);
959
0
  if(r < 0) {
960
0
    if(r == SC_ERROR_FILE_ALREADY_EXISTS) {
961
0
      r = msc_delete_object(card, outputId, 0);
962
0
      if(r < 0) {
963
0
        free(buffer);
964
0
        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
965
0
      }
966
0
      r = msc_create_object(card, outputId, bufferSize, 0x02, 0x02, 0x02);
967
0
      if(r < 0) {
968
0
        free(buffer);
969
0
        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
970
0
      }
971
0
    }
972
0
  }
973
974
0
  r = msc_update_object(card, outputId, 0, buffer, bufferSize);
975
0
  free(buffer);
976
0
  if(r < 0) return r;
977
978
979
0
  sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x32, keyLocation, 0x00);
980
0
  apdu.lc = 6;
981
0
  apdu.data = apduBuffer;
982
0
  apdu.datalen = 6;
983
0
  p = apduBuffer;
984
0
  ushort2bebytes(p, readAcl); p+=2;
985
0
  ushort2bebytes(p, writeAcl); p+=2;
986
0
  ushort2bebytes(p, use);
987
0
  r = sc_transmit_apdu(card, &apdu);
988
0
  LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
989
0
  if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
990
0
    msc_delete_object(card, outputId, 0);
991
0
    return 0;
992
0
  }
993
0
  r = sc_check_sw(card, apdu.sw1, apdu.sw2);
994
0
  if (r) {
995
0
    if (card->ctx->debug >= 2) {
996
0
      sc_log(card->ctx,  "keyimport: got strange SWs: 0x%02X 0x%02X\n",
997
0
           apdu.sw1, apdu.sw2);
998
0
    }
999
    /* this is last ditch cleanup */
1000
0
    msc_delete_object(card, outputId, 0);
1001
0
    LOG_FUNC_RETURN(card->ctx, r);
1002
0
  }
1003
  /* this is last ditch cleanup */
1004
0
  msc_delete_object(card, outputId, 0);
1005
1006
0
  LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
1007
0
}
1008
#undef CPYVAL