* options.h (DBG_CIPHER): Reintroduced it.
authorWerner Koch <wk@gnupg.org>
Thu, 3 Jul 2003 18:08:16 +0000 (18:08 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 3 Jul 2003 18:08:16 +0000 (18:08 +0000)
* seskey.c (encode_session_key): Debug output of the session key.

* pubkey-enc.c (get_it): Handle card case.
* call-agent.c (agent_scd_pkdecrypt): New.
* pkglue.c (pk_encrypt): Add RSA support.

* g10.c (main): Default to --use-agent.

* keygen.c (show_smartcard): Print info about the public key.
(check_smartcard): Check for existing key here.
(gen_card_key): And not anymore here.
(fpr_is_zero): New.
(generate_keypair): Generate both keys for a card.
(smartcard_change_url): Nw.

13 files changed:
g10/ChangeLog
g10/call-agent.c
g10/call-agent.h
g10/g10.c
g10/getkey.c
g10/keyedit.c
g10/keygen.c
g10/options.h
g10/pkglue.c
g10/pubkey-enc.c
g10/seckey-cert.c
g10/seskey.c
g10/sign.c

index bf394f2..681f4cd 100644 (file)
@@ -1,3 +1,25 @@
+2003-07-03  Werner Koch  <wk@gnupg.org>
+
+       * options.h (DBG_CIPHER): Reintroduced it. 
+       * seskey.c (encode_session_key): Debug output of the session key.
+
+       * pubkey-enc.c (get_it): Handle card case.
+       * call-agent.c (agent_scd_pkdecrypt): New.
+       * pkglue.c (pk_encrypt): Add RSA support.
+
+       * g10.c (main): Default to --use-agent.
+
+       * keygen.c (show_smartcard): Print info about the public key.
+       (check_smartcard): Check for existing key here.
+       (gen_card_key): And not anymore here.
+       (fpr_is_zero): New.
+       (generate_keypair): Generate both keys for a card.
+       (smartcard_change_url): Nw.
+
+2003-07-02  Werner Koch  <wk@gnupg.org>
+
+       * seckey-cert.c (is_secret_key_protected): Let it handle mode 1002.
+
 2003-07-01  Werner Koch  <wk@gnupg.org>
 
        * keygen.c (gen_card_key): Obviously we should use the creation
index d38e4c0..ca42365 100644 (file)
@@ -456,7 +456,6 @@ learn_status_cb (void *opaque, const char *line)
   const char *keyword = line;
   int keywordlen;
 
-  log_debug ("got status line `%s'\n", line);
   for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
     ;
   while (spacep (line))
@@ -470,7 +469,7 @@ learn_status_cb (void *opaque, const char *line)
     {
       parm->disp_name = unescape_status_string (line);
     }
-  else if (keywordlen == 10 && !memcmp (keyword, "PUBKEY_URL", keywordlen))
+  else if (keywordlen == 10 && !memcmp (keyword, "PUBKEY-URL", keywordlen))
     {
       parm->pubkey_url = unescape_status_string (line);
     }
@@ -670,7 +669,7 @@ agent_scd_pksign (const char *serialno, int hashalgo,
     sprintf (p, "%02X", indata[i]);
   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
-    return rc;
+    return map_assuan_err (rc);
 
   init_membuf (&data, 1024);
   snprintf (line, DIM(line)-1, "SCD PKSIGN %s", serialno);
@@ -680,9 +679,62 @@ agent_scd_pksign (const char *serialno, int hashalgo,
   if (rc)
     {
       xfree (get_membuf (&data, &len));
-      return rc;
+      return map_assuan_err (rc);
     }
   *r_buf = get_membuf (&data, r_buflen);
 
   return 0;
 }
+
+
+/* Decrypt INDATA of length INDATALEN using the card identified by
+   SERIALNO.  Return the plaintext in a nwly allocated buffer stored
+   at the address of R_BUF. 
+
+   Note, we currently support only RSA or more exactly algorithms
+   taking one input data element. */
+int
+agent_scd_pkdecrypt (const char *serialno,
+                     const unsigned char *indata, size_t indatalen,
+                     char **r_buf, size_t *r_buflen)
+{
+  int rc, i;
+  char *p, line[ASSUAN_LINELENGTH];
+  membuf_t data;
+  size_t len;
+
+  *r_buf = NULL;
+  rc = start_agent ();
+  if (rc)
+    return rc;
+
+  /* FIXME: use secure memory where appropriate */
+  if (indatalen*2 + 50 > DIM(line))
+    return gpg_error (GPG_ERR_GENERAL);
+
+  sprintf (line, "SCD SETDATA ");
+  p = line + strlen (line);
+  for (i=0; i < indatalen ; i++, p += 2 )
+    sprintf (p, "%02X", indata[i]);
+  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+  if (rc)
+    return map_assuan_err (rc);
+
+  init_membuf (&data, 1024);
+  snprintf (line, DIM(line)-1, "SCD PKDECRYPT %s", serialno);
+  line[DIM(line)-1] = 0;
+  rc = assuan_transact (agent_ctx, line,
+                        membuf_data_cb, &data,
+                        NULL, NULL, NULL, NULL);
+  if (rc)
+    {
+      xfree (get_membuf (&data, &len));
+      return map_assuan_err (rc);
+    }
+  *r_buf = get_membuf (&data, r_buflen);
+  if (!*r_buf)
+    return gpg_error (GPG_ERR_ENOMEM);
+
+  return 0;
+}
+
index 2169a53..a6edecf 100644 (file)
@@ -61,12 +61,10 @@ int agent_scd_pksign (const char *keyid, int hashalgo,
                       const unsigned char *indata, size_t indatalen,
                       char **r_buf, size_t *r_buflen);
 
-/* Ask the agent to let the user change the passphrase of the secret
-   key identified by HEXKEYGRIP. */
-int agent_passwd (const char *hexkeygrip);
-
-
-
+/* Send a PKDECRYPT command to the SCdaemon. */
+int agent_scd_pkdecrypt (const char *serialno,
+                         const unsigned char *indata, size_t indatalen,
+                         char **r_buf, size_t *r_buflen);
 
 
 
index 6909e04..d48dada 100644 (file)
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -1228,6 +1228,7 @@ main( int argc, char **argv )
     opt.verify_options=VERIFY_SHOW_POLICY|VERIFY_SHOW_NOTATION;
     opt.trust_model=TM_AUTO;
     opt.mangle_dos_filenames = 1;
+    opt.use_agent = 1;
 
 #if defined (__MINGW32__)
     set_homedir ( read_w32_registry_string( NULL,
@@ -1984,6 +1985,9 @@ main( int argc, char **argv )
     }
 #endif
 
+#warning locking does not work - disabled
+    disable_dotlock ();
+
     if (opt.verbose > 2)
         log_info ("using character set `%s'\n", get_native_charset ());
 
index 79fcaf3..c13d96d 100644 (file)
@@ -898,7 +898,7 @@ get_pubkey_end( GETKEY_CTX ctx )
 /****************
  * Search for a key with the given fingerprint.
  * FIXME:
- * We should replace this with the _byname function.  Thiscsan be done
+ * We should replace this with the _byname function.  This can be done
  * by creating a userID conforming to the unified fingerprint style. 
  */
 int
index 11e2d87..85f2b92 100644 (file)
@@ -923,7 +923,7 @@ change_passphrase( KBNODE keyblock )
        }
        else if( sk->protect.s2k.mode == 1002 ) {
            tty_printf(_("Secret key is actually stored on a card.\n"));
-           no_primary_secrets = 1;
+           goto leave;
        }
        else {
            tty_printf(_("Key is protected.\n"));
index 5dab70f..bfa76d6 100644 (file)
@@ -2096,8 +2096,6 @@ generate_keypair( const char *fname )
       card = check_smartcard (&serialno);
       if (card < 0)
         return;
-      if (card > 1)
-        log_error (_("can't generate subkey here\n"));
     }
   while (card > 1);
 
@@ -2114,55 +2112,75 @@ generate_keypair( const char *fname )
   if (card)
     {
       algo = PUBKEY_ALGO_RSA;
-      use = PUBKEY_USAGE_SIG;
-    }
-  else
-    algo = ask_algo (0, &use);
 
-  if (!algo)
-    { /* default: DSA with ElG subkey of the specified size */
-      both = 1;
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pKEYTYPE;
-      sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
+      sprintf( r->u.value, "%d", algo );
       r->next = para;
       para = r;
-      tty_printf(_("DSA keypair will have 1024 bits.\n"));
       r = xcalloc (1, sizeof *r + 20 );
-      r->key = pKEYLENGTH;
-      strcpy( r->u.value, "1024" );
+      r->key = pKEYUSAGE;
+      strcpy (r->u.value, "sign");
       r->next = para;
       para = r;
-      
-      algo = PUBKEY_ALGO_ELGAMAL_E;
+
       r = xcalloc (1, sizeof *r + 20 );
       r->key = pSUBKEYTYPE;
       sprintf( r->u.value, "%d", algo );
       r->next = para;
       para = r;
-    }
-  else 
-    {
       r = xcalloc (1, sizeof *r + 20 );
-      r->key = pKEYTYPE;
-      sprintf( r->u.value, "%d", algo );
+      r->key = pSUBKEYUSAGE;
+      strcpy (r->u.value, "encrypt");
       r->next = para;
       para = r;
+    }
+  else
+    {
+      algo = ask_algo (0, &use);
       
-      if (use)
+      if (!algo)
+        { /* default: DSA with ElG subkey of the specified size */
+          both = 1;
+          r = xcalloc (1, sizeof *r + 20 );
+          r->key = pKEYTYPE;
+          sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
+          r->next = para;
+          para = r;
+          tty_printf(_("DSA keypair will have 1024 bits.\n"));
+          r = xcalloc (1, sizeof *r + 20 );
+          r->key = pKEYLENGTH;
+          strcpy( r->u.value, "1024" );
+          r->next = para;
+          para = r;
+          
+          algo = PUBKEY_ALGO_ELGAMAL_E;
+          r = xcalloc (1, sizeof *r + 20 );
+          r->key = pSUBKEYTYPE;
+          sprintf( r->u.value, "%d", algo );
+          r->next = para;
+          para = r;
+        }
+      else 
         {
           r = xcalloc (1, sizeof *r + 20 );
-          r->key = pKEYUSAGE;
-          sprintf( r->u.value, "%s%s",
-                   (use & PUBKEY_USAGE_SIG)? "sign ":"",
-                   (use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
+          r->key = pKEYTYPE;
+          sprintf( r->u.value, "%d", algo );
           r->next = para;
           para = r;
+          
+          if (use)
+            {
+              r = xcalloc (1, sizeof *r + 20 );
+              r->key = pKEYUSAGE;
+              sprintf( r->u.value, "%s%s",
+                       (use & PUBKEY_USAGE_SIG)? "sign ":"",
+                       (use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
+              r->next = para;
+              para = r;
+            }
         }
-    }
 
-  if (!card)
-    {
       nbits = ask_keysize( algo );
       r = xcalloc (1, sizeof *r + 20 );
       r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
@@ -2367,12 +2385,21 @@ do_generate_keypair (struct para_data_s *para,
 
   if (get_parameter (para, pSUBKEYTYPE))
     {
-      rc = do_create (get_parameter_algo (para, pSUBKEYTYPE),
-                     get_parameter_uint (para, pSUBKEYLENGTH),
-                     pub_root, sec_root,
-                     get_parameter_dek (para, pPASSPHRASE_DEK),
-                     get_parameter_s2k (para, pPASSPHRASE_S2K),
-                     NULL, get_parameter_u32 (para, pSUBKEYEXPIRE));
+      if (!card)
+        {
+          rc = do_create (get_parameter_algo (para, pSUBKEYTYPE),
+                          get_parameter_uint (para, pSUBKEYLENGTH),
+                          pub_root, sec_root,
+                          get_parameter_dek (para, pPASSPHRASE_DEK),
+                          get_parameter_s2k (para, pPASSPHRASE_S2K),
+                          NULL, get_parameter_u32 (para, pSUBKEYEXPIRE));
+        }
+      else
+        {
+          rc = gen_card_key (PUBKEY_ALGO_RSA, 2, pub_root, sec_root,
+                             get_parameter_u32 (para, pKEYEXPIRE), para);
+        }
+
       if (!rc)
        rc = write_keybinding (pub_root, pub_root, sk,
                               get_parameter_uint (para, pSUBKEYUSAGE));
@@ -2642,13 +2669,15 @@ show_sha1_fpr (const unsigned char *fpr)
         }
     }
   else
-    tty_printf ("[none]");
+    tty_printf (" [none]");
   tty_printf ("\n");
 }
 
 static void
 show_smartcard (struct agent_card_info_s *info)
 {
+  PKT_public_key *pk = xcalloc (1, sizeof *pk);
+
   /* FIXME: Sanitize what we show. */
   tty_printf ("Name of cardholder: %s\n",
               info->disp_name && *info->disp_name? info->disp_name 
@@ -2656,12 +2685,17 @@ show_smartcard (struct agent_card_info_s *info)
   tty_printf ("URL of public key : %s\n",
               info->pubkey_url && *info->pubkey_url? info->pubkey_url 
                                                  : "[not set]");
-  tty_printf ("Signature key ....: ");
+  tty_printf ("Signature key ....:");
   show_sha1_fpr (info->fpr1valid? info->fpr1:NULL);
-  tty_printf ("Encryption key....: ");
+  tty_printf ("Encryption key....:");
   show_sha1_fpr (info->fpr2valid? info->fpr2:NULL);
-  tty_printf ("Authentication key: ");
+  tty_printf ("Authentication key:");
   show_sha1_fpr (info->fpr3valid? info->fpr3:NULL);
+
+  if (info->fpr1valid && !get_pubkey_byfprint (pk, info->fpr1, 20))
+    print_pubkey_info (pk);
+
+  free_public_key( pk );
 }
 
 
@@ -2726,17 +2760,48 @@ smartcard_change_name (const char *current_name)
   if (rc)
     log_error ("error setting Name: %s\n", gpg_strerror (rc));
 
+  xfree (isoname);
+  return rc;
+}
+
+
+static int
+smartcard_change_url (const char *current_url)
+{
+  char *url;
+  int rc;
+
+  url = cpr_get ("keygen.smartcard.url", _("URL to retrieve public key: "));
+  if (!url)
+    return -1;
+  trim_spaces (url);
+  cpr_kill_prompt ();
+
+  rc = agent_scd_setattr ("PUBKEY-URL", url, strlen (url) );
+  if (rc)
+    log_error ("error setting URL: %s\n", gpg_strerror (rc));
+  xfree (url);
   return rc;
 }
 
 
+/* Return true if the SHA1 fingerprint FPR consists only of zeroes. */
+static int
+fpr_is_zero (const char *fpr)
+{
+  int i;
+
+  for (i=0; i < 20 && !fpr[i]; i++)
+    ;
+  return (i == 20);
+}
+
 /* Check whether a smartcatrd is available and alow to select it as
    the target for key generation. 
    
    Return values: -1 = Quit generation
                    0 = No smartcard
-                   1 = Generate primary key
-                   2 = generate subkey
+                   1 = Generate keypair
 */
 static int
 check_smartcard (char **r_serialno)
@@ -2767,9 +2832,8 @@ check_smartcard (char **r_serialno)
       tty_printf ("\n"
                   "N - change cardholder name\n"
                   "U - change public key URL\n"
-                  "1 - generate signature key\n"
-                  "2 - generate encryption key\n"
-                  "3 - generate authentication key\n"
+                  "K - generate signature and encryption key\n"
+                  "A - generate authentication key\n"
                   "Q - quit\n"
                   "\n");
 
@@ -2786,13 +2850,31 @@ check_smartcard (char **r_serialno)
         }
       else if ( *answer == 'U' || *answer == 'u')
         {
+          if (!smartcard_change_url (info.pubkey_url))
+            reread = 1;
         }
-      else if ( *answer == '1' || *answer == '2')
+      else if ( *answer == 'K' || *answer == 'k')
         {
-          rc = *answer - '0';
-          break;
+          if ( (info.fpr1valid && !fpr_is_zero (info.fpr1))
+               || (info.fpr2valid && !fpr_is_zero (info.fpr2)))
+            {
+              tty_printf ("\n");
+              log_error ("WARNING: key does already exists!\n");
+              tty_printf ("\n");
+              if ( cpr_get_answer_is_yes( "keygen.card.replace_key",
+                                          _("Replace existing key? ")))
+                {
+                  rc = 1;
+                  break;
+                }
+            }
+          else
+            {
+              rc = 1;
+              break;
+            }
         }
-      else if ( *answer == '3' )
+      else if ( *answer == 'A' || *answer == 'a' )
         {
           tty_printf (_("Generation of authentication key"
                         " not yet implemented\n"));
@@ -2844,16 +2926,16 @@ gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
 
   assert (algo == PUBKEY_ALGO_RSA);
 
-  rc = agent_scd_genkey (&info, keyno, 0);
-  if (gpg_err_code (rc) == GPG_ERR_EEXIST)
-    {
-      tty_printf ("\n");
-      log_error ("WARNING: key does already exists!\n");
-      tty_printf ("\n");
-      if ( cpr_get_answer_is_yes( "keygen.card.replace_key",
-                                  _("Replace existing key? ")))
-        rc = agent_scd_genkey (&info, keyno, 1);
-    }
+  rc = agent_scd_genkey (&info, keyno, 1);
+/*    if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
+/*      { */
+/*        tty_printf ("\n"); */
+/*        log_error ("WARNING: key does already exists!\n"); */
+/*        tty_printf ("\n"); */
+/*        if ( cpr_get_answer_is_yes( "keygen.card.replace_key", */
+/*                                    _("Replace existing key? "))) */
+/*          rc = agent_scd_genkey (&info, keyno, 1); */
+/*      } */
 
   if (rc)
     {
index a68dc52..85d83e5 100644 (file)
@@ -201,6 +201,7 @@ struct {
 
 
 #define DBG_PACKET (opt.debug & DBG_PACKET_VALUE)
+#define DBG_CIPHER (opt.debug & DBG_CIPHER_VALUE)
 #define DBG_FILTER (opt.debug & DBG_FILTER_VALUE)
 #define DBG_CACHE  (opt.debug & DBG_CACHE_VALUE)
 #define DBG_TRUST  (opt.debug & DBG_TRUST_VALUE)
index 3e37882..7920a52 100644 (file)
@@ -177,6 +177,12 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
                            "(public-key(elg(p%m)(g%m)(y%m)))",
                            pkey[0], pkey[1], pkey[2]);
     }
+  else if (algo == GCRY_PK_RSA)
+    {
+      rc = gcry_sexp_build (&s_pkey, NULL,
+                           "(public-key(rsa(n%m)(e%m)))",
+                           pkey[0], pkey[1]);
+    }
   else
     return GPG_ERR_PUBKEY_ALGO;
 
@@ -202,11 +208,14 @@ pk_encrypt (int algo, gcry_mpi_t * resarr, gcry_mpi_t data, gcry_mpi_t * pkey)
       assert (resarr[0]);
       gcry_sexp_release (list);
 
-      list = gcry_sexp_find_token (s_ciph, "b", 0);
-      assert (list);
-      resarr[1] = gcry_sexp_nth_mpi (list, 1, 0);
-      assert (resarr[1]);
-      gcry_sexp_release (list);
+      if (algo != GCRY_PK_RSA)
+        {
+          list = gcry_sexp_find_token (s_ciph, "b", 0);
+          assert (list);
+          resarr[1] = gcry_sexp_nth_mpi (list, 1, 0);
+          assert (resarr[1]);
+          gcry_sexp_release (list);
+        }
     }
 
   gcry_sexp_release (s_ciph);
@@ -276,3 +285,10 @@ pk_decrypt (int algo, gcry_mpi_t * result, gcry_mpi_t * data,
 
   return 0;
 }
+
+
+
+
+
+
+
index b08394e..d052546 100644 (file)
@@ -38,6 +38,7 @@
 #include "main.h"
 #include "i18n.h"
 #include "pkglue.h"
+#include "call-agent.h"
 
 static int get_it( PKT_pubkey_enc *k,
                   DEK *dek, PKT_secret_key *sk, u32 *keyid );
@@ -136,146 +137,181 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek )
 static int
 get_it( PKT_pubkey_enc *enc, DEK *dek, PKT_secret_key *sk, u32 *keyid )
 {
-    int rc;
-    gcry_mpi_t plain_dek  = NULL;
-    byte *frame = NULL;
-    unsigned n, nframe;
-    u16 csum, csum2;
+  int rc;
+  gcry_mpi_t plain_dek = NULL;
+  byte *frame = NULL;
+  unsigned n, nframe;
+  u16 csum, csum2;
+  int card = 0;
 
-    rc = pk_decrypt (sk->pubkey_algo, &plain_dek, enc->data, sk->skey);
-    if( rc )
-      goto leave;
-    if ( gcry_mpi_aprint (GCRYMPI_FMT_USG, &frame, &nframe, plain_dek))
-      BUG();
-    gcry_mpi_release (plain_dek); plain_dek = NULL;
-
-    /* Now get the DEK (data encryption key) from the frame
-     *
-     * Old versions encode the DEK in in this format (msb is left):
-     *
-     *    0  1  DEK(16 bytes)  CSUM(2 bytes)  0  RND(n bytes) 2
-     *
-     * Later versions encode the DEK like this:
-     *
-     *    0  2  RND(n bytes)  0  A  DEK(k bytes)  CSUM(2 bytes)
-     *
-     * (mpi_get_buffer already removed the leading zero).
-     *
-     * RND are non-zero randow bytes.
-     * A   is the cipher algorithm
-     * DEK is the encryption key (session key) with length k
-     * CSUM
-     */
-    if( DBG_CIPHER )
-       log_printhex ("DEK frame:", frame, nframe );
-    n=0;
-    if( n + 7 > nframe )
-       { rc = GPG_ERR_WRONG_SECKEY; goto leave; }
-    if( frame[n] == 1 && frame[nframe-1] == 2 ) {
-       log_info(_("old encoding of the DEK is not supported\n"));
-       rc = GPG_ERR_CIPHER_ALGO;
-       goto leave;
+  if (sk->is_protected && sk->protect.s2k.mode == 1002)
+    { /* FIXME: Note that we do only support RSA for now. */
+      char *rbuf;
+      size_t rbuflen;
+      char *snbuf;
+      void *indata = NULL;
+      unsigned int indatalen;
+
+      snbuf = serialno_and_fpr_from_sk (sk->protect.iv, sk->protect.ivlen, sk);
+
+      if (gcry_mpi_aprint (GCRYMPI_FMT_USG, &indata, &indatalen,
+                           enc->data[0]))
+        BUG();
+
+      rc = agent_scd_pkdecrypt (snbuf, indata, indatalen, &rbuf, &rbuflen);
+      xfree (snbuf);
+      xfree (indata);
+      if (rc)
+        goto leave;
+
+      frame = rbuf;
+      nframe = rbuflen;
+      card = 1;
     }
-    if( frame[n] != 2 )  /* somethink is wrong */
-       { rc = GPG_ERR_WRONG_SECKEY; goto leave; }
-    for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */
-       ;
-    n++; /* and the zero byte */
-    if( n + 4 > nframe )
-       { rc = GPG_ERR_WRONG_SECKEY; goto leave; }
-
-    dek->keylen = nframe - (n+1) - 2;
-    dek->algo = frame[n++];
-    if( dek->algo ==  CIPHER_ALGO_IDEA )
-       write_status(STATUS_RSA_OR_IDEA);
-    rc = openpgp_cipher_test_algo (dek->algo);
-    if( rc ) {
-       if( !opt.quiet && gpg_err_code (rc) == GPG_ERR_CIPHER_ALGO ) {
-           log_info(_("cipher algorithm %d%s is unknown or disabled\n"),
-                     dek->algo, dek->algo == CIPHER_ALGO_IDEA? " (IDEA)":"");
-           if(dek->algo==CIPHER_ALGO_IDEA)
-             idea_cipher_warn(0);
-       }
-       dek->algo = 0;
-       goto leave;
+  else
+    {
+      void *indata;
+
+      rc = pk_decrypt (sk->pubkey_algo, &plain_dek, enc->data, sk->skey);
+      if( rc )
+        goto leave;
+      if (gcry_mpi_aprint (GCRYMPI_FMT_USG, &indata, &nframe, plain_dek))
+        BUG();
+      frame = indata;
+      gcry_mpi_release (plain_dek); plain_dek = NULL;
     }
-    if( dek->keylen != gcry_cipher_get_algo_keylen (dek->algo) ) {
-       rc = GPG_ERR_WRONG_SECKEY;
-       goto leave;
+
+
+  /* Now get the DEK (data encryption key) from the frame
+   *
+   * Old versions encode the DEK in in this format (msb is left):
+   *
+   *      0  1  DEK(16 bytes)  CSUM(2 bytes)  0  RND(n bytes) 2
+   *
+   * Later versions encode the DEK like this:
+   *
+   *      0  2  RND(n bytes)  0  A  DEK(k bytes)  CSUM(2 bytes)
+   *
+   * (mpi_get_buffer already removed the leading zero).
+   *
+   * RND are non-zero randow bytes.
+   * A   is the cipher algorithm
+   * DEK is the encryption key (session key) with length k
+   * CSUM
+   */
+  if( DBG_CIPHER )
+    log_printhex ("DEK frame:", frame, nframe );
+  n=0;
+  if (!card)
+    {
+      if( n + 7 > nframe )
+        { rc = GPG_ERR_WRONG_SECKEY; goto leave; }
+      if( frame[n] == 1 && frame[nframe-1] == 2 ) {
+        log_info(_("old encoding of the DEK is not supported\n"));
+        rc = GPG_ERR_CIPHER_ALGO;
+        goto leave;
+      }
+      if( frame[n] != 2 )  /* somethink is wrong */
+        { rc = GPG_ERR_WRONG_SECKEY; goto leave; }
+      for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */
+        ;
+      n++; /* and the zero byte */
     }
 
-    /* copy the key to DEK and compare the checksum */
-    csum  = frame[nframe-2] << 8;
-    csum |= frame[nframe-1];
-    memcpy( dek->key, frame+n, dek->keylen );
-    for( csum2=0, n=0; n < dek->keylen; n++ )
-       csum2 += dek->key[n];
-    if( csum != csum2 ) {
-       rc = GPG_ERR_WRONG_SECKEY;
-       goto leave;
+  if( n + 4 > nframe )
+    { rc = GPG_ERR_WRONG_SECKEY; goto leave; }
+  dek->keylen = nframe - (n+1) - 2;
+  dek->algo = frame[n++];
+  if( dek->algo ==  CIPHER_ALGO_IDEA )
+    write_status(STATUS_RSA_OR_IDEA);
+  rc = openpgp_cipher_test_algo (dek->algo);
+  if( rc ) {
+    if( !opt.quiet && gpg_err_code (rc) == GPG_ERR_CIPHER_ALGO ) {
+      log_info(_("cipher algorithm %d%s is unknown or disabled\n"),
+               dek->algo, dek->algo == CIPHER_ALGO_IDEA? " (IDEA)":"");
+      if(dek->algo==CIPHER_ALGO_IDEA)
+        idea_cipher_warn(0);
     }
-    if( DBG_CIPHER )
-       log_printhex ("DEK is:", dek->key, dek->keylen );
-    /* check that the algo is in the preferences and whether it has expired */
-    {
-       PKT_public_key *pk = NULL;
-        KBNODE pkb = get_pubkeyblock (keyid);
+    dek->algo = 0;
+    goto leave;
+  }
+  if( dek->keylen != gcry_cipher_get_algo_keylen (dek->algo) ) {
+    rc = GPG_ERR_WRONG_SECKEY;
+    goto leave;
+  }
 
-       if( !pkb ) {
-            rc = -1;
-           log_error("oops: public key not found for preference check\n");
-        }
-       else if( pkb->pkt->pkt.public_key->selfsigversion > 3
-            && dek->algo != CIPHER_ALGO_3DES
-           && !is_algo_in_prefs( pkb, PREFTYPE_SYM, dek->algo ) ) {
-           /* Don't print a note while we are not on verbose mode,
-            * the cipher is blowfish and the preferences have twofish
-            * listed */
-           if( opt.verbose || dek->algo != CIPHER_ALGO_BLOWFISH
-               || !is_algo_in_prefs( pkb, PREFTYPE_SYM, CIPHER_ALGO_TWOFISH))
-               log_info(_(
-                   "NOTE: cipher algorithm %d not found in preferences\n"),
-                                                                dek->algo );
-       }
+  /* copy the key to DEK and compare the checksum */
+  csum  = frame[nframe-2] << 8;
+  csum |= frame[nframe-1];
+  memcpy( dek->key, frame+n, dek->keylen );
+  for( csum2=0, n=0; n < dek->keylen; n++ )
+    csum2 += dek->key[n];
+  if( csum != csum2 ) {
+    rc = GPG_ERR_WRONG_SECKEY;
+    goto leave;
+  }
+  if( DBG_CIPHER )
+    log_printhex ("DEK is:", dek->key, dek->keylen );
+  /* check that the algo is in the preferences and whether it has expired */
+  {
+    PKT_public_key *pk = NULL;
+    KBNODE pkb = get_pubkeyblock (keyid);
+
+    if( !pkb ) {
+      rc = -1;
+      log_error("oops: public key not found for preference check\n");
+    }
+    else if( pkb->pkt->pkt.public_key->selfsigversion > 3
+             && dek->algo != CIPHER_ALGO_3DES
+             && !is_algo_in_prefs( pkb, PREFTYPE_SYM, dek->algo ) ) {
+      /* Don't print a note while we are not on verbose mode,
+       * the cipher is blowfish and the preferences have twofish
+       * listed */
+      if( opt.verbose || dek->algo != CIPHER_ALGO_BLOWFISH
+          || !is_algo_in_prefs( pkb, PREFTYPE_SYM, CIPHER_ALGO_TWOFISH))
+        log_info(_(
+                   "NOTE: cipher algorithm %d not found in preferences\n"),
+                 dek->algo );
+    }
 
-        if (!rc) {
-            KBNODE k;
+    if (!rc) {
+      KBNODE k;
             
-            for (k=pkb; k; k = k->next) {
-                if (k->pkt->pkttype == PKT_PUBLIC_KEY 
-                    || k->pkt->pkttype == PKT_PUBLIC_SUBKEY){
-                    u32 aki[2];
-                   keyid_from_pk(k->pkt->pkt.public_key, aki);
-
-                    if (aki[0]==keyid[0] && aki[1]==keyid[1]) {
-                        pk = k->pkt->pkt.public_key;
-                        break;
-                    }
-                }
-            }
-            if (!pk)
-                BUG ();
-            if ( pk->expiredate && pk->expiredate <= make_timestamp() ) {
-                log_info(_("NOTE: secret key %08lX expired at %s\n"),
-                         (ulong)keyid[1], asctimestamp( pk->expiredate) );
-            }
-        }
+      for (k=pkb; k; k = k->next) {
+        if (k->pkt->pkttype == PKT_PUBLIC_KEY 
+            || k->pkt->pkttype == PKT_PUBLIC_SUBKEY){
+          u32 aki[2];
+          keyid_from_pk(k->pkt->pkt.public_key, aki);
 
-        if ( pk &&  pk->is_revoked ) {
-            log_info( _("NOTE: key has been revoked") );
-            putc( '\n', log_get_stream() );
-            show_revocation_reason( pk, 1 );
+          if (aki[0]==keyid[0] && aki[1]==keyid[1]) {
+            pk = k->pkt->pkt.public_key;
+            break;
+          }
         }
+      }
+      if (!pk)
+        BUG ();
+      if ( pk->expiredate && pk->expiredate <= make_timestamp() ) {
+        log_info(_("NOTE: secret key %08lX expired at %s\n"),
+                 (ulong)keyid[1], asctimestamp( pk->expiredate) );
+      }
+    }
 
-       release_kbnode (pkb);
-       rc = 0;
+    if ( pk &&  pk->is_revoked ) {
+      log_info( _("NOTE: key has been revoked") );
+      putc( '\n', log_get_stream() );
+      show_revocation_reason( pk, 1 );
     }
 
+    release_kbnode (pkb);
+    rc = 0;
+  }
 
-  leave:
-    gcry_mpi_release (plain_dek);
-    xfree (frame);
-    return rc;
+
+ leave:
+  gcry_mpi_release (plain_dek);
+  xfree (frame);
+  return rc;
 }
 
 
index dff463c..65be7a4 100644 (file)
@@ -297,11 +297,14 @@ check_secret_key( PKT_secret_key *sk, int n )
 /****************
  * check whether the secret key is protected.
  * Returns: 0 not protected, -1 on error or the protection algorithm
+ *                           -2 indicates a card stub.
  */
 int
 is_secret_key_protected( PKT_secret_key *sk )
 {
-    return sk->is_protected? sk->protect.algo : 0;
+    return sk->is_protected?
+               sk->protect.s2k.mode == 1002? -2
+                                           : sk->protect.algo : 0;
 }
 
 
index ae22032..11ebe17 100644 (file)
@@ -30,7 +30,7 @@
 #include "mpi.h"
 #include "main.h"
 #include "i18n.h"
-
+#include "options.h"
 
 /****************
  * Make a session key and put it into DEK
@@ -143,7 +143,11 @@ encode_session_key (DEK *dek, unsigned int nbits)
     memcpy( frame+n, dek->key, dek->keylen ); n += dek->keylen;
     frame[n++] = csum >>8;
     frame[n++] = csum;
-    assert( n == nframe );
+    assert (n == nframe);
+
+    if (DBG_CIPHER)
+      log_printhex ("encoded session key:", frame, nframe );
+
     if (gcry_mpi_scan( &a, GCRYMPI_FMT_USG, frame, &nframe))
       BUG();
     xfree (frame);
index d9ce074..fa1e07b 100644 (file)
@@ -41,6 +41,8 @@
 #include "status.h"
 #include "i18n.h"
 #include "pkglue.h"
+#include "call-agent.h"
+
 
 #ifdef HAVE_DOSISH_SYSTEM
 #define LF "\r\n"