[git] GnuPG - branch, master, updated. gnupg-2.1.21-43-ga64a55e

by Justus Winter cvs at cvs.gnupg.org
Thu Jun 8 14:23:33 CEST 2017


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".

The branch, master has been updated
       via  a64a55e10420cf11e00062b590dffe5d0c3e8192 (commit)
       via  b03fab09e188f7bb10237d4f20455e4026737e4e (commit)
      from  9b43220b8ad1a5c1cd51de3bbfff7ccbcc3fa877 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a64a55e10420cf11e00062b590dffe5d0c3e8192
Author: Justus Winter <justus at g10code.com>
Date:   Tue Jun 6 16:01:40 2017 +0200

    common,gpg,sm: Restrict the use of algorithms according to CO_DE_VS.
    
    * common/compliance.c (gnupg_pk_is_allowed): New function.
    (gnupg_cipher_is_allowed): Likewise.
    (gnupg_digest_is_allowed): Likewise.
    * common/compliance.h (enum pk_use_case): New definition.
    (gnupg_pk_is_allowed): New prototype.
    (gnupg_cipher_is_allowed): Likewise.
    (gnupg_digest_is_allowed): Likewise.
    * g10/decrypt-data.c (decrypt_data): Restrict use of algorithms using
    the new predicates.
    * g10/encrypt.c (encrypt_crypt): Likewise.
    * g10/gpg.c (main): Likewise.
    * g10/pubkey-enc.c (get_session_key): Likewise.
    * g10/sig-check.c (check_signature2): Likewise.
    * g10/sign.c (do_sign): Likewise.
    * sm/decrypt.c (gpgsm_decrypt): Likewise.
    * sm/encrypt.c (gpgsm_encrypt): Likewise.
    * sm/gpgsm.c (main): Likewise.
    * sm/sign.c (gpgsm_sign): Likewise.
    * sm/verify.c (gpgsm_verify): Likewise.
    --
    
    With this change, policies can effectively restrict what algorithms
    are used for different purposes.  The algorithm policy for CO_DE_VS is
    implemented.
    
    GnuPG-bug-id: 3191
    Signed-off-by: Justus Winter <justus at g10code.com>

diff --git a/common/compliance.c b/common/compliance.c
index bcf621a..4078004 100644
--- a/common/compliance.c
+++ b/common/compliance.c
@@ -193,6 +193,105 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
 }
 
 
+/* Return true if ALGO with the given KEYLENGTH is allowed in the
+ * given COMPLIANCE mode.  USE specifies for which use case the
+ * predicate is evaluated.  This way policies can be strict in what
+ * they produce, and liberal in what they accept.  */
+int
+gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
+		     enum pk_use_case use, int algo, gcry_mpi_t key[],
+		     unsigned int keylength, const char *curvename)
+{
+  switch (compliance)
+    {
+    case CO_DE_VS:
+      switch (algo)
+	{
+	case PUBKEY_ALGO_RSA:
+	case PUBKEY_ALGO_RSA_E:
+	case PUBKEY_ALGO_RSA_S:
+	  switch (use)
+	    {
+	    case PK_USE_ENCRYPTION:
+	      return 1;
+	    case PK_USE_DECRYPTION:
+	    case PK_USE_SIGNING:
+	      return (keylength == 2048
+		      || keylength == 3072
+		      || keylength == 4096);
+	    case PK_USE_VERIFICATION:
+	      return (keylength == 2048
+		      || keylength == 3072
+		      || keylength == 4096
+		      || keylength < 2048);
+	    default:
+	      log_assert (!"reached");
+	    }
+	  log_assert (!"reached");
+
+	case PUBKEY_ALGO_DSA:
+	  if (key)
+	    {
+	      size_t L = gcry_mpi_get_nbits (key[0] /* p */);
+	      size_t N = gcry_mpi_get_nbits (key[1] /* q */);
+	      return ((use == PK_USE_SIGNING
+		       && L == 256
+		       && (N == 2048 || N == 3072))
+		      || (use == PK_USE_VERIFICATION
+			  && N < 2048));
+	    }
+	  else
+	    return 0;
+	  log_assert (!"reached");
+
+	case PUBKEY_ALGO_ELGAMAL:
+	case PUBKEY_ALGO_ELGAMAL_E:
+	  return use == PK_USE_ENCRYPTION;
+
+	case PUBKEY_ALGO_ECDH:
+	  return use == PK_USE_ENCRYPTION;
+
+	case PUBKEY_ALGO_ECDSA:
+	  {
+	    int result = 0;
+	    char *curve = NULL;
+
+	    if (! curvename && key)
+	      {
+		curve = openpgp_oid_to_str (key[0]);
+		curvename = openpgp_oid_to_curve (curve, 0);
+		if (!curvename)
+		  curvename = curve;
+	      }
+
+	    result = ((use == PK_USE_SIGNING
+		       && curvename
+		       && (!strcmp (curvename, "brainpoolP256r1")
+			   || !strcmp (curvename, "brainpoolP384r1")
+			   || !strcmp (curvename, "brainpoolP512r1")))
+		      || use == PK_USE_VERIFICATION);
+
+	    xfree (curve);
+	    return result;
+	  }
+
+	case PUBKEY_ALGO_EDDSA:
+	  return 0;
+
+	default:
+	  return 0;
+	}
+      log_assert (!"reached");
+
+    default:
+      /* The default policy is to allow all algorithms.  */
+      return 1;
+    }
+
+  log_assert (!"reached");
+}
+
+
 /* Return true if (CIPHER, MODE) is compliant to the given COMPLIANCE mode.  */
 int
 gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance,
