agent: New GETINFO sub-commands "s2k_count_cal" and "s2k_time".
[gnupg.git] / agent / protect.c
index a78d5a5..fe44f18 100644 (file)
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include "agent.h"
 
 #include "cvt-openpgp.h"
-#include "sexp-parse.h"
+#include "../common/sexp-parse.h"
 
 
-#if GCRYPT_VERSION_NUMBER < 0x010700
-# define OCB_MODE_SUPPORTED 0
-#else
-# define OCB_MODE_SUPPORTED 1
-#endif
-
-/* To use the openpgp-s2k3-ocb-aes scheme by default set the value of
- * this macro to 1.  Note that the caller of agent_protect may
- * override this default.  */
-#define PROT_DEFAULT_TO_OCB 0
-
 /* The protection mode for encryption.  The supported modes for
    decryption are listed in agent_unprotect().  */
 #define PROT_CIPHER        GCRY_CIPHER_AES128
@@ -65,7 +54,7 @@
 
 /* A table containing the information needed to create a protected
    private key.  */
-static struct {
+static const struct {
   const char *algo;
   const char *parmlist;
   int prot_from, prot_to;
@@ -170,7 +159,7 @@ calibrate_s2k_count_one (unsigned long count)
 
 
 /* Measure the time we need to do the hash operations and deduce an
-   S2K count which requires about 100ms of time.  */
+   S2K count which requires roughly some targeted amount of time.  */
 static unsigned long
 calibrate_s2k_count (void)
 {
@@ -182,11 +171,11 @@ calibrate_s2k_count (void)
       ms = calibrate_s2k_count_one (count);
       if (opt.verbose > 1)
         log_info ("S2K calibration: %lu -> %lums\n", count, ms);
-      if (ms > 100)
+      if (ms > AGENT_S2K_CALIBRATION)
         break;
     }
 
-  count = (unsigned long)(((double)count / ms) * 100);
+  count = (unsigned long)(((double)count / ms) * AGENT_S2K_CALIBRATION);
   count /= 1024;
   count *= 1024;
   if (count < 65536)
@@ -202,10 +191,10 @@ calibrate_s2k_count (void)
 }
 
 
-
-/* Return the standard S2K count.  */
+/* Return the calibrated S2K count.  This is only public for the use
+ * of the Assuan getinfo s2k_count_cal command.  */
 unsigned long
-get_standard_s2k_count (void)
+get_calibrated_s2k_count (void)
 {
   static unsigned long count;
 
@@ -217,6 +206,26 @@ get_standard_s2k_count (void)
 }
 
 
+/* Return the standard S2K count.  */
+unsigned long
+get_standard_s2k_count (void)
+{
+  if (opt.s2k_count)
+    return opt.s2k_count < 65536 ? 65536 : opt.s2k_count;
+
+  return get_calibrated_s2k_count ();
+}
+
+
+/* Return the milliseconds required for the standard S2K
+ * operation.  */
+unsigned long
+get_standard_s2k_time (void)
+{
+  return calibrate_s2k_count_one (get_standard_s2k_count ());
+}
+
+
 /* Same as get_standard_s2k_count but return the count in the encoding
    as described by rfc4880.  */
 unsigned char
@@ -249,7 +258,7 @@ get_standard_s2k_count_rfc4880 (void)
 /* Calculate the MIC for a private key or shared secret S-expression.
    SHA1HASH should point to a 20 byte buffer.  This function is
    suitable for all algorithms. */
-static int
+static gpg_error_t
 calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
 {
   const unsigned char *hash_begin, *hash_end;
@@ -353,16 +362,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
   *resultlen = 0;
   *result = NULL;
 
-  if (use_ocb && !OCB_MODE_SUPPORTED)
-    return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
-
   modestr = (use_ocb? "openpgp-s2k3-ocb-aes"
              /*   */: "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc");
 
   rc = gcry_cipher_open (&hd, PROT_CIPHER,
-#if OCB_MODE_SUPPORTED
                          use_ocb? GCRY_CIPHER_MODE_OCB :
-#endif
                          GCRY_CIPHER_MODE_CBC,
                          GCRY_CIPHER_SECURE);
   if (rc)
@@ -397,7 +401,10 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
       outbuf = gcry_malloc_secure (outlen);
     }
   if (!outbuf)
-    rc = out_of_core ();
+    {
+      rc = out_of_core ();
+      goto leave;
+    }
 
   /* Allocate a buffer for the nonce and the salt.  */
   if (!rc)
@@ -437,11 +444,13 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
         }
     }
 
