[git] GnuPG - branch, master, updated. gnupg-2.1.0beta3-385-gdb3b528

by Werner Koch cvs at cvs.gnupg.org
Tue Apr 15 19:48:05 CEST 2014


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  db3b528239c9d56bc71fd2283e07a3f1d91e4fd0 (commit)
       via  d25d00b89efed461d344028d0e2e2be38cc77628 (commit)
       via  c4d983239a3f0a18c77f0a5aeba520a81a1b86e8 (commit)
       via  e549799db66be30cdd68a3e6cdca9c6a050466d1 (commit)
       via  e3a4ff89a0b106e678bf9d0a4d47917123071140 (commit)
      from  3132bd90dc8db9c7fd19ba201918e95891306dc5 (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 db3b528239c9d56bc71fd2283e07a3f1d91e4fd0
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Apr 15 16:40:48 2014 +0200

    gpg: Re-enable secret key deletion.
    
    * g10/call-agent.c (agent_delete_key): New.
    * g10/keydb.h (FORMAT_KEYDESC_DELKEY): New.
    * g10/passphrase.c (gpg_format_keydesc): Support new format.
    * g10/delkey.c (do_delete_key): Add secret key deletion.

diff --git a/doc/DETAILS b/doc/DETAILS
index 3f9e747..03c200e 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -818,6 +818,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
     - 1 :: No such key
     - 2 :: Must delete secret key first
     - 3 :: Ambigious specification
+    - 4 :: Key is stored on a smartcard.
 
 *** PROGRESS <what> <char> <cur> <total>
     Used by the primegen and Public key functions to indicate
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 4ce6a06..5ad0983 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -2127,6 +2127,44 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
 
 
 

+/* Ask the agent to delete the key identified by HEXKEYGRIP.  If DESC
+   is not NULL, display DESC instead of the default description
+   message.  */
+gpg_error_t
+agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
+{
+  gpg_error_t err;
+  char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s dfltparm;
+
+  memset (&dfltparm, 0, sizeof dfltparm);
+  dfltparm.ctrl = ctrl;
+
+  err = start_agent (ctrl, 0);
+  if (err)
+    return err;
+
+  if (!hexkeygrip || strlen (hexkeygrip) != 40)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  if (desc)
+    {
+      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+      err = assuan_transact (agent_ctx, line,
+                             NULL, NULL, NULL, NULL, NULL, NULL);
+      if (err)
+        return err;
+    }
+
+  snprintf (line, DIM(line)-1, "DELETE_KEY %s", hexkeygrip);
+  err = assuan_transact (agent_ctx, line, NULL, NULL,
+                         default_inq_cb, &dfltparm,
+                         NULL, NULL);
+  return err;
+}
+
+
+

 /* Ask the agent to change the passphrase of the key identified by
    HEXKEYGRIP.  If DESC is not NULL, display DESC instead of the
    default description message.  If CACHE_NONCE_ADDR is not NULL the
diff --git a/g10/call-agent.h b/g10/call-agent.h
index 2b944d2..1deb854 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -185,6 +185,10 @@ gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip,
                               const char *desc, char **cache_nonce_addr,
                               unsigned char **r_result, size_t *r_resultlen);
 
+/* Delete a key from the agent.  */
+gpg_error_t agent_delete_key (ctrl_t ctrl, const char *hexkeygrip,
+                              const char *desc);
+
 /* Change the passphrase of a key.  */
 gpg_error_t agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
                           char **cache_nonce_addr, char **passwd_nonce_addr);
diff --git a/g10/delkey.c b/g10/delkey.c
index 2e4477b..3de705d 100644
--- a/g10/delkey.c
+++ b/g10/delkey.c
@@ -40,6 +40,7 @@
 #include "ttyio.h"
 #include "status.h"
 #include "i18n.h"
