speedo: Improve speedo Makefile.
[gnupg.git] / g10 / import.c
index 7ba7303..ca35ce1 100644 (file)
@@ -1,6 +1,7 @@
 /* import.c - import a key into our key storage.
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
  *               2007, 2010, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2014  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -62,15 +63,19 @@ struct stats_s {
 
 static int import (ctrl_t ctrl,
                    IOBUF inp, const char* fname, struct stats_s *stats,
-                  unsigned char **fpr, size_t *fpr_len, unsigned int options);
+                  unsigned char **fpr, size_t *fpr_len, unsigned int options,
+                  import_screener_t screener, void *screener_arg);
 static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root );
 static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
 static int import_one (ctrl_t ctrl,
                        const char *fname, KBNODE keyblock,struct stats_s *stats,
-                       unsigned char **fpr,size_t *fpr_len,
-                       unsigned int options,int from_sk);
+                       unsigned char **fpr, size_t *fpr_len,
+                       unsigned int options, int from_sk, int silent,
+                       import_screener_t screener, void *screener_arg);
 static int import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
-                              struct stats_s *stats, unsigned int options);
+                              struct stats_s *stats, int batch,
+                              unsigned int options, int for_migration,
+                              import_screener_t screener, void *screener_arg);
 static int import_revoke_cert( const char *fname, KBNODE node,
                                struct stats_s *stats);
 static int chk_self_sigs( const char *fname, KBNODE keyblock,
@@ -167,7 +172,8 @@ import_release_stats_handle (void *p)
 static int
 import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
                      void *stats_handle, unsigned char **fpr, size_t *fpr_len,
-                     unsigned int options )
+                     unsigned int options,
+                      import_screener_t screener, void *screener_arg)
 {
     int i, rc = 0;
     struct stats_s *stats = stats_handle;
@@ -176,7 +182,8 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
         stats = import_new_stats_handle ();
 
     if (inp) {
-      rc = import (ctrl, inp, "[stream]", stats, fpr, fpr_len, options);
+      rc = import (ctrl, inp, "[stream]", stats, fpr, fpr_len, options,
+                   screener, screener_arg);
     }
     else {
         if( !fnames && !nnames )
@@ -197,7 +204,8 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
                log_error(_("can't open '%s': %s\n"), fname, strerror(errno) );
            else
              {
-               rc = import (ctrl, inp2, fname, stats, fpr, fpr_len, options);
+               rc = import (ctrl, inp2, fname, stats, fpr, fpr_len, options,
+                             screener, screener_arg);
                iobuf_close(inp2);
                 /* Must invalidate that ugly cache to actually close it. */
                 iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE,
@@ -222,25 +230,26 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
        interactive or by not setting no-auto-check-trustdb */
 
     if(!(options&IMPORT_FAST))
-      trustdb_check_or_update();
+      check_or_update_trustdb ();
 
     return rc;
 }
 
+
 void
 import_keys (ctrl_t ctrl, char **fnames, int nnames,
             void *stats_handle, unsigned int options )
 {
   import_keys_internal (ctrl, NULL, fnames, nnames, stats_handle,
-                        NULL, NULL, options);
+                        NULL, NULL, options, NULL, NULL);
 }
 
 int
 import_keys_stream (ctrl_t ctrl, IOBUF inp, void *stats_handle,
-                   unsigned char **fpr, size_t *fpr_len,unsigned int options)
+                   unsigned char **fpr, size_t *fpr_len, unsigned int options)
 {
   return import_keys_internal (ctrl, inp, NULL, 0, stats_handle,
-                               fpr, fpr_len, options);
+                               fpr, fpr_len, options, NULL, NULL);
 }
 
 
@@ -248,7 +257,8 @@ import_keys_stream (ctrl_t ctrl, IOBUF inp, void *stats_handle,
 int
 import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
                        unsigned char **fpr, size_t *fpr_len,
-                       unsigned int options)
+                       unsigned int options,
+                       import_screener_t screener, void *screener_arg)
 {
   int rc;
   iobuf_t inp;
@@ -262,7 +272,8 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
     }
 
   rc = import_keys_internal (ctrl, inp, NULL, 0, stats_handle,
-                             fpr, fpr_len, options);
+                             fpr, fpr_len, options,
+                             screener, screener_arg);
 
   iobuf_close (inp);
   return rc;
