[git] GnuPG - branch, master, updated. gnupg-2.1.10-100-g4970868

by Werner Koch cvs at cvs.gnupg.org
Fri Jan 8 17:27:33 CET 2016


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  4970868d8d84d3a64b067e5aafc9f097621758d3 (commit)
       via  34bca9cd4b8517795833cb754b0d5b1dd33b08ed (commit)
      from  2aa42baaf3dd7c3ae613ae0c61760a17c8adfcd0 (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 4970868d8d84d3a64b067e5aafc9f097621758d3
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Jan 8 17:22:32 2016 +0100

    gpg: New command --export-ssh-key
    
    * g10/export.c: Include membuf.h and host2net.h.
    (key_to_sshblob): New.
    (export_ssh_key): New.
    * g10/gpg.c (aExportSshKey): New.
    (opts): Add command.
    (main): Implement that command.
    --
    
    GnuPG-bug-id: 2212
    
    I have done only a few tests rights now and the ECDSA curves do not
    yet work.  However ssh-keygen -l accept RSA and ed25519 keys exported
    using this command.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/g10/export.c b/g10/export.c
index 95ddb9d..f415c1b 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -1,7 +1,7 @@
 /* export.c - Export keys in the OpenPGP defined format.
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
  *               2005, 2010 Free Software Foundation, Inc.
- * Copyright (C) 1998-2015  Werner Koch
+ * Copyright (C) 1998-2016  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -34,6 +34,8 @@
 #include "util.h"
 #include "main.h"
 #include "i18n.h"
+#include "membuf.h"
+#include "host2net.h"
 #include "trustdb.h"
 #include "call-agent.h"
 
@@ -1350,3 +1352,295 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
     log_info(_("WARNING: nothing exported\n"));
   return err;
 }
+
+
+
+

+static gpg_error_t
+key_to_sshblob (membuf_t *mb, const char *identifier, ...)
+{
+  va_list arg_ptr;
+  gpg_error_t err = 0;
+  unsigned char nbuf[4];
+  unsigned char *buf;
+  size_t buflen;
+  gcry_mpi_t a;
+
+  ulongtobuf (nbuf, (ulong)strlen (identifier));
+  put_membuf (mb, nbuf, 4);
+  put_membuf_str (mb, identifier);
+  va_start (arg_ptr, identifier);
+  while ((a = va_arg (arg_ptr, gcry_mpi_t)))
+    {
+      err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, &buf, &buflen, a);
+      if (err)
+        break;
+      if (!strcmp (identifier, "ssh-ed25519")
+          && buflen > 5 && buf[4] == 0x40)
+        {
+          /* We need to strip our 0x40 prefix.  */
+          put_membuf (mb, "\x00\x00\x00\x20", 4);
+          put_membuf (mb, buf+5, buflen-5);
+        }
+      else
+        put_membuf (mb, buf, buflen);
+      gcry_free (buf);
+    }
+  va_end (arg_ptr);
+  return err;
+}
+
+/* Export the key identified by USERID in the SSH public key format.
+   The function exports the latest subkey with Authentication
+   capability unless the '!' suffix is used to export a specific
+   key.  */
+gpg_error_t
+export_ssh_key (ctrl_t ctrl, const char *userid)
+{
+  gpg_error_t err;
+  kbnode_t keyblock = NULL;
+  KEYDB_SEARCH_DESC desc;
+  u32 latest_date;
+  u32 curtime = make_timestamp ();
+  kbnode_t latest_key, node;
+  PKT_public_key *pk;
+  const char *identifier;
+  membuf_t mb;
+  estream_t fp = NULL;
+  struct b64state b64_state;
+  const char *fname = "-";
+
+  init_membuf (&mb, 4096);
+
+  /* We need to know whether the key has been specified using the
+     exact syntax ('!' suffix).  Thus we need to run a
+     classify_user_id on our own.  */
+  err = classify_user_id (userid, &desc, 1);
+
+  /* Get the public key.  */
+  if (!err)
+    {
+      getkey_ctx_t getkeyctx;
+
+      err = get_pubkey_byname (ctrl, &getkeyctx, NULL, userid, &keyblock,
+                               NULL,
+                               0  /* Only usable keys or given exact. */,
+                               1  /* No AKL lookup.  */);
+      if (!err)
+        {
+          err = getkey_next (getkeyctx, NULL, NULL);
+          if (!err)
+            err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
+          else if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
+            err = 0;
+        }
+      getkey_end (getkeyctx);
+    }
+  if (err)
+    {
+      log_error (_("key \"%s\" not found: %s\n"), userid, gpg_strerror (err));
+      return err;
+    }
+
+  /* The finish_lookup code in getkey.c does not handle auth keys,
+     thus we have to duplicate the code here to find the latest
+     subkey.  However, if the key has been found using an exact match
+     ('!' notation) we use that key without any further checks and
+     even allow the use of the primary key. */
+  latest_date = 0;
+  latest_key = NULL;
+  for (node = keyblock; node; node = node->next)
+    {
+      if ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+           || node->pkt->pkttype == PKT_PUBLIC_KEY)
+          && node->pkt->pkt.public_key->flags.exact)
+        {
+          latest_key = node;
+          break;
+        }
+    }
+  if (!latest_key)
+    {
+      for (node = keyblock; node; node = node->next)
+        {
+          if (node->pkt->pkttype != PKT_PUBLIC_SUBKEY)
+            continue;
+
+          pk = node->pkt->pkt.public_key;
+          if (DBG_LOOKUP)
+            log_debug ("\tchecking subkey %08lX\n",
+                       (ulong) keyid_from_pk (pk, NULL));
+          if (!(pk->pubkey_usage & PUBKEY_USAGE_AUTH))
+            {
+              if (DBG_LOOKUP)
+                log_debug ("\tsubkey not usable for authentication\n");
+              continue;
+            }
+          if (!pk->flags.valid)
+            {
+              if (DBG_LOOKUP)
+                log_debug ("\tsubkey not valid\n");
+              continue;
+            }
+          if (pk->flags.revoked)
+            {
+              if (DBG_LOOKUP)
+                log_debug ("\tsubkey has been revoked\n");
+              continue;
+            }
+          if (pk->has_expired)
+            {
+              if (DBG_LOOKUP)
+                log_debug ("\tsubkey has expired\n");
+              continue;
+            }
+          if (pk->timestamp > curtime && !opt.ignore_valid_from)
+            {
+              if (DBG_LOOKUP)
+                log_debug ("\tsubkey not yet valid\n");
+              continue;
+            }
+          if (DBG_LOOKUP)
+            log_debug ("\tsubkey might be fine\n");
+          /* In case a key has a timestamp of 0 set, we make sure that it
+             is used.  A better change would be to compare ">=" but that
+             might also change the selected keys and is as such a more
+             intrusive change.  */
+          if (pk->timestamp > latest_date || (!pk->timestamp && !latest_date))
+            {
+              latest_date = pk->timestamp;
+              latest_key = node;
+            }
+        }
+    }
+
+  if (!latest_key)
+    {
+      err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
+      log_error (_("key \"%s\" not found: %s\n"), userid, gpg_strerror (err));
+      goto leave;
+    }
+
+  pk = latest_key->pkt->pkt.public_key;
+  if (DBG_LOOKUP)
+    log_debug ("\tusing key %08lX\n", (ulong) keyid_from_pk (pk, NULL));
+
+  switch (pk->pubkey_algo)
+    {
+    case PUBKEY_ALGO_DSA:
+      identifier = "ssh-dss";
+      err = key_to_sshblob (&mb, identifier,
+                            pk->pkey[0], pk->pkey[1], pk->pkey[2], pk->pkey[3],
+                            NULL);
+      break;
+
+    case PUBKEY_ALGO_RSA:
+    case PUBKEY_ALGO_RSA_S:
+      identifier = "ssh-rsa";
+      err = key_to_sshblob (&mb, identifier, pk->pkey[1], pk->pkey[0], NULL);
+      break;
+
+    case PUBKEY_ALGO_ECDSA:
+      {
+        char *curveoid;
+        const char *curve;
+
+        curveoid = openpgp_oid_to_str (pk->pkey[0]);
+        if (!curveoid)
+          err = gpg_error_from_syserror ();
+        else if (!(curve = openpgp_oid_to_curve (curveoid, 0)))
+          err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+        else
+          {
+            if (!strcmp (curve, "nistp256"))
+              identifier = "ecdsa-sha2-nistp256";
+            else if (!strcmp (curve, "nistp384"))
+              identifier = "ecdsa-sha2-nistp384";
+            else if (!strcmp (curve, "nistp521"))
+              identifier = "ecdsa-sha2-nistp521";
+            else
+              identifier = NULL;
+
+            if (!identifier)
+              err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+            else
+              err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL);
+          }
+        xfree (curveoid);
+      }
+      break;
+
+    case PUBKEY_ALGO_EDDSA:
+      if (!openpgp_oid_is_ed25519 (pk->pkey[0]))
+        err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
+      else
+        {
+          identifier = "ssh-ed25519";
+          err = key_to_sshblob (&mb, identifier, pk->pkey[1], NULL);
+        }
+      break;
+
+    case PUBKEY_ALGO_ELGAMAL_E:
+    case PUBKEY_ALGO_ELGAMAL:
+      err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
+      break;
+
+    default:
+      err = GPG_ERR_PUBKEY_ALGO;
+      break;
+    }
+
+  if (err)
+    goto leave;
+
+  if (opt.outfile && *opt.outfile && strcmp (opt.outfile, "-"))
+    fp = es_fopen ((fname = opt.outfile), "w");
+  else
+    fp = es_stdout;
+  if (!fp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error (_("error creating '%s': %s\n"), fname, gpg_strerror (err));
+      goto leave;
+    }
+
+  es_fprintf (fp, "%s ", identifier);
+  err = b64enc_start_es (&b64_state, fp, "");
+  if (err)
+    goto leave;
+  {
+    void *blob;
+    size_t bloblen;
+
+    blob = get_membuf (&mb, &bloblen);
+    if (!blob)
+      err = gpg_error_from_syserror ();
+    else
+      err = b64enc_write (&b64_state, blob, bloblen);
+    xfree (blob);
+    if (err)
+      goto leave;
+  }
+  err = b64enc_finish (&b64_state);
+  if (err)
+    goto leave;
+  es_fprintf (fp, " openpgp:0x%08lX\n", (ulong)keyid_from_pk (pk, NULL));
+
+  if (es_ferror (fp))
+    err = gpg_error_from_syserror ();
+  else
+    {
+      if (es_fclose (fp))
+        err = gpg_error_from_syserror ();
+      fp = NULL;
+    }
+
+  if (err)
+    log_error (_("error writing '%s': %s\n"), fname, gpg_strerror (err));
+
+ leave:
+  es_fclose (fp);
+  xfree (get_membuf (&mb, NULL));
+  release_kbnode (keyblock);
+  return err;
+}
diff --git a/g10/gpg.c b/g10/gpg.c
index 9b6a142..4287bda 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1,6 +1,6 @@
 /* gpg.c - The GnuPG utility (main for gpg)
  * Copyright (C) 1998-2011 Free Software Foundation, Inc.
- * Copyright (C) 1997-2014 Werner Koch
+ * Copyright (C) 1997-2016 Werner Koch
  * Copyright (C) 2015 g10 Code GmbH
  *
  * This file is part of GnuPG.
@@ -141,6 +141,7 @@ enum cmd_and_opt_values
     aExport,
     aExportSecret,
     aExportSecretSub,
+    aExportSshKey,
     aCheckKeys,
     aGenRevoke,
     aDesigRevoke,
@@ -453,6 +454,7 @@ static ARGPARSE_OPTS opts[] = {
   ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ),
   ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ),
   ARGPARSE_c (aExportSecretSub, "export-secret-subkeys" , "@" ),
+  ARGPARSE_c (aExportSshKey, "export-ssh-key", "@" ),
   ARGPARSE_c (aImport, "import", N_("import/merge keys")),
   ARGPARSE_c (aFastImport, "fast-import", "@"),
 #ifdef ENABLE_CARD_SUPPORT
@@ -2400,6 +2402,7 @@ main (int argc, char **argv)
 	  case aListSigs:
 	  case aExportSecret:
 	  case aExportSecretSub:
+	  case aExportSshKey:
 	  case aSym:
 	  case aClearsign:
 	  case aGenRevoke:
@@ -4184,6 +4187,17 @@ main (int argc, char **argv)
 	free_strlist(sl);
 	break;
 
+      case aExportSshKey:
+        if (argc != 1)
+          wrong_args ("--export-ssh-key <user-id>");
+        rc = export_ssh_key (ctrl, argv[0]);
+        if (rc)
+          {
+            write_status_failure ("export-ssh-key", rc);
+            log_error (_("export as ssh key failed: %s\n"), gpg_strerror (rc));
+          }
+	break;
+
      case aSearchKeys:
 	sl = NULL;
 	for (; argc; argc--, argv++)
diff --git a/g10/main.h b/g10/main.h
index 0682172..503f262 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -368,6 +368,8 @@ gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
                                        char **cache_nonce_addr, const char *hexgrip,
                                        PKT_public_key *pk);
 
+gpg_error_t export_ssh_key (ctrl_t ctrl, const char *userid);
+
 /*-- dearmor.c --*/
 int dearmor_file( const char *fname );
 int enarmor_file( const char *fname );

