LCOV - code coverage report
Current view: top level - scd - app-nks.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 572 0.0 %
Date: 2016-09-12 13:01:59 Functions: 0 20 0.0 %

          Line data    Source code
       1             : /* app-nks.c - The Telesec NKS card application.
       2             :  * Copyright (C) 2004, 2007, 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             : /* Notes:
      21             : 
      22             :   - We are now targeting TCOS 3 cards and it may happen that there is
      23             :     a regression towards TCOS 2 cards.  Please report.
      24             : 
      25             :   - The TKS3 AUT key is not used.  It seems that it is only useful for
      26             :     the internal authentication command and not accessible by other
      27             :     applications.  The key itself is in the encryption class but the
      28             :     corresponding certificate has only the digitalSignature
      29             :     capability.
      30             : 
      31             :   - If required, we automagically switch between the NKS application
      32             :     and the SigG application.  This avoids to use the DINSIG
      33             :     application which is somewhat limited, has no support for Secure
      34             :     Messaging as required by TCOS 3 and has no way to change the PIN
      35             :     or even set the NullPIN.
      36             : 
      37             :   - We use the prefix NKS-DF01 for TCOS 2 cards and NKS-NKS3 for newer
      38             :     cards.  This is because the NKS application has moved to DF02 with
      39             :     TCOS 3 and thus we better use a DF independent tag.
      40             : 
      41             :   - We use only the global PINs for the NKS application.
      42             : 
      43             :  */
      44             : 
      45             : #include <config.h>
      46             : #include <errno.h>
      47             : #include <stdio.h>
      48             : #include <stdlib.h>
      49             : #include <string.h>
      50             : #include <assert.h>
      51             : #include <time.h>
      52             : 
      53             : #include "scdaemon.h"
      54             : #include "i18n.h"
      55             : #include "iso7816.h"
      56             : #include "app-common.h"
      57             : #include "tlv.h"
      58             : #include "apdu.h"
      59             : #include "host2net.h"
      60             : 
      61             : static char const aid_nks[]  = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 };
      62             : static char const aid_sigg[] = { 0xD2, 0x76, 0x00, 0x00, 0x66, 0x01 };
      63             : 
      64             : 
      65             : static struct
      66             : {
      67             :   int is_sigg;   /* Valid for SigG application.  */
      68             :   int fid;       /* File ID. */
      69             :   int nks_ver;   /* 0 for NKS version 2, 3 for version 3. */
      70             :   int certtype;  /* Type of certificate or 0 if it is not a certificate. */
      71             :   int iskeypair; /* If true has the FID of the corresponding certificate. */
      72             :   int issignkey; /* True if file is a key usable for signing. */
      73             :   int isenckey;  /* True if file is a key usable for decryption. */
      74             :   unsigned char kid;  /* Corresponding key references.  */
      75             : } filelist[] = {
      76             :   { 0, 0x4531, 0, 0,  0xC000, 1, 0, 0x80 }, /* EF_PK.NKS.SIG */
      77             :   { 0, 0xC000, 0, 101 },                    /* EF_C.NKS.SIG  */
      78             :   { 0, 0x4331, 0, 100 },
      79             :   { 0, 0x4332, 0, 100 },
      80             :   { 0, 0xB000, 0, 110 },                    /* EF_PK.RCA.NKS */
      81             :   { 0, 0x45B1, 0, 0,  0xC200, 0, 1, 0x81 }, /* EF_PK.NKS.ENC */
      82             :   { 0, 0xC200, 0, 101 },                    /* EF_C.NKS.ENC  */
      83             :   { 0, 0x43B1, 0, 100 },
      84             :   { 0, 0x43B2, 0, 100 },
      85             : /* The authentication key is not used.  */
      86             : /*   { 0, 0x4571, 3, 0,  0xC500, 0, 0, 0x82 }, /\* EF_PK.NKS.AUT *\/ */
      87             : /*   { 0, 0xC500, 3, 101 },                    /\* EF_C.NKS.AUT  *\/ */
      88             :   { 0, 0x45B2, 3, 0,  0xC201, 0, 1, 0x83 }, /* EF_PK.NKS.ENC1024 */
      89             :   { 0, 0xC201, 3, 101 },                    /* EF_C.NKS.ENC1024  */
      90             :   { 1, 0x4531, 3, 0,  0xC000, 1, 1, 0x84 }, /* EF_PK.CH.SIG  */
      91             :   { 1, 0xC000, 0, 101 },                    /* EF_C.CH.SIG  */
      92             :   { 1, 0xC008, 3, 101 },                    /* EF_C.CA.SIG  */
      93             :   { 1, 0xC00E, 3, 111 },                    /* EF_C.RCA.SIG  */
      94             :   { 0, 0 }
      95             : };
      96             : 
      97             : 
      98             : 
      99             : /* Object with application (i.e. NKS) specific data.  */
     100             : struct app_local_s {
     101             :   int nks_version;  /* NKS version.  */
     102             : 
     103             :   int sigg_active;  /* True if switched to the SigG application.  */
     104             :   int sigg_msig_checked;/*  True if we checked for a mass signature card.  */
     105             :   int sigg_is_msig; /* True if this is a mass signature card.  */
     106             : 
     107             :   int need_app_select; /* Need to re-select the application.  */
     108             : 
     109             : };
     110             : 
     111             : 
     112             : 
     113             : static gpg_error_t switch_application (app_t app, int enable_sigg);
     114             : 
     115             : 
     116             : 
     117             : /* Release local data. */
     118             : static void
     119           0 : do_deinit (app_t app)
     120             : {
     121           0 :   if (app && app->app_local)
     122             :     {
     123           0 :       xfree (app->app_local);
     124           0 :       app->app_local = NULL;
     125             :     }
     126           0 : }
     127             : 
     128             : 
     129             : static int
     130           0 : all_zero_p (void *buffer, size_t length)
     131             : {
     132             :   char *p;
     133             : 
     134           0 :   for (p=buffer; length; length--, p++)
     135           0 :     if (*p)
     136           0 :       return 0;
     137           0 :   return 1;
     138             : }
     139             : 
     140             : 
     141             : /* Read the file with FID, assume it contains a public key and return
     142             :    its keygrip in the caller provided 41 byte buffer R_GRIPSTR. */
     143             : static gpg_error_t
     144           0 : keygripstr_from_pk_file (app_t app, int fid, char *r_gripstr)
     145             : {
     146             :   gpg_error_t err;
     147             :   unsigned char grip[20];
     148             :   unsigned char *buffer[2];
     149             :   size_t buflen[2];
     150             :   gcry_sexp_t sexp;
     151             :   int i;
     152           0 :   int offset[2] = { 0, 0 };
     153             : 
     154           0 :   err = iso7816_select_file (app->slot, fid, 0, NULL, NULL);
     155           0 :   if (err)
     156           0 :     return err;
     157           0 :   err = iso7816_read_record (app->slot, 1, 1, 0, &buffer[0], &buflen[0]);
     158           0 :   if (err)
     159           0 :     return err;
     160           0 :   err = iso7816_read_record (app->slot, 2, 1, 0, &buffer[1], &buflen[1]);
     161           0 :   if (err)
     162             :     {
     163           0 :       xfree (buffer[0]);
     164           0 :       return err;
     165             :     }
     166             : 
     167           0 :   if (app->app_local->nks_version < 3)
     168             :     {
     169             :       /* Old versions of NKS store the values in a TLV encoded format.
     170             :          We need to do some checks.  */
     171           0 :       for (i=0; i < 2; i++)
     172             :         {
     173             :           /* Check that the value appears like an integer encoded as
     174             :              Simple-TLV.  We don't check the tag because the tests cards I
     175             :              have use 1 for both, the modulus and the exponent - the
     176             :              example in the documentation gives 2 for the exponent. */
     177           0 :           if (buflen[i] < 3)
     178           0 :             err = gpg_error (GPG_ERR_TOO_SHORT);
     179           0 :           else if (buffer[i][1] != buflen[i]-2 )
     180           0 :             err = gpg_error (GPG_ERR_INV_OBJ);
     181             :           else
     182           0 :             offset[i] = 2;
     183             :         }
     184             :     }
     185             :   else
     186             :     {
     187             :       /* Remove leading zeroes to get a correct keygrip.  Take care of
     188             :          negative numbers.  We should also fix it the same way in
     189             :          libgcrypt but we can't yet rely on it yet.  */
     190           0 :       for (i=0; i < 2; i++)
     191             :         {
     192           0 :           while (buflen[i]-offset[i] > 1
     193           0 :                  && !buffer[i][offset[i]]
     194           0 :                  && !(buffer[i][offset[i]+1] & 0x80))
     195           0 :             offset[i]++;
     196             :         }
     197             :     }
     198             : 
     199             :   /* Check whether negative values are not prefixed with a zero and
     200             :      fix that.  */
     201           0 :   for (i=0; i < 2; i++)
     202             :     {
     203           0 :       if ((buflen[i]-offset[i]) && (buffer[i][offset[i]] & 0x80))
     204             :         {
     205             :           unsigned char *newbuf;
     206             :           size_t newlen;
     207             : 
     208           0 :           newlen = 1 + buflen[i] - offset[i];
     209           0 :           newbuf = xtrymalloc (newlen);
     210           0 :           if (!newlen)
     211             :             {
     212           0 :               xfree (buffer[0]);
     213           0 :               xfree (buffer[1]);
     214           0 :               return gpg_error_from_syserror ();
     215             :             }
     216           0 :           newbuf[0] = 0;
     217           0 :           memcpy (newbuf+1, buffer[i]+offset[i], buflen[i] - offset[i]);
     218           0 :           xfree (buffer[i]);
     219           0 :           buffer[i] = newbuf;
     220           0 :           buflen[i] = newlen;
     221           0 :           offset[i] = 0;
     222             :         }
     223             :     }
     224             : 
     225           0 :   if (!err)
     226           0 :     err = gcry_sexp_build (&sexp, NULL,
     227             :                            "(public-key (rsa (n %b) (e %b)))",
     228           0 :                            (int)buflen[0]-offset[0], buffer[0]+offset[0],
     229           0 :                            (int)buflen[1]-offset[1], buffer[1]+offset[1]);
     230             : 
     231           0 :   xfree (buffer[0]);
     232           0 :   xfree (buffer[1]);
     233           0 :   if (err)
     234           0 :     return err;
     235             : 
     236           0 :   if (!gcry_pk_get_keygrip (sexp, grip))
     237             :     {
     238           0 :       err = gpg_error (GPG_ERR_INTERNAL); /* i.e. RSA not supported by
     239             :                                              libgcrypt. */
     240             :     }
     241             :   else
     242             :     {
     243           0 :       bin2hex (grip, 20, r_gripstr);
     244             :     }
     245           0 :   gcry_sexp_release (sexp);
     246           0 :   return err;
     247             : }
     248             : 
     249             : 
     250             : /* TCOS responds to a verify with empty data (i.e. without the Lc
     251             :    byte) with the status of the PIN.  PWID is the PIN ID, If SIGG is
     252             :    true, the application is switched into SigG mode.
     253             :    Returns:
     254             :             -1 = Error retrieving the data,
     255             :             -2 = No such PIN,
     256             :             -3 = PIN blocked,
     257             :             -4 = NullPIN activ,
     258             :         n >= 0 = Number of verification attempts left.  */
     259             : static int
     260           0 : get_chv_status (app_t app, int sigg, int pwid)
     261             : {
     262           0 :   unsigned char *result = NULL;
     263             :   size_t resultlen;
     264             :   char command[4];
     265             :   int rc;
     266             : 
     267           0 :   if (switch_application (app, sigg))
     268           0 :     return sigg? -2 : -1; /* No such PIN / General error.  */
     269             : 
     270           0 :   command[0] = 0x00;
     271           0 :   command[1] = 0x20;
     272           0 :   command[2] = 0x00;
     273           0 :   command[3] = pwid;
     274             : 
     275           0 :   if (apdu_send_direct (app->slot, 0, (unsigned char *)command,
     276             :                         4, 0, &result, &resultlen))
     277           0 :     rc = -1; /* Error. */
     278           0 :   else if (resultlen < 2)
     279           0 :     rc = -1; /* Error. */
     280             :   else
     281             :     {
     282           0 :       unsigned int sw = buf16_to_uint (result+resultlen-2);
     283             : 
     284           0 :       if (sw == 0x6a88)
     285           0 :         rc = -2; /* No such PIN.  */
     286           0 :       else if (sw == 0x6983)
     287           0 :         rc = -3; /* PIN is blocked.  */
     288           0 :       else if (sw == 0x6985)
     289           0 :         rc = -4; /* NullPIN is activ.  */
     290           0 :       else if ((sw & 0xfff0) == 0x63C0)
     291           0 :         rc = (sw & 0x000f); /* PIN has N tries left.  */
     292             :       else
     293           0 :         rc = -1; /* Other error.  */
     294             :     }
     295           0 :   xfree (result);
     296             : 
     297           0 :   return rc;
     298             : }
     299             : 
     300             : 
     301             : /* Implement the GETATTR command.  This is similar to the LEARN
     302             :    command but returns just one value via the status interface. */
     303             : static gpg_error_t
     304           0 : do_getattr (app_t app, ctrl_t ctrl, const char *name)
     305             : {
     306             :   static struct {
     307             :     const char *name;
     308             :     int special;
     309             :   } table[] = {
     310             :     { "$AUTHKEYID",   1 },
     311             :     { "NKS-VERSION",  2 },
     312             :     { "CHV-STATUS",   3 },
     313             :     { NULL, 0 }
     314             :   };
     315           0 :   gpg_error_t err = 0;
     316             :   int idx;
     317             :   char buffer[100];
     318             : 
     319           0 :   err = switch_application (app, 0);
     320           0 :   if (err)
     321           0 :     return err;
     322             : 
     323           0 :   for (idx=0; table[idx].name && strcmp (table[idx].name, name); idx++)
     324             :     ;
     325           0 :   if (!table[idx].name)
     326           0 :     return gpg_error (GPG_ERR_INV_NAME);
     327             : 
     328           0 :   switch (table[idx].special)
     329             :     {
     330             :     case 1: /* $AUTHKEYID */
     331             :       {
     332             :         /* NetKey 3.0 cards define an authentication key but according
     333             :            to the specs this key is only usable for encryption and not
     334             :            signing.  it might work anyway but it has not yet been
     335             :            tested - fixme.  Thus for now we use the NKS signature key
     336             :            for authentication.  */
     337           0 :         char const tmp[] = "NKS-NKS3.4531";
     338           0 :         send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
     339             :       }
     340           0 :       break;
     341             : 
     342             :     case 2: /* NKS-VERSION */
     343           0 :       snprintf (buffer, sizeof buffer, "%d", app->app_local->nks_version);
     344           0 :       send_status_info (ctrl, table[idx].name,
     345             :                         buffer, strlen (buffer), NULL, 0);
     346           0 :       break;
     347             : 
     348             :     case 3: /* CHV-STATUS */
     349             :       {
     350             :         /* Returns: PW1.CH PW2.CH PW1.CH.SIG PW2.CH.SIG That are the
     351             :            two global passwords followed by the two SigG passwords.
     352             :            For the values, see the function get_chv_status.  */
     353             :         int tmp[4];
     354             : 
     355             :         /* We use a helper array so that we can control that there is
     356             :            no superfluous application switch.  Note that PW2.CH.SIG
     357             :            really has the identifier 0x83 and not 0x82 as one would
     358             :            expect.  */
     359           0 :         tmp[0] = get_chv_status (app, 0, 0x00);
     360           0 :         tmp[1] = get_chv_status (app, 0, 0x01);
     361           0 :         tmp[2] = get_chv_status (app, 1, 0x81);
     362           0 :         tmp[3] = get_chv_status (app, 1, 0x83);
     363           0 :         snprintf (buffer, sizeof buffer,
     364             :                   "%d %d %d %d", tmp[0], tmp[1], tmp[2], tmp[3]);
     365           0 :         send_status_info (ctrl, table[idx].name,
     366             :                           buffer, strlen (buffer), NULL, 0);
     367             :       }
     368           0 :       break;
     369             : 
     370             : 
     371             :     default:
     372           0 :       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     373           0 :       break;
     374             :     }
     375             : 
     376           0 :   return err;
     377             : }
     378             : 
     379             : 
     380             : 
     381             : static void
     382           0 : do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, int is_sigg)
     383             : {
     384             :   gpg_error_t err;
     385             :   char ct_buf[100], id_buf[100];
     386             :   int i;
     387             :   const char *tag;
     388             : 
     389           0 :   if (is_sigg)
     390           0 :     tag = "SIGG";
     391           0 :   else if (app->app_local->nks_version < 3)
     392           0 :     tag = "DF01";
     393             :   else
     394           0 :     tag = "NKS3";
     395             : 
     396             :   /* Output information about all useful objects in the NKS application. */
     397           0 :   for (i=0; filelist[i].fid; i++)
     398             :     {
     399           0 :       if (filelist[i].nks_ver > app->app_local->nks_version)
     400           0 :         continue;
     401             : 
     402           0 :       if (!!filelist[i].is_sigg != !!is_sigg)
     403           0 :         continue;
     404             : 
     405           0 :       if (filelist[i].certtype && !(flags &1))
     406           0 :         {
     407             :           size_t len;
     408             : 
     409           0 :           len = app_help_read_length_of_cert (app->slot,
     410             :                                               filelist[i].fid, NULL);
     411           0 :           if (len)
     412             :             {
     413             :               /* FIXME: We should store the length in the application's
     414             :                  context so that a following readcert does only need to
     415             :                  read that many bytes. */
     416           0 :               snprintf (ct_buf, sizeof ct_buf, "%d", filelist[i].certtype);
     417           0 :               snprintf (id_buf, sizeof id_buf, "NKS-%s.%04X",
     418             :                         tag, filelist[i].fid);
     419           0 :               send_status_info (ctrl, "CERTINFO",
     420             :                                 ct_buf, strlen (ct_buf),
     421             :                                 id_buf, strlen (id_buf),
     422             :                                 NULL, (size_t)0);
     423             :             }
     424             :         }
     425           0 :       else if (filelist[i].iskeypair)
     426             :         {
     427             :           char gripstr[40+1];
     428             : 
     429           0 :           err = keygripstr_from_pk_file (app, filelist[i].fid, gripstr);
     430           0 :           if (err)
     431           0 :             log_error ("can't get keygrip from FID 0x%04X: %s\n",
     432             :                        filelist[i].fid, gpg_strerror (err));
     433             :           else
     434             :             {
     435           0 :               snprintf (id_buf, sizeof id_buf, "NKS-%s.%04X",
     436             :                         tag, filelist[i].fid);
     437           0 :               send_status_info (ctrl, "KEYPAIRINFO",
     438             :                                 gripstr, 40,
     439             :                                 id_buf, strlen (id_buf),
     440             :                                 NULL, (size_t)0);
     441             :             }
     442             :         }
     443             :     }
     444             : 
     445             : 
     446           0 : }
     447             : 
     448             : 
     449             : static gpg_error_t
     450           0 : do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
     451             : {
     452             :   gpg_error_t err;
     453             : 
     454           0 :   err = switch_application (app, 0);
     455           0 :   if (err)
     456           0 :     return err;
     457             : 
     458           0 :   do_learn_status_core (app, ctrl, flags, 0);
     459             : 
     460           0 :   err = switch_application (app, 1);
     461           0 :   if (err)
     462           0 :     return 0;  /* Silently ignore if we can't switch to SigG.  */
     463             : 
     464           0 :   do_learn_status_core (app, ctrl, flags, 1);
     465             : 
     466           0 :   return 0;
     467             : }
     468             : 
     469             : 
     470             : 
     471             : 
     472             : /* Read the certificate with id CERTID (as returned by learn_status in
     473             :    the CERTINFO status lines) and return it in the freshly allocated
     474             :    buffer put into CERT and the length of the certificate put into
     475             :    CERTLEN. */
     476             : static gpg_error_t
     477           0 : do_readcert (app_t app, const char *certid,
     478             :              unsigned char **cert, size_t *certlen)
     479             : {
     480             :   int i, fid;
     481             :   gpg_error_t err;
     482             :   unsigned char *buffer;
     483             :   const unsigned char *p;
     484             :   size_t buflen, n;
     485             :   int class, tag, constructed, ndef;
     486             :   size_t totobjlen, objlen, hdrlen;
     487           0 :   int rootca = 0;
     488           0 :   int is_sigg = 0;
     489             : 
     490           0 :   *cert = NULL;
     491           0 :   *certlen = 0;
     492             : 
     493           0 :   if (!strncmp (certid, "NKS-NKS3.", 9))
     494             :     ;
     495           0 :   else if (!strncmp (certid, "NKS-DF01.", 9))
     496             :     ;
     497           0 :   else if (!strncmp (certid, "NKS-SIGG.", 9))
     498           0 :     is_sigg = 1;
     499             :   else
     500           0 :     return gpg_error (GPG_ERR_INV_ID);
     501             : 
     502           0 :   err = switch_application (app, is_sigg);
     503           0 :   if (err)
     504           0 :     return err;
     505             : 
     506           0 :   certid += 9;
     507           0 :   if (!hexdigitp (certid) || !hexdigitp (certid+1)
     508           0 :       || !hexdigitp (certid+2) || !hexdigitp (certid+3)
     509           0 :       || certid[4])
     510           0 :     return gpg_error (GPG_ERR_INV_ID);
     511           0 :   fid = xtoi_4 (certid);
     512           0 :   for (i=0; filelist[i].fid; i++)
     513           0 :     if ((filelist[i].certtype || filelist[i].iskeypair)
     514           0 :         && filelist[i].fid == fid)
     515           0 :       break;
     516           0 :   if (!filelist[i].fid)
     517           0 :     return gpg_error (GPG_ERR_NOT_FOUND);
     518             : 
     519             :   /* If the requested objects is a plain public key, redirect it to
     520             :      the corresponding certificate.  The whole system is a bit messy
     521             :      because we sometime use the key directly or let the caller
     522             :      retrieve the key from the certificate.  The rationale for
     523             :      that is to support not-yet stored certificates. */
     524           0 :   if (filelist[i].iskeypair)
     525           0 :     fid = filelist[i].iskeypair;
     526             : 
     527             : 
     528             :   /* Read the entire file.  fixme: This could be optimized by first
     529             :      reading the header to figure out how long the certificate
     530             :      actually is. */
     531           0 :   err = iso7816_select_file (app->slot, fid, 0, NULL, NULL);
     532           0 :   if (err)
     533             :     {
     534           0 :       log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
     535           0 :       return err;
     536             :     }
     537             : 
     538           0 :   err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
     539           0 :   if (err)
     540             :     {
     541           0 :       log_error ("error reading certificate from FID 0x%04X: %s\n",
     542             :                  fid, gpg_strerror (err));
     543           0 :       return err;
     544             :     }
     545             : 
     546           0 :   if (!buflen || *buffer == 0xff)
     547             :     {
     548           0 :       log_info ("no certificate contained in FID 0x%04X\n", fid);
     549           0 :       err = gpg_error (GPG_ERR_NOT_FOUND);
     550           0 :       goto leave;
     551             :     }
     552             : 
     553             :   /* Now figure something out about the object. */
     554           0 :   p = buffer;
     555           0 :   n = buflen;
     556           0 :   err = parse_ber_header (&p, &n, &class, &tag, &constructed,
     557             :                           &ndef, &objlen, &hdrlen);
     558           0 :   if (err)
     559           0 :     goto leave;
     560           0 :   if ( class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed )
     561             :     ;
     562           0 :   else if ( class == CLASS_UNIVERSAL && tag == TAG_SET && constructed )
     563           0 :     rootca = 1;
     564             :   else
     565           0 :     return gpg_error (GPG_ERR_INV_OBJ);
     566           0 :   totobjlen = objlen + hdrlen;
     567           0 :   assert (totobjlen <= buflen);
     568             : 
     569           0 :   err = parse_ber_header (&p, &n, &class, &tag, &constructed,
     570             :                           &ndef, &objlen, &hdrlen);
     571           0 :   if (err)
     572           0 :     goto leave;
     573             : 
     574           0 :   if (rootca)
     575             :     ;
     576           0 :   else if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed)
     577             :     {
     578             :       const unsigned char *save_p;
     579             : 
     580             :       /* The certificate seems to be contained in a userCertificate
     581             :          container.  Skip this and assume the following sequence is
     582             :          the certificate. */
     583           0 :       if (n < objlen)
     584             :         {
     585           0 :           err = gpg_error (GPG_ERR_INV_OBJ);
     586           0 :           goto leave;
     587             :         }
     588           0 :       p += objlen;
     589           0 :       n -= objlen;
     590           0 :       save_p = p;
     591           0 :       err = parse_ber_header (&p, &n, &class, &tag, &constructed,
     592             :                               &ndef, &objlen, &hdrlen);
     593           0 :       if (err)
     594           0 :         goto leave;
     595           0 :       if ( !(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed) )
     596           0 :         return gpg_error (GPG_ERR_INV_OBJ);
     597           0 :       totobjlen = objlen + hdrlen;
     598           0 :       assert (save_p + totobjlen <= buffer + buflen);
     599           0 :       memmove (buffer, save_p, totobjlen);
     600             :     }
     601             : 
     602           0 :   *cert = buffer;
     603           0 :   buffer = NULL;
     604           0 :   *certlen = totobjlen;
     605             : 
     606             :  leave:
     607           0 :   xfree (buffer);
     608           0 :   return err;
     609             : }
     610             : 
     611             : 
     612             : /* Handle the READKEY command. On success a canonical encoded
     613             :    S-expression with the public key will get stored at PK and its
     614             :    length at PKLEN; the caller must release that buffer.  On error PK
     615             :    and PKLEN are not changed and an error code is returned.  As of now
     616             :    this function is only useful for the internal authentication key.
     617             :    Other keys are automagically retrieved via by means of the
     618             :    certificate parsing code in commands.c:cmd_readkey.  For internal
     619             :    use PK and PKLEN may be NULL to just check for an existing key.  */
     620             : static gpg_error_t
     621           0 : do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
     622             : {
     623             :   gpg_error_t err;
     624             :   unsigned char *buffer[2];
     625             :   size_t buflen[2];
     626           0 :   unsigned short path[1] = { 0x4500 };
     627             : 
     628             :   /* We use a generic name to retrieve PK.AUT.IFD-SPK.  */
     629           0 :   if (!strcmp (keyid, "$IFDAUTHKEY") && app->app_local->nks_version >= 3)
     630             :     ;
     631             :   else /* Return the error code expected by cmd_readkey.  */
     632           0 :     return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
     633             : 
     634             :   /* Access the KEYD file which is always in the master directory.  */
     635           0 :   err = iso7816_select_path (app->slot, path, DIM (path), NULL, NULL);
     636           0 :   if (err)
     637           0 :     return err;
     638             :   /* Due to the above select we need to re-select our application.  */
     639           0 :   app->app_local->need_app_select = 1;
     640             :   /* Get the two records.  */
     641           0 :   err = iso7816_read_record (app->slot, 5, 1, 0, &buffer[0], &buflen[0]);
     642           0 :   if (err)
     643           0 :     return err;
     644           0 :   if (all_zero_p (buffer[0], buflen[0]))
     645             :     {
     646           0 :       xfree (buffer[0]);
     647           0 :       return gpg_error (GPG_ERR_NOT_FOUND);
     648             :     }
     649           0 :   err = iso7816_read_record (app->slot, 6, 1, 0, &buffer[1], &buflen[1]);
     650           0 :   if (err)
     651             :     {
     652           0 :       xfree (buffer[0]);
     653           0 :       return err;
     654             :     }
     655             : 
     656           0 :   if (pk && pklen)
     657             :     {
     658           0 :       *pk = make_canon_sexp_from_rsa_pk (buffer[0], buflen[0],
     659           0 :                                          buffer[1], buflen[1],
     660             :                                          pklen);
     661           0 :       if (!*pk)
     662           0 :         err = gpg_error_from_syserror ();
     663             :     }
     664             : 
     665           0 :   xfree (buffer[0]);
     666           0 :   xfree (buffer[1]);
     667           0 :   return err;
     668             : }
     669             : 
     670             : 
     671             : /* Handle the WRITEKEY command for NKS.  This function expects a
     672             :    canonical encoded S-expression with the public key in KEYDATA and
     673             :    its length in KEYDATALEN.  The only supported KEYID is
     674             :    "$IFDAUTHKEY" to store the terminal key on the card.  Bit 0 of
     675             :    FLAGS indicates whether an existing key shall get overwritten.
     676             :    PINCB and PINCB_ARG are the usual arguments for the pinentry
     677             :    callback.  */
     678             : static gpg_error_t
     679           0 : do_writekey (app_t app, ctrl_t ctrl,
     680             :              const char *keyid, unsigned int flags,
     681             :              gpg_error_t (*pincb)(void*, const char *, char **),
     682             :              void *pincb_arg,
     683             :              const unsigned char *keydata, size_t keydatalen)
     684             : {
     685             :   gpg_error_t err;
     686           0 :   int force = (flags & 1);
     687           0 :   const unsigned char *rsa_n = NULL;
     688           0 :   const unsigned char *rsa_e = NULL;
     689             :   size_t rsa_n_len, rsa_e_len;
     690             :   unsigned int nbits;
     691             : 
     692             :   (void)ctrl;
     693             :   (void)pincb;
     694             :   (void)pincb_arg;
     695             : 
     696           0 :   if (!strcmp (keyid, "$IFDAUTHKEY") && app->app_local->nks_version >= 3)
     697             :     ;
     698             :   else
     699           0 :     return gpg_error (GPG_ERR_INV_ID);
     700             : 
     701           0 :   if (!force && !do_readkey (app, keyid, NULL, NULL))
     702           0 :     return gpg_error (GPG_ERR_EEXIST);
     703             : 
     704             :   /* Parse the S-expression.  */
     705           0 :   err = get_rsa_pk_from_canon_sexp (keydata, keydatalen,
     706             :                                     &rsa_n, &rsa_n_len, &rsa_e, &rsa_e_len);
     707           0 :   if (err)
     708           0 :     goto leave;
     709             : 
     710             :   /* Check that the parameters match the requirements.  */
     711           0 :   nbits = app_help_count_bits (rsa_n, rsa_n_len);
     712           0 :   if (nbits != 1024)
     713             :     {
     714           0 :       log_error (_("RSA modulus missing or not of size %d bits\n"), 1024);
     715           0 :       err = gpg_error (GPG_ERR_BAD_PUBKEY);
     716           0 :       goto leave;
     717             :     }
     718             : 
     719           0 :   nbits = app_help_count_bits (rsa_e, rsa_e_len);
     720           0 :   if (nbits < 2 || nbits > 32)
     721             :     {
     722           0 :       log_error (_("RSA public exponent missing or larger than %d bits\n"),
     723             :                  32);
     724           0 :       err = gpg_error (GPG_ERR_BAD_PUBKEY);
     725           0 :       goto leave;
     726             :     }
     727             : 
     728             : /*   /\* Store them.  *\/ */
     729             : /*   err = verify_pin (app, 0, NULL, pincb, pincb_arg); */
     730             : /*   if (err) */
     731             : /*     goto leave; */
     732             : 
     733             :   /* Send the MSE:Store_Public_Key.  */
     734           0 :   err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
     735             : /*   mse = xtrymalloc (1000); */
     736             : 
     737             : /*   mse[0] = 0x80; /\* Algorithm reference.  *\/ */
     738             : /*   mse[1] = 1; */
     739             : /*   mse[2] = 0x17; */
     740             : /*   mse[3] = 0x84; /\* Private key reference.  *\/ */
     741             : /*   mse[4] = 1; */
     742             : /*   mse[5] = 0x77; */
     743             : /*   mse[6] = 0x7F; /\* Public key parameter.  *\/ */
     744             : /*   mse[7] = 0x49; */
     745             : /*   mse[8] = 0x81; */
     746             : /*   mse[9] = 3 + 0x80 + 2 + rsa_e_len; */
     747             : /*   mse[10] = 0x81; /\* RSA modulus of 128 byte.  *\/ */
     748             : /*   mse[11] = 0x81; */
     749             : /*   mse[12] = rsa_n_len; */
     750             : /*   memcpy (mse+12, rsa_n, rsa_n_len); */
     751             : /*   mse[10] = 0x82; /\* RSA public exponent of up to 4 bytes.  *\/ */
     752             : /*   mse[12] = rsa_e_len; */
     753             : /*   memcpy (mse+12, rsa_e, rsa_e_len); */
     754             : /*   err = iso7816_manage_security_env (app->slot, 0x81, 0xB6, */
     755             : /*                                      mse, sizeof mse); */
     756             : 
     757             :  leave:
     758           0 :   return err;
     759             : }
     760             : 
     761             : 
     762             : static gpg_error_t
     763           0 : basic_pin_checks (const char *pinvalue, int minlen, int maxlen)
     764             : {
     765           0 :   if (strlen (pinvalue) < minlen)
     766             :     {
     767           0 :       log_error ("PIN is too short; minimum length is %d\n", minlen);
     768           0 :       return gpg_error (GPG_ERR_BAD_PIN);
     769             :     }
     770           0 :   if (strlen (pinvalue) > maxlen)
     771             :     {
     772           0 :       log_error ("PIN is too large; maximum length is %d\n", maxlen);
     773           0 :       return gpg_error (GPG_ERR_BAD_PIN);
     774             :     }
     775           0 :   return 0;
     776             : }
     777             : 
     778             : 
     779             : /* Verify the PIN if required.  */
     780             : static gpg_error_t
     781           0 : verify_pin (app_t app, int pwid, const char *desc,
     782             :             gpg_error_t (*pincb)(void*, const char *, char **),
     783             :             void *pincb_arg)
     784             : {
     785             :   pininfo_t pininfo;
     786             :   int rc;
     787             : 
     788           0 :   if (!desc)
     789           0 :     desc = "PIN";
     790             : 
     791           0 :   memset (&pininfo, 0, sizeof pininfo);
     792           0 :   pininfo.fixedlen = -1;
     793           0 :   pininfo.minlen = 6;
     794           0 :   pininfo.maxlen = 16;
     795             : 
     796           0 :   if (!opt.disable_pinpad
     797           0 :       && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) )
     798             :     {
     799           0 :       rc = pincb (pincb_arg, desc, NULL);
     800           0 :       if (rc)
     801             :         {
     802           0 :           log_info (_("PIN callback returned error: %s\n"),
     803             :                     gpg_strerror (rc));
     804           0 :           return rc;
     805             :         }
     806             : 
     807           0 :       rc = iso7816_verify_kp (app->slot, pwid, &pininfo);
     808           0 :       pincb (pincb_arg, NULL, NULL);  /* Dismiss the prompt. */
     809             :     }
     810             :   else
     811             :     {
     812             :       char *pinvalue;
     813             : 
     814           0 :       rc = pincb (pincb_arg, desc, &pinvalue);
     815           0 :       if (rc)
     816             :         {
     817           0 :           log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
     818           0 :           return rc;
     819             :         }
     820             : 
     821           0 :       rc = basic_pin_checks (pinvalue, pininfo.minlen, pininfo.maxlen);
     822           0 :       if (rc)
     823             :         {
     824           0 :           xfree (pinvalue);
     825           0 :           return rc;
     826             :         }
     827             : 
     828           0 :       rc = iso7816_verify (app->slot, pwid, pinvalue, strlen (pinvalue));
     829           0 :       xfree (pinvalue);
     830             :     }
     831             : 
     832           0 :   if (rc)
     833             :     {
     834           0 :       if ( gpg_err_code (rc) == GPG_ERR_USE_CONDITIONS )
     835           0 :         log_error (_("the NullPIN has not yet been changed\n"));
     836             :       else
     837           0 :         log_error ("verify PIN failed\n");
     838           0 :       return rc;
     839             :     }
     840             : 
     841           0 :   return 0;
     842             : }
     843             : 
     844             : 
     845             : /* Create the signature and return the allocated result in OUTDATA.
     846             :    If a PIN is required the PINCB will be used to ask for the PIN;
     847             :    that callback should return the PIN in an allocated buffer and
     848             :    store that in the 3rd argument.  */
     849             : static gpg_error_t
     850           0 : do_sign (app_t app, const char *keyidstr, int hashalgo,
     851             :          gpg_error_t (*pincb)(void*, const char *, char **),
     852             :          void *pincb_arg,
     853             :          const void *indata, size_t indatalen,
     854             :          unsigned char **outdata, size_t *outdatalen )
     855             : {
     856             :   static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
     857             :     { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
     858             :       0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
     859             :   static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
     860             :     { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
     861             :       0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
     862             :   int rc, i;
     863           0 :   int is_sigg = 0;
     864             :   int fid;
     865             :   unsigned char kid;
     866             :   unsigned char data[83];   /* Must be large enough for a SHA-1 digest
     867             :                                + the largest OID prefix. */
     868             :   size_t datalen;
     869             : 
     870           0 :   if (!keyidstr || !*keyidstr)
     871           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     872           0 :   switch (indatalen)
     873             :     {
     874           0 :     case 16: case 20: case 35: case 47: case 51: case 67: case 83: break;
     875           0 :     default: return gpg_error (GPG_ERR_INV_VALUE);
     876             :     }
     877             : 
     878             :   /* Check that the provided ID is valid.  This is not really needed
     879             :      but we do it to enforce correct usage by the caller. */
     880           0 :   if (!strncmp (keyidstr, "NKS-NKS3.", 9) )
     881             :     ;
     882           0 :   else if (!strncmp (keyidstr, "NKS-DF01.", 9) )
     883             :     ;
     884           0 :   else if (!strncmp (keyidstr, "NKS-SIGG.", 9) )
     885           0 :     is_sigg = 1;
     886             :   else
     887           0 :     return gpg_error (GPG_ERR_INV_ID);
     888           0 :   keyidstr += 9;
     889             : 
     890           0 :   rc = switch_application (app, is_sigg);
     891           0 :   if (rc)
     892           0 :     return rc;
     893             : 
     894           0 :   if (is_sigg && app->app_local->sigg_is_msig)
     895             :     {
     896           0 :       log_info ("mass signature cards are not allowed\n");
     897           0 :       return gpg_error (GPG_ERR_NOT_SUPPORTED);
     898             :     }
     899             : 
     900           0 :   if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
     901           0 :       || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
     902           0 :       || keyidstr[4])
     903           0 :     return gpg_error (GPG_ERR_INV_ID);
     904           0 :   fid = xtoi_4 (keyidstr);
     905           0 :   for (i=0; filelist[i].fid; i++)
     906           0 :     if (filelist[i].iskeypair && filelist[i].fid == fid)
     907           0 :       break;
     908           0 :   if (!filelist[i].fid)
     909           0 :     return gpg_error (GPG_ERR_NOT_FOUND);
     910           0 :   if (!filelist[i].issignkey)
     911           0 :     return gpg_error (GPG_ERR_INV_ID);
     912           0 :   kid = filelist[i].kid;
     913             : 
     914             :   /* Prepare the DER object from INDATA.  */
     915           0 :   if (app->app_local->nks_version > 2 && (indatalen == 35
     916           0 :                                           || indatalen == 47
     917           0 :                                           || indatalen == 51
     918           0 :                                           || indatalen == 67
     919           0 :                                           || indatalen == 83))
     920             :     {
     921             :       /* The caller send data matching the length of the ASN.1 encoded
     922             :          hash for SHA-{1,224,256,384,512}.  Assume that is okay.  */
     923           0 :       assert (indatalen <= sizeof data);
     924           0 :       memcpy (data, indata, indatalen);
     925           0 :       datalen = indatalen;
     926             :     }
     927           0 :   else if (indatalen == 35)
     928             :     {
     929             :       /* Alright, the caller was so kind to send us an already
     930             :          prepared DER object.  This is for TCOS 2. */
     931           0 :       if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha1_prefix, 15))
     932             :         ;
     933           0 :       else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata,rmd160_prefix,15))
     934             :         ;
     935             :       else
     936           0 :         return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
     937           0 :       memcpy (data, indata, indatalen);
     938           0 :       datalen = 35;
     939             :     }
     940           0 :   else if (indatalen == 20)
     941             :     {
     942           0 :       if (hashalgo == GCRY_MD_SHA1)
     943           0 :         memcpy (data, sha1_prefix, 15);
     944           0 :       else if (hashalgo == GCRY_MD_RMD160)
     945           0 :         memcpy (data, rmd160_prefix, 15);
     946             :       else
     947           0 :         return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
     948           0 :       memcpy (data+15, indata, indatalen);
     949           0 :       datalen = 35;
     950             :     }
     951             :   else
     952           0 :     return gpg_error (GPG_ERR_INV_VALUE);
     953             : 
     954             : 
     955             :   /* Send an MSE for PSO:Computer_Signature.  */
     956           0 :   if (app->app_local->nks_version > 2)
     957             :     {
     958             :       unsigned char mse[6];
     959             : 
     960           0 :       mse[0] = 0x80; /* Algorithm reference.  */
     961           0 :       mse[1] = 1;
     962           0 :       mse[2] = 2;    /* RSA, card does pkcs#1 v1.5 padding, no ASN.1 check.  */
     963           0 :       mse[3] = 0x84; /* Private key reference.  */
     964           0 :       mse[4] = 1;
     965           0 :       mse[5] = kid;
     966           0 :       rc = iso7816_manage_security_env (app->slot, 0x41, 0xB6,
     967             :                                         mse, sizeof mse);
     968             :     }
     969             :   /* Verify using PW1.CH.  */
     970           0 :   if (!rc)
     971           0 :     rc = verify_pin (app, 0, NULL, pincb, pincb_arg);
     972             :   /* Compute the signature.  */
     973           0 :   if (!rc)
     974           0 :     rc = iso7816_compute_ds (app->slot, 0, data, datalen, 0,
     975             :                              outdata, outdatalen);
     976           0 :   return rc;
     977             : }
     978             : 
     979             : 
     980             : 
     981             : /* Decrypt the data in INDATA and return the allocated result in OUTDATA.
     982             :    If a PIN is required the PINCB will be used to ask for the PIN; it
     983             :    should return the PIN in an allocated buffer and put it into PIN.  */
     984             : static gpg_error_t
     985           0 : do_decipher (app_t app, const char *keyidstr,
     986             :              gpg_error_t (*pincb)(void*, const char *, char **),
     987             :              void *pincb_arg,
     988             :              const void *indata, size_t indatalen,
     989             :              unsigned char **outdata, size_t *outdatalen,
     990             :              unsigned int *r_info)
     991             : {
     992             :   int rc, i;
     993           0 :   int is_sigg = 0;
     994             :   int fid;
     995             :   int kid;
     996             : 
     997             :   (void)r_info;
     998             : 
     999           0 :   if (!keyidstr || !*keyidstr || !indatalen)
    1000           0 :     return gpg_error (GPG_ERR_INV_VALUE);
    1001             : 
    1002             :   /* Check that the provided ID is valid.  This is not really needed
    1003             :      but we do it to to enforce correct usage by the caller. */
    1004           0 :   if (!strncmp (keyidstr, "NKS-NKS3.", 9) )
    1005             :     ;
    1006           0 :   else if (!strncmp (keyidstr, "NKS-DF01.", 9) )
    1007             :     ;
    1008           0 :   else if (!strncmp (keyidstr, "NKS-SIGG.", 9) )
    1009           0 :     is_sigg = 1;
    1010             :   else
    1011           0 :     return gpg_error (GPG_ERR_INV_ID);
    1012           0 :   keyidstr += 9;
    1013             : 
    1014           0 :   rc = switch_application (app, is_sigg);
    1015           0 :   if (rc)
    1016           0 :     return rc;
    1017             : 
    1018           0 :   if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
    1019           0 :       || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
    1020           0 :       || keyidstr[4])
    1021           0 :     return gpg_error (GPG_ERR_INV_ID);
    1022           0 :   fid = xtoi_4 (keyidstr);
    1023           0 :   for (i=0; filelist[i].fid; i++)
    1024           0 :     if (filelist[i].iskeypair && filelist[i].fid == fid)
    1025           0 :       break;
    1026           0 :   if (!filelist[i].fid)
    1027           0 :     return gpg_error (GPG_ERR_NOT_FOUND);
    1028           0 :   if (!filelist[i].isenckey)
    1029           0 :     return gpg_error (GPG_ERR_INV_ID);
    1030           0 :   kid = filelist[i].kid;
    1031             : 
    1032           0 :   if (app->app_local->nks_version > 2)
    1033             :     {
    1034             :       unsigned char mse[6];
    1035           0 :       mse[0] = 0x80; /* Algorithm reference.  */
    1036           0 :       mse[1] = 1;
    1037           0 :       mse[2] = 0x0a; /* RSA no padding.  (0x1A is pkcs#1.5 padding.)  */
    1038           0 :       mse[3] = 0x84; /* Private key reference.  */
    1039           0 :       mse[4] = 1;
    1040           0 :       mse[5] = kid;
    1041           0 :       rc = iso7816_manage_security_env (app->slot, 0x41, 0xB8,
    1042             :                                         mse, sizeof mse);
    1043             :     }
    1044             :   else
    1045             :     {
    1046             :       static const unsigned char mse[] =
    1047             :         {
    1048             :           0x80, 1, 0x10, /* Select algorithm RSA. */
    1049             :           0x84, 1, 0x81  /* Select local secret key 1 for decryption. */
    1050             :         };
    1051           0 :       rc = iso7816_manage_security_env (app->slot, 0xC1, 0xB8,
    1052             :                                         mse, sizeof mse);
    1053             : 
    1054             :     }
    1055             : 
    1056           0 :   if (!rc)
    1057           0 :     rc = verify_pin (app, 0, NULL, pincb, pincb_arg);
    1058             : 
    1059             :   /* Note that we need to use extended length APDUs for TCOS 3 cards.
    1060             :      Command chaining does not work.  */
    1061           0 :   if (!rc)
    1062           0 :     rc = iso7816_decipher (app->slot, app->app_local->nks_version > 2? 1:0,
    1063             :                            indata, indatalen, 0, 0x81,
    1064             :                            outdata, outdatalen);
    1065           0 :   return rc;
    1066             : }
    1067             : 
    1068             : 
    1069             : 
    1070             : /* Parse a password ID string.  Returns NULL on error or a string
    1071             :    suitable as passpahrse prompt on success.  On success stores the
    1072             :    reference value for the password at R_PWID and a flag indicating
    1073             :    that the SigG application is to be used at R_SIGG.  If NEW_MODE is
    1074             :    true, the returned description is suitable for a new Password.
    1075             :    Supported values for PWIDSTR are:
    1076             : 
    1077             :      PW1.CH       - Global password 1
    1078             :      PW2.CH       - Global password 2
    1079             :      PW1.CH.SIG   - SigG password 1
    1080             :      PW2.CH.SIG   - SigG password 2
    1081             :  */
    1082             : static const char *
    1083           0 : parse_pwidstr (const char *pwidstr, int new_mode, int *r_sigg, int *r_pwid)
    1084             : {
    1085             :   const char *desc;
    1086             : 
    1087           0 :   if (!pwidstr)
    1088           0 :     desc = NULL;
    1089           0 :   else if (!strcmp (pwidstr, "PW1.CH"))
    1090             :     {
    1091           0 :       *r_sigg = 0;
    1092           0 :       *r_pwid = 0x00;
    1093             :       /* TRANSLATORS: Do not translate the "|*|" prefixes but keep
    1094             :          them verbatim at the start of the string.  */
    1095           0 :       desc = (new_mode
    1096             :               ? _("|N|Please enter a new PIN for the standard keys.")
    1097             :               : _("||Please enter the PIN for the standard keys."));
    1098             :     }
    1099           0 :   else if (!strcmp (pwidstr, "PW2.CH"))
    1100             :     {
    1101           0 :       *r_pwid = 0x01;
    1102           0 :       desc = (new_mode
    1103             :               ? _("|NP|Please enter a new PIN Unblocking Code (PUK) "
    1104             :                   "for the standard keys.")
    1105             :               : _("|P|Please enter the PIN Unblocking Code (PUK) "
    1106             :                   "for the standard keys."));
    1107             :     }
    1108           0 :   else if (!strcmp (pwidstr, "PW1.CH.SIG"))
    1109             :     {
    1110           0 :       *r_pwid = 0x81;
    1111           0 :       *r_sigg = 1;
    1112           0 :       desc = (new_mode
    1113             :               ? _("|N|Please enter a new PIN for the key to create "
    1114             :                   "qualified signatures.")
    1115             :               : _("||Please enter the PIN for the key to create "
    1116             :                   "qualified signatures."));
    1117             :     }
    1118           0 :   else if (!strcmp (pwidstr, "PW2.CH.SIG"))
    1119             :     {
    1120           0 :       *r_pwid = 0x83;  /* Yes, that is 83 and not 82.  */
    1121           0 :       *r_sigg = 1;
    1122           0 :       desc = (new_mode
    1123             :               ? _("|NP|Please enter a new PIN Unblocking Code (PUK) "
    1124             :                   "for the key to create qualified signatures.")
    1125             :               : _("|P|Please enter the PIN Unblocking Code (PUK) "
    1126             :                   "for the key to create qualified signatures."));
    1127             :     }
    1128             :   else
    1129             :     {
    1130           0 :       *r_pwid = 0; /* Only to avoid gcc warning in calling function.  */
    1131           0 :       desc = NULL; /* Error.  */
    1132             :     }
    1133             : 
    1134           0 :   return desc;
    1135             : }
    1136             : 
    1137             : 
    1138             : /* Handle the PASSWD command. See parse_pwidstr() for allowed values
    1139             :    for CHVNOSTR.  */
    1140             : static gpg_error_t
    1141           0 : do_change_pin (app_t app, ctrl_t ctrl,  const char *pwidstr,
    1142             :                unsigned int flags,
    1143             :                gpg_error_t (*pincb)(void*, const char *, char **),
    1144             :                void *pincb_arg)
    1145             : {
    1146             :   gpg_error_t err;
    1147           0 :   char *newpin = NULL;
    1148           0 :   char *oldpin = NULL;
    1149             :   size_t newpinlen;
    1150             :   size_t oldpinlen;
    1151             :   int is_sigg;
    1152             :   const char *newdesc;
    1153             :   int pwid;
    1154             :   pininfo_t pininfo;
    1155             : 
    1156             :   (void)ctrl;
    1157             : 
    1158             :   /* The minimum length is enforced by TCOS, the maximum length is
    1159             :      just a reasonable value.  */
    1160           0 :   memset (&pininfo, 0, sizeof pininfo);
    1161           0 :   pininfo.minlen = 6;
    1162           0 :   pininfo.maxlen = 16;
    1163             : 
    1164           0 :   newdesc = parse_pwidstr (pwidstr, 1, &is_sigg, &pwid);
    1165           0 :   if (!newdesc)
    1166           0 :     return gpg_error (GPG_ERR_INV_ID);
    1167             : 
    1168           0 :   err = switch_application (app, is_sigg);
    1169           0 :   if (err)
    1170           0 :     return err;
    1171             : 
    1172           0 :   if ((flags & APP_CHANGE_FLAG_NULLPIN))
    1173             :     {
    1174             :       /* With the nullpin flag, we do not verify the PIN - it would
    1175             :          fail if the Nullpin is still set.  */
    1176           0 :       oldpin = xtrycalloc (1, 6);
    1177           0 :       if (!oldpin)
    1178             :         {
    1179           0 :           err = gpg_error_from_syserror ();
    1180           0 :           goto leave;
    1181             :         }
    1182           0 :       oldpinlen = 6;
    1183             :     }
    1184             :   else
    1185             :     {
    1186             :       const char *desc;
    1187             :       int dummy1, dummy2;
    1188             : 
    1189           0 :       if ((flags & APP_CHANGE_FLAG_RESET))
    1190             :         {
    1191             :           /* Reset mode: Ask for the alternate PIN.  */
    1192             :           const char *altpwidstr;
    1193             : 
    1194           0 :           if (!strcmp (pwidstr, "PW1.CH"))
    1195           0 :             altpwidstr = "PW2.CH";
    1196           0 :           else if (!strcmp (pwidstr, "PW2.CH"))
    1197           0 :             altpwidstr = "PW1.CH";
    1198           0 :           else if (!strcmp (pwidstr, "PW1.CH.SIG"))
    1199           0 :             altpwidstr = "PW2.CH.SIG";
    1200           0 :           else if (!strcmp (pwidstr, "PW2.CH.SIG"))
    1201           0 :             altpwidstr = "PW1.CH.SIG";
    1202             :           else
    1203             :             {
    1204           0 :               err = gpg_error (GPG_ERR_BUG);
    1205           0 :               goto leave;
    1206             :             }
    1207           0 :           desc = parse_pwidstr (altpwidstr, 0, &dummy1, &dummy2);
    1208             :         }
    1209             :       else
    1210             :         {
    1211             :           /* Regular change mode:  Ask for the old PIN.  */
    1212           0 :           desc = parse_pwidstr (pwidstr, 0, &dummy1, &dummy2);
    1213             :         }
    1214           0 :       err = pincb (pincb_arg, desc, &oldpin);
    1215           0 :       if (err)
    1216             :         {
    1217           0 :           log_error ("error getting old PIN: %s\n", gpg_strerror (err));
    1218           0 :           goto leave;
    1219             :         }
    1220           0 :       oldpinlen = strlen (oldpin);
    1221           0 :       err = basic_pin_checks (oldpin, pininfo.minlen, pininfo.maxlen);
    1222           0 :       if (err)
    1223           0 :         goto leave;
    1224             :     }
    1225             : 
    1226           0 :   err = pincb (pincb_arg, newdesc, &newpin);
    1227           0 :   if (err)
    1228             :     {
    1229           0 :       log_error (_("error getting new PIN: %s\n"), gpg_strerror (err));
    1230           0 :       goto leave;
    1231             :     }
    1232           0 :   newpinlen = strlen (newpin);
    1233             : 
    1234           0 :   err = basic_pin_checks (newpin, pininfo.minlen, pininfo.maxlen);
    1235           0 :   if (err)
    1236           0 :     goto leave;
    1237             : 
    1238           0 :   if ((flags & APP_CHANGE_FLAG_RESET))
    1239             :     {
    1240             :       char *data;
    1241           0 :       size_t datalen = oldpinlen + newpinlen;
    1242             : 
    1243           0 :       data = xtrymalloc (datalen);
    1244           0 :       if (!data)
    1245             :         {
    1246           0 :           err = gpg_error_from_syserror ();
    1247           0 :           goto leave;
    1248             :         }
    1249           0 :       memcpy (data, oldpin, oldpinlen);
    1250           0 :       memcpy (data+oldpinlen, newpin, newpinlen);
    1251           0 :       err = iso7816_reset_retry_counter_with_rc (app->slot, pwid,
    1252             :                                                  data, datalen);
    1253           0 :       wipememory (data, datalen);
    1254           0 :       xfree (data);
    1255             :     }
    1256             :   else
    1257           0 :     err = iso7816_change_reference_data (app->slot, pwid,
    1258             :                                          oldpin, oldpinlen,
    1259             :                                          newpin, newpinlen);
    1260             :  leave:
    1261           0 :   xfree (oldpin);
    1262           0 :   xfree (newpin);
    1263           0 :   return err;
    1264             : }
    1265             : 
    1266             : 
    1267             : /* Perform a simple verify operation.  KEYIDSTR should be NULL or empty.  */
    1268             : static gpg_error_t
    1269           0 : do_check_pin (app_t app, const char *pwidstr,
    1270             :               gpg_error_t (*pincb)(void*, const char *, char **),
    1271             :               void *pincb_arg)
    1272             : {
    1273             :   gpg_error_t err;
    1274             :   int pwid;
    1275             :   int is_sigg;
    1276             :   const char *desc;
    1277             : 
    1278           0 :   desc = parse_pwidstr (pwidstr, 0, &is_sigg, &pwid);
    1279           0 :   if (!desc)
    1280           0 :     return gpg_error (GPG_ERR_INV_ID);
    1281             : 
    1282           0 :   err = switch_application (app, is_sigg);
    1283           0 :   if (err)
    1284           0 :     return err;
    1285             : 
    1286           0 :   return verify_pin (app, pwid, desc, pincb, pincb_arg);
    1287             : }
    1288             : 
    1289             : 
    1290             : /* Return the version of the NKS application.  */
    1291             : static int
    1292           0 : get_nks_version (int slot)
    1293             : {
    1294           0 :   unsigned char *result = NULL;
    1295             :   size_t resultlen;
    1296             :   int type;
    1297             : 
    1298           0 :   if (iso7816_apdu_direct (slot, "\x80\xaa\x06\x00\x00", 5, 0,
    1299             :                            &result, &resultlen))
    1300           0 :     return 2; /* NKS 2 does not support this command.  */
    1301             : 
    1302             :   /* Example value:    04 11 19 22 21 6A 20 80 03 03 01 01 01 00 00 00
    1303             :                        vv tt ccccccccccccccccc aa bb cc vvvvvvvvvvv xx
    1304             :      vendor (Philips) -+  |  |                 |  |  |  |           |
    1305             :      chip type -----------+  |                 |  |  |  |           |
    1306             :      chip id ----------------+                 |  |  |  |           |
    1307             :      card type (3 - tcos 3) -------------------+  |  |  |           |
    1308             :      OS version of card type ---------------------+  |  |           |
    1309             :      OS release of card type ------------------------+  |           |
    1310             :      OS vendor internal version ------------------------+           |
    1311             :      RFU -----------------------------------------------------------+
    1312             :   */
    1313           0 :   if (resultlen < 16)
    1314           0 :     type = 0;  /* Invalid data returned.  */
    1315             :   else
    1316           0 :     type = result[8];
    1317           0 :   xfree (result);
    1318             : 
    1319           0 :   return type;
    1320             : }
    1321             : 
    1322             : 
    1323             : /* If ENABLE_SIGG is true switch to the SigG application if not yet
    1324             :    active.  If false switch to the NKS application if not yet active.
    1325             :    Returns 0 on success.  */
    1326             : static gpg_error_t
    1327           0 : switch_application (app_t app, int enable_sigg)
    1328             : {
    1329             :   gpg_error_t err;
    1330             : 
    1331           0 :   if (((app->app_local->sigg_active && enable_sigg)
    1332           0 :        || (!app->app_local->sigg_active && !enable_sigg))
    1333           0 :       && !app->app_local->need_app_select)
    1334           0 :     return 0;  /* Already switched.  */
    1335             : 
    1336           0 :   log_info ("app-nks: switching to %s\n", enable_sigg? "SigG":"NKS");
    1337           0 :   if (enable_sigg)
    1338           0 :     err = iso7816_select_application (app->slot, aid_sigg, sizeof aid_sigg, 0);
    1339             :   else
    1340           0 :     err = iso7816_select_application (app->slot, aid_nks, sizeof aid_nks, 0);
    1341             : 
    1342           0 :   if (!err && enable_sigg && app->app_local->nks_version >= 3
    1343           0 :       && !app->app_local->sigg_msig_checked)
    1344             :     {
    1345             :       /* Check whether this card is a mass signature card.  */
    1346             :       unsigned char *buffer;
    1347             :       size_t buflen;
    1348             :       const unsigned char *tmpl;
    1349             :       size_t tmpllen;
    1350             : 
    1351           0 :       app->app_local->sigg_msig_checked = 1;
    1352           0 :       app->app_local->sigg_is_msig = 1;
    1353           0 :       err = iso7816_select_file (app->slot, 0x5349, 0, NULL, NULL);
    1354           0 :       if (!err)
    1355           0 :         err = iso7816_read_record (app->slot, 1, 1, 0, &buffer, &buflen);
    1356           0 :       if (!err)
    1357             :         {
    1358           0 :           tmpl = find_tlv (buffer, buflen, 0x7a, &tmpllen);
    1359           0 :           if (tmpl && tmpllen == 12
    1360           0 :               && !memcmp (tmpl,
    1361             :                           "\x93\x02\x00\x01\xA4\x06\x83\x01\x81\x83\x01\x83",
    1362             :                           12))
    1363           0 :             app->app_local->sigg_is_msig = 0;
    1364           0 :           xfree (buffer);
    1365             :         }
    1366           0 :       if (app->app_local->sigg_is_msig)
    1367           0 :         log_info ("This is a mass signature card\n");
    1368             :     }
    1369             : 
    1370           0 :   if (!err)
    1371             :     {
    1372           0 :       app->app_local->need_app_select = 0;
    1373           0 :       app->app_local->sigg_active = enable_sigg;
    1374             :     }
    1375             :   else
    1376           0 :     log_error ("app-nks: error switching to %s: %s\n",
    1377             :                enable_sigg? "SigG":"NKS", gpg_strerror (err));
    1378             : 
    1379           0 :   return err;
    1380             : }
    1381             : 
    1382             : 
    1383             : /* Select the NKS application.  */
    1384             : gpg_error_t
    1385           0 : app_select_nks (app_t app)
    1386             : {
    1387           0 :   int slot = app->slot;
    1388             :   int rc;
    1389             : 
    1390           0 :   rc = iso7816_select_application (slot, aid_nks, sizeof aid_nks, 0);
    1391           0 :   if (!rc)
    1392             :     {
    1393           0 :       app->apptype = "NKS";
    1394             : 
    1395           0 :       app->app_local = xtrycalloc (1, sizeof *app->app_local);
    1396           0 :       if (!app->app_local)
    1397             :         {
    1398           0 :           rc = gpg_error (gpg_err_code_from_errno (errno));
    1399           0 :           goto leave;
    1400             :         }
    1401             : 
    1402           0 :       app->app_local->nks_version = get_nks_version (slot);
    1403           0 :       if (opt.verbose)
    1404           0 :         log_info ("Detected NKS version: %d\n", app->app_local->nks_version);
    1405             : 
    1406           0 :       app->fnc.deinit = do_deinit;
    1407           0 :       app->fnc.learn_status = do_learn_status;
    1408           0 :       app->fnc.readcert = do_readcert;
    1409           0 :       app->fnc.readkey = do_readkey;
    1410           0 :       app->fnc.getattr = do_getattr;
    1411           0 :       app->fnc.setattr = NULL;
    1412           0 :       app->fnc.writekey = do_writekey;
    1413           0 :       app->fnc.genkey = NULL;
    1414           0 :       app->fnc.sign = do_sign;
    1415           0 :       app->fnc.auth = NULL;
    1416           0 :       app->fnc.decipher = do_decipher;
    1417           0 :       app->fnc.change_pin = do_change_pin;
    1418           0 :       app->fnc.check_pin = do_check_pin;
    1419             :    }
    1420             : 
    1421             :  leave:
    1422           0 :   if (rc)
    1423           0 :     do_deinit (app);
    1424           0 :   return rc;
    1425             : }

Generated by: LCOV version 1.11