@@ -271,7 +282,8 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
 
 static int
 import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
-       unsigned char **fpr,size_t *fpr_len,unsigned int options )
+       unsigned char **fpr,size_t *fpr_len, unsigned int options,
+       import_screener_t screener, void *screener_arg)
 {
     PACKET *pending_pkt = NULL;
     KBNODE keyblock = NULL;  /* Need to initialize because gcc can't
@@ -293,9 +305,12 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
     while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) {
        if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
           rc = import_one (ctrl, fname, keyblock,
-                           stats, fpr, fpr_len, options, 0);
+                           stats, fpr, fpr_len, options, 0, 0,
+                           screener, screener_arg);
        else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
-          rc = import_secret_one (ctrl, fname, keyblock, stats, options);
+          rc = import_secret_one (ctrl, fname, keyblock, stats,
+                                  opt.batch, options, 0,
+                                  screener, screener_arg);
        else if( keyblock->pkt->pkttype == PKT_SIGNATURE
                 && keyblock->pkt->pkt.signature->sig_class == 0x20 )
            rc = import_revoke_cert( fname, keyblock, stats );
@@ -320,6 +335,58 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
 }
 
 
+/* Helper to migrate secring.gpg to GnuPG 2.1.  */
+gpg_error_t
+import_old_secring (ctrl_t ctrl, const char *fname)
+{
+  gpg_error_t err;
+  iobuf_t inp;
+  PACKET *pending_pkt = NULL;
+  kbnode_t keyblock = NULL;  /* Need to initialize because gcc can't
+                                grasp the return semantics of
+                                read_block. */
+  struct stats_s *stats;
+
+  inp = iobuf_open (fname);
+  if (inp && is_secured_file (iobuf_get_fd (inp)))
+    {
+      iobuf_close (inp);
+      inp = NULL;
+      gpg_err_set_errno (EPERM);
+    }
+  if (!inp)
+    {
+      err = gpg_error_from_syserror ();
+      log_error (_("can't open '%s': %s\n"), fname, gpg_strerror (err));
+      return err;
+    }
+
+  getkey_disable_caches();
+  stats = import_new_stats_handle ();
+  while (!(err = read_block (inp, &pending_pkt, &keyblock)))
+    {
+      if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
+        err = import_secret_one (ctrl, fname, keyblock, stats, 1, 0, 1,
+                                 NULL, NULL);
+      release_kbnode (keyblock);
+      if (err)
+        break;
+    }
+  import_release_stats_handle (stats);
+  if (err == -1)
+    err = 0;
+  else if (err && gpg_err_code (err) != G10ERR_INV_KEYRING)
+    log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err));
+  else if (err)
+    log_error ("import from '%s' failed: %s\n", fname, gpg_strerror (err));
+
+  iobuf_close (inp);
+  iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
+
+  return err;
+}
+
+
 void
 import_print_stats (void *hd)
 {
@@ -771,16 +838,18 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
 }
 
 /****************
- * Try to import one keyblock. Return an error only in serious cases, but
- * never for an invalid keyblock.  It uses log_error to increase the
- * internal errorcount, so that invalid input can be detected by programs
- * which called gpg.
+ * Try to import one keyblock. Return an error only in serious cases,
+ * but never for an invalid keyblock.  It uses log_error to increase
+ * the internal errorcount, so that invalid input can be detected by
+ * programs which called gpg.  If SILENT is no messages are printed -
+ * even most error messages are suppressed.
  */
 static int
 import_one (ctrl_t ctrl,
             const char *fname, KBNODE keyblock, struct stats_s *stats,
-           unsigned char **fpr,size_t *fpr_len,unsigned int options,
-           int from_sk )
+           unsigned char **fpr, size_t *fpr_len, unsigned int options,
+           int from_sk, int silent,
+            import_screener_t screener, void *screener_arg)
 {
     PKT_public_key *pk;
     PKT_public_key *pk_orig;
@@ -792,6 +861,7 @@ import_one (ctrl_t ctrl,
     int mod_key = 0;
     int same_key = 0;
     int non_self = 0;
+    char pkstrbuf[PUBKEY_STRING_SIZE];
 
     /* get the key and print some info about it */
     node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
@@ -803,11 +873,10 @@ import_one (ctrl_t ctrl,
     keyid_from_pk( pk, keyid );
     uidnode = find_next_kbnode( keyblock, PKT_USER_ID );
 
-    if( opt.verbose && !opt.interactive )
+    if (opt.verbose && !opt.interactive && !silent)
       {
-       log_info( "pub  %4u%c/%s %s  ",
-                 nbits_from_pk( pk ),
-                 pubkey_letter( pk->pubkey_algo ),
+       log_info( "pub  %s/%s %s  ",
+                 pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
                  keystr_from_pk(pk), datestr_from_pk(pk) );
        if (uidnode)
          print_utf8_buffer (log_get_stream (),
@@ -819,11 +888,19 @@ import_one (ctrl_t ctrl,
 
     if( !uidnode )
       {
-       log_error( _("key %s: no user ID\n"), keystr_from_pk(pk));
+        if (!silent)
+          log_error( _("key %s: no user ID\n"), keystr_from_pk(pk));
        return 0;
       }
 
-    if (opt.interactive) {
+    if (screener && screener (keyblock, screener_arg))
+      {
+        log_error (_("key %s: %s\n"), keystr_from_pk (pk),
+                   _("rejected by import screener"));
+        return 0;
+      }
+
+    if (opt.interactive && !silent) {
         if(is_status_enabled())
          print_import_check (pk, uidnode->pkt->pkt.user_id);
        merge_keys_and_selfsig (keyblock);
@@ -856,7 +933,7 @@ import_one (ctrl_t ctrl,
        return rc== -1? 0:rc;
 
     /* If we allow such a thing, mark unsigned uids as valid */
-    if( opt.allow_non_selfsigned_uid )
+    if( opt.allow_non_selfsigned_uid)
       for( node=keyblock; node; node = node->next )
        if( node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) )
          {
@@ -869,9 +946,11 @@ import_one (ctrl_t ctrl,
          }
 
     if( !delete_inv_parts( fname, keyblock, keyid, options ) ) {
-        log_error( _("key %s: no valid user IDs\n"), keystr_from_pk(pk));
-       if( !opt.quiet )
-         log_info(_("this may be caused by a missing self-signature\n"));
+        if (!silent) {
+           log_error( _("key %s: no valid user IDs\n"), keystr_from_pk(pk));
+           if( !opt.quiet )
+             log_info(_("this may be caused by a missing self-signature\n"));
+        }
        stats->no_user_id++;
        return 0;
     }
@@ -881,12 +960,13 @@ import_one (ctrl_t ctrl,
     rc = get_pubkey_fast ( pk_orig, keyid );
     if( rc && rc != G10ERR_NO_PUBKEY && rc != G10ERR_UNU_PUBKEY )
       {
-       log_error( _("key %s: public key not found: %s\n"),
-                  keystr(keyid), g10_errstr(rc));
+        if (!silent)
+          log_error (_("key %s: public key not found: %s\n"),
+                     keystr(keyid), g10_errstr(rc));
       }
     else if ( rc && (opt.import_options&IMPORT_MERGE_ONLY) )
       {
-       if( opt.verbose )
+       if( opt.verbose && !silent )
          log_info( _("key %s: new key - skipped\n"), keystr(keyid));
        rc = 0;
        stats->skipped_new_keys++;
@@ -896,7 +976,7 @@ import_one (ctrl_t ctrl,
 
         rc = keydb_locate_writable (hd, NULL);
        if (rc) {
-           log_error (_("no writable keyring found: %s\n"), g10_errstr (rc));
+            log_error (_("no writable keyring found: %s\n"), g10_errstr (rc));
             keydb_release (hd);
            return G10ERR_GENERAL;
        }
@@ -921,7 +1001,7 @@ import_one (ctrl_t ctrl,
         keydb_release (hd);
 
        /* we are ready */
-       if( !opt.quiet )
+       if( !opt.quiet && !silent)
          {
            char *p=get_user_id_native (keyid);
            log_info( _("key %s: public key \"%s\" imported\n"),
@@ -948,7 +1028,8 @@ import_one (ctrl_t ctrl,
         * weird is going on */
        if( cmp_public_keys( pk_orig, pk ) )
          {
-           log_error( _("key %s: doesn't match our copy\n"),keystr(keyid));
+            if (!silent)
+              log_error( _("key %s: doesn't match our copy\n"),keystr(keyid));
            goto leave;
          }
 
@@ -1011,7 +1092,7 @@ import_one (ctrl_t ctrl,
              revalidation_mark ();
 
            /* we are ready */
-           if( !opt.quiet )
+           if( !opt.quiet && !silent)
              {
                char *p=get_user_id_native(keyid);
                if( n_uids == 1 )
@@ -1053,7 +1134,7 @@ import_one (ctrl_t ctrl,
            stats->n_sigs_cleaned +=n_sigs_cleaned;
            stats->n_uids_cleaned +=n_uids_cleaned;
 
-            if (is_status_enabled ())
+            if (is_status_enabled () && !silent)
               print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
        }
        else
@@ -1062,7 +1143,7 @@ import_one (ctrl_t ctrl,
             if (is_status_enabled ())
              print_import_ok (pk, 0);
 
-           if( !opt.quiet )
+           if( !opt.quiet && !silent)
              {
                char *p=get_user_id_native(keyid);
                log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p);
@@ -1128,41 +1209,13 @@ import_one (ctrl_t ctrl,
 }
 
 
-/* Extract one MPI value from the S-expression PKEY which is expected
-   to hold a "public-key".  Returns NULL on error.  */
-static gcry_mpi_t
-one_mpi_from_pkey (gcry_sexp_t pkey, const char *name, size_t namelen)
-{
-  gcry_sexp_t list, l2;
-  gcry_mpi_t a;
-
-  list = gcry_sexp_find_token (pkey, "public-key", 0);
-  if (!list)
-    return NULL;
-  l2 = gcry_sexp_cadr (list);
-  gcry_sexp_release (list);
-  list = l2;
-  if (!list)
-    return NULL;
-
-  l2 = gcry_sexp_find_token (list, name, namelen);
-  if (!l2)
-    {
-      gcry_sexp_release (list);
-      return NULL;
-    }
-  a = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
-  gcry_sexp_release (l2);
-  gcry_sexp_release (list);
-
-  return a;
-}
-
-
 /* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent.  The
-   function prints diagnostics and returns an error code. */
+   function prints diagnostics and returns an error code.  If BATCH is
+   true the secret keys are stored by gpg-agent in the transfer format
+   (i.e. no re-protection and aksing for passphrases). */
 static gpg_error_t
-transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
+transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock,
+                      int batch)
 {
   gpg_error_t err = 0;
   void *kek = NULL;
@@ -1174,18 +1227,15 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
   int nskey;
   membuf_t mbuf;
   int i, j;
-  unsigned int n;
-  void *format_args_buf_ptr[PUBKEY_MAX_NSKEY];
-  int   format_args_buf_int[PUBKEY_MAX_NSKEY];
   void *format_args[2*PUBKEY_MAX_NSKEY];
   gcry_sexp_t skey, prot, tmpsexp;
+  gcry_sexp_t curve = NULL;
   unsigned char *transferkey = NULL;
   size_t transferkeylen;
   gcry_cipher_hd_t cipherhd = NULL;
   unsigned char *wrappedkey = NULL;
   size_t wrappedkeylen;
   char *cache_nonce = NULL;
-  gcry_mpi_t ecc_params[5] = {NULL, NULL, NULL, NULL, NULL};
 
   /* Get the current KEK.  */
   err = agent_keywrap_key (ctrl, 0, &kek, &keklen);
@@ -1263,65 +1313,30 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
           || pk->pubkey_algo == PUBKEY_ALGO_EDDSA
           || pk->pubkey_algo == PUBKEY_ALGO_ECDH)
         {
-          /* We need special treatment for ECC algorithms.  OpenPGP
-             stores only the curve name but the agent expects a full
-             key.  This is so that we can keep all curve name
-             validation code out of gpg-agent.  */
-#if PUBKEY_MAX_NSKEY < 7
-#error  PUBKEY_MAX_NSKEY too low for ECC
-#endif
-          char *curve = openpgp_oid_to_str (pk->pkey[0]);
-          if (!curve)
+          /* The ECC case.  */
+          char *curvestr = openpgp_oid_to_str (pk->pkey[0]);
+          if (!curvestr)
             err = gpg_error_from_syserror ();
           else
             {
-              gcry_sexp_t cparam = gcry_pk_get_param (GCRY_PK_ECC, curve);
-
-              xfree (curve);
-              if (!cparam)
-                err = gpg_error (GPG_ERR_UNKNOWN_CURVE);
-              else
+              err = gcry_sexp_build (&curve, NULL, "(curve %s)", curvestr);
+              xfree (curvestr);
+              if (!err)
                 {
-                  const char *s;
-
-                  /* Append the curve parameters P, A, B, G and N.  */
-                  for (i=j=0; !err && *(s = "pabgn"+i); i++)
-                    {
-                      ecc_params[i] = one_mpi_from_pkey (cparam, s, 1);
-                      if (!ecc_params[i])
-                        err = gpg_error (GPG_ERR_INV_CURVE);
-                      else
-                        {
-                          put_membuf_str (&mbuf, " _ %m");
-                          format_args[j++] = ecc_params+i;
-                        }
-                    }
-                  gcry_sexp_release (cparam);
-                  if (!err)
-                    {
-                      /* Append the public key element Q.  */
-                      put_membuf_str (&mbuf, " _ %m");
-                      format_args[j++] = pk->pkey + 1;
-
-                      /* Append the secret key element D.  Note that
-                         for ECDH we need to skip PKEY[2] because this
-                         holds the KEK which is not needed.  */
-                      i = pk->pubkey_algo == PUBKEY_ALGO_ECDH? 3 : 2;
-                      if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
-                        {
-                          put_membuf_str (&mbuf, " e %b");
-                          format_args_buf_ptr[i]
-                            = gcry_mpi_get_opaque (pk->pkey[i],&n);
-                          format_args_buf_int[i] = (n+7)/8;
-                          format_args[j++] = format_args_buf_int + i;
-                          format_args[j++] = format_args_buf_ptr + i;
-                        }
-                      else
-                        {
-                          put_membuf_str (&mbuf, " _ %m");
-                          format_args[j++] = pk->pkey + i;
-                        }
-                    }
+                  j = 0;
+                  /* Append the public key element Q.  */
+                  put_membuf_str (&mbuf, " _ %m");
+                  format_args[j++] = pk->pkey + 1;
+
+                  /* Append the secret key element D.  For ECDH we
+                     skip PKEY[2] because this holds the KEK which is
+                     not needed by gpg-agent.  */
+                  i = pk->pubkey_algo == PUBKEY_ALGO_ECDH? 3 : 2;
+                  if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1))
+                    put_membuf_str (&mbuf, " e %m");
+                  else
+                    put_membuf_str (&mbuf, " _ %m");
+                  format_args[j++] = pk->pkey + i;
                 }
             }
         }
@@ -1331,23 +1346,16 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
           for (i=j=0; i < nskey; i++)
             {
               if (!pk->pkey[i])
-                ; /* Protected keys only have NPKEY+1 elements.  */
-              else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
-                {
-                  put_membuf_str (&mbuf, " e %b");
-                  format_args_buf_ptr[i] = gcry_mpi_get_opaque (pk->pkey[i],&n);
-                  format_args_buf_int[i] = (n+7)/8;
-                  format_args[j++] = format_args_buf_int + i;
-                  format_args[j++] = format_args_buf_ptr + i;
-                }
+                continue; /* Protected keys only have NPKEY+1 elements.  */
+
+              if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1))
+                put_membuf_str (&mbuf, " e %m");
               else
-                {
-                  put_membuf_str (&mbuf, " _ %m");
-                  format_args[j++] = pk->pkey + i;
-                }
+                put_membuf_str (&mbuf, " _ %m");
+              format_args[j++] = pk->pkey + i;
             }
         }
-      put_membuf_str (&mbuf, ")\n");
+      put_membuf_str (&mbuf, ")");
       put_membuf (&mbuf, "", 1);
       if (err)
         xfree (get_membuf (&mbuf, NULL));
@@ -1398,12 +1406,13 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
                                "(openpgp-private-key\n"
                                " (version %d)\n"
                                " (algo %s)\n"
-                               " %S\n"
+                               " %S%S\n"
                                " (csum %d)\n"
                                " %S)\n",
                                pk->version,
                                openpgp_pk_algo_name (pk->pubkey_algo),
-                               skey, (int)(unsigned long)ski->csum, prot);
+                               curve, skey,
+                               (int)(unsigned long)ski->csum, prot);
       gcry_sexp_release (skey);
       gcry_sexp_release (prot);
       if (!err)
@@ -1431,9 +1440,9 @@ 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);
+                                wrappedkey, wrappedkeylen, batch);
         xfree (desc);
       }
       if (!err)
@@ -1463,8 +1472,7 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
     }
 
  leave:
-  for (i=0; i < DIM (ecc_params); i++)
-    gcry_mpi_release (ecc_params[i]);
+  gcry_sexp_release (curve);
   xfree (cache_nonce);
   xfree (wrappedkey);
   xfree (transferkey);
@@ -1530,7 +1538,9 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
  */
 static int
 import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
-                   struct stats_s *stats, unsigned int options)
+                   struct stats_s *stats, int batch, unsigned int options,
+                   int for_migration,
+                   import_screener_t screener, void *screener_arg)
 {
   PKT_public_key *pk;
   struct seckey_info *ski;
@@ -1539,6 +1549,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
   int rc = 0;
   int nr_prev;
   kbnode_t pub_keyblock;
+  char pkstrbuf[PUBKEY_STRING_SIZE];
 
   /* Get the key and print some info about it */
   node = find_kbnode (keyblock, PKT_SECRET_KEY);
@@ -1550,11 +1561,17 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
   keyid_from_pk (pk, keyid);
   uidnode = find_next_kbnode (keyblock, PKT_USER_ID);
 
-  if (opt.verbose)
+  if (screener && screener (keyblock, screener_arg))
+    {
+      log_error (_("secret key %s: %s\n"), keystr_from_pk (pk),
+                 _("rejected by import screener"));
+      return 0;
+  }
+
+  if (opt.verbose && !for_migration)
     {
-      log_info ("sec  %4u%c/%s %s   ",
-                nbits_from_pk (pk),
-                pubkey_letter (pk->pubkey_algo),
+      log_info ("sec  %s/%s %s   ",
+                pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
                 keystr_from_pk (pk), datestr_from_pk (pk));
       if (uidnode)
         print_utf8_buffer (log_get_stream (), uidnode->pkt->pkt.user_id->name,
@@ -1563,9 +1580,17 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
     }
   stats->secret_read++;
 
+  if ((options & IMPORT_NO_SECKEY))
+    {
+      if (!for_migration)
+        log_error (_("importing secret keys not allowed\n"));
+      return 0;
+    }
+
   if (!uidnode)
     {
-      log_error( _("key %s: no user ID\n"), keystr_from_pk (pk));
+      if (!for_migration)
+        log_error( _("key %s: no user ID\n"), keystr_from_pk (pk));
       return 0;
     }
 
@@ -1581,8 +1606,9 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
      cipher algorithm (only checks the primary key, though).  */
   if (ski->algo > 110)
     {
-      log_error (_("key %s: secret key with invalid cipher %d"
-                   " - skipped\n"), keystr_from_pk (pk), ski->algo);
+      if (!for_migration)
+        log_error (_("key %s: secret key with invalid cipher %d"
+                     " - skipped\n"), keystr_from_pk (pk), ski->algo);
       return 0;
     }
 
@@ -1612,7 +1638,8 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
         public key block, and below we will output another one for
         the secret keys.  FIXME?  */
       import_one (ctrl, fname, pub_keyblock, stats,
-                 NULL, NULL, options, 1);
+                 NULL, NULL, options, 1, for_migration,
+                  screener, screener_arg);
 
       /* Fixme: We should check for an invalid keyblock and
         cancel the secret key import in this case.  */
@@ -1634,7 +1661,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
           else
             {
              nr_prev = stats->secret_imported;
-              if (!transfer_secret_keys (ctrl, stats, keyblock))
+              if (!transfer_secret_keys (ctrl, stats, keyblock, batch))
                 {
                  int status = 16;
                   if (!opt.quiet)