root/trunk/src/libopensc/muscle.c

Revision 3510, 28.0 KB (checked in by ludovic.rousseau, 7 months ago)

Use size_t instead of int when needed, plus some other minor changes

Patch bug.1 included in Ticket #176

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