Fix strerror vs. gpg_strerror usage.
[gnupg.git] / agent / cvt-openpgp.c
index 8105ae6..ec0fd0a 100644 (file)
@@ -30,7 +30,7 @@
 
 
 /* Helper to pass data via the callback to do_unprotect. */
-struct try_do_unprotect_arg_s 
+struct try_do_unprotect_arg_s
 {
   int  is_v4;
   int  is_protected;
@@ -80,6 +80,14 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
                              "(public-key(rsa(n%m)(e%m)))", pkey[0], pkey[1]);
       break;
 
+    case GCRY_PK_ECDSA:
+    case GCRY_PK_ECDH:
+      err = gcry_sexp_build (&s_pkey, NULL,
+                             "(public-key(ecc(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)))",
+                             pkey[0], pkey[1], pkey[2], pkey[3], pkey[4],
+                             pkey[5]);
+      break;
+
     default:
       err = gpg_error (GPG_ERR_PUBKEY_ALGO);
       break;
@@ -94,7 +102,8 @@ get_keygrip (int pubkey_algo, gcry_mpi_t *pkey, unsigned char *grip)
 
 
 /* Convert a secret key given as algorithm id and an array of key
-   parameters into our s-expression based format.  */
+   parameters into our s-expression based format.  Note that
+   PUBKEY_ALGO has an gcrypt algorithm number. */
 static gpg_error_t
 convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
 {
@@ -126,6 +135,19 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
                              "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
                              skey[0], skey[1], skey[2], skey[3], skey[4],
                              skey[5]);
+      break;
+
+    case GCRY_PK_ECDSA:
+    case GCRY_PK_ECDH:
+      /* Although our code would work with "ecc" we explicitly use
+         "ecdh" or "ecdsa" to implicitly set the key capabilities.  */
+      err = gcry_sexp_build (&s_skey, NULL,
+                             "(private-key(%s(p%m)(a%m)(b%m)(g%m)(n%m)(q%m)"
+                             "(d%m)))",
+                             pubkey_algo == GCRY_PK_ECDSA?"ecdsa":"ecdh",
+                             skey[0], skey[1], skey[2], skey[3], skey[4],
+                             skey[5], skey[6]);
+      break;
 
     default:
       err = gpg_error (GPG_ERR_PUBKEY_ALGO);