+#include "call-agent.h"
 
 
 /****************
@@ -52,7 +53,7 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
 {
   gpg_error_t err;
   kbnode_t keyblock = NULL;
-  kbnode_t node;
+  kbnode_t node, kbctx;
   KEYDB_HANDLE hd;
   PKT_public_key *pk = NULL;
   u32 keyid[2];
@@ -156,9 +157,47 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
     {
       if (secret)
 	{
-	  log_error (_("deleting secret key not implemented\n"));
-	  err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* FIXME */
-	  goto leave;
+          char *prompt;
+          gpg_error_t firsterr = 0;
+          char *hexgrip;
+
+          setup_main_keyids (keyblock);
+          for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
+            {
+              if (!(node->pkt->pkttype == PKT_PUBLIC_KEY
+                    || node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
+                continue;
+
+              if (agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
+                continue;  /* No secret key for that public (sub)key.  */
+
+              prompt = gpg_format_keydesc (node->pkt->pkt.public_key,
+                                           FORMAT_KEYDESC_DELKEY, 1);
+              err = hexkeygrip_from_pk (node->pkt->pkt.public_key, &hexgrip);
+              if (!err)
+                err = agent_delete_key (NULL, hexgrip, prompt);
+              xfree (prompt);
+              xfree (hexgrip);
+              if (err)
+                {
+                  if (gpg_err_code (err) == GPG_ERR_KEY_ON_CARD)
+                    write_status_text (STATUS_DELETE_PROBLEM, "1");
+                  log_error (_("deleting secret %s failed: %s\n"),
+                             (node->pkt->pkttype == PKT_PUBLIC_KEY
+                              ? _("key"):_("subkey")),
+                             gpg_strerror (err));
+                  if (!firsterr)
+                    firsterr = err;
+                  if (gpg_err_code (err) == GPG_ERR_CANCELED
+                      || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
+                    break;
+                }
+
+            }
+
+          err = firsterr;
+          if (firsterr)
+            goto leave;
 	}
       else
 	{
diff --git a/g10/getkey.c b/g10/getkey.c
index 777f383..458672a 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1237,6 +1237,38 @@ getkey_end (getkey_ctx_t ctx)
  ************* Merging stuff ********************
  ************************************************/
 
+/* Set the mainkey_id fields for all keys in KEYBLOCK.  This is
+   usually done by merge_selfsigs but at some places we only need the
+   main_kid but the the full merging.  The function also guarantees
+   that all pk->keyids are computed. */
+void
+setup_main_keyids (kbnode_t keyblock)
+{
+  u32 kid[2], mainkid[2];
+  kbnode_t kbctx, node;
+  PKT_public_key *pk;
+
+  if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
+    BUG ();
+  pk = keyblock->pkt->pkt.public_key;
+
+  keyid_from_pk (pk, mainkid);
+  for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
+    {
+      if (!(node->pkt->pkttype == PKT_PUBLIC_KEY
+            || node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
+        continue;
+      pk = node->pkt->pkt.public_key;
+      keyid_from_pk (pk, kid); /* Make sure pk->keyid is set.  */
+      if (!pk->main_keyid[0] && !pk->main_keyid[1])
+        {
+          pk->main_keyid[0] = mainkid[0];
+          pk->main_keyid[1] = mainkid[1];
+        }
+    }
+}
+
+
 /* Merge all self-signatures with the keys.  */
 void
 merge_keys_and_selfsig (KBNODE keyblock)
diff --git a/g10/keydb.h b/g10/keydb.h
index 492cde3..b21d955 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -201,7 +201,7 @@ void emit_status_need_passphrase (u32 *keyid, u32 *mainkeyid, int pubkey_algo);
 #define FORMAT_KEYDESC_NORMAL  0
 #define FORMAT_KEYDESC_IMPORT  1
 #define FORMAT_KEYDESC_EXPORT  2
-
+#define FORMAT_KEYDESC_DELKEY  3
 char *gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped);
 
 
@@ -248,6 +248,7 @@ void getkey_end (getkey_ctx_t ctx);
 
 gpg_error_t enum_secret_keys (void **context, PKT_public_key *pk);
 
+void setup_main_keyids (kbnode_t keyblock);
 void merge_keys_and_selfsig( KBNODE keyblock );
 char*get_user_id_string( u32 *keyid );
 char*get_user_id_string_native( u32 *keyid );
diff --git a/g10/passphrase.c b/g10/passphrase.c
index 7c1d6aa..280d8a9 100644
--- a/g10/passphrase.c
+++ b/g10/passphrase.c
@@ -702,7 +702,7 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
                        (int)uidlen, uid,
                        nbits_from_pk (pk), algo_name,
                        keystr (pk->keyid), timestr,
-                       maink?maink:"", trailer );
+                       maink?maink:"", trailer);
   xfree (maink);
   xfree (uid);
 

commit d25d00b89efed461d344028d0e2e2be38cc77628
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Apr 15 15:29:45 2014 +0200

    gpg: Re-indent a file.
    
    * g10/delkey.c: Re-indent.
    (do_delete_key, delete_keys): Change return type top gpg_error_t.

diff --git a/g10/delkey.c b/g10/delkey.c
index 22f2219..2e4477b 100644
--- a/g10/delkey.c
+++ b/g10/delkey.c
@@ -1,6 +1,7 @@
 /* delkey.c - delete keys
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004,
  *               2005, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -46,171 +47,189 @@
  * r_sec_avail will be set if a secret key is available and the public
  * key can't be deleted for that reason.
  */
-static int
+static gpg_error_t
 do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
 {
-    int rc = 0;
-    KBNODE keyblock = NULL;
-    KBNODE node;
-    KEYDB_HANDLE hd = keydb_new ();
-    PKT_public_key *pk = NULL;
-    u32 keyid[2];
-    int okay=0;
-    int yes;
-    KEYDB_SEARCH_DESC desc;
-    int exactmatch;
-
-    *r_sec_avail = 0;
-
-    /* Search the userid */
-    rc = classify_user_id (username, &desc, 1);
-    exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR
-                  || desc.mode == KEYDB_SEARCH_MODE_FPR16
-                  || desc.mode == KEYDB_SEARCH_MODE_FPR20);
-    if (!rc)
-      rc = keydb_search (hd, &desc, 1, NULL);
-    if (rc) {
-	log_error (_("key \"%s\" not found: %s\n"), username, g10_errstr (rc));
-	write_status_text( STATUS_DELETE_PROBLEM, "1" );
-	goto leave;
+  gpg_error_t err;
+  kbnode_t keyblock = NULL;
+  kbnode_t node;
+  KEYDB_HANDLE hd;
+  PKT_public_key *pk = NULL;
+  u32 keyid[2];
+  int okay=0;
+  int yes;
+  KEYDB_SEARCH_DESC desc;
+  int exactmatch;
+
+  *r_sec_avail = 0;
+
+  hd = keydb_new ();
+
+  /* Search the userid.  */
+  err = classify_user_id (username, &desc, 1);
+  exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR
+                || desc.mode == KEYDB_SEARCH_MODE_FPR16
+                || desc.mode == KEYDB_SEARCH_MODE_FPR20);
+  if (!err)
+    err = keydb_search (hd, &desc, 1, NULL);
+  if (err)
+    {
+      log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err));
+      write_status_text (STATUS_DELETE_PROBLEM, "1");
+      goto leave;
     }
 
-    /* read the keyblock */
-    rc = keydb_get_keyblock (hd, &keyblock );
-    if (rc) {
-	log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
-	goto leave;
+  /* Read the keyblock.  */
+  err = keydb_get_keyblock (hd, &keyblock);
+  if (err)
+    {
+      log_error (_("error reading keyblock: %s\n"), gpg_strerror (err) );
+      goto leave;
     }
 
-    /* get the keyid from the keyblock */
-    node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
-    if( !node ) {
-	log_error("Oops; key not found anymore!\n");
-	rc = G10ERR_GENERAL;
-	goto leave;
+  /* Get the keyid from the keyblock.  */
+  node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
+  if (!node)
+    {
+      log_error ("Oops; key not found anymore!\n");
+      err = gpg_error (GPG_ERR_GENERAL);
+      goto leave;
+    }
+  pk = node->pkt->pkt.public_key;
+  keyid_from_pk (pk, keyid);
+
+  if (!secret && !force)
+    {
+      if (have_secret_key_with_kid (keyid))
+        {
+          *r_sec_avail = 1;
+          err = gpg_error (GPG_ERR_EOF);
+          goto leave;
+        }
+      else
+        err = 0;
     }
 
-    pk = node->pkt->pkt.public_key;
-    keyid_from_pk( pk, keyid );
-
-    if (!secret && !force)
-      {
-        if (have_secret_key_with_kid (keyid))
-          {
-            *r_sec_avail = 1;
-            rc = -1;
-            goto leave;
-          }
-        else
-          rc = 0;
-      }
-
-    if( rc )
-	rc = 0;
-    else if (opt.batch && exactmatch)
-        okay++;
-    else if( opt.batch && secret )
-      {
-	log_error(_("can't do this in batch mode\n"));
-        log_info (_("(unless you specify the key by fingerprint)\n"));
-      }
-    else if( opt.batch && opt.answer_yes )
-	okay++;
-    else if( opt.batch )
-      {
-	log_error(_("can't do this in batch mode without \"--yes\"\n"));
-        log_info (_("(unless you specify the key by fingerprint)\n"));
-      }
-    else {
-        if( secret )
-            print_seckey_info (pk);
-        else
-            print_pubkey_info (NULL, pk );
-	tty_printf( "\n" );
-
-	yes = cpr_get_answer_is_yes( secret? "delete_key.secret.okay"
-					   : "delete_key.okay",
-			      _("Delete this key from the keyring? (y/N) "));
-	if( !cpr_enabled() && secret && yes ) {
-	    /* I think it is not required to check a passphrase; if
-	     * the user is so stupid as to let others access his secret keyring
-	     * (and has no backup) - it is up him to read some very
-	     * basic texts about security.
-	     */
-	    yes = cpr_get_answer_is_yes("delete_key.secret.okay",
-			 _("This is a secret key! - really delete? (y/N) "));
+  if (opt.batch && exactmatch)
+    okay++;
+  else if (opt.batch && secret)
+    {
+      log_error(_("can't do this in batch mode\n"));
+      log_info (_("(unless you specify the key by fingerprint)\n"));
+    }
+  else if (opt.batch && opt.answer_yes)
+    okay++;
+  else if (opt.batch)
+    {
+      log_error(_("can't do this in batch mode without \"--yes\"\n"));
+      log_info (_("(unless you specify the key by fingerprint)\n"));
+    }
+  else
+    {
+      if (secret)
+        print_seckey_info (pk);
+      else
+        print_pubkey_info (NULL, pk );
+      tty_printf( "\n" );
+
+      yes = cpr_get_answer_is_yes
+        (secret? "delete_key.secret.okay": "delete_key.okay",
+         _("Delete this key from the keyring? (y/N) "));
+
+      if (!cpr_enabled() && secret && yes)
+        {
+          /* I think it is not required to check a passphrase; if the
+           * user is so stupid as to let others access his secret
+           * keyring (and has no backup) - it is up him to read some
+           * very basic texts about security.  */
+          yes = cpr_get_answer_is_yes
+            ("delete_key.secret.okay",
+             _("This is a secret key! - really delete? (y/N) "));
 	}
-	if( yes )
-	    okay++;
+
+      if (yes)
+        okay++;
     }
 
 
-    if( okay ) {
+  if (okay)
+    {
       if (secret)
 	{
 	  log_error (_("deleting secret key not implemented\n"));
-	  rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* FIXME */
+	  err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* FIXME */
 	  goto leave;
 	}
       else
 	{
-	  rc = keydb_delete_keyblock (hd);
-	  if (rc) {
-	    log_error (_("deleting keyblock failed: %s\n"), g10_errstr(rc) );
-	    goto leave;
-	  }
+	  err = keydb_delete_keyblock (hd);
+	  if (err)
+            {
+              log_error (_("deleting keyblock failed: %s\n"),
+                         gpg_strerror (err));
+              goto leave;
+            }
 	}
 
       /* Note that the ownertrust being cleared will trigger a
 	 revalidation_mark().  This makes sense - only deleting keys
 	 that have ownertrust set should trigger this. */
 
-      if (!secret && pk && clear_ownertrusts (pk)) {
-	if (opt.verbose)
-	  log_info (_("ownertrust information cleared\n"));
-      }
+      if (!secret && pk && clear_ownertrusts (pk))
+        {
+          if (opt.verbose)
+            log_info (_("ownertrust information cleared\n"));
+        }
     }
 
-  leave:
-    keydb_release (hd);
-    release_kbnode (keyblock);
-    return rc;
+ leave:
+  keydb_release (hd);
+  release_kbnode (keyblock);
+  return err;
 }
 
 /****************
  * Delete a public or secret key from a keyring.
  */
-int
-delete_keys( strlist_t names, int secret, int allow_both )
+gpg_error_t
+delete_keys (strlist_t names, int secret, int allow_both)
 {
-    int rc, avail, force=(!allow_both && !secret && opt.expert);
-
-    /* Force allows us to delete a public key even if a secret key
-       exists. */
-
-    for(;names;names=names->next) {
-       rc = do_delete_key (names->d, secret, force, &avail );
-       if ( rc && avail ) {
-	 if ( allow_both ) {
-	   rc = do_delete_key (names->d, 1, 0, &avail );
-	   if ( !rc )
-	     rc = do_delete_key (names->d, 0, 0, &avail );
-	 }
-	 else {
-	   log_error(_(
-	      "there is a secret key for public key \"%s\"!\n"),names->d);
-	   log_info(_(
-	      "use option \"--delete-secret-keys\" to delete it first.\n"));
-	   write_status_text( STATUS_DELETE_PROBLEM, "2" );
-	   return rc;
-	 }
-       }
-
-       if(rc) {
-	 log_error("%s: delete key failed: %s\n", names->d, g10_errstr(rc) );
-	 return rc;
-       }
+  gpg_error_t err;
+  int avail;
+  int force = (!allow_both && !secret && opt.expert);
+
+  /* Force allows us to delete a public key even if a secret key
+     exists. */
+
+  for ( ;names ; names=names->next )
+    {
+      err = do_delete_key (names->d, secret, force, &avail);
+      if (err && avail)
+        {
+          if (allow_both)
+            {
+              err = do_delete_key (names->d, 1, 0, &avail);
+              if (!err)
+                err = do_delete_key (names->d, 0, 0, &avail);
+            }
+          else
+            {
+              log_error (_("there is a secret key for public key \"%s\"!\n"),
+                         names->d);
+              log_info(_("use option \"--delete-secret-keys\" to delete"
+                         " it first.\n"));
+              write_status_text (STATUS_DELETE_PROBLEM, "2");
+              return err;
+            }
+        }
+
+      if (err)
+        {
+          log_error ("%s: delete key failed: %s\n",
+                     names->d, gpg_strerror (err));
+          return err;
+        }
     }
 
-    return 0;
+  return 0;
 }
diff --git a/g10/main.h b/g10/main.h
index ce77a83..04abb4f 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -230,7 +230,7 @@ int check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
 			  u32 *r_expiredate, int *r_expired );
 
 /*-- delkey.c --*/
-int delete_keys( strlist_t names, int secret, int allow_both );
+gpg_error_t delete_keys (strlist_t names, int secret, int allow_both);
 
 /*-- keyedit.c --*/
 void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,

commit c4d983239a3f0a18c77f0a5aeba520a81a1b86e8
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Apr 15 16:40:48 2014 +0200

    gpg: Fix regression in secret key export.
    
    * agent/cvt-openpgp.c (convert_to_openpgp): Fix use
    gcry_sexp_extract_param.
    * g10/export.c (do_export_stream): Provide a proper prompt to the
    agent.
    --
    
    NB: The export needs more work, in particular the ECC algorithms.

diff --git a/agent/command.c b/agent/command.c
index 52876a9..e17232e 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -2147,7 +2147,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
 
   if (!ctrl->server_local->export_key)
     {
-      err = set_error (GPG_ERR_MISSING_KEY, "did you run KEYWRAP_KEY");
+      err = set_error (GPG_ERR_MISSING_KEY, "did you run KEYWRAP_KEY ?");
       goto leave;
     }
 
diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c
index 5718bd9..4c34130 100644
--- a/agent/cvt-openpgp.c
+++ b/agent/cvt-openpgp.c
@@ -1,7 +1,7 @@
 /* cvt-openpgp.c - Convert an OpenPGP key to our internal format.
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2006, 2009,
  *               2010 Free Software Foundation, Inc.
- * Copyright (C) 2013 Werner Koch
+ * Copyright (C) 2013, 2014 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -1134,7 +1134,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
   gcry_sexp_t list, l2;
   char *name;
   const char *algoname;
-  const char *elems;
   int npkey, nskey;
   gcry_mpi_t array[10];
   char protect_iv[16];
@@ -1170,55 +1169,62 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
     {
       algoname = "rsa";
       npkey = 2;
-      elems = "nedpqu";
+      nskey = 6;
+      err = gcry_sexp_extract_param (list, NULL, "nedpqu",
+                                     array+0, array+1, array+2, array+3,
+                                     array+4, array+5, NULL);
     }
   else if (!strcmp (name, "elg"))
     {
       algoname = "elg";
       npkey = 3;
-      elems = "pgyx";
+      nskey = 4;
+      err = gcry_sexp_extract_param (list, NULL, "pgyx",
+                                     array+0, array+1, array+2, array+3,
+                                     NULL);
     }
   else if (!strcmp (name, "dsa"))
     {
       algoname = "dsa";
       npkey = 4;
-      elems = "pqgyx";
+      nskey = 5;
+      err = gcry_sexp_extract_param (list, NULL, "pqgyx",
+                                     array+0, array+1, array+2, array+3,
+                                     array+4, NULL);
     }
   else if (!strcmp (name, "ecc"))
     {
+      /* FIXME: We need to use the curve parameter.  */
       algoname = "?"; /* Decide later by checking the usage.  */
       npkey = 6;
-      elems = "pabgnqd";
+      nskey = 7;
+      err = gcry_sexp_extract_param (list, NULL, "pabgnqd",
+                                     array+0, array+1, array+2, array+3,
+                                     array+4, array+5, array+6, NULL);
     }
   else if (!strcmp (name, "ecdsa"))
     {
       algoname = "ecdsa";
       npkey = 6;
-      elems = "pabgnqd";
+      nskey = 7;
+      err = gcry_sexp_extract_param (list, NULL, "pabgnqd",
+                                     array+0, array+1, array+2, array+3,
+                                     array+4, array+5, array+6, NULL);
     }
   else if (!strcmp (name, "ecdh"))
     {
       algoname = "ecdh";
       npkey = 6;
-      elems = "pabgnqd";
+      nskey= 7;
+      err = gcry_sexp_extract_param (list, NULL, "pabgnqd",
+                                     array+0, array+1, array+2, array+3,
+                                     array+4, array+5, array+6, NULL);
     }
   else
     {
-      algoname = "";
-      npkey = 0;
-      elems = NULL;
+      err = gpg_error (GPG_ERR_PUBKEY_ALGO);
     }
   xfree (name);
-  assert (!elems || strlen (elems) < DIM (array) );
-  nskey = elems? strlen (elems) : 0;
-
-  /* Extract the parameters and put them into an array.  */
-  if (!elems)
-    err = gpg_error (GPG_ERR_PUBKEY_ALGO);
-  else
-    err = gcry_sexp_extract_param (list, NULL, elems,
-                                   array+0, array+1, array+2, array+3, array+4,
-                                   array+5, array+6, NULL);
   gcry_sexp_release (list);
   if (err)
     return err;
diff --git a/g10/export.c b/g10/export.c
index fffaf79..9aa012e 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -830,6 +830,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
           log_error ("public key packet not found in keyblock - skipped\n");
           continue;
         }
+      setup_main_keyids (keyblock);  /* gpg_format_keydesc needs it.  */
       pk = node->pkt->pkt.public_key;
       keyid_from_pk (pk, keyid);
 
@@ -1077,8 +1078,13 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
                     log_info ("key %s: asking agent for the secret parts\n",
                               keystr_with_sub (keyid, subkid));
 
-                  err = agent_export_key (ctrl, hexgrip, "Key foo", NULL,
-                                          &wrappedkey, &wrappedkeylen);
+                  {
+                    char *prompt = gpg_format_keydesc (pk,
+                                                       FORMAT_KEYDESC_EXPORT,1);
+                    err = agent_export_key (ctrl, hexgrip, prompt, NULL,
+                                            &wrappedkey, &wrappedkeylen);
+                    xfree (prompt);
+                  }
                   if (err)
                     goto unwraperror;
                   if (wrappedkeylen < 24)

commit e549799db66be30cdd68a3e6cdca9c6a050466d1
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Apr 14 14:40:18 2014 +0200

    gpg: Change pinentry prompt to talk about "secret key".
    
    * g10/passphrase.c (gpg_format_keydesc): Add mode 2.  Change strings.
    * g10/keydb.h (FORMAT_KEYDESC_NORMAL, FORMAT_KEYDESC_IMPORT)
    (FORMAT_KEYDESC_EXPORT): New.  Use them for clarity.
    --
    
    The use of the term "certificate" was more confusing than helpful.

diff --git a/g10/import.c b/g10/import.c
index c3ad536..8223041 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -1431,7 +1431,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
 
       /* Send the wrapped key to the agent.  */
       {
-        char *desc = gpg_format_keydesc (pk, 1, 1);
+        char *desc = gpg_format_keydesc (pk, FORMAT_KEYDESC_IMPORT, 1);
         err = agent_import_key (ctrl, desc, &cache_nonce,
                                 wrappedkey, wrappedkeylen, opt.batch);
         xfree (desc);
diff --git a/g10/keydb.h b/g10/keydb.h
index 6834fc9..492cde3 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -198,6 +198,10 @@ void next_to_last_passphrase(void);
 
 void emit_status_need_passphrase (u32 *keyid, u32 *mainkeyid, int pubkey_algo);
 
+#define FORMAT_KEYDESC_NORMAL  0
+#define FORMAT_KEYDESC_IMPORT  1
+#define FORMAT_KEYDESC_EXPORT  2
+
 char *gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped);
 
 
diff --git a/g10/keyedit.c b/g10/keyedit.c
index c4d7ca8..9e5fb8f 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -1200,7 +1200,7 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
           if (err)
             goto leave;
 
-          desc = gpg_format_keydesc (pk, 0, 1);
+          desc = gpg_format_keydesc (pk, FORMAT_KEYDESC_NORMAL, 1);
           err = agent_passwd (ctrl, hexgrip, desc, &cache_nonce, &passwd_nonce);
           xfree (desc);
 
diff --git a/g10/passphrase.c b/g10/passphrase.c
index bd0f0ff..7c1d6aa 100644
--- a/g10/passphrase.c
+++ b/g10/passphrase.c
@@ -645,29 +645,49 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
   char *maink;
   char *desc;
   const char *prompt;
+  const char *trailer = "";
+  int is_subkey;
 
+  is_subkey = (pk->main_keyid[0] && pk->main_keyid[1]
+               && pk->keyid[0] != pk->main_keyid[0]
+               && pk->keyid[1] != pk->main_keyid[1]);
   algo_name = openpgp_pk_algo_name (pk->pubkey_algo);
   timestr = strtimestamp (pk->timestamp);
-  uid = get_user_id (pk->keyid, &uidlen);
+  uid = get_user_id (is_subkey? pk->main_keyid:pk->keyid, &uidlen);
 
   orig_codeset = i18n_switchto_utf8 ();
 
-  if (pk->main_keyid[0] && pk->main_keyid[1]
-      && pk->keyid[0] != pk->main_keyid[0]
-      && pk->keyid[1] != pk->main_keyid[1])
+  if (is_subkey)
     maink = xtryasprintf (_(" (main key ID %s)"), keystr (pk->main_keyid));
   else
     maink = NULL;
 
   switch (mode)
     {
-    case 0:
+    case FORMAT_KEYDESC_NORMAL:
       prompt = _("Please enter the passphrase to unlock the"
-                 " secret key for the OpenPGP certificate:");
+                 " OpenPGP secret key:");
       break;
-    case 1:
+    case FORMAT_KEYDESC_IMPORT:
       prompt = _("Please enter the passphrase to import the"
-                 " secret key for the OpenPGP certificate:");
+                 " OpenPGP secret key:");
+      break;
+    case FORMAT_KEYDESC_EXPORT:
+      if (is_subkey)
+        prompt = _("Please enter the passphrase to export the"
+                   " OpenPGP secret subkey:");
+      else
+        prompt = _("Please enter the passphrase to export the"
+                   " OpenPGP secret key:");
+      break;
+    case FORMAT_KEYDESC_DELKEY:
+      if (is_subkey)
+        prompt = _("Do you really want to permanently delete the"
+                   " OpenPGP secret subkey key:");
+      else
+        prompt = _("Do you really want to permanently delete the"
+                   " OpenPGP secret key:");
+      trailer = "?";
       break;
     default:
       prompt = "?";
@@ -677,12 +697,12 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
   desc = xtryasprintf (_("%s\n"
                          "\"%.*s\"\n"
                          "%u-bit %s key, ID %s,\n"
-                         "created %s%s.\n"),
+                         "created %s%s.\n%s"),
                        prompt,
                        (int)uidlen, uid,
                        nbits_from_pk (pk), algo_name,
                        keystr (pk->keyid), timestr,
-                       maink?maink:"" );
+                       maink?maink:"", trailer );
   xfree (maink);
   xfree (uid);
 
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index 042a255..a563ec0 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -200,7 +200,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
     }
 
   /* Decrypt. */
