card: New command 'authenticate'.
authorWerner Koch <wk@gnupg.org>
Thu, 31 Jan 2019 15:06:47 +0000 (16:06 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 31 Jan 2019 15:06:47 +0000 (16:06 +0100)
* tools/card-tool-misc.c (hex_to_buffer): New.
* tools/gpg-card-tool.c (get_data_from_file): Change to allow returning
a string.
(cmd_authenticate): New.
(cmds): Add command "authenticate".

Signed-off-by: Werner Koch <wk@gnupg.org>
tools/card-tool-misc.c
tools/card-tool.h
tools/gpg-card-tool.c

index 0f5fcc0..06fcb67 100644 (file)
@@ -42,3 +42,38 @@ find_kinfo (card_info_t info, const char *keyref)
       return kinfo;
   return NULL;
 }
+
+
+/* Convert STRING into a newly allocated buffer while translating the
+ * hex numbers.  Blanks and colons are allowed to separate pairs of
+ * hex digits.  Returns NULL on error or a newly malloced buffer and
+ * its length in LENGTH.  */
+void *
+hex_to_buffer (const char *string, size_t *r_length)
+{
+  unsigned char *buffer;
+  const char *s;
+  size_t n;
+
+  buffer = xtrymalloc (strlen (string)+1);
+  if (!buffer)
+    return NULL;
+  for (s=string, n=0; *s; s++)
+    {
+      if (ascii_isspace (*s) || *s == ':')
+        continue;
+      if (hexdigitp (s) && hexdigitp (s+1))
+        {
+          buffer[n++] = xtoi_2 (s);
+          s++;
+        }
+      else
+        {
+          xfree (buffer);
+          gpg_err_set_errno (EINVAL);
+          return NULL;
+        }
+    }
+  *r_length = n;
+  return buffer;
+}
index 05d6ea4..bea618a 100644 (file)
@@ -189,6 +189,7 @@ gpg_error_t test_get_matching_keys (const char *hexgrip);
 
 /*-- card-tool-misc.c --*/
 key_info_t find_kinfo (card_info_t info, const char *keyref);
+void *hex_to_buffer (const char *string, size_t *r_length);
 
 
 /*-- card-call-scd.c --*/
index 07b8bc6..3145229 100644 (file)
@@ -326,8 +326,11 @@ main (int argc, char **argv)
 
 /* Read data from file FNAME up to MAX_GET_DATA_FROM_FILE characters.
  * On error return an error code and stores NULL at R_BUFFER; on
- * success returns 0, stpres the number of bytes read at R_BUFLEN and
- * the address of a newly allocated buffer at R_BUFFER. */
+ * success returns 0 and stores the number of bytes read at R_BUFLEN
+ * and the address of a newly allocated buffer at R_BUFFER.  A
+ * complementary nul byte is always appended to the data but not
+ * counted; this allows to pass NULL for R-BUFFER and consider the
+ * returned data as a string. */
 static gpg_error_t
 get_data_from_file (const char *fname, char **r_buffer, size_t *r_buflen)
 {
@@ -337,7 +340,8 @@ get_data_from_file (const char *fname, char **r_buffer, size_t *r_buflen)
   int n;
 
   *r_buffer = NULL;
-  *r_buflen = 0;
+  if (r_buflen)
+    *r_buflen = 0;
 
   fp = es_fopen (fname, "rb");
   if (!fp)
@@ -356,7 +360,7 @@ get_data_from_file (const char *fname, char **r_buffer, size_t *r_buflen)
       return err;
     }
 
-  n = es_fread (data, 1, MAX_GET_DATA_FROM_FILE, fp);
+  n = es_fread (data, 1, MAX_GET_DATA_FROM_FILE - 1, fp);
   es_fclose (fp);
   if (n < 0)
     {
@@ -365,8 +369,11 @@ get_data_from_file (const char *fname, char **r_buffer, size_t *r_buflen)
       xfree (data);
       return err;
     }
+  data[n] = 0;
+
   *r_buffer = data;
-  *r_buflen = n;
+  if (r_buflen)
+    *r_buflen = n;
   return 0;
 }
 
@@ -951,6 +958,73 @@ cmd_verify (card_info_t info, char *argstr)
 }
 
 
+static gpg_error_t
+cmd_authenticate (card_info_t info, char *argstr)
+{
+  gpg_error_t err;
+  int opt_setkey;
+  int opt_raw;
+  char *string = NULL;
+  char *key = NULL;
+  size_t keylen;
+
+  if (!info)
+    return print_help
+      ("AUTHENTICATE [--setkey] [--raw] [< FILE]|KEY\n\n"
+       "Perform a mutual autentication either by reading the key\n"
+       "from FILE or by taking it from the command line.  Without\n"
+       "the option --raw the key is expected to be hex encoded.\n"
+       "To install a new administration key --setkey is used; this\n"
+       "requires a prior authentication with the old key.",
+       APP_TYPE_PIV, 0);
+
+  if (info->apptype != APP_TYPE_PIV)
+    {
+      log_info ("Note: This is a PIV only command.\n");
+      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+    }
+
+  opt_setkey = has_leading_option (argstr, "--setkey");
+  opt_raw = has_leading_option (argstr, "--raw");
+  argstr = skip_options (argstr);
+
+  if (*argstr == '<')  /* Read key from a file. */
+    {
+      for (argstr++; spacep (argstr); argstr++)
+        ;
+      err = get_data_from_file (argstr, &string, NULL);
+      if (err)
+        goto leave;
+    }
+
+  if (opt_raw)
+    {
+      key = string? string : xstrdup (argstr);
+      string = NULL;
+      keylen = strlen (key);
+    }
+  else
+    {
+      key = hex_to_buffer (string? string: argstr, &keylen);
+      if (!key)
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+    }
+  err = scd_setattr (opt_setkey? "SET-ADM-KEY":"AUTH-ADM-KEY", key, keylen);
+
+ leave:
+  if (key)
+    {
+      wipememory (key, keylen);
+      xfree (key);
+    }
+  xfree (string);
+  return err;
+}
+
+
 /* Helper for cmd_name to qyery a part of name.  */
 static char *
 ask_one_name (const char *prompt)
@@ -2610,7 +2684,7 @@ enum cmdids
     cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSALUT, cmdCAFPR,
     cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
     cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP,
-    cmdKEYATTR, cmdUIF,
+    cmdKEYATTR, cmdUIF, cmdAUTHENTICATE,
     cmdINVCMD
   };
 
@@ -2641,6 +2715,7 @@ static struct
   { "passwd"  , cmdPASSWD, 0, N_("menu to change or unblock the PIN")},
   { "verify"  , cmdVERIFY, 0, N_("verify the PIN and list all data")},
   { "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code")},
+  { "authenticate",cmdAUTHENTICATE, 0,N_("authenticate to the card")},
   { "reset"   , cmdRESET,  0, N_("send a reset to the card daemon")},
   { "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
   { "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
@@ -2871,6 +2946,7 @@ interactive_loop (void)
           if (!err)
             redisplay = 1;
           break;
+        case cmdAUTHENTICATE: err = cmd_authenticate (info, argstr); break;
         case cmdNAME:      err = cmd_name (info, argstr); break;
         case cmdURL:       err = cmd_url (info, argstr);  break;
        case cmdFETCH:     err = cmd_fetch (info);  break;