+  if (rc)
+    goto leave;
+
   /* Set the IV/nonce.  */
-  if (!rc)
-    {
-      rc = gcry_cipher_setiv (hd, iv, use_ocb? 12 : blklen);
-    }
+  rc = gcry_cipher_setiv (hd, iv, use_ocb? 12 : blklen);
+  if (rc)
+    goto leave;
 
   if (use_ocb)
     {
@@ -452,7 +461,6 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
       if (!rc)
         rc = gcry_cipher_authenticate
           (hd, protbegin+protlen, hashlen - (protbegin+protlen - hashbegin));
-
     }
   else
     {
@@ -464,9 +472,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
       rc = gcry_md_open (&md, GCRY_MD_SHA1, 0 );
       if (!rc)
         {
-          gcry_md_write (md, hashbegin, hashlen);
+          gcry_md_write (md, hashbegin, protbegin - hashbegin);
+          gcry_md_write (md, protbegin, protlen);
           gcry_md_write (md, timestamp_exp, timestamp_exp_len);
-          gcry_md_write (md, ")", 1);
+          gcry_md_write (md, protbegin+protlen,
+                         hashlen - (protbegin+protlen - hashbegin));
           memcpy (hashvalue, gcry_md_read (md, GCRY_MD_SHA1), 20);
           gcry_md_close (md);
         }
@@ -498,7 +508,6 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
           p += blklen;
         }
       assert ( p - outbuf == outlen);
-#if OCB_MODE_SUPPORTED
       if (use_ocb)
         {
           gcry_cipher_final (hd);
@@ -510,20 +519,16 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
             }
         }
       else
-#endif /*OCB_MODE_SUPPORTED*/
         {
           rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
         }
     }
 
+  if (rc)
+    goto leave;
+
   /* Release cipher handle and check for errors.  */
   gcry_cipher_close (hd);
-  if (rc)
-    {
-      xfree (iv);
-      xfree (outbuf);
-      return rc;
-    }
 
   /* Now allocate the buffer we want to return.  This is
 
@@ -562,6 +567,12 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
   xfree (iv);
   xfree (outbuf);
   return 0;
+
+ leave:
+  gcry_cipher_close (hd);
+  xfree (iv);
+  xfree (outbuf);
+  return rc;
 }
 
 
@@ -591,7 +602,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
   int have_curve = 0;
 
   if (use_ocb == -1)
-    use_ocb = PROT_DEFAULT_TO_OCB;
+    use_ocb = opt.enable_extended_key_format;
 
   /* Create an S-expression with the protected-at timestamp.  */
   memcpy (timestamp_exp, "(12:protected-at15:", 19);
