LCOV - code coverage report
Current view: top level - scd - iso7816.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 322 0.0 %
Date: 2016-09-12 12:29:17 Functions: 0 27 0.0 %

          Line data    Source code
       1             : /* iso7816.c - ISO 7816 commands
       2             :  * Copyright (C) 2003, 2004, 2008, 2009 Free Software Foundation, Inc.
       3             :  *
       4             :  * This file is part of GnuPG.
       5             :  *
       6             :  * GnuPG is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * GnuPG 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
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include <config.h>
      21             : #include <errno.h>
      22             : #include <stdio.h>
      23             : #include <stdlib.h>
      24             : #include <string.h>
      25             : 
      26             : #if defined(GNUPG_SCD_MAIN_HEADER)
      27             : #include GNUPG_SCD_MAIN_HEADER
      28             : #elif GNUPG_MAJOR_VERSION == 1
      29             : /* This is used with GnuPG version < 1.9.  The code has been source
      30             :    copied from the current GnuPG >= 1.9  and is maintained over
      31             :    there. */
      32             : #include "options.h"
      33             : #include "errors.h"
      34             : #include "memory.h"
      35             : #include "util.h"
      36             : #include "i18n.h"
      37             : #else /* GNUPG_MAJOR_VERSION != 1 */
      38             : #include "scdaemon.h"
      39             : #endif /* GNUPG_MAJOR_VERSION != 1 */
      40             : 
      41             : #include "iso7816.h"
      42             : #include "apdu.h"
      43             : 
      44             : 
      45             : #define CMD_SELECT_FILE 0xA4
      46             : #define CMD_VERIFY                ISO7816_VERIFY
      47             : #define CMD_CHANGE_REFERENCE_DATA ISO7816_CHANGE_REFERENCE_DATA
      48             : #define CMD_RESET_RETRY_COUNTER   ISO7816_RESET_RETRY_COUNTER
      49             : #define CMD_GET_DATA    0xCA
      50             : #define CMD_PUT_DATA    0xDA
      51             : #define CMD_MSE         0x22
      52             : #define CMD_PSO         0x2A
      53             : #define CMD_INTERNAL_AUTHENTICATE 0x88
      54             : #define CMD_GENERATE_KEYPAIR      0x47
      55             : #define CMD_GET_CHALLENGE         0x84
      56             : #define CMD_READ_BINARY 0xB0
      57             : #define CMD_READ_RECORD 0xB2
      58             : 
      59             : static gpg_error_t
      60           0 : map_sw (int sw)
      61             : {
      62             :   gpg_err_code_t ec;
      63             : 
      64           0 :   switch (sw)
      65             :     {
      66           0 :     case SW_EEPROM_FAILURE: ec = GPG_ERR_HARDWARE; break;
      67           0 :     case SW_TERM_STATE:     ec = GPG_ERR_OBJ_TERM_STATE; break;
      68           0 :     case SW_WRONG_LENGTH:   ec = GPG_ERR_INV_VALUE; break;
      69           0 :     case SW_SM_NOT_SUP:     ec = GPG_ERR_NOT_SUPPORTED; break;
      70           0 :     case SW_CC_NOT_SUP:     ec = GPG_ERR_NOT_SUPPORTED; break;
      71           0 :     case SW_CHV_WRONG:      ec = GPG_ERR_BAD_PIN; break;
      72           0 :     case SW_CHV_BLOCKED:    ec = GPG_ERR_PIN_BLOCKED; break;
      73           0 :     case SW_USE_CONDITIONS: ec = GPG_ERR_USE_CONDITIONS; break;
      74           0 :     case SW_NOT_SUPPORTED:  ec = GPG_ERR_NOT_SUPPORTED; break;
      75           0 :     case SW_BAD_PARAMETER:  ec = GPG_ERR_INV_VALUE; break;
      76           0 :     case SW_FILE_NOT_FOUND: ec = GPG_ERR_ENOENT; break;
      77           0 :     case SW_RECORD_NOT_FOUND:ec= GPG_ERR_NOT_FOUND; break;
      78           0 :     case SW_REF_NOT_FOUND:  ec = GPG_ERR_NO_OBJ; break;
      79           0 :     case SW_BAD_P0_P1:      ec = GPG_ERR_INV_VALUE; break;
      80           0 :     case SW_EXACT_LENGTH:   ec = GPG_ERR_INV_VALUE; break;
      81           0 :     case SW_INS_NOT_SUP:    ec = GPG_ERR_CARD; break;
      82           0 :     case SW_CLA_NOT_SUP:    ec = GPG_ERR_CARD; break;
      83           0 :     case SW_SUCCESS:        ec = 0; break;
      84             : 
      85           0 :     case SW_HOST_OUT_OF_CORE: ec = GPG_ERR_ENOMEM; break;
      86           0 :     case SW_HOST_INV_VALUE:   ec = GPG_ERR_INV_VALUE; break;
      87           0 :     case SW_HOST_INCOMPLETE_CARD_RESPONSE: ec = GPG_ERR_CARD; break;
      88           0 :     case SW_HOST_NOT_SUPPORTED: ec = GPG_ERR_NOT_SUPPORTED; break;
      89           0 :     case SW_HOST_LOCKING_FAILED: ec = GPG_ERR_BUG; break;
      90           0 :     case SW_HOST_BUSY:           ec = GPG_ERR_EBUSY; break;
      91           0 :     case SW_HOST_NO_CARD:        ec = GPG_ERR_CARD_NOT_PRESENT; break;
      92           0 :     case SW_HOST_CARD_INACTIVE:  ec = GPG_ERR_CARD_RESET; break;
      93           0 :     case SW_HOST_CARD_IO_ERROR:  ec = GPG_ERR_EIO; break;
      94           0 :     case SW_HOST_GENERAL_ERROR:  ec = GPG_ERR_GENERAL; break;
      95           0 :     case SW_HOST_NO_READER:      ec = GPG_ERR_ENODEV; break;
      96           0 :     case SW_HOST_ABORTED:        ec = GPG_ERR_CANCELED; break;
      97           0 :     case SW_HOST_NO_PINPAD:      ec = GPG_ERR_NOT_SUPPORTED; break;
      98             : 
      99             :     default:
     100           0 :       if ((sw & 0x010000))
     101           0 :         ec = GPG_ERR_GENERAL; /* Should not happen. */
     102           0 :       else if ((sw & 0xff00) == SW_MORE_DATA)
     103           0 :         ec = 0; /* This should actually never been seen here. */
     104             :       else
     105           0 :         ec = GPG_ERR_CARD;
     106             :     }
     107           0 :   return gpg_error (ec);
     108             : }
     109             : 
     110             : /* Map a status word from the APDU layer to a gpg-error code.  */
     111             : gpg_error_t
     112           0 : iso7816_map_sw (int sw)
     113             : {
     114             :   /* All APDU functions should return 0x9000 on success but for
     115             :      historical reasons of the implementation some return 0 to
     116             :      indicate success.  We allow for that here. */
     117           0 :   return sw? map_sw (sw) : 0;
     118             : }
     119             : 
     120             : 
     121             : /* This function is specialized version of the SELECT FILE command.
     122             :    SLOT is the card and reader as created for example by
     123             :    apdu_open_reader (), AID is a buffer of size AIDLEN holding the
     124             :    requested application ID.  The function can't be used to enumerate
     125             :    AIDs and won't return the AID on success.  The return value is 0
     126             :    for okay or a GPG error code.  Note that ISO error codes are
     127             :    internally mapped.  Bit 0 of FLAGS should be set if the card does
     128             :    not understand P2=0xC0. */
     129             : gpg_error_t
     130           0 : iso7816_select_application (int slot, const char *aid, size_t aidlen,
     131             :                             unsigned int flags)
     132             : {
     133             :   int sw;
     134           0 :   sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE, 4,
     135           0 :                          (flags&1)? 0 :0x0c, aidlen, aid);
     136           0 :   return map_sw (sw);
     137             : }
     138             : 
     139             : 
     140             : gpg_error_t
     141           0 : iso7816_select_file (int slot, int tag, int is_dir,
     142             :                      unsigned char **result, size_t *resultlen)
     143             : {
     144             :   int sw, p0, p1;
     145             :   unsigned char tagbuf[2];
     146             : 
     147           0 :   tagbuf[0] = (tag >> 8) & 0xff;
     148           0 :   tagbuf[1] = tag & 0xff;
     149             : 
     150           0 :   if (result || resultlen)
     151             :     {
     152           0 :       *result = NULL;
     153           0 :       *resultlen = 0;
     154           0 :       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     155             :     }
     156             :   else
     157             :     {
     158           0 :       p0 = (tag == 0x3F00)? 0: is_dir? 1:2;
     159           0 :       p1 = 0x0c; /* No FC return. */
     160           0 :       sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE,
     161             :                              p0, p1, 2, (char*)tagbuf );
     162           0 :       return map_sw (sw);
     163             :     }
     164             : 
     165             :   return 0;
     166             : }
     167             : 
     168             : 
     169             : /* Do a select file command with a direct path. */
     170             : gpg_error_t
     171           0 : iso7816_select_path (int slot, const unsigned short *path, size_t pathlen,
     172             :                      unsigned char **result, size_t *resultlen)
     173             : {
     174             :   int sw, p0, p1;
     175             :   unsigned char buffer[100];
     176             :   int buflen;
     177             : 
     178           0 :   if (result || resultlen)
     179             :     {
     180           0 :       *result = NULL;
     181           0 :       *resultlen = 0;
     182           0 :       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     183             :     }
     184             : 
     185           0 :   if (pathlen/2 >= sizeof buffer)
     186           0 :     return gpg_error (GPG_ERR_TOO_LARGE);
     187             : 
     188           0 :   for (buflen = 0; pathlen; pathlen--, path++)
     189             :     {
     190           0 :       buffer[buflen++] = (*path >> 8);
     191           0 :       buffer[buflen++] = *path;
     192             :     }
     193             : 
     194           0 :   p0 = 0x08;
     195           0 :   p1 = 0x0c; /* No FC return. */
     196           0 :   sw = apdu_send_simple (slot, 0, 0x00, CMD_SELECT_FILE,
     197             :                          p0, p1, buflen, (char*)buffer );
     198           0 :   return map_sw (sw);
     199             : }
     200             : 
     201             : 
     202             : /* This is a private command currently only working for TCOS cards. */
     203             : gpg_error_t
     204           0 : iso7816_list_directory (int slot, int list_dirs,
     205             :                         unsigned char **result, size_t *resultlen)
     206             : {
     207             :   int sw;
     208             : 
     209           0 :   if (!result || !resultlen)
     210           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     211           0 :   *result = NULL;
     212           0 :   *resultlen = 0;
     213             : 
     214           0 :   sw = apdu_send (slot, 0, 0x80, 0xAA, list_dirs? 1:2, 0, -1, NULL,
     215             :                   result, resultlen);
     216           0 :   if (sw != SW_SUCCESS)
     217             :     {
     218             :       /* Make sure that pending buffers are released. */
     219           0 :       xfree (*result);
     220           0 :       *result = NULL;
     221           0 :       *resultlen = 0;
     222             :     }
     223           0 :   return map_sw (sw);
     224             : }
     225             : 
     226             : 
     227             : /* This funcion sends an already formatted APDU to the card.  With
     228             :    HANDLE_MORE set to true a MORE DATA status will be handled
     229             :    internally.  The return value is a gpg error code (i.e. a mapped
     230             :    status word).  This is basically the same as apdu_send_direct but
     231             :    it maps the status word and does not return it in the result
     232             :    buffer.  */
     233             : gpg_error_t
     234           0 : iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen,
     235             :                      int handle_more,
     236             :                      unsigned char **result, size_t *resultlen)
     237             : {
     238             :   int sw;
     239             : 
     240           0 :   if (!result || !resultlen)
     241           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     242           0 :   *result = NULL;
     243           0 :   *resultlen = 0;
     244             : 
     245           0 :   sw = apdu_send_direct (slot, 0, apdudata, apdudatalen, handle_more,
     246             :                          result, resultlen);
     247           0 :   if (!sw)
     248             :     {
     249           0 :       if (*resultlen < 2)
     250           0 :         sw = SW_HOST_GENERAL_ERROR;
     251             :       else
     252             :         {
     253           0 :           sw = ((*result)[*resultlen-2] << 8) | (*result)[*resultlen-1];
     254           0 :           (*resultlen)--;
     255           0 :           (*resultlen)--;
     256             :         }
     257             :     }
     258           0 :   if (sw != SW_SUCCESS)
     259             :     {
     260             :       /* Make sure that pending buffers are released. */
     261           0 :       xfree (*result);
     262           0 :       *result = NULL;
     263           0 :       *resultlen = 0;
     264             :     }
     265           0 :   return map_sw (sw);
     266             : }
     267             : 
     268             : 
     269             : /* Check whether the reader supports the ISO command code COMMAND on
     270             :    the pinpad.  Returns 0 on success.  */
     271             : gpg_error_t
     272           0 : iso7816_check_pinpad (int slot, int command, pininfo_t *pininfo)
     273             : {
     274             :   int sw;
     275             : 
     276           0 :   sw = apdu_check_pinpad (slot, command, pininfo);
     277           0 :   return iso7816_map_sw (sw);
     278             : }
     279             : 
     280             : 
     281             : /* Perform a VERIFY command on SLOT using the card holder verification
     282             :    vector CHVNO.  With PININFO non-NULL the pinpad of the reader will
     283             :    be used.  Returns 0 on success. */
     284             : gpg_error_t
     285           0 : iso7816_verify_kp (int slot, int chvno, pininfo_t *pininfo)
     286             : {
     287             :   int sw;
     288             : 
     289           0 :   sw = apdu_pinpad_verify (slot, 0x00, CMD_VERIFY, 0, chvno, pininfo);
     290           0 :   return map_sw (sw);
     291             : }
     292             : 
     293             : /* Perform a VERIFY command on SLOT using the card holder verification
     294             :    vector CHVNO with a CHV of length CHVLEN.  Returns 0 on success. */
     295             : gpg_error_t
     296           0 : iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
     297             : {
     298             :   int sw;
     299             : 
     300           0 :   sw = apdu_send_simple (slot, 0, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
     301           0 :   return map_sw (sw);
     302             : }
     303             : 
     304             : /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
     305             :    verification vector CHVNO.  With PININFO non-NULL the pinpad of the
     306             :    reader will be used.  If IS_EXCHANGE is 0, a "change reference
     307             :    data" is done, otherwise an "exchange reference data".  */
     308             : gpg_error_t
     309           0 : iso7816_change_reference_data_kp (int slot, int chvno, int is_exchange,
     310             :                                   pininfo_t *pininfo)
     311             : {
     312             :   int sw;
     313             : 
     314           0 :   sw = apdu_pinpad_modify (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
     315             :                            is_exchange ? 1 : 0, chvno, pininfo);
     316           0 :   return map_sw (sw);
     317             : }
     318             : 
     319             : /* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
     320             :    verification vector CHVNO.  If the OLDCHV is NULL (and OLDCHVLEN
     321             :    0), a "change reference data" is done, otherwise an "exchange
     322             :    reference data".  The new reference data is expected in NEWCHV of
     323             :    length NEWCHVLEN.  */
     324             : gpg_error_t
     325           0 : iso7816_change_reference_data (int slot, int chvno,
     326             :                                const char *oldchv, size_t oldchvlen,
     327             :                                const char *newchv, size_t newchvlen)
     328             : {
     329             :   int sw;
     330             :   char *buf;
     331             : 
     332           0 :   if ((!oldchv && oldchvlen)
     333           0 :       || (oldchv && !oldchvlen)
     334           0 :       || !newchv || !newchvlen )
     335           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     336             : 
     337           0 :   buf = xtrymalloc (oldchvlen + newchvlen);
     338           0 :   if (!buf)
     339           0 :     return gpg_error (gpg_err_code_from_errno (errno));
     340           0 :   if (oldchvlen)
     341           0 :     memcpy (buf, oldchv, oldchvlen);
     342           0 :   memcpy (buf+oldchvlen, newchv, newchvlen);
     343             : 
     344           0 :   sw = apdu_send_simple (slot, 0, 0x00, CMD_CHANGE_REFERENCE_DATA,
     345             :                          oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
     346           0 :   xfree (buf);
     347           0 :   return map_sw (sw);
     348             : 
     349             : }
     350             : 
     351             : 
     352             : gpg_error_t
     353           0 : iso7816_reset_retry_counter_with_rc (int slot, int chvno,
     354             :                                      const char *data, size_t datalen)
     355             : {
     356             :   int sw;
     357             : 
     358           0 :   if (!data || !datalen )
     359           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     360             : 
     361           0 :   sw = apdu_send_simple (slot, 0, 0x00, CMD_RESET_RETRY_COUNTER,
     362             :                          0, chvno, datalen, data);
     363           0 :   return map_sw (sw);
     364             : }
     365             : 
     366             : 
     367             : gpg_error_t
     368           0 : iso7816_reset_retry_counter (int slot, int chvno,
     369             :                              const char *newchv, size_t newchvlen)
     370             : {
     371             :   int sw;
     372             : 
     373           0 :   sw = apdu_send_simple (slot, 0, 0x00, CMD_RESET_RETRY_COUNTER,
     374             :                          2, chvno, newchvlen, newchv);
     375           0 :   return map_sw (sw);
     376             : }
     377             : 
     378             : 
     379             : 
     380             : /* Perform a GET DATA command requesting TAG and storing the result in
     381             :    a newly allocated buffer at the address passed by RESULT.  Return
     382             :    the length of this data at the address of RESULTLEN. */
     383             : gpg_error_t
     384           0 : iso7816_get_data (int slot, int extended_mode, int tag,
     385             :                   unsigned char **result, size_t *resultlen)
     386             : {
     387             :   int sw;
     388             :   int le;
     389             : 
     390           0 :   if (!result || !resultlen)
     391           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     392           0 :   *result = NULL;
     393           0 :   *resultlen = 0;
     394             : 
     395           0 :   if (extended_mode > 0 && extended_mode < 256)
     396           0 :     le = 65534; /* Not 65535 in case it is used as some special flag.  */
     397           0 :   else if (extended_mode > 0)
     398           0 :     le = extended_mode;
     399             :   else
     400           0 :     le = 256;
     401             : 
     402           0 :   sw = apdu_send_le (slot, extended_mode, 0x00, CMD_GET_DATA,
     403           0 :                      ((tag >> 8) & 0xff), (tag & 0xff), -1, NULL, le,
     404             :                      result, resultlen);
     405           0 :   if (sw != SW_SUCCESS)
     406             :     {
     407             :       /* Make sure that pending buffers are released. */
     408           0 :       xfree (*result);
     409           0 :       *result = NULL;
     410           0 :       *resultlen = 0;
     411           0 :       return map_sw (sw);
     412             :     }
     413             : 
     414           0 :   return 0;
     415             : }
     416             : 
     417             : 
     418             : /* Perform a PUT DATA command on card in SLOT.  Write DATA of length
     419             :    DATALEN to TAG.  EXTENDED_MODE controls whether extended length
     420             :    headers or command chaining is used instead of single length
     421             :    bytes. */
     422             : gpg_error_t
     423           0 : iso7816_put_data (int slot, int extended_mode, int tag,
     424             :                   const void *data, size_t datalen)
     425             : {
     426             :   int sw;
     427             : 
     428           0 :   sw = apdu_send_simple (slot, extended_mode, 0x00, CMD_PUT_DATA,
     429           0 :                          ((tag >> 8) & 0xff), (tag & 0xff),
     430             :                          datalen, (const char*)data);
     431           0 :   return map_sw (sw);
     432             : }
     433             : 
     434             : /* Same as iso7816_put_data but uses an odd instruction byte.  */
     435             : gpg_error_t
     436           0 : iso7816_put_data_odd (int slot, int extended_mode, int tag,
     437             :                       const void *data, size_t datalen)
     438             : {
     439             :   int sw;
     440             : 
     441           0 :   sw = apdu_send_simple (slot, extended_mode, 0x00, CMD_PUT_DATA+1,
     442           0 :                          ((tag >> 8) & 0xff), (tag & 0xff),
     443             :                          datalen, (const char*)data);
     444           0 :   return map_sw (sw);
     445             : }
     446             : 
     447             : /* Manage Security Environment.  This is a weird operation and there
     448             :    is no easy abstraction for it.  Furthermore, some card seem to have
     449             :    a different interpreation of 7816-8 and thus we resort to let the
     450             :    caller decide what to do. */
     451             : gpg_error_t
     452           0 : iso7816_manage_security_env (int slot, int p1, int p2,
     453             :                              const unsigned char *data, size_t datalen)
     454             : {
     455             :   int sw;
     456             : 
     457           0 :   if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 )
     458           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     459             : 
     460           0 :   sw = apdu_send_simple (slot, 0, 0x00, CMD_MSE, p1, p2,
     461             :                          data? datalen : -1, (const char*)data);
     462           0 :   return map_sw (sw);
     463             : }
     464             : 
     465             : 
     466             : /* Perform the security operation COMPUTE DIGITAL SIGANTURE.  On
     467             :    success 0 is returned and the data is availavle in a newly
     468             :    allocated buffer stored at RESULT with its length stored at
     469             :    RESULTLEN.  For LE see do_generate_keypair. */
     470             : gpg_error_t
     471           0 : iso7816_compute_ds (int slot, int extended_mode,
     472             :                     const unsigned char *data, size_t datalen, int le,
     473             :                     unsigned char **result, size_t *resultlen)
     474             : {
     475             :   int sw;
     476             : 
     477           0 :   if (!data || !datalen || !result || !resultlen)
     478           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     479           0 :   *result = NULL;
     480           0 :   *resultlen = 0;
     481             : 
     482           0 :   if (!extended_mode)
     483           0 :     le = 256;  /* Ignore provided Le and use what apdu_send uses. */
     484           0 :   else if (le >= 0 && le < 256)
     485           0 :     le = 256;
     486             : 
     487           0 :   sw = apdu_send_le (slot, extended_mode,
     488             :                      0x00, CMD_PSO, 0x9E, 0x9A,
     489             :                      datalen, (const char*)data,
     490             :                      le,
     491             :                      result, resultlen);
     492           0 :   if (sw != SW_SUCCESS)
     493             :     {
     494             :       /* Make sure that pending buffers are released. */
     495           0 :       xfree (*result);
     496           0 :       *result = NULL;
     497           0 :       *resultlen = 0;
     498           0 :       return map_sw (sw);
     499             :     }
     500             : 
     501           0 :   return 0;
     502             : }
     503             : 
     504             : 
     505             : /* Perform the security operation DECIPHER.  PADIND is the padding
     506             :    indicator to be used.  It should be 0 if no padding is required, a
     507             :    value of -1 suppresses the padding byte.  On success 0 is returned
     508             :    and the plaintext is available in a newly allocated buffer stored
     509             :    at RESULT with its length stored at RESULTLEN.  For LE see
     510             :    do_generate_keypair. */
     511             : gpg_error_t
     512           0 : iso7816_decipher (int slot, int extended_mode,
     513             :                   const unsigned char *data, size_t datalen, int le,
     514             :                   int padind, unsigned char **result, size_t *resultlen)
     515             : {
     516             :   int sw;
     517             :   unsigned char *buf;
     518             : 
     519           0 :   if (!data || !datalen || !result || !resultlen)
     520           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     521           0 :   *result = NULL;
     522           0 :   *resultlen = 0;
     523             : 
     524           0 :   if (!extended_mode)
     525           0 :     le = 256;  /* Ignore provided Le and use what apdu_send uses. */
     526           0 :   else if (le >= 0 && le < 256)
     527           0 :     le = 256;
     528             : 
     529           0 :   if (padind >= 0)
     530             :     {
     531             :       /* We need to prepend the padding indicator. */
     532           0 :       buf = xtrymalloc (datalen + 1);
     533           0 :       if (!buf)
     534           0 :         return gpg_error (gpg_err_code_from_errno (errno));
     535             : 
     536           0 :       *buf = padind; /* Padding indicator. */
     537           0 :       memcpy (buf+1, data, datalen);
     538           0 :       sw = apdu_send_le (slot, extended_mode,
     539             :                          0x00, CMD_PSO, 0x80, 0x86,
     540             :                          datalen+1, (char*)buf, le,
     541             :                          result, resultlen);
     542           0 :       xfree (buf);
     543             :     }
     544             :   else
     545             :     {
     546           0 :       sw = apdu_send_le (slot, extended_mode,
     547             :                          0x00, CMD_PSO, 0x80, 0x86,
     548             :                          datalen, (const char *)data, le,
     549             :                          result, resultlen);
     550             :     }
     551           0 :   if (sw != SW_SUCCESS)
     552             :     {
     553             :       /* Make sure that pending buffers are released. */
     554           0 :       xfree (*result);
     555           0 :       *result = NULL;
     556           0 :       *resultlen = 0;
     557           0 :       return map_sw (sw);
     558             :     }
     559             : 
     560           0 :   return 0;
     561             : }
     562             : 
     563             : 
     564             : /*  For LE see do_generate_keypair.  */
     565             : gpg_error_t
     566           0 : iso7816_internal_authenticate (int slot, int extended_mode,
     567             :                                const unsigned char *data, size_t datalen,
     568             :                                int le,
     569             :                                unsigned char **result, size_t *resultlen)
     570             : {
     571             :   int sw;
     572             : 
     573           0 :   if (!data || !datalen || !result || !resultlen)
     574           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     575           0 :   *result = NULL;
     576           0 :   *resultlen = 0;
     577             : 
     578           0 :   if (!extended_mode)
     579           0 :     le = 256;  /* Ignore provided Le and use what apdu_send uses. */
     580           0 :   else if (le >= 0 && le < 256)
     581           0 :     le = 256;
     582             : 
     583           0 :   sw = apdu_send_le (slot, extended_mode,
     584             :                      0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0,
     585             :                      datalen, (const char*)data,
     586             :                      le,
     587             :                      result, resultlen);
     588           0 :   if (sw != SW_SUCCESS)
     589             :     {
     590             :       /* Make sure that pending buffers are released. */
     591           0 :       xfree (*result);
     592           0 :       *result = NULL;
     593           0 :       *resultlen = 0;
     594           0 :       return map_sw (sw);
     595             :     }
     596             : 
     597           0 :   return 0;
     598             : }
     599             : 
     600             : 
     601             : /* LE is the expected return length.  This is usually 0 except if
     602             :    extended length mode is used and more than 256 byte will be
     603             :    returned.  In that case a value of -1 uses a large default
     604             :    (e.g. 4096 bytes), a value larger 256 used that value.  */
     605             : static gpg_error_t
     606           0 : do_generate_keypair (int slot, int extended_mode, int read_only,
     607             :                      const unsigned char *data, size_t datalen,
     608             :                      int le,
     609             :                      unsigned char **result, size_t *resultlen)
     610             : {
     611             :   int sw;
     612             : 
     613           0 :   if (!data || !datalen || !result || !resultlen)
     614           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     615           0 :   *result = NULL;
     616           0 :   *resultlen = 0;
     617             : 
     618           0 :   sw = apdu_send_le (slot, extended_mode,
     619             :                      0x00, CMD_GENERATE_KEYPAIR, read_only? 0x81:0x80, 0,
     620             :                      datalen, (const char*)data,
     621           0 :                      le >= 0 && le < 256? 256:le,
     622             :                      result, resultlen);
     623           0 :   if (sw != SW_SUCCESS)
     624             :     {
     625             :       /* Make sure that pending buffers are released. */
     626           0 :       xfree (*result);
     627           0 :       *result = NULL;
     628           0 :       *resultlen = 0;
     629           0 :       return map_sw (sw);
     630             :     }
     631             : 
     632           0 :   return 0;
     633             : }
     634             : 
     635             : 
     636             : gpg_error_t
     637           0 : iso7816_generate_keypair (int slot, int extended_mode,
     638             :                           const unsigned char *data, size_t datalen,
     639             :                           int le,
     640             :                           unsigned char **result, size_t *resultlen)
     641             : {
     642           0 :   return do_generate_keypair (slot, extended_mode, 0,
     643             :                               data, datalen, le, result, resultlen);
     644             : }
     645             : 
     646             : 
     647             : gpg_error_t
     648           0 : iso7816_read_public_key (int slot, int extended_mode,
     649             :                          const unsigned char *data, size_t datalen,
     650             :                          int le,
     651             :                          unsigned char **result, size_t *resultlen)
     652             : {
     653           0 :   return do_generate_keypair (slot, extended_mode, 1,
     654             :                               data, datalen, le, result, resultlen);
     655             : }
     656             : 
     657             : 
     658             : 
     659             : gpg_error_t
     660           0 : iso7816_get_challenge (int slot, int length, unsigned char *buffer)
     661             : {
     662             :   int sw;
     663             :   unsigned char *result;
     664             :   size_t resultlen, n;
     665             : 
     666           0 :   if (!buffer || length < 1)
     667           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     668             : 
     669             :   do
     670             :     {
     671           0 :       result = NULL;
     672           0 :       n = length > 254? 254 : length;
     673           0 :       sw = apdu_send_le (slot, 0,
     674             :                          0x00, CMD_GET_CHALLENGE, 0, 0, -1, NULL, n,
     675             :                          &result, &resultlen);
     676           0 :       if (sw != SW_SUCCESS)
     677             :         {
     678             :           /* Make sure that pending buffers are released. */
     679           0 :           xfree (result);
     680           0 :           return map_sw (sw);
     681             :         }
     682           0 :       if (resultlen > n)
     683           0 :         resultlen = n;
     684           0 :       memcpy (buffer, result, resultlen);
     685           0 :       buffer += resultlen;
     686           0 :       length -= resultlen;
     687           0 :       xfree (result);
     688             :     }
     689           0 :   while (length > 0);
     690             : 
     691           0 :   return 0;
     692             : }
     693             : 
     694             : /* Perform a READ BINARY command requesting a maximum of NMAX bytes
     695             :    from OFFSET.  With NMAX = 0 the entire file is read. The result is
     696             :    stored in a newly allocated buffer at the address passed by RESULT.
     697             :    Returns the length of this data at the address of RESULTLEN. */
     698             : gpg_error_t
     699           0 : iso7816_read_binary (int slot, size_t offset, size_t nmax,
     700             :                      unsigned char **result, size_t *resultlen)
     701             : {
     702             :   int sw;
     703             :   unsigned char *buffer;
     704             :   size_t bufferlen;
     705           0 :   int read_all = !nmax;
     706             :   size_t n;
     707             : 
     708           0 :   if (!result || !resultlen)
     709           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     710           0 :   *result = NULL;
     711           0 :   *resultlen = 0;
     712             : 
     713             :   /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
     714             :      we check for this limit. */
     715           0 :   if (offset > 32767)
     716           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     717             : 
     718             :   do
     719             :     {
     720           0 :       buffer = NULL;
     721           0 :       bufferlen = 0;
     722           0 :       n = read_all? 0 : nmax;
     723           0 :       sw = apdu_send_le (slot, 0, 0x00, CMD_READ_BINARY,
     724           0 :                          ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
     725             :                          n, &buffer, &bufferlen);
     726           0 :       if ( SW_EXACT_LENGTH_P(sw) )
     727             :         {
     728           0 :           n = (sw & 0x00ff);
     729           0 :           sw = apdu_send_le (slot, 0, 0x00, CMD_READ_BINARY,
     730           0 :                              ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
     731             :                              n, &buffer, &bufferlen);
     732             :         }
     733             : 
     734           0 :       if (*result && sw == SW_BAD_P0_P1)
     735             :         {
     736             :           /* Bad Parameter means that the offset is outside of the
     737             :              EF. When reading all data we take this as an indication
     738             :              for EOF.  */
     739           0 :           break;
     740             :         }
     741             : 
     742           0 :       if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
     743             :         {
     744             :           /* Make sure that pending buffers are released. */
     745           0 :           xfree (buffer);
     746           0 :           xfree (*result);
     747           0 :           *result = NULL;
     748           0 :           *resultlen = 0;
     749           0 :           return map_sw (sw);
     750             :         }
     751           0 :       if (*result) /* Need to extend the buffer. */
     752             :         {
     753           0 :           unsigned char *p = xtryrealloc (*result, *resultlen + bufferlen);
     754           0 :           if (!p)
     755             :             {
     756           0 :               gpg_error_t err = gpg_error_from_syserror ();
     757           0 :               xfree (buffer);
     758           0 :               xfree (*result);
     759           0 :               *result = NULL;
     760           0 :               *resultlen = 0;
     761           0 :               return err;
     762             :             }
     763           0 :           *result = p;
     764           0 :           memcpy (*result + *resultlen, buffer, bufferlen);
     765           0 :           *resultlen += bufferlen;
     766           0 :           xfree (buffer);
     767           0 :           buffer = NULL;
     768             :         }
     769             :       else /* Transfer the buffer into our result. */
     770             :         {
     771           0 :           *result = buffer;
     772           0 :           *resultlen = bufferlen;
     773             :         }
     774           0 :       offset += bufferlen;
     775           0 :       if (offset > 32767)
     776           0 :         break; /* We simply truncate the result for too large
     777             :                   files. */
     778           0 :       if (nmax > bufferlen)
     779           0 :         nmax -= bufferlen;
     780             :       else
     781           0 :         nmax = 0;
     782             :     }
     783           0 :   while ((read_all && sw != SW_EOF_REACHED) || (!read_all && nmax));
     784             : 
     785           0 :   return 0;
     786             : }
     787             : 
     788             : /* Perform a READ RECORD command. RECNO gives the record number to
     789             :    read with 0 indicating the current record.  RECCOUNT must be 1 (not
     790             :    all cards support reading of more than one record).  SHORT_EF
     791             :    should be 0 to read the current EF or contain a short EF. The
     792             :    result is stored in a newly allocated buffer at the address passed
     793             :    by RESULT.  Returns the length of this data at the address of
     794             :    RESULTLEN. */
     795             : gpg_error_t
     796           0 : iso7816_read_record (int slot, int recno, int reccount, int short_ef,
     797             :                      unsigned char **result, size_t *resultlen)
     798             : {
     799             :   int sw;
     800             :   unsigned char *buffer;
     801             :   size_t bufferlen;
     802             : 
     803           0 :   if (!result || !resultlen)
     804           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     805           0 :   *result = NULL;
     806           0 :   *resultlen = 0;
     807             : 
     808             :   /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
     809             :      we check for this limit. */
     810           0 :   if (recno < 0 || recno > 255 || reccount != 1
     811           0 :       || short_ef < 0 || short_ef > 254 )
     812           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     813             : 
     814           0 :   buffer = NULL;
     815           0 :   bufferlen = 0;
     816           0 :   sw = apdu_send_le (slot, 0, 0x00, CMD_READ_RECORD,
     817             :                      recno,
     818             :                      short_ef? short_ef : 0x04,
     819             :                      -1, NULL,
     820             :                      0, &buffer, &bufferlen);
     821             : 
     822           0 :   if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
     823             :     {
     824             :       /* Make sure that pending buffers are released. */
     825           0 :       xfree (buffer);
     826           0 :       xfree (*result);
     827           0 :       *result = NULL;
     828           0 :       *resultlen = 0;
     829           0 :       return map_sw (sw);
     830             :     }
     831           0 :   *result = buffer;
     832           0 :   *resultlen = bufferlen;
     833             : 
     834           0 :   return 0;
     835             : }

Generated by: LCOV version 1.11