@@ -232,6 +331,57 @@ gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance,
 }
 
 
+/* Return true if CIPHER is allowed in the given COMPLIANCE mode.  If
+ * PRODUCER is true, the predicate is evaluated for the producer, if
+ * false for the consumer.  This way policies can be strict in what
+ * they produce, and liberal in what they accept.  */
+int
+gnupg_cipher_is_allowed (enum gnupg_compliance_mode compliance, int producer,
+			 cipher_algo_t cipher,
+			 enum gcry_cipher_modes mode)
+{
+  switch (compliance)
+    {
+    case CO_DE_VS:
+      switch (cipher)
+	{
+	case CIPHER_ALGO_AES:
+	case CIPHER_ALGO_AES192:
+	case CIPHER_ALGO_AES256:
+	case CIPHER_ALGO_3DES:
+	  switch (module)
+	    {
+	    case GNUPG_MODULE_NAME_GPG:
+	      return mode == GCRY_CIPHER_MODE_NONE || mode == GCRY_CIPHER_MODE_CFB;
+	    case GNUPG_MODULE_NAME_GPGSM:
+	      return mode == GCRY_CIPHER_MODE_NONE || mode == GCRY_CIPHER_MODE_CBC;
+	    }
+	  log_assert (!"reached");
+
+	case CIPHER_ALGO_BLOWFISH:
+	case CIPHER_ALGO_CAMELLIA128:
+	case CIPHER_ALGO_CAMELLIA192:
+	case CIPHER_ALGO_CAMELLIA256:
+	case CIPHER_ALGO_CAST5:
+	case CIPHER_ALGO_IDEA:
+	case CIPHER_ALGO_TWOFISH:
+	  return (module == GNUPG_MODULE_NAME_GPG
+		  && (mode == GCRY_CIPHER_MODE_NONE || mode == GCRY_CIPHER_MODE_CFB)
+		  && ! producer);
+	default:
+	  return 0;
+	}
+      log_assert (!"reached");
+
+    default:
+      /* The default policy is to allow all algorithms.  */
+      return 1;
+    }
+
+  log_assert (!"reached");
+}
+
+
 /* Return true if DIGEST is compliant to the given COMPLIANCE mode.  */
 int
 gnupg_digest_is_compliant (enum gnupg_compliance_mode compliance, digest_algo_t digest)
@@ -260,6 +410,44 @@ gnupg_digest_is_compliant (enum gnupg_compliance_mode compliance, digest_algo_t
 }
 
 
