[git] GnuPG - branch, master, updated. gnupg-2.2.7-359-gfcec5b4

by Werner Koch cvs at cvs.gnupg.org
Thu Feb 7 11:05:55 CET 2019


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  fcec5b40e589b2ef201efb89f22a952feb4a9069 (commit)
       via  090b5f804aee41a36a9ee1fbf0976109970d810d (commit)
      from  b5b1f721582df9d0379cb68b4faeceed32a56e49 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit fcec5b40e589b2ef201efb89f22a952feb4a9069
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Feb 7 11:05:22 2019 +0100

    card: Support reading and writing PIV certificates
    
    * scd/app-piv.c (add_tlv): New.
    (put_data): New.
    (do_writecert): New.
    (do_setattr): Remove usused special mode 0.
    * tools/gpg-card-tool.c (cmd_writecert): Allow other cards than
    OPENPGP.
    (cmd_readcert): Ditto.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/scd/app-piv.c b/scd/app-piv.c
index cfc4a27..59f2725 100644
--- a/scd/app-piv.c
+++ b/scd/app-piv.c
@@ -426,6 +426,157 @@ dump_all_do (int slot)
 }
 
 
+/* Create a TLV tag and value and store it at BUFFER.  Return the
+ * length of tag and length.  A LENGTH greater than 65535 is
+ * truncated.  TAG must be less or equal to 2^16.  If BUFFER is NULL,
+ * only the required length is computed.  */
+static size_t
+add_tlv (unsigned char *buffer, unsigned int tag, size_t length)
+{
+  if (length > 0xffff)
+    length = 0xffff;
+
+  if (buffer)
+    {
+      unsigned char *p = buffer;
+
+      if (tag > 0xff)
+        *p++ = tag >> 8;
+      *p++ = tag;
+      if (length < 128)
+        *p++ = length;
+      else if (length < 256)
+        {
+          *p++ = 0x81;
+          *p++ = length;
+        }
+      else
+        {
+          *p++ = 0x82;
+          *p++ = length >> 8;
+          *p++ = length;
+        }
+
+      return p - buffer;
+    }
+  else
+    {
+      size_t n = 0;
+
+      if (tag > 0xff)
+        n++;
+      n++;
+      if (length < 128)
+        n++;
+      else if (length < 256)
+        n += 2;
+      else
+        n += 3;
+      return n;
+    }
+}
+
+
+/* Wrapper around iso7816_put_data_odd which also sets the tag into
+ * the '5C' data object.  The varargs are tuples of (int,size_t,void)
+ * with the tag, the length and the actual data.  A (0,0,NULL) tuple
+ * terminates the list.  Up to 10 tuples are supported.  */
+static gpg_error_t
+put_data (int slot, unsigned int tag, ...)
+{
+  gpg_error_t err;
+  va_list arg_ptr;
+  struct {
+    int tag;
+    size_t len;
+    const void *data;
+  } argv[10];
+  int i, argc;
+  unsigned char data5c[5];
+  size_t data5clen;
+  unsigned char *data = NULL;
+  size_t datalen;
+  unsigned char *p;
+  size_t n;
+
+  /* Collect all args.  Check that length is <= 2^16 to match the
+   * behaviour of add_tlv.  */
+  va_start (arg_ptr, tag);
+  argc = 0;
+  while (((argv[argc].tag = va_arg (arg_ptr, int))))
+    {
+      argv[argc].len = va_arg (arg_ptr, size_t);
+      argv[argc].data = va_arg (arg_ptr, const void *);
+      if (argc >= DIM (argv)-1 || argv[argc].len > 0xffff)
+        {
+          va_end (arg_ptr);
+          return GPG_ERR_EINVAL;
+        }
+      argc++;
+    }
+  va_end (arg_ptr);
+
+  /* Build the TLV with the tag to be updated.  */
+  data5c[0] = 0x5c; /* Tag list */
+  if (tag <= 0xff)
+    {
+      data5c[1] = 1;
+      data5c[2] = tag;
+      data5clen = 3;
+    }
+  else if (tag <= 0xffff)
+    {
+      data5c[1] = 2;
+      data5c[2] = (tag >> 8);
+      data5c[3] = tag;
+      data5clen = 4;
+    }
+  else
+    {
+      data5c[1] = 3;
+      data5c[2] = (tag >> 16);
+      data5c[3] = (tag >> 8);
+      data5c[4] = tag;
+      data5clen = 5;
+    }
+
+  /* Compute the required buffer length and allocate the buffer.  */
+  n = 0;
+  for (i=0; i < argc; i++)
+    {
+      n += add_tlv (NULL, argv[i].tag, argv[i].len);
+      n += argv[i].len;
+    }
+  datalen = data5clen + add_tlv (NULL, 0x53, n) + n;
+  data = xtrymalloc (datalen);
+  if (!data)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+
+  /* Copy that data to the buffer.  */
+  p = data;
+  memcpy (p, data5c, data5clen);
+  p += data5clen;
+  p += add_tlv (p, 0x53, n);
+  for (i=0; i < argc; i++)
+    {
+      p += add_tlv (p, argv[i].tag, argv[i].len);
+      memcpy (p, argv[i].data, argv[i].len);
+      p += argv[i].len;
+    }
+  log_assert ( data + datalen == p );
+  log_printhex (data, datalen, "Put data");
+  err = iso7816_put_data_odd (slot, -1 /* use command chaining */,
+                              0x3fff, data, datalen);
+
+ leave:
+  xfree (data);
+  return err;
+}
+
+
 /* Parse the key reference KEYREFSTR which is expected to hold a key
  * reference for a CHV object.  Return the one octet keyref or -1 for
  * an invalid reference.  */
