Add CVE number.
[gnupg.git] / scd / app-nks.c
index f14b679..514ae10 100644 (file)
@@ -1,11 +1,11 @@
 /* app-nks.c - The Telesec NKS 2.0 card application.
- *     Copyright (C) 2004 Free Software Foundation, Inc.
+ * Copyright (C) 2004, 2007 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include <time.h>
 
 #include "scdaemon.h"
-
+#include "i18n.h"
 #include "iso7816.h"
 #include "app-common.h"
 #include "tlv.h"
 
-static struct {
+static struct
+{
   int fid;       /* File ID. */
   int certtype;  /* Type of certificate or 0 if it is not a certificate. */
   int iskeypair; /* If true has the FID of the correspoding certificate. */
@@ -117,8 +117,8 @@ keygripstr_from_pk_file (int slot, int fid, char *r_gripstr)
 
 
 
-static int
-do_learn_status (APP app, CTRL ctrl)
+static gpg_error_t
+do_learn_status (app_t app, ctrl_t ctrl)
 {
   gpg_error_t err;
   char ct_buf[100], id_buf[100];
@@ -175,7 +175,7 @@ do_learn_status (APP app, CTRL ctrl)
    the CERTINFO status lines) and return it in the freshly allocated
    buffer put into CERT and the length of the certificate put into
    CERTLEN. */