+/* Return true if DIGEST is allowed in the given COMPLIANCE mode.  If
+ * PRODUCER is true, the predicate is evaluated for the producer, if
+ * false for the consumer.  This way policies can be strict in what
+ * they produce, and liberal in what they accept.  */
+int
+gnupg_digest_is_allowed (enum gnupg_compliance_mode compliance, int producer,
+			 digest_algo_t digest)
+{
+  switch (compliance)
+    {
+    case CO_DE_VS:
+      switch (digest)
+	{
+	case DIGEST_ALGO_SHA256:
+	case DIGEST_ALGO_SHA384:
+	case DIGEST_ALGO_SHA512:
+	  return 1;
+	case DIGEST_ALGO_SHA1:
+	case DIGEST_ALGO_SHA224:
+	case DIGEST_ALGO_RMD160:
+	  return ! producer;
+	case DIGEST_ALGO_MD5:
+	case GCRY_MD_WHIRLPOOL:
+	  return ! producer && module == GNUPG_MODULE_NAME_GPGSM;
+	default:
+	  return 0;
+	}
+      log_assert (!"reached");
+
+    default:
+      /* The default policy is to allow all algorithms.  */
+      return 1;
+    }
+
+  log_assert (!"reached");
+}
+
+
 const char *
 gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance)
 {
diff --git a/common/compliance.h b/common/compliance.h
index e57495d..b2c9695 100644
--- a/common/compliance.h
+++ b/common/compliance.h
@@ -41,14 +41,28 @@ enum gnupg_compliance_mode
     CO_PGP6, CO_PGP7, CO_PGP8, CO_DE_VS
   };
 
+enum pk_use_case
+  {
+    PK_USE_ENCRYPTION, PK_USE_DECRYPTION,
+    PK_USE_SIGNING, PK_USE_VERIFICATION,
+  };
+
 int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
                            gcry_mpi_t key[], unsigned int keylength,
                            const char *curvename);
+int gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
+                         enum pk_use_case use, int algo, gcry_mpi_t key[],
+                         unsigned int keylength, const char *curvename);
 int gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance,
                                cipher_algo_t cipher,
                                enum gcry_cipher_modes mode);
+int gnupg_cipher_is_allowed (enum gnupg_compliance_mode compliance, int producer,
+                             cipher_algo_t cipher,
+                             enum gcry_cipher_modes mode);
 int gnupg_digest_is_compliant (enum gnupg_compliance_mode compliance,
                                digest_algo_t digest);
+int gnupg_digest_is_allowed (enum gnupg_compliance_mode compliance, int producer,
+                             digest_algo_t digest);
 const char *gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance);
 
 struct gnupg_compliance_option
diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c
index 96e2487..7023301 100644
--- a/g10/decrypt-data.c
+++ b/g10/decrypt-data.c
@@ -29,6 +29,7 @@
 #include "options.h"
 #include "../common/i18n.h"
 #include "../common/status.h"
+#include "../common/compliance.h"
 
 
 static int mdc_decode_filter ( void *opaque, int control, IOBUF a,
@@ -97,6 +98,17 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
       dek->algo_info_printed = 1;
     }
 
+  /* Check compliance.  */
+  if (! gnupg_cipher_is_allowed (opt.compliance, 0, dek->algo, GCRY_CIPHER_MODE_CFB))
+    {
+      log_error (_ ("you may not use cipher algorithm '%s'"
+		    " while in %s mode\n"),
+		 openpgp_cipher_algo_name (dek->algo),
+		 gnupg_compliance_option_string (opt.compliance));
+      rc = gpg_error (GPG_ERR_CIPHER_ALGO);
+      goto leave;
+    }
+
   {
     char buf[20];
 
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 66f49f4..ee2f078 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -38,6 +38,7 @@
 #include "../common/i18n.h"
 #include "../common/status.h"
 #include "pkglue.h"
+#include "../common/compliance.h"
 
 
 static int encrypt_simple( const char *filename, int mode, int use_seskey );
@@ -612,6 +613,35 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
       cfx.dek->algo = opt.def_cipher_algo;
     }
 