@@ -153,7 +175,7 @@ hash_passphrase_and_set_key (const char *passphrase,
   keylen = gcry_cipher_get_algo_keylen (protect_algo);
   if (!keylen)
     return gpg_error (GPG_ERR_INTERNAL);
-  
+
   key = xtrymalloc_secure (keylen);
   if (!key)
     return gpg_error_from_syserror ();
@@ -173,7 +195,7 @@ static u16
 checksum (const unsigned char *p, unsigned int n)
 {
   u16 a;
-  
+
   for (a=0; n; n-- )
     a += *p++;
   return a;
@@ -201,6 +223,10 @@ do_unprotect (const char *passphrase,
 
   *r_key = NULL;
 
+ /* Unfortunately, the OpenPGP PK algorithm numbers need to be
+    re-mapped for Libgcrypt.    */
+  pubkey_algo = map_pk_openpgp_to_gcry (pubkey_algo);
+
   /* Count the actual number of MPIs is in the array and set the
      remainder to NULL for easier processing later on.  */
   for (skeylen = 0; skey[skeylen]; skeylen++)
@@ -218,9 +244,6 @@ do_unprotect (const char *passphrase,
 
   if (gcry_pk_test_algo (pubkey_algo))
     {
-      /* The algorithm numbers are Libgcrypt numbers but fortunately
-         the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
-         numbers.  */
       log_info (_("public key algorithm %d (%s) is not supported\n"),
                 pubkey_algo, gcry_pk_algo_name (pubkey_algo));
       return gpg_error (GPG_ERR_PUBKEY_ALGO);
@@ -240,7 +263,7 @@ do_unprotect (const char *passphrase,
     return gpg_error (GPG_ERR_MISSING_VALUE);
   if (nskey+1 >= skeysize)
     return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
-  
+
   /* Check whether SKEY is at all protected.  If it is not protected
      merely verify the checksum.  */
   if (!is_protected)
@@ -252,7 +275,7 @@ do_unprotect (const char *passphrase,
         {
           if (!skey[i] || gcry_mpi_get_flag (skey[i], GCRYMPI_FLAG_OPAQUE))
             return gpg_error (GPG_ERR_BAD_SECKEY);
-          
+
           err = gcry_mpi_print (GCRYMPI_FMT_PGP, NULL, 0, &nbytes, skey[i]);
           if (!err)
             {
@@ -269,7 +292,7 @@ do_unprotect (const char *passphrase,
           if (err)
             return err;
         }
-      
+
       if (actual_csum != desired_csum)
         return gpg_error (GPG_ERR_CHECKSUM);
       return 0;
@@ -282,7 +305,7 @@ do_unprotect (const char *passphrase,
          the OpenPGP algorithm numbers map one-to-one to the Libgcrypt
          numbers.  */
       log_info (_("protection algorithm %d (%s) is not supported\n"),
-                protect_algo, gcry_cipher_algo_name (protect_algo));
+                protect_algo, gnupg_cipher_algo_name (protect_algo));
       return gpg_error (GPG_ERR_CIPHER_ALGO);
     }
 
@@ -292,7 +315,7 @@ do_unprotect (const char *passphrase,
                 s2k_algo, gcry_md_algo_name (s2k_algo));
       return gpg_error (GPG_ERR_DIGEST_ALGO);
     }
-  
+
   err = gcry_cipher_open (&cipher_hd, protect_algo,
                           GCRY_CIPHER_MODE_CFB,
                           (GCRY_CIPHER_SECURE
@@ -311,10 +334,10 @@ do_unprotect (const char *passphrase,
     {
       gcry_cipher_close (cipher_hd);
       return err;
-    }  
+    }
 
   gcry_cipher_setiv (cipher_hd, protect_iv, protect_ivlen);
-  
+
   actual_csum = 0;
   if (pkt_version >= 4)
     {
@@ -347,15 +370,15 @@ do_unprotect (const char *passphrase,
         {
           /* This is the new SHA1 checksum method to detect tampering
              with the key as used by the Klima/Rosa attack.  */
-          desired_csum = 0; 
+          desired_csum = 0;
           actual_csum = 1;  /* Default to bad checksum.  */
 
-          if (ndata < 20) 
+          if (ndata < 20)
             log_error ("not enough bytes for SHA-1 checksum\n");
-          else 
+          else
             {
               gcry_md_hd_t h;
-              
+
               if (gcry_md_open (&h, GCRY_MD_SHA1, 1))
                 BUG(); /* Algo not available. */
               gcry_md_write (h, data, ndata - 20);
@@ -365,13 +388,13 @@ do_unprotect (const char *passphrase,
               gcry_md_close (h);
             }
         }
-      else 
+      else
         {
           /* Old 16 bit checksum method.  */
           if (ndata < 2)
             {
               log_error ("not enough bytes for checksum\n");
-              desired_csum = 0; 
+              desired_csum = 0;
               actual_csum = 1;  /* Mark checksum bad.  */
             }
           else
@@ -385,7 +408,7 @@ do_unprotect (const char *passphrase,
                 }
             }
         }
-      
+
       /* Better check it here.  Otherwise the gcry_mpi_scan would fail
          because the length may have an arbitrary value.  */
       if (desired_csum == actual_csum)
@@ -436,7 +459,7 @@ do_unprotect (const char *passphrase,
               gcry_cipher_close (cipher_hd);
               return gpg_error (GPG_ERR_BAD_SECKEY);
             }
-          
+
           buffer = xtrymalloc_secure (ndata);
           if (!buffer)
             {
@@ -444,7 +467,7 @@ do_unprotect (const char *passphrase,
               gcry_cipher_close (cipher_hd);
               return err;
             }
-              
+
           gcry_cipher_sync (cipher_hd);
           buffer[0] = p[0];
           buffer[1] = p[1];
@@ -525,7 +548,7 @@ try_do_unprotect_cb (struct pin_entry_info_s *pi)
    pointed to by GRIP.  On error NULL is stored at all return
    arguments.  */
 gpg_error_t
-convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp, 
+convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
                       unsigned char *grip, const char *prompt,
                       const char *cache_nonce,
                       unsigned char **r_key, char **r_passphrase)
@@ -593,7 +616,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
       if (!protect_algo && !!strcmp (string, "IDEA"))
         protect_algo = GCRY_CIPHER_IDEA;
       xfree (string);
-      
+
       value = gcry_sexp_nth_data (list, 3, &valuelen);
       if (!value || !valuelen || valuelen > sizeof iv)
         goto bad_seckey;
@@ -779,7 +802,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
         err = try_do_unprotect_cb (pi);
     }
   if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE)
-    err = agent_askpin (ctrl, prompt, NULL, NULL, pi, NULL);
+    err = agent_askpin (ctrl, prompt, NULL, NULL, pi);
   skeyidx = pi_arg.skeyidx;
   if (!err)
     {
@@ -816,7 +839,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
  bad_seckey:
   err = gpg_error (GPG_ERR_BAD_SECKEY);
   goto leave;
-  
+
  outofmem:
   err = gpg_error (GPG_ERR_ENOMEM);
   goto leave;
@@ -842,13 +865,13 @@ key_from_sexp (gcry_sexp_t sexp, const char *elems, gcry_mpi_t *array)
         }
       array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
       gcry_sexp_release (l2);
-      if (!array[idx]) 
+      if (!array[idx])
         {
           err = gpg_error (GPG_ERR_INV_OBJ); /* Required parameter invalid.  */
           goto leave;
         }
     }
-  
+
  leave:
   if (err)
     {
@@ -996,7 +1019,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
       gcry_sexp_release (list);
       return gpg_error (GPG_ERR_INV_OBJ); /* Invalid structure of object. */
     }
-  
+
   algo = gcry_pk_map_name (name);
   xfree (name);
 
@@ -1007,6 +1030,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
     case GCRY_PK_ELG_E: algoname = "elg";   npkey = 3; elems = "pgyx";    break;
     case GCRY_PK_DSA:   algoname = "dsa";   npkey = 4; elems = "pqgyx";   break;
     case GCRY_PK_ECDSA: algoname = "ecdsa"; npkey = 6; elems = "pabgnqd"; break;
+    case GCRY_PK_ECDH:  algoname = "ecdh";  npkey = 6; elems = "pabgnqd"; break;
     default:            algoname = "";      npkey = 0; elems = NULL;      break;
     }
   assert (!elems || strlen (elems) < DIM (array) );
@@ -1022,7 +1046,10 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
 
   gcry_create_nonce (protect_iv, sizeof protect_iv);
   gcry_create_nonce (salt, sizeof salt);
-  s2k_count = get_standard_s2k_count ();
+  /* We need to use the encoded S2k count.  It is not possible to
+     encode it after it has been used because the encoding procedure
+     may round the value up.  */
+  s2k_count = get_standard_s2k_count_rfc4880 ();
   err = apply_protection (array, npkey, nskey, passphrase,
                           GCRY_CIPHER_AES, protect_iv, sizeof protect_iv,
                           3, GCRY_MD_SHA1, salt, s2k_count);
@@ -1035,11 +1062,11 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
       void *format_args_buf_ptr[1];
       int   format_args_buf_int[1];
       void *format_args[10+2];
-      size_t n;
-      gcry_sexp_t tmpkey, tmpsexp;
-      
+      unsigned int n;
+      gcry_sexp_t tmpkey, tmpsexp = NULL;
+
       snprintf (countbuf, sizeof countbuf, "%lu", s2k_count);
-      
+
       init_membuf (&mbuf, 50);
       put_membuf_str (&mbuf, "(skey");
       for (i=j=0; i < npkey; i++)
@@ -1072,7 +1099,7 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
                                " %S\n"
                                " (protection sha1 aes %b 1:3 sha1 %b %s))\n",
                                algoname,
-                               tmpkey, 
+                               tmpkey,
                                (int)sizeof protect_iv, protect_iv,
                                (int)sizeof salt, salt,
                                countbuf);
@@ -1084,7 +1111,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
 
   for (i=0; i < DIM (array); i++)
     gcry_mpi_release (array[i]);
-  
+
   return err;
 }
-