@@ -802,13 +953,6 @@ do_setattr (app_t app, const char *name,
 
   switch (table[idx].special)
     {
-    case 0:
-      err = iso7816_put_data (app->slot, 0, table[idx].tag, value, valuelen);
-      if (err)
-        log_error ("failed to set '%s': %s\n",
-                   table[idx].name, gpg_strerror (err));
-      break;
-
     case 1:
       err = auth_adm_key (app, value, valuelen);
       break;
@@ -2062,6 +2206,45 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keyrefstr, const char *keytype,
 }
 
 
+/* Write the certificate (CERT,CERTLEN) to the card at CERTREFSTR.
+ * CERTREFSTR is either the OID of the certificate's container data
+ * object or of the form "PIV.<two_hexdigit_keyref>". */
+static gpg_error_t
+do_writecert (app_t app, ctrl_t ctrl,
+              const char *certrefstr,
+              gpg_error_t (*pincb)(void*, const char *, char **),
+              void *pincb_arg,
+              const unsigned char *cert, size_t certlen)
+{
+  gpg_error_t err;
+  data_object_t dobj;
+
+  (void)ctrl;
+  (void)pincb;     /* Not used; instead authentication is needed.  */
+  (void)pincb_arg;
+
+  dobj = find_dobj_by_keyref (app, certrefstr);
+  if (!dobj || !*dobj->keyref)
+    return gpg_error (GPG_ERR_INV_ID);
+
+  /* FIXME: Check that the authentication has already been done.  */
+
+  flush_cached_data (app, dobj->tag);
+
+  err = put_data (app->slot, dobj->tag,
+                  (int)0x70, (size_t)certlen, cert,/* Certificate */
+                  (int)0x71, (size_t)1,       "",  /* No compress */
+                  (int)0xfe, (size_t)0,       "",  /* Empty LRC. */
+                  (int)0,    (size_t)0,       NULL);
+  if (err)
+    log_error ("piv: failed to write cert to %s: %s\n",
+               dobj->keyref, gpg_strerror (err));
+
+
+  return err;
+}
+
+
 /* Select the PIV application on the card in SLOT.  This function must
  * be used before any other PIV application functions. */
 gpg_error_t
@@ -2152,7 +2335,7 @@ app_select_piv (app_t app)
   app->fnc.readkey = do_readkey;
   app->fnc.getattr = do_getattr;
   app->fnc.setattr = do_setattr;
-  /* app->fnc.writecert = do_writecert; */
+  app->fnc.writecert = do_writecert;
   /* app->fnc.writekey = do_writekey; */
   app->fnc.genkey = do_genkey;
   /* app->fnc.sign = do_sign; */
diff --git a/tools/gpg-card-tool.c b/tools/gpg-card-tool.c
index 08248f7..9170132 100644
--- a/tools/gpg-card-tool.c
+++ b/tools/gpg-card-tool.c
@@ -1551,36 +1551,41 @@ cmd_writecert (card_info_t info, char *argstr)
 {
   gpg_error_t err;
   int opt_clear;
-  int do_no;
+  char *certref_buffer = NULL;
+  char *certref;
   char *data = NULL;
   size_t datalen;
 
   if (!info)
     return print_help
-      ("WRITECERT [--clear] 3 < FILE\n\n"
+      ("WRITECERT [--clear] CERTREF < FILE\n\n"
        "Write a certificate for key 3.  Unless --clear is given\n"
-       "the file argement is mandatory.  The option --clear removes\n"
+       "the file argument is mandatory.  The option --clear removes\n"
        "the certificate from the card.",
-       APP_TYPE_OPENPGP, 0);
+       APP_TYPE_OPENPGP, APP_TYPE_PIV, 0);
 
   opt_clear = has_leading_option (argstr, "--clear");
   argstr = skip_options (argstr);
 
-  if (digitp (argstr))
+  certref = argstr;
+  if ((argstr = strchr (certref, ' ')))
     {
-      do_no = atoi (argstr);
-      while (digitp (argstr))
-        argstr++;
-      while (spacep (argstr))
-        argstr++;
+      *argstr++ = 0;
+      trim_spaces (certref);
+      trim_spaces (argstr);
     }
-  else
-    do_no = 0;
+  else /* Let argstr point to an empty string.  */
+    argstr = certref + strlen (certref);
 
-  if (do_no != 3)
+  if (info->apptype == APP_TYPE_OPENPGP)
     {
-      err = gpg_error (GPG_ERR_INV_ARG);
-      goto leave;
+      if (ascii_strcasecmp (certref, "OPENPGP.3") && strcmp (certref, "3"))
+        {
+          err = gpg_error (GPG_ERR_INV_ID);
+          log_error ("Error: CERTREF must be \"3\" or \"OPENPGP.3\"\n");
+          goto leave;
+        }
+      certref = certref_buffer = xstrdup ("OPENPGP.3");
     }
 
   if (opt_clear)
@@ -1602,10 +1607,11 @@ cmd_writecert (card_info_t info, char *argstr)
       goto leave;
     }
 
-  err = scd_writecert ("OPENPGP.3", data, datalen);
+  err = scd_writecert (certref, data, datalen);
 
  leave:
   xfree (data);
+  xfree (certref_buffer);
   return err;
 }
 