commit 34bca9cd4b8517795833cb754b0d5b1dd33b08ed
Author: Werner Koch <wk at gnupg.org>
Date:   Fri Jan 8 15:16:12 2016 +0100

    gpg: Add an exact search flag to the PK struct.
    
    * g10/getkey.c (merge_selfsigs_subkey): Clear exact flag.
    (finish_lookup): Set exact flag.
    * g10/packet.h (PKT_public_key): Add field flags.exact.
    --
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/g10/getkey.c b/g10/getkey.c
index e66be0d..37a5b56 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -2510,6 +2510,7 @@ merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
   keytimestamp = subpk->timestamp;
 
   subpk->flags.valid = 0;
+  subpk->flags.exact = 0;
   subpk->main_keyid[0] = mainpk->main_keyid[0];
   subpk->main_keyid[1] = mainpk->main_keyid[1];
 
@@ -2836,6 +2837,8 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
 
   u32 latest_date;
   KBNODE latest_key;
+  PKT_public_key *pk;
+
 
   assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
 
@@ -2850,6 +2853,8 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
 	      assert (k->pkt->pkttype == PKT_PUBLIC_KEY
 		      || k->pkt->pkttype == PKT_PUBLIC_SUBKEY);
 	      foundk = k;
+              pk = k->pkt->pkt.public_key;
+              pk->flags.exact = 1;
 	      break;
 	    }
 	}