@@ -701,7 +712,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
     return rc;
 
   /* Now create the protected version of the key.  Note that the 10
-     extra bytes are for for the inserted "protected-" string (the
+     extra bytes are for the inserted "protected-" string (the
      beginning of the plaintext reads: "((11:private-key(" ).  The 35
      term is the space for (12:protected-at15:<timestamp>).  */
   *resultlen = (10
@@ -737,7 +748,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
 
 \f
 /* Do the actual decryption and check the return list for consistency.  */
-static int
+static gpg_error_t
 do_decryption (const unsigned char *aad_begin, size_t aad_len,
                const unsigned char *aadhole_begin, size_t aadhole_len,
                const unsigned char *protected, size_t protectedlen,
@@ -747,15 +758,12 @@ do_decryption (const unsigned char *aad_begin, size_t aad_len,
                int prot_cipher, int prot_cipher_keylen, int is_ocb,
                unsigned char **result)
 {
-  int rc = 0;
+  int rc;
   int blklen;
   gcry_cipher_hd_t hd;
   unsigned char *outbuf;
   size_t reallen;
 
-  if (is_ocb && !OCB_MODE_SUPPORTED)
-    return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
-
   blklen = gcry_cipher_get_algo_blklen (prot_cipher);
   if (is_ocb)
     {
@@ -772,9 +780,7 @@ do_decryption (const unsigned char *aad_begin, size_t aad_len,
     }
 
   rc = gcry_cipher_open (&hd, prot_cipher,
-#if OCB_MODE_SUPPORTED
                          is_ocb? GCRY_CIPHER_MODE_OCB :
-#endif
                          GCRY_CIPHER_MODE_CBC,
                          GCRY_CIPHER_SECURE);
   if (rc)
@@ -811,7 +817,6 @@ do_decryption (const unsigned char *aad_begin, size_t aad_len,
   /* Decrypt.  */
   if (!rc)
     {
-#if OCB_MODE_SUPPORTED
       if (is_ocb)
         {
           rc = gcry_cipher_authenticate (hd, aad_begin,
@@ -828,10 +833,16 @@ do_decryption (const unsigned char *aad_begin, size_t aad_len,
                                         protected, protectedlen - 16);
             }
           if (!rc)
-            rc = gcry_cipher_checktag (hd, protected + protectedlen - 16, 16);
+            {
+              rc = gcry_cipher_checktag (hd, protected + protectedlen - 16, 16);
+              if (gpg_err_code (rc) == GPG_ERR_CHECKSUM)
+                {
+                  /* Return Bad Passphrase instead of checksum error */
+                  rc = gpg_error (GPG_ERR_BAD_PASSPHRASE);
+                }
+            }
         }
       else
-#endif /*OCB_MODE_SUPPORTED*/
         {
           rc = gcry_cipher_decrypt (hd, outbuf, protectedlen,
                                     protected, protectedlen);
@@ -849,8 +860,6 @@ do_decryption (const unsigned char *aad_begin, size_t aad_len,
   /* Do a quick check on the data structure. */
   if (*outbuf != '(' && outbuf[1] != '(')
     {
-      /* Note that in OCB mode this is actually invalid _encrypted_
-       * data and not a bad passphrase.  */
       xfree (outbuf);
       return gpg_error (GPG_ERR_BAD_PASSPHRASE);
     }
@@ -874,7 +883,7 @@ do_decryption (const unsigned char *aad_begin, size_t aad_len,
  * CUTOFF and CUTLEN will receive the offset and the length of the
  * resulting list which should go into the MIC calculation but then be
  * removed.  */
-static int
+static gpg_error_t
 merge_lists (const unsigned char *protectedkey,
              size_t replacepos,
              const unsigned char *cleartext,
@@ -1027,13 +1036,13 @@ merge_lists (const unsigned char *protectedkey,
 /* Unprotect the key encoded in canonical format.  We assume a valid
    S-Exp here.  If a protected-at item is available, its value will
    be stored at protected_at unless this is NULL.  */
-int
+gpg_error_t
 agent_unprotect (ctrl_t ctrl,
                  const unsigned char *protectedkey, const char *passphrase,
                  gnupg_isotime_t protected_at,
                  unsigned char **result, size_t *resultlen)
 {
-  static struct {
+  static const struct {
     const char *name; /* Name of the protection method. */
     int algo;         /* (A zero indicates the "openpgp-native" hack.)  */
     int keylen;       /* Used key length in bytes.  */
@@ -1175,8 +1184,7 @@ agent_unprotect (ctrl_t ctrl,
         is_ocb = algotable[i].is_ocb;
         break;
       }
-  if (i == DIM (algotable)
-      || (is_ocb && !OCB_MODE_SUPPORTED))
+  if (i == DIM (algotable))
     return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
 
   if (!prot_cipher)  /* This is "openpgp-native".  */
@@ -1308,6 +1316,7 @@ agent_unprotect (ctrl_t ctrl,
   return 0;
 }
 
+
 /* Check the type of the private key, this is one of the constants:
    PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
    value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
@@ -1566,7 +1575,7 @@ agent_shadow_key (const unsigned char *pubkey,
 
 /* Parse a canonical encoded shadowed key and return a pointer to the
    inner list with the shadow_info */
-int
+gpg_error_t
 agent_get_shadow_info (const unsigned char *shadowkey,
                        unsigned char const **shadow_info)
 {