+  /* Check compliance.  */
+  if (! gnupg_cipher_is_allowed (opt.compliance, 1, cfx.dek->algo,
+                                 GCRY_CIPHER_MODE_CFB))
+    {
+      log_error (_ ("you may not use cipher algorithm '%s'"
+		    " while in %s mode\n"),
+		 openpgp_cipher_algo_name (cfx.dek->algo),
+		 gnupg_compliance_option_string (opt.compliance));
+      rc = gpg_error (GPG_ERR_CIPHER_ALGO);
+      goto leave;
+    }
+
+  {
+    pk_list_t pkr;
+    for (pkr = pk_list; pkr; pkr = pkr->next)
+      {
+        PKT_public_key *pk = pkr->pk;
+        if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_ENCRYPTION, pk->pubkey_algo,
+                                   pk->pkey, nbits_from_pk (pk), NULL))
+          {
+            log_error ("key %s not suitable for encryption while in %s mode\n",
+                       keystr_from_pk (pk),
+                       gnupg_compliance_option_string (opt.compliance));
+            rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
+            goto leave;
+          }
+      }
+  }
+
   cfx.dek->use_mdc = use_mdc (pk_list,cfx.dek->algo);
 
   /* Only do the is-file-already-compressed check if we are using a
diff --git a/g10/gpg.c b/g10/gpg.c
index f01c82d..d777d13 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -62,6 +62,7 @@
 #include "../common/init.h"
 #include "../common/mbox-util.h"
 #include "../common/shareddefs.h"
+#include "../common/compliance.h"
 
 #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
 #define MY_O_BINARY  O_BINARY
@@ -3866,6 +3867,43 @@ main (int argc, char **argv)
 	  }
       }
 
+    /* Check our chosen algorithms against the list of allowed
+     * algorithms in the current compliance mode, and fail hard if it
+     * is not.  This is us being nice to the user informing her early
+     * that the chosen algorithms are not available.  We also check
+     * and enforce this right before the actual operation.  */
+    if (opt.def_cipher_algo
+	&& ! gnupg_cipher_is_allowed (opt.compliance,
+				      cmd == aEncr
+				      || cmd == aSignEncr
+				      || cmd == aEncrSym
+				      || cmd == aSym
+				      || cmd == aSignSym
+				      || cmd == aSignEncrSym,
+				      opt.def_cipher_algo,
+				      GCRY_CIPHER_MODE_NONE))
+      log_error (_ ("you may not use cipher algorithm '%s'"
+		    " while in %s mode\n"),
+		 openpgp_cipher_algo_name (opt.def_cipher_algo),
+		 gnupg_compliance_option_string (opt.compliance));
+
+    if (opt.def_digest_algo
+	&& ! gnupg_digest_is_allowed (opt.compliance,
+				      cmd == aSign
+				      || cmd == aSignEncr
+				      || cmd == aSignEncrSym
+				      || cmd == aSignSym
+				      || cmd == aClearsign,
+				      opt.def_digest_algo))
+      log_error (_ ("you may not use digest algorithm '%s'"
+		    " while in %s mode\n"),
+		 gcry_md_algo_name (opt.def_digest_algo),
+		 gnupg_compliance_option_string (opt.compliance));
+
+    /* Fail hard.  */
+    if (log_get_errorcount (0))
+	g10_exit (2);
+
     /* Set the random seed file. */
     if( use_random_seed ) {
       char *p = make_filename (gnupg_homedir (), "random_seed", NULL );
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index d0eaab7..9a7c091 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -35,6 +35,7 @@
 #include "pkglue.h"
 #include "call-agent.h"
 #include "../common/host2net.h"
+#include "../common/compliance.h"
 
 
 static gpg_error_t get_it (ctrl_t ctrl, PKT_pubkey_enc *k,
@@ -88,7 +89,20 @@ get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek)
       sk = xmalloc_clear (sizeof *sk);
       sk->pubkey_algo = k->pubkey_algo; /* We want a pubkey with this algo.  */
       if (!(rc = get_seckey (ctrl, sk, k->keyid)))
-        rc = get_it (ctrl, k, dek, sk, k->keyid);
+        {
+          /* Check compliance.  */
+          if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
+                                     sk->pubkey_algo,
+                                     sk->pkey, nbits_from_pk (sk), NULL))
+            {
+              log_info ("key %s not suitable for decryption while in %s mode\n",
+                        keystr_from_pk (sk), gnupg_compliance_option_string (opt.compliance));
+              free_public_key (sk);
+              return gpg_error (GPG_ERR_PUBKEY_ALGO);
+            }
+
+          rc = get_it (ctrl, k, dek, sk, k->keyid);
+        }
     }
   else if (opt.skip_hidden_recipients)
     rc = gpg_error (GPG_ERR_NO_SECKEY);