-  desc = gpg_format_keydesc (sk, 0, 1);
+  desc = gpg_format_keydesc (sk, FORMAT_KEYDESC_NORMAL, 1);
   err = agent_pkdecrypt (NULL, keygrip,
                          desc, sk->keyid, sk->main_keyid, sk->pubkey_algo,
                          s_data, &frame, &nframe, &padding);
diff --git a/g10/sign.c b/g10/sign.c
index d9f2dd3..8a87888 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -270,7 +270,7 @@ do_sign (PKT_public_key *pksk, PKT_signature *sig,
       char *desc;
       gcry_sexp_t s_sigval;
 
-      desc = gpg_format_keydesc (pksk, 0, 1);
+      desc = gpg_format_keydesc (pksk, FORMAT_KEYDESC_NORMAL, 1);
       err = agent_pksign (NULL/*ctrl*/, cache_nonce, hexgrip, desc,
                           pksk->keyid, pksk->main_keyid, pksk->pubkey_algo,
                           dp, gcry_md_get_algo_dlen (mdalgo), mdalgo,

commit e3a4ff89a0b106e678bf9d0a4d47917123071140
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Apr 15 16:40:48 2014 +0200

    agent: Add command DELETE_KEY.
    
    * agent/command.c (cmd_delete_key): New.
    * agent/findkey.c (modify_description): Add '%C' feature.
    (remove_key_file): New.
    (agent_delete_key): New.
    * agent/command-ssh.c (search_control_file): Make arg R_DISABLE
    optional.
    
    * configure.ac: Require libgpg-error 1.13.

diff --git a/agent/agent.h b/agent/agent.h
index 58e5841..4ed8c7f 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -334,6 +334,8 @@ int agent_key_available (const unsigned char *grip);
 gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
                                       int *r_keytype,
                                       unsigned char **r_shadow_info);
+gpg_error_t agent_delete_key (ctrl_t ctrl, const char *desc_text,
+                              const unsigned char *grip);
 
 /*-- call-pinentry.c --*/
 void initialize_module_call_pinentry (void);
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index 364a8cc..a814681 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -1031,7 +1031,8 @@ search_control_file (ssh_control_file_t cf, const char *hexgrip,
 
   assert (strlen (hexgrip) == 40 );
 
-  *r_disabled = 0;
+  if (r_disabled)
+    *r_disabled = 0;
   if (r_ttl)
     *r_ttl = 0;
   if (r_confirm)
@@ -1047,7 +1048,8 @@ search_control_file (ssh_control_file_t cf, const char *hexgrip,
     }
   if (!err)
     {
-      *r_disabled = cf->item.disabled;
+      if (r_disabled)
+        *r_disabled = cf->item.disabled;
       if (r_ttl)
         *r_ttl = cf->item.ttl;
       if (r_confirm)
diff --git a/agent/command.c b/agent/command.c
index fab27f0..52876a9 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -695,7 +695,7 @@ static const char hlp_setkeydesc[] =
   "blanks unless they are percent or '+' escaped.\n"
   "\n"
   "The description is only valid for the next PKSIGN, PKDECRYPT,\n"
-  "IMPORT_KEY or EXPORT_KEY operation.";
+  "IMPORT_KEY, EXPORT_KEY, or DELETE_KEY operation.";
 static gpg_error_t
 cmd_setkeydesc (assuan_context_t ctx, char *line)
 {
@@ -2244,6 +2244,39 @@ cmd_export_key (assuan_context_t ctx, char *line)
 
   return leave_cmd (ctx, err);
 }
+
+
+

+static const char hlp_delete_key[] =
+  "DELETE_KEY <hexstring_with_keygrip>\n"
+  "\n"
+  "Delete a secret key from the key store.\n"
+  "As safeguard the agent asks the user for confirmation.\n";
+static gpg_error_t
+cmd_delete_key (assuan_context_t ctx, char *line)
+{
+  ctrl_t ctrl = assuan_get_pointer (ctx);
+  gpg_error_t err;
+  unsigned char grip[20];
+
+  line = skip_options (line);
+
+  err = parse_keygrip (ctx, line, grip);
+  if (err)
+    goto leave;
+
+  err = agent_delete_key (ctrl, ctrl->server_local->keydesc, grip);
+  if (err)
+    goto leave;
+
+ leave:
+  xfree (ctrl->server_local->keydesc);
+  ctrl->server_local->keydesc = NULL;
+
+  return leave_cmd (ctx, err);
+}
+
+
 

 static const char hlp_keytocard[] =
   "KEYTOCARD [--force] <hexstring_with_keygrip> <serialno> <id> <timestamp>\n"
@@ -2926,6 +2959,7 @@ register_commands (assuan_context_t ctx)
     { "KEYWRAP_KEY",    cmd_keywrap_key, hlp_keywrap_key },
     { "IMPORT_KEY",     cmd_import_key, hlp_import_key },
     { "EXPORT_KEY",     cmd_export_key, hlp_export_key },
+    { "DELETE_KEY",     cmd_delete_key, hlp_delete_key },
     { "GETVAL",         cmd_getval,    hlp_getval },
     { "PUTVAL",         cmd_putval,    hlp_putval },
     { "UPDATESTARTUPTTY",  cmd_updatestartuptty, hlp_updatestartuptty },
diff --git a/agent/findkey.c b/agent/findkey.c
index 84d2cfd..e01c5c1 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -1,6 +1,7 @@
 /* findkey.c - Locate the secret key
  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
  *               2010, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2014 Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -189,6 +190,7 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
 
    %% - Replaced by a single %
    %c - Replaced by the content of COMMENT.
+   %C - Same as %c but put into parentheses.
    %F - Replaced by an ssh style fingerprint computed from KEY.
 
    The functions returns 0 on success or an error code.  On success a
@@ -240,6 +242,20 @@ modify_description (const char *in, const char *comment, const gcry_sexp_t key,
                     out_len += comment_length;
                   break;
 
+                case 'C': /* Comment.  */
+                  if (!comment_length)
+                    ;
+                  else if (out)
+                    {
+                      *out++ = '(';
+                      memcpy (out, comment, comment_length);
+                      out += comment_length;
+                      *out++ = ')';
+                    }
+                  else
+                    out_len += comment_length + 2;
+                  break;
+
                 case 'F': /* SSH style fingerprint.  */
                   if (!ssh_fpr && key)
                     ssh_get_fingerprint_string (key, &ssh_fpr);
@@ -536,6 +552,24 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
 }
 
 
+/* Remove the key identified by GRIP from the private key directory.  */
+static gpg_error_t
+remove_key_file (const unsigned char *grip)
+{
+  gpg_error_t err = 0;
+  char *fname;
+  char hexgrip[40+4+1];
+
+  bin2hex (grip, 20, hexgrip);
+  strcpy (hexgrip+40, ".key");
+  fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
+  if (gnupg_remove (fname))
+    err = gpg_error_from_syserror ();
+  xfree (fname);
+  return err;
+}
+
+
 /* Return the secret key as an S-Exp in RESULT after locating it using
    the GRIP.  If the operation shall be diverted to a token, an
    allocated S-expression with the shadow_info part from the file is
@@ -1145,3 +1179,112 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
   xfree (buf);
   return err;
 }
+
+
+

+/* Delete the key with GRIP from the disk after having asked for
+   confirmation using DESC_TEXT.  Common error codes are:
+     GPG_ERR_NO_SECKEY
+     GPG_ERR_KEY_ON_CARD
+     GPG_ERR_NOT_CONFIRMED
+*/
+gpg_error_t
+agent_delete_key (ctrl_t ctrl, const char *desc_text,
+                  const unsigned char *grip)
+{
+  gpg_error_t err;
+  gcry_sexp_t s_skey = NULL;
+  unsigned char *buf = NULL;
+  size_t len;
+  char *desc_text_final = NULL;
+  char *comment = NULL;
+  ssh_control_file_t cf = NULL;
+  char hexgrip[40+4+1];
+  char *default_desc = NULL;
+
+  err = read_key_file (grip, &s_skey);
+  if (gpg_err_code (err) == GPG_ERR_ENOENT)
+    err = gpg_error (GPG_ERR_NO_SECKEY);
+  if (err)
+    goto leave;
+
+  err = make_canon_sexp (s_skey, &buf, &len);
+  if (err)
+    goto leave;
+
+  switch (agent_private_key_type (buf))
+    {
+    case PRIVATE_KEY_CLEAR:
+    case PRIVATE_KEY_PROTECTED:
+      {
+        bin2hex (grip, 20, hexgrip);
+        if (!desc_text)
+          {
+            default_desc = xtryasprintf
+              ("Do you really want to delete the key identified by keygrip%%0A"
+               "  %s%%0A  %%C%%0A?", hexgrip);
+            desc_text = default_desc;
+          }
+
+        /* Note, that we will take the comment as a C string for
+           display purposes; i.e. all stuff beyond a Nul character is
+           ignored.  */
+        {
+          gcry_sexp_t comment_sexp;
+
+          comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
+          if (comment_sexp)
+            comment = gcry_sexp_nth_string (comment_sexp, 1);
+          gcry_sexp_release (comment_sexp);
+        }
+
+	if (desc_text)
+          err = modify_description (desc_text, comment? comment:"", s_skey,
+                                    &desc_text_final);
+	if (err)
+          goto leave;
+
+        err = agent_get_confirmation (ctrl, desc_text_final,
+                                      _("Delete key"), _("No"), 0);
+        if (err)
+          goto leave;
+
+        cf = ssh_open_control_file ();
+        if (cf)
+          {
+            if (!ssh_search_control_file (cf, hexgrip, NULL, NULL, NULL))
+              {
+                err = agent_get_confirmation
+                  (ctrl,
+                   _("Warning: This key is also listed for use with SSH!\n"
+                     "Deleting the key will may remove your ability to"
+                     "access remote machines."),
+                   _("Delete key"), _("No"), 0);
+                if (err)
+                  goto leave;
+              }
+          }
+
+        err = remove_key_file (grip);
+      }
+      break;
+
+    case PRIVATE_KEY_SHADOWED:
+      err = gpg_error (GPG_ERR_KEY_ON_CARD);
+      break;
+
+    default:
+      log_error ("invalid private key format\n");
+      err = gpg_error (GPG_ERR_BAD_SECKEY);
+      break;
+    }
+
+ leave:
+  ssh_close_control_file (cf);
+  gcry_free (comment);
+  xfree (desc_text_final);
+  xfree (default_desc);
+  xfree (buf);
+  gcry_sexp_release (s_skey);
+  return err;
+}
diff --git a/configure.ac b/configure.ac
index e384fba..096e3e1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -44,7 +44,7 @@ m4_define([mym4_full_version],[mym4_version[]mym4_betastring])
 
 AC_INIT([gnupg],[mym4_full_version], [http://bugs.gnupg.org])
 
-NEED_GPG_ERROR_VERSION=1.11
+NEED_GPG_ERROR_VERSION=1.13
 
 NEED_LIBGCRYPT_API=1
 NEED_LIBGCRYPT_VERSION=1.6.0

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

Summary of changes:
 agent/agent.h       |    2 +
 agent/command-ssh.c |    6 +-
 agent/command.c     |   38 +++++-
 agent/cvt-openpgp.c |   48 ++++----
 agent/findkey.c     |  143 +++++++++++++++++++++++
 configure.ac        |    2 +-
 doc/DETAILS         |    1 +
 g10/call-agent.c    |   38 ++++++
 g10/call-agent.h    |    4 +
 g10/delkey.c        |  324 ++++++++++++++++++++++++++++++---------------------
 g10/export.c        |   10 +-
 g10/getkey.c        |   32 +++++
 g10/import.c        |    2 +-
 g10/keydb.h         |    5 +
 g10/keyedit.c       |    2 +-
 g10/main.h          |    2 +-
 g10/passphrase.c    |   40 +++++--
 g10/pubkey-enc.c    |    2 +-
 g10/sign.c          |    2 +-
 19 files changed, 527 insertions(+), 176 deletions(-)


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




More information about the Gnupg-commits mailing list