"Fossies" - the Fresh Open Source Software Archive

Member "opensc-0.22.0/src/libopensc/muscle.c" (10 Aug 2021, 28413 Bytes) of package /linux/privat/opensc-0.22.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "muscle.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.20.0_vs_0.21.0.

    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 
   21 #if 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 #define MSC_RSA_PUBLIC      0x01
   31 #define MSC_RSA_PRIVATE     0x02
   32 #define MSC_RSA_PRIVATE_CRT 0x03
   33 #define MSC_DSA_PUBLIC      0x04
   34 #define MSC_DSA_PRIVATE     0x05
   35 
   36 static msc_id inputId = { { 0xFF, 0xFF, 0xFF, 0xFF } };
   37 static msc_id outputId = { { 0xFF, 0xFF, 0xFF, 0xFE } };
   38 
   39 int msc_list_objects(sc_card_t* card, u8 next, mscfs_file_t* file) {
   40     sc_apdu_t apdu;
   41     u8 fileData[14];
   42     int r;
   43 
   44     sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x58, next, 0x00);
   45     apdu.le = 14;
   46     apdu.resplen = 14;
   47     apdu.resp = fileData;
   48     r = sc_transmit_apdu(card, &apdu);
   49     if (r)
   50         return r;
   51     
   52     if(apdu.sw1 == 0x9C && apdu.sw2 == 0x12) {
   53         return 0;
   54     }
   55     r = sc_check_sw(card, apdu.sw1, apdu.sw2);
   56     if (r)
   57         return r;
   58     if(apdu.resplen == 0) /* No more left */
   59         return 0;
   60     if (apdu.resplen != 14) {
   61         sc_log(card->ctx, 
   62              "expected 14 bytes, got %"SC_FORMAT_LEN_SIZE_T"u.\n",
   63              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 
   75 int 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     sc_log(card->ctx, 
   84         "READ: Offset: %x\tLength: %"SC_FORMAT_LEN_SIZE_T"u\n", offset,
   85          dataLength);
   86     memcpy(buffer, objectId.id, 4);
   87     ulong2bebytes(buffer + 4, offset);
   88     buffer[8] = (u8)dataLength;
   89     apdu.data = buffer;
   90     apdu.datalen = 9;
   91     apdu.lc = 9;
   92     apdu.le = dataLength;
   93     apdu.resplen = dataLength;
   94     apdu.resp = data; 
   95     r = sc_transmit_apdu(card, &apdu);
   96     LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
   97     if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
   98         return dataLength;
   99     if(apdu.sw1 == 0x9C) {
  100         if(apdu.sw2 == 0x07) {
  101             SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_FILE_NOT_FOUND);
  102         } else if(apdu.sw2 == 0x06) {
  103             SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_ALLOWED);
  104         } else if(apdu.sw2 == 0x0F) {
  105             /* GUESSED */
  106             SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
  107         }
  108     }
  109     sc_log(card->ctx, 
  110         "got strange SWs: 0x%02X 0x%02X\n", apdu.sw1, apdu.sw2);
  111     return dataLength;
  112     
  113 }
  114 
  115 int msc_read_object(sc_card_t *card, msc_id objectId, int offset, u8 *data, size_t dataLength)
  116 {
  117     int r;
  118     size_t i;
  119     size_t max_read_unit = MSC_MAX_READ;
  120 
  121     for(i = 0; i < dataLength; i += max_read_unit) {
  122         r = msc_partial_read_object(card, objectId, offset + i, data + i, MIN(dataLength - i, max_read_unit));
  123         LOG_TEST_RET(card->ctx, r, "Error in partial object read");
  124     }
  125     return dataLength;
  126 }
  127 
  128 int msc_zero_object(sc_card_t *card, msc_id objectId, size_t dataLength)
  129 {
  130     u8 zeroBuffer[MSC_MAX_APDU];
  131     size_t i;
  132     size_t max_write_unit = MSC_MAX_SEND - 9; /* - 9 for object ID+length */
  133 
  134     memset(zeroBuffer, 0, max_write_unit);
  135     for(i = 0; i < dataLength; i += max_write_unit) {
  136         int r = msc_partial_update_object(card, objectId, i, zeroBuffer, MIN(dataLength - i, max_write_unit));
  137         LOG_TEST_RET(card->ctx, r, "Error in zeroing file update");
  138     }
  139     return 0;
  140 }
  141 
  142 int msc_create_object(sc_card_t *card, msc_id objectId, size_t objectSize, unsigned short readAcl, unsigned short writeAcl, unsigned short deleteAcl)
  143 {
  144     u8 buffer[14];
  145     sc_apdu_t apdu;
  146     int r;
  147 
  148     sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x5A, 0x00, 0x00);
  149     apdu.lc = 14;
  150     apdu.data = buffer,
  151     apdu.datalen = 14;
  152     
  153     memcpy(buffer, objectId.id, 4);
  154     ulong2bebytes(buffer + 4, objectSize);
  155     ushort2bebytes(buffer + 8, readAcl);
  156     ushort2bebytes(buffer + 10, writeAcl);
  157     ushort2bebytes(buffer + 12, deleteAcl);
  158     r = sc_transmit_apdu(card, &apdu);
  159     LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
  160     if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
  161         return objectSize;
  162     if(apdu.sw1 == 0x9C) {
  163         if(apdu.sw2 == 0x01) {
  164             SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_MEMORY_FAILURE);
  165         } else if(apdu.sw2 == 0x08) {
  166             SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_FILE_ALREADY_EXISTS);
  167         } else if(apdu.sw2 == 0x06) {
  168             SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_ALLOWED);
  169         }
  170     }
  171     if (card->ctx->debug >= 2) {
  172         sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
  173              apdu.sw1, apdu.sw2);
  174     }
  175     msc_zero_object(card, objectId, objectSize);
  176     return objectSize;
  177 }
  178 
  179 /* Update up to MSC_MAX_READ - 9 bytes */
  180 int msc_partial_update_object(sc_card_t *card, msc_id objectId, int offset, const u8 *data, size_t dataLength)
  181 {
  182     u8 buffer[MSC_MAX_APDU];
  183     sc_apdu_t apdu;
  184     int r;
  185 
  186     sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x54, 0x00, 0x00);
  187     apdu.lc = dataLength + 9;
  188     if (card->ctx->debug >= 2)
  189         sc_log(card->ctx, 
  190              "WRITE: Offset: %x\tLength: %"SC_FORMAT_LEN_SIZE_T"u\n",
  191              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     LOG_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, SC_LOG_DEBUG_VERBOSE, SC_ERROR_FILE_NOT_FOUND);
  206         } else if(apdu.sw2 == 0x06) {
  207             SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_ALLOWED);
  208         } else if(apdu.sw2 == 0x0F) {
  209             /* GUESSED */
  210             SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
  211         }
  212     }
  213     if (card->ctx->debug >= 2) {
  214         sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
  215              apdu.sw1, apdu.sw2);
  216     }
  217     return dataLength;
  218 }
  219 
  220 int 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         LOG_TEST_RET(card->ctx, r, "Error in partial object update");
  228     }
  229     return dataLength;
  230 }
  231 
  232 int 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     LOG_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, SC_LOG_DEBUG_VERBOSE, SC_ERROR_FILE_NOT_FOUND);
  248         } else if(apdu.sw2 == 0x06) {
  249             SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_ALLOWED);
  250         }
  251     }
  252     if (card->ctx->debug >= 2) {
  253         sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
  254              apdu.sw1, apdu.sw2);
  255     }
  256     return 0;
  257 }
  258 
  259 int 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     LOG_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, SC_LOG_DEBUG_VERBOSE,  SC_ERROR_CARD_CMD_FAILED);
  277 }
  278 
  279 /* Truncate the nulls at the end of a PIN, useful in padding is unnecessarily added */
  280 static void truncatePinNulls(const u8* pin, int *pinLength) {
  281     for(; *pinLength > 0; (*pinLength)--) {
  282         if(pin[*pinLength - 1]) break;
  283     }
  284 }
  285 
  286 int 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     LOG_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         LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
  306     } else if(apdu.sw1 == 0x9C && apdu.sw2 == 0x02) {
  307         LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
  308     } else if(apdu.sw1 == 0x69 && apdu.sw2 == 0x83) {
  309         LOG_FUNC_RETURN(card->ctx, SC_ERROR_AUTH_METHOD_BLOCKED);
  310     }
  311     
  312     SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,  SC_ERROR_PIN_CODE_INCORRECT);
  313 }
  314 
  315 /* USE ISO_VERIFY due to tries return */
  316 void 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 
  331 int 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     LOG_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         LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
  351     } else if(apdu.sw1 == 0x9C && apdu.sw2 == 0x02) {
  352         LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
  353     } else if(apdu.sw1 == 0x69 && apdu.sw2 == 0x83) {
  354         LOG_FUNC_RETURN(card->ctx, SC_ERROR_AUTH_METHOD_BLOCKED);
  355     }
  356     
  357     SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,  SC_ERROR_PIN_CODE_INCORRECT);
  358 }
  359 
  360 void 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 
  375 int 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     LOG_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         LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
  393     } else if(apdu.sw1 == 0x9C && apdu.sw2 == 0x02) {
  394         LOG_FUNC_RETURN(card->ctx, SC_ERROR_PIN_CODE_INCORRECT);
  395     } else if(apdu.sw1 == 0x69 && apdu.sw2 == 0x83) {
  396         LOG_FUNC_RETURN(card->ctx, SC_ERROR_AUTH_METHOD_BLOCKED);
  397     }
  398     
  399     SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,  SC_ERROR_PIN_CODE_INCORRECT);
  400 }
  401 
  402 /* USE ISO_VERIFY due to tries return */
  403 void 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     apdu->lc = pinLength + newPinLength + 2;
  425     apdu->datalen = apdu->lc;
  426     apdu->data = buffer;
  427 }
  428 
  429 int msc_get_challenge(sc_card_t *card, unsigned short dataLength, unsigned short seedLength, u8 *seedData, u8 *outputData)
  430 {
  431     sc_apdu_t apdu;
  432     int r, location, cse;
  433     size_t 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) LOG_FUNC_RETURN(card->ctx, 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, 0x62, 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) LOG_FUNC_RETURN(card->ctx, 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     LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
  472     if(location == 1) {
  473         if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
  474             return SC_SUCCESS;
  475         } else {
  476             r = sc_check_sw(card, apdu.sw1, apdu.sw2);
  477             if (r) {
  478                 if (card->ctx->debug >= 2) {
  479                     sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
  480                          apdu.sw1, apdu.sw2);
  481                 }
  482                 LOG_FUNC_RETURN(card->ctx, r);
  483             }
  484             LOG_FUNC_RETURN(card->ctx, 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_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
  492                          apdu.sw1, apdu.sw2);
  493                 }
  494                 LOG_FUNC_RETURN(card->ctx, r);
  495             }
  496             LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
  497         }
  498         r = msc_read_object(card, inputId, 2, outputData, dataLength);
  499         if(r < 0)
  500             LOG_FUNC_RETURN(card->ctx, r);
  501         msc_delete_object(card, inputId,0);
  502         LOG_FUNC_RETURN(card->ctx, r);
  503     }
  504 }
  505 
  506 int msc_generate_keypair(sc_card_t *card, int privateKey, int publicKey, int algorithm, int keySize, int options)
  507 {
  508     sc_apdu_t apdu;
  509     u8 buffer[16]; /* Key pair payload length */
  510     u8 *ptr = buffer;
  511     int r;
  512     unsigned short prRead = 0xFFFF, prWrite = 0x0002, prCompute = 0x0002,
  513         puRead = 0x0000, puWrite = 0x0002, puCompute = 0x0000;
  514 
  515     assert(privateKey <= 0x0F && publicKey <= 0x0F);
  516     
  517     sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x30, privateKey, publicKey);
  518 
  519     *ptr = algorithm; ptr++;
  520     
  521     ushort2bebytes(ptr, keySize);
  522     ptr+=2;
  523     
  524     ushort2bebytes(ptr, prRead);
  525     ptr+=2;
  526     ushort2bebytes(ptr, prWrite);
  527     ptr+=2;
  528     ushort2bebytes(ptr, prCompute);
  529     ptr+=2;
  530     
  531     ushort2bebytes(ptr, puRead);
  532     ptr+=2;
  533     ushort2bebytes(ptr, puWrite);
  534     ptr+=2;
  535     ushort2bebytes(ptr, puCompute);
  536     ptr+=2;
  537     
  538     *ptr = 0; /* options; -- no options for now, they need extra data */
  539     
  540     apdu.data = buffer;
  541     apdu.datalen = 16;
  542     apdu.lc = 16;
  543     
  544     r = sc_transmit_apdu(card, &apdu);
  545     LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
  546     if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
  547         return 0;
  548     }
  549     r = sc_check_sw(card, apdu.sw1, apdu.sw2);
  550     if (r) {
  551         if (card->ctx->debug >= 2) {
  552             sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
  553                  apdu.sw1, apdu.sw2);
  554         }
  555         LOG_FUNC_RETURN(card->ctx, r);
  556     }
  557     LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
  558 }
  559 
  560 int msc_extract_key(sc_card_t *card, 
  561             int keyLocation)
  562 {
  563     sc_apdu_t apdu;
  564     u8 encoding = 0;
  565     int r;
  566 
  567     sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x34, keyLocation, 0x00);
  568     apdu.data = &encoding;
  569     apdu.datalen = 1;
  570     apdu.lc = 1;
  571     r = sc_transmit_apdu(card, &apdu);
  572     LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
  573     if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
  574         return 0;
  575     }
  576     r = sc_check_sw(card, apdu.sw1, apdu.sw2);
  577     if (r) {
  578         if (card->ctx->debug >= 2) {
  579             sc_log(card->ctx,  "got strange SWs: 0x%02X 0x%02X\n",
  580                  apdu.sw1, apdu.sw2);
  581         }
  582         LOG_FUNC_RETURN(card->ctx, r);
  583     }
  584     LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
  585 }
  586 
  587 int msc_extract_rsa_public_key(sc_card_t *card, 
  588             int keyLocation,
  589             size_t* modLength, 
  590             u8** modulus,
  591             size_t* expLength,
  592             u8** exponent)
  593 {
  594     int r;
  595     u8 buffer[1024]; /* Should be plenty... */
  596     int fileLocation = 1;
  597 
  598     r = msc_extract_key(card, keyLocation);
  599     if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
  600     
  601     /* Read keyType, keySize, and what should be the modulus size */
  602     r = msc_read_object(card, inputId, fileLocation, buffer, 5);
  603     fileLocation += 5;
  604     if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
  605     
  606     if(buffer[0] != MSC_RSA_PUBLIC) LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
  607     *modLength = (buffer[3] << 8) | buffer[4];
  608     /* Read the modulus and the exponent length */
  609 
  610     if (*modLength + 2 > sizeof buffer)
  611         LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
  612     r = msc_read_object(card, inputId, fileLocation, buffer, *modLength + 2);
  613     fileLocation += *modLength + 2;
  614     if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
  615     
  616     *modulus = malloc(*modLength);
  617     if(!*modulus) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
  618     memcpy(*modulus, buffer, *modLength);
  619     *expLength = (buffer[*modLength] << 8) | buffer[*modLength + 1];
  620     if (*expLength > sizeof buffer)
  621         return SC_ERROR_OUT_OF_MEMORY;
  622     r = msc_read_object(card, inputId, fileLocation, buffer, *expLength);
  623     if(r < 0) {
  624         free(*modulus); *modulus = NULL;
  625         LOG_FUNC_RETURN(card->ctx, r);
  626     }
  627     *exponent = malloc(*expLength);
  628     if(!*exponent) {
  629         free(*modulus);
  630         LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
  631     }
  632     memcpy(*exponent, buffer, *expLength);
  633     return 0;
  634 }
  635 
  636 
  637 
  638 /* For the moment, only support streaming data to the card 
  639     in blocks, not through file IO */
  640 int msc_compute_crypt_init(sc_card_t *card, 
  641             int keyLocation,
  642             int cipherMode,
  643             int cipherDirection,
  644             const u8* initData,
  645             u8* outputData,
  646             size_t dataLength,
  647             size_t* outputDataLength)
  648 {
  649     sc_apdu_t apdu;
  650     u8 buffer[MSC_MAX_APDU];
  651     u8 *ptr;
  652     int r;
  653 
  654     u8 outputBuffer[MSC_MAX_APDU + 2];
  655     sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x36, keyLocation, 0x01); /* Init */
  656     apdu.data = buffer;
  657     apdu.datalen = dataLength + 5;
  658     apdu.lc = dataLength + 5;
  659 
  660     memset(outputBuffer, 0, sizeof(outputBuffer));
  661     apdu.resp = outputBuffer;
  662     apdu.resplen = dataLength + 2;
  663     apdu.le = dataLength + 2;
  664     ptr = buffer;
  665     *ptr = cipherMode; ptr++;
  666     *ptr = cipherDirection; ptr++;
  667     *ptr = 0x01; ptr++; /* DATA LOCATION: APDU */
  668     *ptr = (dataLength >> 8) & 0xFF; ptr++;
  669     *ptr = dataLength & 0xFF; ptr++;
  670     memcpy(ptr, initData, dataLength);
  671 
  672     r = sc_transmit_apdu(card, &apdu);
  673     LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
  674     if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
  675         short receivedData = outputBuffer[0] << 8 | outputBuffer[1];
  676         *outputDataLength = receivedData;
  677 
  678         assert(receivedData <= MSC_MAX_APDU);
  679         memcpy(outputData, outputBuffer + 2, receivedData);
  680         return 0;
  681     }
  682     r = sc_check_sw(card, apdu.sw1, apdu.sw2);
  683     if (r) {
  684         if (card->ctx->debug >= 2) {
  685             sc_log(card->ctx,  "init: got strange SWs: 0x%02X 0x%02X\n",
  686                  apdu.sw1, apdu.sw2);
  687         }
  688         LOG_FUNC_RETURN(card->ctx, r);
  689     }
  690     LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
  691 }
  692 
  693 int msc_compute_crypt_final(
  694             sc_card_t *card, 
  695             int keyLocation,
  696             const u8* inputData,
  697             u8* outputData,
  698             size_t dataLength,
  699             size_t* outputDataLength)
  700 {
  701     sc_apdu_t apdu;
  702     u8 buffer[MSC_MAX_APDU];
  703     u8 outputBuffer[MSC_MAX_APDU + 2];
  704     u8 *ptr;
  705     int r;
  706 
  707     sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x36, keyLocation, 0x03); /* Final */
  708     
  709     apdu.data = buffer;
  710     apdu.datalen = dataLength + 3;
  711     apdu.lc = dataLength + 3;
  712     
  713     memset(outputBuffer, 0, sizeof(outputBuffer));
  714     apdu.resp = outputBuffer;
  715     apdu.resplen = dataLength + 2;
  716     apdu.le = dataLength +2;
  717     ptr = buffer;
  718     *ptr = 0x01; ptr++; /* DATA LOCATION: APDU */
  719     *ptr = (dataLength >> 8) & 0xFF; ptr++;
  720     *ptr = dataLength & 0xFF; ptr++;
  721     memcpy(ptr, inputData, dataLength);
  722     
  723     r = sc_transmit_apdu(card, &apdu);
  724     LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
  725     if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
  726         short receivedData = outputBuffer[0] << 8 | outputBuffer[1];
  727         *outputDataLength = receivedData;
  728         assert(receivedData <= MSC_MAX_APDU);
  729         memcpy(outputData, outputBuffer + 2, receivedData);
  730         return 0;
  731     }
  732     r = sc_check_sw(card, apdu.sw1, apdu.sw2);
  733     if (r) {
  734         if (card->ctx->debug >= 2) {
  735             sc_log(card->ctx,  "final: got strange SWs: 0x%02X 0x%02X\n",
  736                  apdu.sw1, apdu.sw2);
  737         }
  738         LOG_FUNC_RETURN(card->ctx, r);
  739     }
  740     LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
  741 }
  742 
  743 /* Stream data to the card through file IO */
  744 static int msc_compute_crypt_final_object(
  745             sc_card_t *card, 
  746             int keyLocation,
  747             const u8* inputData,
  748             u8* outputData,
  749             size_t dataLength,
  750             size_t* outputDataLength)
  751 {
  752     sc_apdu_t apdu;
  753     u8 buffer[MSC_MAX_APDU];
  754     u8 *ptr;
  755     int r;
  756 
  757     sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x36, keyLocation, 0x03); /* Final */
  758     
  759     apdu.data = buffer;
  760     apdu.datalen = 1;
  761     apdu.lc = 1;
  762     
  763     ptr = buffer;
  764     *ptr = 0x02;
  765     ptr++; /* DATA LOCATION: OBJECT */
  766     *ptr = (dataLength >> 8) & 0xFF;
  767     ptr++;
  768     *ptr = dataLength & 0xFF;
  769     ptr++;
  770     memcpy(ptr, inputData, dataLength);
  771 
  772     r = msc_create_object(card, outputId, dataLength + 2, 0x02, 0x02, 0x02);
  773     if(r < 0) { 
  774         if(r == SC_ERROR_FILE_ALREADY_EXISTS) {
  775             r = msc_delete_object(card, outputId, 0);
  776             if(r < 0) {
  777                 SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
  778             }
  779             r = msc_create_object(card, outputId, dataLength + 2, 0x02, 0x02, 0x02);
  780             if(r < 0) {
  781                 SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
  782             }
  783         }
  784     }
  785 
  786     r = msc_update_object(card, outputId, 0, buffer + 1, dataLength + 2);
  787     if(r < 0) return r; 
  788     
  789     r = sc_transmit_apdu(card, &apdu);
  790     LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
  791     if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
  792         r = msc_read_object(card, inputId, 2, outputData, dataLength);
  793         if (r >= 0)
  794             *outputDataLength = r;
  795         msc_delete_object(card, outputId, 0);
  796         msc_delete_object(card, inputId, 0);
  797         return r;
  798     }
  799     r = sc_check_sw(card, apdu.sw1, apdu.sw2);
  800     if (r) {
  801         if (card->ctx->debug >= 2) {
  802             sc_log(card->ctx,  "final: got strange SWs: 0x%02X 0x%02X\n",
  803                  apdu.sw1, apdu.sw2);
  804         }
  805     } else {
  806         r = SC_ERROR_CARD_CMD_FAILED;
  807     }
  808     /* this is last ditch cleanup */    
  809     msc_delete_object(card, outputId, 0);
  810     
  811     LOG_FUNC_RETURN(card->ctx, r);
  812 }
  813 
  814 int msc_compute_crypt(sc_card_t *card, 
  815             int keyLocation,
  816             int cipherMode,
  817             int cipherDirection,
  818             const u8* data,
  819             u8* outputData,
  820             size_t dataLength,
  821             size_t outputDataLength)
  822 {
  823     size_t left = dataLength;
  824     const u8* inPtr = data;
  825     u8* outPtr = outputData;
  826     int toSend;
  827     int r;
  828 
  829     size_t received = 0;
  830     assert(outputDataLength >= dataLength);
  831     
  832     /* Don't send data during init... apparently current version does not support it */
  833     toSend = 0;
  834     r = msc_compute_crypt_init(card, 
  835         keyLocation, 
  836         cipherMode, 
  837         cipherDirection, 
  838         inPtr, 
  839         outPtr, 
  840         toSend,
  841         &received);
  842     if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
  843     left -= toSend;
  844     inPtr += toSend;
  845     outPtr += received;
  846 
  847     toSend = MIN(left, MSC_MAX_APDU - 5);
  848     /* If the card supports extended APDUs, or the data fits in
  849            one normal APDU, use it for the data exchange */
  850     if (left < (MSC_MAX_SEND - 4) || (card->caps & SC_CARD_CAP_APDU_EXT) != 0) {
  851         r = msc_compute_crypt_final(card,
  852             keyLocation,
  853             inPtr,
  854             outPtr,
  855             toSend,
  856             &received);
  857         if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
  858     } else { /* Data is too big: use objects */
  859         r = msc_compute_crypt_final_object(card,
  860             keyLocation,
  861             inPtr,
  862             outPtr,
  863             toSend,
  864             &received);
  865         if(r < 0) LOG_FUNC_RETURN(card->ctx, r);
  866     }   
  867     outPtr += received;
  868 
  869     return outPtr - outputData; /* Amt received */
  870 }
  871 
  872 /* USED IN KEY ITEM WRITING */
  873 #define CPYVAL(valName) \
  874     ushort2bebytes(p, data->valName ## Length); p+= 2; \
  875     memcpy(p, data->valName ## Value, data->valName ## Length); p+= data->valName ## Length
  876 
  877 int msc_import_key(sc_card_t *card,
  878     int keyLocation,
  879     sc_cardctl_muscle_key_info_t *data)
  880 {
  881     unsigned short readAcl = 0xFFFF,
  882         writeAcl = 0x0002,
  883         use = 0x0002,
  884         keySize = data->keySize;
  885     int bufferSize = 0;
  886     u8 *buffer, *p;
  887     u8 apduBuffer[6];
  888     sc_apdu_t apdu;
  889     int r;
  890 
  891     assert(data->keyType == 0x02 || data->keyType == 0x03);
  892     if(data->keyType == 0x02) {
  893         if( (data->pLength == 0 || !data->pValue)
  894         || (data->modLength == 0 || !data->modValue))
  895             SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); 
  896     } else if(data->keyType == 0x03) {
  897         if( (data->pLength == 0 || !data->pValue)
  898         || (data->qLength == 0 || !data->qValue)
  899         || (data->pqLength == 0 || !data->pqValue)
  900         || (data->dp1Length == 0 || !data->dp1Value)
  901         || (data->dq1Length == 0 || !data->dq1Value))
  902             SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS); 
  903     } else {
  904         SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
  905     }
  906     
  907     if(data->keyType == 0x02) {
  908         bufferSize = 4 + 4 + data->pLength + data->modLength;
  909     } else if(data->keyType == 0x03) {
  910         bufferSize = 4 + 10
  911             + data->pLength + data->qLength + data->pqLength
  912             + data->dp1Length + data->dq1Length;
  913     }
  914     buffer = malloc(bufferSize);
  915     if(!buffer) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
  916     p = buffer;
  917     *p = 0x00; p++; /* Encoding plain */
  918     *p = data->keyType; p++; /* RSA_PRIVATE */
  919     ushort2bebytes(p, keySize); p+=2; /* key size */
  920     
  921     if(data->keyType == 0x02) {
  922         CPYVAL(mod);
  923         CPYVAL(p);
  924     } else if(data->keyType == 0x03) {
  925         CPYVAL(p);
  926         CPYVAL(q);
  927         CPYVAL(pq);
  928         CPYVAL(dp1);
  929         CPYVAL(dq1);
  930     }
  931     
  932     r = msc_create_object(card, outputId, bufferSize, 0x02, 0x02, 0x02);
  933     if(r < 0) { 
  934         if(r == SC_ERROR_FILE_ALREADY_EXISTS) {
  935             r = msc_delete_object(card, outputId, 0);
  936             if(r < 0) {
  937                 free(buffer);
  938                 SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
  939             }
  940             r = msc_create_object(card, outputId, bufferSize, 0x02, 0x02, 0x02);
  941             if(r < 0) {
  942                 free(buffer);
  943                 SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
  944             }
  945         }
  946     }
  947     
  948     r = msc_update_object(card, outputId, 0, buffer, bufferSize);
  949     free(buffer);
  950     if(r < 0) return r;
  951     
  952     
  953     sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x32, keyLocation, 0x00);
  954     apdu.lc = 6;
  955     apdu.data = apduBuffer;
  956     apdu.datalen = 6;
  957     p = apduBuffer;
  958     ushort2bebytes(p, readAcl); p+=2;
  959     ushort2bebytes(p, writeAcl); p+=2;
  960     ushort2bebytes(p, use); 
  961     r = sc_transmit_apdu(card, &apdu);
  962     LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
  963     if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
  964         msc_delete_object(card, outputId, 0);
  965         return 0;
  966     }
  967     r = sc_check_sw(card, apdu.sw1, apdu.sw2);
  968     if (r) {
  969         if (card->ctx->debug >= 2) {
  970             sc_log(card->ctx,  "keyimport: got strange SWs: 0x%02X 0x%02X\n",
  971                  apdu.sw1, apdu.sw2);
  972         }
  973         /* this is last ditch cleanup */
  974         msc_delete_object(card, outputId, 0);
  975         LOG_FUNC_RETURN(card->ctx, r);
  976     }
  977     /* this is last ditch cleanup */
  978     msc_delete_object(card, outputId, 0);
  979 
  980     LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
  981 }
  982 #undef CPYVAL