-static int
+static gpg_error_t
 do_readcert (app_t app, const char *certid,
              unsigned char **cert, size_t *certlen)
 {
@@ -207,8 +207,8 @@ do_readcert (app_t app, const char *certid,
 
   /* If the requested objects is a plain public key, redirect it to
      the corresponding certificate.  The whole system is a bit messy
-     becuase we sometime use the key directly or let the caller
-     retrieve the key from the certificate.  The valid point behind
+     because we sometime use the key directly or let the caller
+     retrieve the key from the certificate.  The rationale for
      that is to support not-yet stored certificates. */
   if (filelist[i].iskeypair)
     fid = filelist[i].iskeypair;
@@ -299,19 +299,48 @@ do_readcert (app_t app, const char *certid,
 
 
 /* Verify the PIN if required.  */
-static int
+static gpg_error_t
 verify_pin (app_t app,
-            int (pincb)(void*, const char *, char **),
+            gpg_error_t (*pincb)(void*, const char *, char **),
             void *pincb_arg)
 {
+  iso7816_pininfo_t pininfo;
+  int rc;
+
   /* Note that force_chv1 is never set but we do it here anyway so
      that other applications may reuse this function.  For example it
      makes sense to set force_chv1 for German signature law cards.
      NKS is very similar to the DINSIG draft standard. */
-  if (!app->did_chv1 || app->force_chv1 ) 
+  if ( app->did_chv1 && !app->force_chv1 ) 
+    return 0;  /* No need to verify it again.  */
+
+  memset (&pininfo, 0, sizeof pininfo);
+  pininfo.mode = 1;
+  pininfo.minlen = 6;
+  pininfo.maxlen = 16;
+
+  if (!opt.disable_keypad
+      && !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
+    {
+      rc = pincb (pincb_arg,
+                  _("||Please enter your PIN at the reader's keypad"),
+                  NULL);
+      if (rc)
+        {
+          log_info (_("PIN callback returned error: %s\n"),
+                    gpg_strerror (rc));
+          return rc;
+        }
+      /* Although it is possible to use a local PIN, we use the global
+         PIN for this application.  */
+      rc = iso7816_verify_kp (app->slot, 0, "", 0, &pininfo); 
+      /* Dismiss the prompt. */
+      pincb (pincb_arg, NULL, NULL);
+    }
+  else
     {
       char *pinvalue;
-      int rc;
 
       rc = pincb (pincb_arg, "PIN", &pinvalue); 
       if (rc)
@@ -320,34 +349,39 @@ verify_pin (app_t app,
           return rc;
         }
 
-      /* The follwoing limits are due to TCOS but also defined in the
+      /* The following limits are due to TCOS but also defined in the
          NKS specs. */
-      if (strlen (pinvalue) < 6)
+      if (strlen (pinvalue) < pininfo.minlen)
         {
-          log_error ("PIN is too short; minimum length is 6\n");
+          log_error ("PIN is too short; minimum length is %d\n",
+                     pininfo.minlen);
           xfree (pinvalue);
           return gpg_error (GPG_ERR_BAD_PIN);
         }
-      else if (strlen (pinvalue) > 16)
+      else if (strlen (pinvalue) > pininfo.maxlen)
         {
-          log_error ("PIN is too large; maximum length is 16\n");
+          log_error ("PIN is too large; maximum length is %d\n",
+                     pininfo.maxlen);
           xfree (pinvalue);
           return gpg_error (GPG_ERR_BAD_PIN);
         }
 
-      /* Also it is possible to use a local PIN, we use the gloabl
+      /* Although it is possible to use a local PIN, we use the global
          PIN for this application.  */
       rc = iso7816_verify (app->slot, 0, pinvalue, strlen (pinvalue));
-      if (rc)
-        {
-          log_error ("verify PIN failed\n");
-          xfree (pinvalue);
-          return rc;
-        }
-      app->did_chv1 = 1;
       xfree (pinvalue);
     }
 
+  if (rc)
+    {
+      if ( gpg_err_code (rc) == GPG_ERR_USE_CONDITIONS )
+        log_error (_("the NullPIN has not yet been changed\n"));
+      else
+        log_error ("verify PIN failed\n");
+      return rc;
+    }
+  app->did_chv1 = 1;
+
   return 0;
 }
 
@@ -357,12 +391,12 @@ verify_pin (app_t app,
    If a PIN is required the PINCB will be used to ask for the PIN;
    that callback should return the PIN in an allocated buffer and
    store that in the 3rd argument.  */
-static in
+static gpg_error_
 do_sign (app_t app, const char *keyidstr, int hashalgo,
-         int (pincb)(void*, const char *, char **),
-           void *pincb_arg,
-           const void *indata, size_t indatalen,
-           unsigned char **outdata, size_t *outdatalen )
+         gpg_error_t (*pincb)(void*, const char *, char **),
+         void *pincb_arg,
+         const void *indata, size_t indatalen,
+         unsigned char **outdata, size_t *outdatalen )
 {
   static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
     { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
@@ -381,7 +415,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
     return gpg_error (GPG_ERR_INV_VALUE);
 
   /* Check that the provided ID is vaid.  This is not really needed
-     but we do it to to enforce correct usage by the caller. */
+     but we do it to enforce correct usage by the caller. */
   if (strncmp (keyidstr, "NKS-DF01.", 9) ) 
     return gpg_error (GPG_ERR_INV_ID);
   keyidstr += 9;
@@ -435,9 +469,9 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
 /* Decrypt the data in INDATA and return the allocated result in OUTDATA.
    If a PIN is required the PINCB will be used to ask for the PIN; it
    should return the PIN in an allocated buffer and put it into PIN.  */
-static in
+static gpg_error_
 do_decipher (app_t app, const char *keyidstr,
-             int (pincb)(void*, const char *, char **),
+             gpg_error_t (*pincb)(void*, const char *, char **),
              void *pincb_arg,
              const void *indata, size_t indatalen,
              unsigned char **outdata, size_t *outdatalen )
@@ -452,7 +486,7 @@ do_decipher (app_t app, const char *keyidstr,
   if (!keyidstr || !*keyidstr || !indatalen)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  /* Check that the provided ID is vaid.  This is not really needed
+  /* Check that the provided ID is valid.  This is not really needed
      but we do it to to enforce correct usage by the caller. */
   if (strncmp (keyidstr, "NKS-DF01.", 9) ) 
     return gpg_error (GPG_ERR_INV_ID);
@@ -484,15 +518,15 @@ do_decipher (app_t app, const char *keyidstr,
 
 
 
-/* Select the NKS 2.0 application on the card in SLOT.  */
-int
-app_select_nks (APP app)
+/* Select the NKS 2.0 application.  */
+gpg_error_t
+app_select_nks (app_t app)
 {
   static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 };
   int slot = app->slot;
   int rc;
   
-  rc = iso7816_select_application (slot, aid, sizeof aid);
+  rc = iso7816_select_application (slot, aid, sizeof aid, 0);
   if (!rc)
     {
       app->apptype = "NKS";