@@ -1614,37 +1620,42 @@ static gpg_error_t
 cmd_readcert (card_info_t info, char *argstr)
 {
   gpg_error_t err;
-  int do_no;
+  char *certref_buffer = NULL;
+  char *certref;
   void *data = NULL;
   size_t datalen;
   const char *fname;
 
   if (!info)
     return print_help
-      ("READCERT 3 > FILE\n\n"
+      ("READCERT CERTREF > FILE\n\n"
        "Read the certificate for key 3 and store it in FILE.",
-       APP_TYPE_OPENPGP, 0);
+       APP_TYPE_OPENPGP, APP_TYPE_PIV, 0);
 
   argstr = skip_options (argstr);
 
-  if (digitp (argstr))
+  certref = argstr;
+  if ((argstr = strchr (certref, ' ')))
     {
-      do_no = atoi (argstr);
-      while (digitp (argstr))
-        argstr++;
-      while (spacep (argstr))
-        argstr++;
+      *argstr++ = 0;
+      trim_spaces (certref);
+      trim_spaces (argstr);
     }
-  else
-    do_no = 0;
+  else /* Let argstr point to an empty string.  */
+    argstr = certref + strlen (certref);
 
-  if (do_no != 3)
+  if (info->apptype == APP_TYPE_OPENPGP)
     {
-      err = gpg_error (GPG_ERR_INV_ARG);
-      goto leave;
+      if (ascii_strcasecmp (certref, "OPENPGP.3") && strcmp (certref, "3"))
+        {
+          err = gpg_error (GPG_ERR_INV_ID);
+          log_error ("Error: CERTREF must be \"3\" or \"OPENPGP.3\"\n");
+          goto leave;
+        }
+      certref = certref_buffer = xstrdup ("OPENPGP.3");
     }
 
-  if (*argstr == '>')  /* Read it from a file */
+  if (*argstr == '>')  /* Write it to a file */
     {
       for (argstr++; spacep (argstr); argstr++)
         ;
@@ -1656,7 +1667,7 @@ cmd_readcert (card_info_t info, char *argstr)
       goto leave;
     }
 
-  err = scd_readcert ("OPENPGP.3", &data, &datalen);
+  err = scd_readcert (certref, &data, &datalen);
   if (err)
     goto leave;
 
@@ -1664,6 +1675,7 @@ cmd_readcert (card_info_t info, char *argstr)
 
  leave:
   xfree (data);
+  xfree (certref_buffer);
   return err;
 }
 

commit 090b5f804aee41a36a9ee1fbf0976109970d810d
Author: Werner Koch <wk at gnupg.org>
Date:   Thu Feb 7 08:16:02 2019 +0100

    card: Add readline completion for help arguments
    
    --

diff --git a/tools/gpg-card-tool.c b/tools/gpg-card-tool.c
index fd7aa9a..08248f7 100644
--- a/tools/gpg-card-tool.c
+++ b/tools/gpg-card-tool.c
@@ -3249,9 +3249,12 @@ command_completion (const char *text, int start, int end)
   (void)end;
 
   /* If we are at the start of a line, we try and command-complete.
-   * If not, just do nothing for now. */
+   * If not, just do nothing for now.  The support for help completion
+   * needs to be more smarter. */
   if (!start)
     return rl_completion_matches (text, command_generator);
+  else if (start == 5 && !ascii_strncasecmp (rl_line_buffer, "help ", 5))
+    return rl_completion_matches (text, command_generator);
 
   rl_attempted_completion_over = 1;
 

-----------------------------------------------------------------------

Summary of changes:
 scd/app-piv.c         | 199 ++++++++++++++++++++++++++++++++++++++++++++++++--
 tools/gpg-card-tool.c |  81 +++++++++++---------
 2 files changed, 239 insertions(+), 41 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list