@@ -116,6 +130,16 @@ get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek)
             log_info (_("anonymous recipient; trying secret key %s ...\n"),
                       keystr (keyid));
 
+          /* Check compliance.  */
+          if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
+                                     sk->pubkey_algo,
+                                     sk->pkey, nbits_from_pk (sk), NULL))
+            {
+              log_info ("key %s not suitable for decryption while in %s mode\n",
+                        keystr_from_pk (sk), gnupg_compliance_option_string (opt.compliance));
+              continue;
+            }
+
           rc = get_it (ctrl, k, dek, sk, keyid);
           if (!rc)
             {
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 19906e2..ef97e17 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -33,6 +33,7 @@
 #include "../common/i18n.h"
 #include "options.h"
 #include "pkglue.h"
+#include "../common/compliance.h"
 
 static int check_signature_end (PKT_public_key *pk, PKT_signature *sig,
 				gcry_md_hd_t digest,
@@ -132,6 +133,15 @@ check_signature2 (ctrl_t ctrl,
 
     if ( (rc=openpgp_md_test_algo(sig->digest_algo)) )
       ; /* We don't have this digest. */
+    else if (! gnupg_digest_is_allowed (opt.compliance, 0, sig->digest_algo))
+      {
+	/* Compliance failure.  */
+	log_info (_ ("you may not use digest algorithm '%s'"
+		     " while in %s mode\n"),
+		  gcry_md_algo_name (sig->digest_algo),
+		  gnupg_compliance_option_string (opt.compliance));
+	rc = gpg_error (GPG_ERR_DIGEST_ALGO);
+      }
     else if ((rc=openpgp_pk_test_algo(sig->pubkey_algo)))
       ; /* We don't have this pubkey algo. */
     else if (!gcry_md_is_enabled (digest,sig->digest_algo))
@@ -146,6 +156,15 @@ check_signature2 (ctrl_t ctrl,
       }
     else if( get_pubkey (ctrl, pk, sig->keyid ) )
       rc = gpg_error (GPG_ERR_NO_PUBKEY);
+    else if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
+				    pk->pubkey_algo, pk->pkey, nbits_from_pk (pk),
+				    NULL))
+      {
+	/* Compliance failure.  */
+	log_info ("key %s not suitable for signature verification while in %s mode\n",
+		  keystr_from_pk (pk), gnupg_compliance_option_string (opt.compliance));
+	rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
+      }
     else if(!pk->flags.valid)
       {
         /* You cannot have a good sig from an invalid key.  */
diff --git a/g10/sign.c b/g10/sign.c
index 6b55fff..024dd06 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -41,6 +41,7 @@
 #include "../common/sysutils.h"
 #include "call-agent.h"
 #include "../common/mbox-util.h"
+#include "../common/compliance.h"
 
 #ifdef HAVE_DOSISH_SYSTEM
 #define LF "\r\n"
@@ -277,6 +278,27 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
   if (!mdalgo)
     mdalgo = gcry_md_get_algo (md);
 
+  /* Check compliance.  */
+  if (! gnupg_digest_is_allowed (opt.compliance, 1, mdalgo))
+    {
+      log_error (_ ("you may not use digest algorithm '%s'"
+		    " while in %s mode\n"),
+		 gcry_md_algo_name (mdalgo),
+		 gnupg_compliance_option_string (opt.compliance));
+      err = gpg_error (GPG_ERR_DIGEST_ALGO);
+      goto leave;
+    }
+
+  if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pksk->pubkey_algo,
+                             pksk->pkey, nbits_from_pk (pksk), NULL))
+    {
+      log_error ("key %s not suitable for signing while in %s mode\n",
+                 keystr_from_pk (pksk),
+                 gnupg_compliance_option_string (opt.compliance));
+      err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+      goto leave;
+    }
+
   print_digest_algo_note (mdalgo);
   dp = gcry_md_read  (md, mdalgo);
   sig->digest_algo = mdalgo;