@@ -2893,8 +2898,6 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
       /* Either start a loop or check just this one subkey.  */
       for (k = foundk ? foundk : keyblock; k; k = nextk)
 	{
-	  PKT_public_key *pk;
-
 	  if (foundk)
 	    /* If FOUNDK is not NULL, then only consider that exact
 	       key, i.e., don't iterate.  */
@@ -2968,7 +2971,6 @@ finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
        - we're just considering the primary key.  */
   if ((!latest_key && !ctx->exact) || foundk == keyblock || req_prim)
     {
-      PKT_public_key *pk;
       if (DBG_LOOKUP && !foundk && !req_prim)
 	log_debug ("\tno suitable subkeys found - trying primary\n");
       pk = keyblock->pkt->pkt.public_key;
@@ -3015,7 +3017,7 @@ found:
 
   if (latest_key)
     {
-      PKT_public_key *pk = latest_key->pkt->pkt.public_key;
+      pk = latest_key->pkt->pkt.public_key;
       if (pk->user_id)
 	free_user_id (pk->user_id);
       pk->user_id = scopy_user_id (foundu);
diff --git a/g10/packet.h b/g10/packet.h
index 9eb16cf..16524f8 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -298,6 +298,7 @@ typedef struct
     unsigned int dont_cache:1;    /* Do not cache this key.  */
     unsigned int backsig:2;       /* 0=none, 1=bad, 2=good.  */
     unsigned int serialno_valid:1;/* SERIALNO below is valid.  */
+    unsigned int exact:1;         /* Found via exact (!) search.  */
   } flags;
   PKT_user_id *user_id;   /* If != NULL: found by that uid. */
   struct revocation_key *revkey;

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

Summary of changes:
 g10/export.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 g10/getkey.c |  10 +-
 g10/gpg.c    |  16 +++-
 g10/main.h   |   2 +
 g10/packet.h |   1 +
 5 files changed, 319 insertions(+), 6 deletions(-)


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




More information about the Gnupg-commits mailing list