scd: One new and one improved 7816 function.
authorWerner Koch <wk@gnupg.org>
Sun, 20 Jan 2019 10:41:23 +0000 (11:41 +0100)
committerWerner Koch <wk@gnupg.org>
Sun, 20 Jan 2019 10:41:23 +0000 (11:41 +0100)
* scd/apdu.c (apdu_send_direct): New arg R_SW.
* scd/command.c (cmd_apdu): Ditto.
* scd/iso7816.c (iso7816_apdu_direct): New arg R_SW.
(iso7816_general_authenticate): New.
* scd/app-nks.c (get_chv_status, get_nks_version): Pass NULL for new
arg.
--

iso7816_general_authenticate will be used for the PIV card support.
The new arg to iso7816_apdu_direct and apdu_send_direct allows to get
the raw status word back without the need to handle an output buffer.

Signed-off-by: Werner Koch <wk@gnupg.org>
scd/apdu.c
scd/apdu.h
scd/app-nks.c
scd/command.c
scd/iso7816.c
scd/iso7816.h

index f3e2a12..816938a 100644 (file)
@@ -3063,19 +3063,25 @@ apdu_send_simple (int slot, int extended_mode,
 
 
 /* This is a more generic version of the apdu sending routine.  It
-   takes an already formatted APDU in APDUDATA or length APDUDATALEN
-   and returns with an APDU including the status word.  With
-   HANDLE_MORE set to true this function will handle the MORE DATA
-   status and return all APDUs concatenated with one status word at
-   the end.  If EXTENDED_LENGTH is != 0 extended lengths are allowed
-   with a max. result data length of EXTENDED_LENGTH bytes.  The
-   function does not return a regular status word but 0 on success.
-   If the slot is locked, the function returns immediately with an
-   error.  */
+ * takes an already formatted APDU in APDUDATA or length APDUDATALEN
+ * and returns with an APDU including the status word.  With
+ * HANDLE_MORE set to true this function will handle the MORE DATA
+ * status and return all APDUs concatenated with one status word at
+ * the end.  If EXTENDED_LENGTH is != 0 extended lengths are allowed
+ * with a max. result data length of EXTENDED_LENGTH bytes.  The
+ * function does not return a regular status word but 0 on success.
+ * If the slot is locked, the function returns immediately with an
+ * error.
+ *
+ * Out of historical reasons the function returns 0 on success and
+ * outs the status word at the end of the result to be able to get the
+ * status word in the case of a not provided RETBUF, R_SW can be used
+ * to store the SW.  But note that R_SW qill only be set if the
+ * function returns 0. */
 int
 apdu_send_direct (int slot, size_t extended_length,
                   const unsigned char *apdudata, size_t apdudatalen,
-                  int handle_more,
+                  int handle_more, unsigned int *r_sw,
                   unsigned char **retbuf, size_t *retbuflen)
 {
 #define SHORT_RESULT_BUFFER_SIZE 258
@@ -3282,9 +3288,13 @@ apdu_send_direct (int slot, size_t extended_length,
       (*retbuf)[(*retbuflen)++] = sw;
     }
 
+  if (r_sw)
+    *r_sw = sw;
+
   if (DBG_CARD_IO && retbuf)
     log_printhex (*retbuf, *retbuflen, "      dump: ");
 
+
   return 0;
 }
 
index 8621ddc..1392aab 100644 (file)
@@ -138,7 +138,7 @@ int apdu_send_le (int slot, int extended_mode,
                   unsigned char **retbuf, size_t *retbuflen);
 int apdu_send_direct (int slot, size_t extended_length,
                       const unsigned char *apdudata, size_t apdudatalen,
-                      int handle_more,
+                      int handle_more, unsigned int *r_sw,
                       unsigned char **retbuf, size_t *retbuflen);
 const char *apdu_get_reader_name (int slot);
 
index 9e720f0..801ab90 100644 (file)
@@ -273,7 +273,7 @@ get_chv_status (app_t app, int sigg, int pwid)
   command[3] = pwid;
 
   if (apdu_send_direct (app->slot, 0, (unsigned char *)command,
-                        4, 0, &result, &resultlen))
+                        4, 0, NULL, &result, &resultlen))
     rc = -1; /* Error. */
   else if (resultlen < 2)
     rc = -1; /* Error. */
@@ -1300,7 +1300,7 @@ get_nks_version (int slot)
   int type;
 
   if (iso7816_apdu_direct (slot, "\x80\xaa\x06\x00\x00", 5, 0,
-                           &result, &resultlen))
+                           NULL, &result, &resultlen))
     return 2; /* NKS 2 does not support this command.  */
 
   /* Example value:    04 11 19 22 21 6A 20 80 03 03 01 01 01 00 00 00
index 9df2611..ea4ccbc 100644 (file)
@@ -333,7 +333,7 @@ static const char hlp_learn[] =
   "or a \"CANCEL\" to force the function to terminate with a Cancel\n"
   "error message.\n"
   "\n"
-  "With the option --keypairinfo only KEYPARIINFO lstatus lines are\n"
+  "With the option --keypairinfo only KEYPARIINFO status lines are\n"
   "returned.\n"
   "\n"
   "The response of this command is a list of status lines formatted as\n"
@@ -346,6 +346,7 @@ static const char hlp_learn[] =
   "    P15     = PKCS-15 structure used\n"
   "    DINSIG  = DIN SIG\n"
   "    OPENPGP = OpenPGP card\n"
+  "    PIV     = PIV card\n"
   "    NKS     = NetKey card\n"
   "\n"
   "are implemented.  These strings are aliases for the AID\n"
@@ -1663,7 +1664,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
 
       rc = apdu_send_direct (app->slot, exlen,
                              apdu, apdulen, handle_more,
-                             &result, &resultlen);
+                             NULL, &result, &resultlen);
       if (rc)
         log_error ("apdu_send_direct failed: %s\n", gpg_strerror (rc));
       else
index 43c0bcd..c8a2138 100644 (file)
@@ -50,6 +50,7 @@
 #define CMD_PUT_DATA    0xDA
 #define CMD_MSE         0x22
 #define CMD_PSO         0x2A
+#define CMD_GENERAL_AUTHENTICATE  0x87
 #define CMD_INTERNAL_AUTHENTICATE 0x88
 #define CMD_GENERATE_KEYPAIR      0x47
 #define CMD_GET_CHALLENGE         0x84
@@ -225,24 +226,28 @@ iso7816_list_directory (int slot, int list_dirs,
    internally.  The return value is a gpg error code (i.e. a mapped
    status word).  This is basically the same as apdu_send_direct but
    it maps the status word and does not return it in the result
-   buffer.  */
+   buffer.  However, it R_SW is not NULL the status word is stored
+   R_SW for closer inspection. */
 gpg_error_t
 iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen,