@@ -321,6 +343,7 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
     }
   xfree (hexgrip);
 
+ leave:
   if (err)
     log_error (_("signing failed: %s\n"), gpg_strerror (err));
   else
diff --git a/sm/decrypt.c b/sm/decrypt.c
index a36f690..6909b15 100644
--- a/sm/decrypt.c
+++ b/sm/decrypt.c
@@ -358,6 +358,17 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
               goto leave;
             }
 
+          /* Check compliance.  */
+          if (! gnupg_cipher_is_allowed (opt.compliance, 0, algo, mode))
+            {
+              log_error (_ ("you may not use cipher algorithm '%s'"
+                            " while in %s mode\n"),
+                         gcry_cipher_algo_name (algo),
+                         gnupg_compliance_option_string (opt.compliance));
+              rc = gpg_error (GPG_ERR_CIPHER_ALGO);
+              goto leave;
+            }
+
           /* For CMS, CO_DE_VS demands CBC mode.  */
           is_de_vs = gnupg_cipher_is_compliant (CO_DE_VS, algo, mode);
 
@@ -465,15 +476,27 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
                   hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
                   desc = gpgsm_format_keydesc (cert);
 
-                  /* Check that all certs are compliant with CO_DE_VS.  */
-                  if (is_de_vs)
-                    {
-                      unsigned int nbits;
-                      int pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
-
-                      is_de_vs = gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL,
-                                                        nbits, NULL);
-                    }
+                  {
+                    unsigned int nbits;
+                    int pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
+
+                    /* Check compliance.  */
+                    if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_DECRYPTION,
+                                               pk_algo, NULL, nbits, NULL))
+                      {
+                        log_error ("certificate ID 0x%08lX not suitable for "
+                                   "decryption while in %s mode\n",
+                                   gpgsm_get_short_fingerprint (cert, NULL),
+                                   gnupg_compliance_option_string (opt.compliance));
+                        rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
+                        goto oops;
+                      }
+
+                    /* Check that all certs are compliant with CO_DE_VS.  */
+                    is_de_vs = (is_de_vs
+                                && gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL,
+                                                          nbits, NULL));
+                  }
 
                 oops:
                   if (rc)
diff --git a/sm/encrypt.c b/sm/encrypt.c
index c43a9e6..45860a8 100644
--- a/sm/encrypt.c
+++ b/sm/encrypt.c
@@ -33,6 +33,7 @@
 
 #include "keydb.h"
 #include "../common/i18n.h"
+#include "../common/compliance.h"
 
 
 struct dek_s {
@@ -405,6 +406,19 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp)
       goto leave;
     }
 
+  /* Check compliance.  */
+  if (! gnupg_cipher_is_allowed (opt.compliance, 1,
+                                 gcry_cipher_map_name (opt.def_cipher_algoid),
+                                 gcry_cipher_mode_from_oid (opt.def_cipher_algoid)))
+    {
+      log_error (_ ("you may not use cipher algorithm '%s'"
+		    " while in %s mode\n"),
+		 opt.def_cipher_algoid,
+		 gnupg_compliance_option_string (opt.compliance));
+      rc = gpg_error (GPG_ERR_CIPHER_ALGO);
+      goto leave;
+    }
+
   /* Create a session key */
   dek = xtrycalloc_secure (1, sizeof *dek);
   if (!dek)
