Fix strerror vs. gpg_strerror usage.
[gnupg.git] / agent / cvt-openpgp.c
index 73c31f7..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,10 +80,12 @@ 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:
+    case GCRY_PK_ECDSA:
+    case GCRY_PK_ECDH:
       err = gcry_sexp_build (&s_pkey, NULL,
-                             "(public-key(ecc(c%m)(q%m)))", pkey[0], pkey[1]);
+                             "(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:
@@ -100,9 +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. 
-   pubkey_algo is a libgcrypt ID
- */
+   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)
 {
@@ -111,8 +112,6 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
 
   *r_key = NULL;
 
-  pubkey_algo = map_pk_openpgp_to_gcry( pubkey_algo );
-
   switch (pubkey_algo)
     {
     case GCRY_PK_DSA:
@@ -139,15 +138,15 @@ convert_secret_key (gcry_sexp_t *r_key, int pubkey_algo, gcry_mpi_t *skey)
       break;
 
     case GCRY_PK_ECDSA:
-      err = gcry_sexp_build (&s_skey, NULL,
-                             "(private-key(ecdsa(c%m)(q%m)(d%m)))",
-                             skey[0], skey[1], skey[2]);
-      break;
-
     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(ecdh(c%m)(q%m)(p%m)(d%m)))",
-                             skey[0], skey[1], skey[2], skey[3]);
+                             "(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:
@@ -176,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 ();
@@ -196,7 +195,7 @@ static u16
 checksum (const unsigned char *p, unsigned int n)
 {
   u16 a;
-  
+
   for (a=0; n; n-- )
     a += *p++;
   return a;
@@ -224,9 +223,9 @@ 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 );
+ /* 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.  */
@@ -264,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)
@@ -276,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)
             {
@@ -293,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;
@@ -316,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
@@ -335,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)
     {
@@ -371,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);
@@ -389,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
@@ -409,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)
@@ -460,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)
             {
@@ -468,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];
@@ -549,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)
@@ -617,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;
@@ -655,7 +654,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
   string = gcry_sexp_nth_string (list, 1);
   if (!string)
     goto bad_seckey;
-  pubkey_algo = gcry_pk_map_name (string);     /* ligcrypt IDs */
+  pubkey_algo = gcry_pk_map_name (string);
   xfree (string);
 
   if (gcry_pk_algo_info (pubkey_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
@@ -840,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;
@@ -866,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)
     {
@@ -1020,9 +1019,8 @@ 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);
-  log_debug ( "convert to openpgp begin for algo=%s\n", name );
   xfree (name);
 
   switch (algo)
@@ -1031,8 +1029,8 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
     case GCRY_PK_ELG:   algoname = "elg";   npkey = 3; elems = "pgyx";    break;
     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 = 2; elems = "cqd";     break;
-    case GCRY_PK_ECDH:  algoname = "ecdh";  npkey = 3; elems = "cqpd";    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) );
@@ -1048,11 +1046,13 @@ 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);
-  ///log_debug ( "convert to openpgp: after applying protection, err = %d\n", err );
   /* Turn it into the transfer key S-expression.  Note that we always
      return a protected key.  */
   if (!err)
@@ -1062,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;
+      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++)
@@ -1082,8 +1082,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
       put_membuf_str (&mbuf, ")\n");
       put_membuf (&mbuf, "", 1);
 
-      ///log_debug ( "convert to openpgp: calling gcry_sexp_build\n" );
-
       tmpkey = NULL;
       {
         char *format = get_membuf (&mbuf, NULL);
@@ -1093,7 +1091,6 @@ convert_to_openpgp (ctrl_t ctrl, gcry_sexp_t s_key, const char *passphrase,
           err = gcry_sexp_build_array (&tmpkey, NULL, format, format_args);
         xfree (format);
       }
-      ///log_debug ( "convert to openpgp: calling gcry_sexp_build before err=%d\n", err );
       if (!err)
         err = gcry_sexp_build (&tmpsexp, NULL,
                                "(openpgp-private-key\n"
@@ -1102,11 +1099,10 @@ 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);
-      ///log_debug ( "convert to openpgp: after gcry_sexp_build, err = %d\n", err );
       gcry_sexp_release (tmpkey);
       if (!err)
         err = make_canon_sexp_pad (tmpsexp, 0, r_transferkey, r_transferkeylen);
@@ -1116,8 +1112,5 @@ 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]);
 
-  log_debug ( "convert to openpgp end with err=%d\n", err );
-  
   return err;
 }
-