-                     int handle_more,
+                     int handle_more, unsigned int *r_sw,
                      unsigned char **result, size_t *resultlen)
 {
-  int sw;
+  int sw, sw2;
 
-  if (!result || !resultlen)
-    return gpg_error (GPG_ERR_INV_VALUE);
-  *result = NULL;
-  *resultlen = 0;
+  if (result)
+    {
+      *result = NULL;
+      *resultlen = 0;
+    }
 
   sw = apdu_send_direct (slot, 0, apdudata, apdudatalen, handle_more,
-                         result, resultlen);
+                         &sw2, result, resultlen);
   if (!sw)
     {
-      if (*resultlen < 2)
+      if (!result)
+        sw = sw2;
+      else if (*resultlen < 2)
         sw = SW_HOST_GENERAL_ERROR;
       else
         {
@@ -251,13 +256,15 @@ iso7816_apdu_direct (int slot, const void *apdudata, size_t apdudatalen,
           (*resultlen)--;
         }
     }
-  if (sw != SW_SUCCESS)
+  if (sw != SW_SUCCESS && result)
     {
       /* Make sure that pending buffers are released. */
       xfree (*result);
       *result = NULL;
       *resultlen = 0;
     }
+  if (r_sw)
+    *r_sw = sw;
   return map_sw (sw);
 }
 
@@ -621,7 +628,7 @@ iso7816_decipher (int slot, int extended_mode,
 }
 
 
-/*  For LE see do_generate_keypair.  */
+/* For LE see do_generate_keypair.  */
 gpg_error_t
 iso7816_internal_authenticate (int slot, int extended_mode,
                                const unsigned char *data, size_t datalen,
@@ -658,6 +665,44 @@ iso7816_internal_authenticate (int slot, int extended_mode,
 }
 
 
+/* For LE see do_generate_keypair.  */
+gpg_error_t
+iso7816_general_authenticate (int slot, int extended_mode,
+                              int algoref, int keyref,
+                              const unsigned char *data, size_t datalen,
+                              int le,
+                              unsigned char **result, size_t *resultlen)
+{
+  int sw;
+
+  if (!data || !datalen || !result || !resultlen)
+    return gpg_error (GPG_ERR_INV_VALUE);
+  *result = NULL;
+  *resultlen = 0;
+
+  if (!extended_mode)
+    le = 256;  /* Ignore provided Le and use what apdu_send uses. */
+  else if (le >= 0 && le < 256)
+    le = 256;
+
+  sw = apdu_send_le (slot, extended_mode,
+                     0x00, CMD_GENERAL_AUTHENTICATE, algoref, keyref,
+                     datalen, (const char*)data,
+                     le,
+                     result, resultlen);
+  if (sw != SW_SUCCESS)
+    {
+      /* Make sure that pending buffers are released. */
+      xfree (*result);
+      *result = NULL;
+      *resultlen = 0;
+      return map_sw (sw);
+    }
+
+  return 0;
+}
+
+
 /* LE is the expected return length.  This is usually 0 except if
    extended length mode is used and more than 256 byte will be
    returned.  In that case a value of -1 uses a large default
index 332fc0e..4a366e6 100644 (file)
@@ -63,7 +63,7 @@ gpg_error_t iso7816_list_directory (int slot, int list_dirs,
                                     unsigned char **result, size_t *resultlen);
 gpg_error_t iso7816_apdu_direct (int slot,
                                  const void *apdudata, size_t apdudatalen,
-                                 int handle_more,
+                                 int handle_more, unsigned int *r_sw,
                                  unsigned char **result, size_t *resultlen);
 gpg_error_t iso7816_check_pinpad (int slot, int command,
                                   pininfo_t *pininfo);
@@ -104,6 +104,13 @@ gpg_error_t iso7816_internal_authenticate (int slot, int extended_mode,
                                    const unsigned char *data, size_t datalen,
                                    int le,
                                    unsigned char **result, size_t *resultlen);
+gpg_error_t iso7816_general_authenticate (int slot, int extended_mode,
+                                          int algoref, int keyref,
+                                          const unsigned char *data,
+                                          size_t datalen,
+                                          int le,
+                                          unsigned char **result,
+                                          size_t *resultlen);
 gpg_error_t iso7816_generate_keypair (int slot, int extended_mode,
                                     const char *data, size_t datalen,
                                     int le,