@@ -448,6 +462,20 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp)
     {
       unsigned char *encval;
 
+      /* Check compliance.  */
+      unsigned int nbits;
+      int pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
+      if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_ENCRYPTION, pk_algo,
+                                 NULL, nbits, NULL))
+        {
+          log_error ("certificate ID 0x%08lX not suitable for "
+                     "encryption while in %s mode\n",
+                     gpgsm_get_short_fingerprint (cl->cert, NULL),
+                     gnupg_compliance_option_string (opt.compliance));
+          rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
+          goto leave;
+        }
+
       rc = encrypt_dek (dek, cl->cert, &encval);
       if (rc)
         {
diff --git a/sm/gpgsm.c b/sm/gpgsm.c
index f749cfd..c462544 100644
--- a/sm/gpgsm.c
+++ b/sm/gpgsm.c
@@ -1614,6 +1614,43 @@ main ( int argc, char **argv)
         }
     }
 
+  /* Check our chosen algorithms against the list of allowed
+   * algorithms in the current compliance mode, and fail hard if it is
+   * not.  This is us being nice to the user informing her early that
+   * the chosen algorithms are not available.  We also check and
+   * enforce this right before the actual operation.  */
+  if (! gnupg_cipher_is_allowed (opt.compliance,
+                                 cmd == aEncr || cmd == aSignEncr,
+                                 gcry_cipher_map_name (opt.def_cipher_algoid),
+                                 GCRY_CIPHER_MODE_NONE)
+      && ! gnupg_cipher_is_allowed (opt.compliance,
+                                    cmd == aEncr || cmd == aSignEncr,
+                                    gcry_cipher_mode_from_oid (opt.def_cipher_algoid),
+                                    GCRY_CIPHER_MODE_NONE))
+    log_error (_ ("you may not use cipher algorithm '%s'"
+                  " while in %s mode\n"),
+               opt.def_cipher_algoid, gnupg_compliance_option_string (opt.compliance));
+
+  if (forced_digest_algo
+      && ! gnupg_digest_is_allowed (opt.compliance,
+                                     cmd == aSign
+                                     || cmd == aSignEncr
+                                     || cmd == aClearsign,
+                                     opt.forced_digest_algo))
+    log_error (_ ("you may not use digest algorithm '%s'"
+                  " while in %s mode\n"),
+               forced_digest_algo, gnupg_compliance_option_string (opt.compliance));
+
+  if (extra_digest_algo
+      && ! gnupg_digest_is_allowed (opt.compliance,
+                                     cmd == aSign
+                                     || cmd == aSignEncr
+                                     || cmd == aClearsign,
+                                     opt.extra_digest_algo))
+    log_error (_ ("you may not use digest algorithm '%s'"
+                  " while in %s mode\n"),
+               forced_digest_algo, gnupg_compliance_option_string (opt.compliance));
+
   if (log_get_errorcount(0))
     gpgsm_exit(2);
 
diff --git a/sm/sign.c b/sm/sign.c
index e65562d..2fbee75 100644
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -460,6 +460,33 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
           break;
         }
       cl->hash_algo_oid = oid;
+
+      /* Check compliance.  */
+      if (! gnupg_digest_is_allowed (opt.compliance, 1, cl->hash_algo))
+        {
+          log_error (_ ("you may not use digest algorithm '%s'"
+                        " while in %s mode\n"),
+                     gcry_md_algo_name (cl->hash_algo),
+                     gnupg_compliance_option_string (opt.compliance));
+          err = gpg_error (GPG_ERR_DIGEST_ALGO);
+          goto leave;
+        }
+
+      {
+        unsigned int nbits;
+        int pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
+
+        if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo,
+                                   NULL, nbits, NULL))
+          {
+            log_error ("certificate ID 0x%08lX not suitable for "
+                       "signing while in %s mode\n",
+                       gpgsm_get_short_fingerprint (cl->cert, NULL),
+                       gnupg_compliance_option_string (opt.compliance));
+            err = gpg_error (GPG_ERR_PUBKEY_ALGO);
+            goto leave;
+          }
+      }
     }
 
   if (opt.verbose)
diff --git a/sm/verify.c b/sm/verify.c
index e19c04e..89f06ef 100644
--- a/sm/verify.c
+++ b/sm/verify.c
@@ -450,6 +450,37 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
           goto next_signer;
         }
 
+      /* Check compliance.  */
+      {
+        unsigned int nbits;
+        int pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
+
+        if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
+                                   pk_algo, NULL, nbits, NULL))
+          {
+            log_error ("certificate ID 0x%08lX not suitable for "
+                       "verification while in %s mode\n",
+                       gpgsm_get_short_fingerprint (cert, NULL),
+                       gnupg_compliance_option_string (opt.compliance));
+            goto next_signer;
+          }
+
+        if (! gnupg_digest_is_allowed (opt.compliance, 0, sigval_hash_algo))
+          {
+            log_error (_ ("you may not use digest algorithm '%s'"
+                          " while in %s mode\n"),
+                       gcry_md_algo_name (sigval_hash_algo),
+                       gnupg_compliance_option_string (opt.compliance));
+            goto next_signer;
+          }
+
+        /* Check compliance with CO_DE_VS.  */
+        if (gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL)
+            && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo))
+          gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE,
+                        gnupg_status_compliance_flag (CO_DE_VS));
+      }
+
       log_info (_("Signature made "));
       if (*sigtime)
         dump_isotime (sigtime);
@@ -632,17 +663,6 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
                     (verifyflags & VALIDATE_FLAG_CHAIN_MODEL)?
                     "0 chain": "0 shell");
 
-      /* Check compliance with CO_DE_VS.  */
-      {
-        unsigned int nbits;
-        int pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
-
-        if (gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL)
-            && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo))
-          gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE,
-                        gnupg_status_compliance_flag (CO_DE_VS));
-      }
-
     next_signer:
       rc = 0;
       xfree (issuer);

commit b03fab09e188f7bb10237d4f20455e4026737e4e
Author: Justus Winter <justus at g10code.com>
Date:   Thu Jun 8 13:55:47 2017 +0200

    gpg: Fix computation of compliance with CO_DE_VS.
    
    * g10/mainproc.c (proc_encrypted): Symmetric encryption is also in
    compliance with CO_DE_VS.
    
    GnuPG-bug-id: 3059
    Signed-off-by: Justus Winter <justus at g10code.com>

diff --git a/g10/mainproc.c b/g10/mainproc.c
index 26cd0a9..2db8de1 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -602,8 +602,8 @@ proc_encrypted (CTX c, PACKET *pkt)
 
   /* Compute compliance with CO_DE_VS.  */
   if (!result && is_status_enabled ()
-      /* Symmetric encryption voids compliance.  */
-      && c->symkeys == 0
+      /* Symmetric encryption and asymmetric encryption voids compliance.  */
+      && ((c->symkeys > 0) != (c->pkenc_list != NULL))
       /* Overriding session key voids compliance.  */
       && opt.override_session_key == NULL
       /* Check symmetric cipher.  */
@@ -613,7 +613,8 @@ proc_encrypted (CTX c, PACKET *pkt)
       int compliant = 1;
       PKT_public_key *pk = xmalloc (sizeof *pk);
 
-      log_assert (c->pkenc_list || !"where else did the session key come from!?");
+      log_assert (c->pkenc_list || c->symkeys
+                  || !"where else did the session key come from!?");
 
       /* Now check that every key used to encrypt the session key is
        * compliant.  */

-----------------------------------------------------------------------

Summary of changes:
 common/compliance.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 common/compliance.h |  14 ++++
 g10/decrypt-data.c  |  12 ++++
 g10/encrypt.c       |  30 +++++++++
 g10/gpg.c           |  38 +++++++++++
 g10/mainproc.c      |   7 +-
 g10/pubkey-enc.c    |  26 +++++++-
 g10/sig-check.c     |  19 ++++++
 g10/sign.c          |  23 +++++++
 sm/decrypt.c        |  41 +++++++++---
 sm/encrypt.c        |  28 ++++++++
 sm/gpgsm.c          |  37 +++++++++++
 sm/sign.c           |  27 ++++++++
 sm/verify.c         |  42 +++++++++---
 14 files changed, 508 insertions(+), 24 deletions(-)


hooks/post-receive
-- 
The GNU Privacy Guard
http://git.gnupg.org




More information about the Gnupg-commits mailing list