gpg,sm: Fix compliance checking for decryption.
authorWerner Koch <wk@gnupg.org>
Thu, 27 Jul 2017 11:56:38 +0000 (13:56 +0200)
committerWerner Koch <wk@gnupg.org>
Thu, 27 Jul 2017 11:56:38 +0000 (13:56 +0200)
* common/compliance.c (gnupg_pk_is_compliant): Remove the Elgamal
signing check.  We don't support Elgamal signing at all.
(gnupg_pk_is_allowed) <de-vs>: Revert encryption/decryption for RSA.
Check the curvenames for ECDH.
* g10/pubkey-enc.c (get_session_key): Print only a warning if the key
is not compliant.
* sm/decrypt.c (gpgsm_decrypt): Ditto.  Use the same string as in gpg
so that we have only one translation.
--

We always allow decryption and print only a note if the key was not
complaint at the encryption site.

GnuPG-bug-id: 3308
Signed-off-by: Werner Koch <wk@gnupg.org>
common/compliance.c
g10/pubkey-enc.c
sm/decrypt.c

index 268ea4d..9511724 100644 (file)
@@ -99,7 +99,7 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
                       gcry_mpi_t key[], unsigned int keylength,
                        const char *curvename)
 {
-  enum { is_rsa, is_dsa, is_pgp5, is_elg_sign, is_ecc } algotype;
+  enum { is_rsa, is_dsa, is_elg, is_ecc } algotype;
   int result = 0;
 
   if (! initialized)
@@ -118,7 +118,7 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
       break;
 
     case PUBKEY_ALGO_ELGAMAL_E:
-      algotype = is_pgp5;
+      algotype = is_elg;
       break;
 
     case PUBKEY_ALGO_ECDH:
@@ -128,8 +128,7 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
       break;
 
     case PUBKEY_ALGO_ELGAMAL:
-      algotype = is_elg_sign;
-      break;
+      return 0; /* Signing with Elgamal is not at all supported.  */
 
     default: /* Unknown.  */
       return 0;
@@ -141,7 +140,7 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
 
       switch (algotype)
         {
-        case is_pgp5:
+        case is_elg:
           result = 0;
           break;
 
@@ -183,11 +182,6 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
         }
       xfree (curve);
     }
-  else if (algotype == is_elg_sign)
-    {
-      /* An Elgamal signing key is only RFC-2440 compliant.  */
-      result = (compliance == CO_RFC2440);
-    }
   else
     {
       result = 1; /* Assume compliance.  */
@@ -219,9 +213,9 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
        case PUBKEY_ALGO_RSA_S:
          switch (use)
            {
-           case PK_USE_ENCRYPTION:
-             return 1;
            case PK_USE_DECRYPTION:
+             return 1;
+           case PK_USE_ENCRYPTION:
            case PK_USE_SIGNING:
              return (keylength == 2048
                      || keylength == 3072
@@ -253,10 +247,34 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
 
        case PUBKEY_ALGO_ELGAMAL:
        case PUBKEY_ALGO_ELGAMAL_E:
-         return use == PK_USE_ENCRYPTION;
+         return use == PK_USE_DECRYPTION;
 
        case PUBKEY_ALGO_ECDH:
-         return use == PK_USE_ENCRYPTION;
+         if (use == PK_USE_DECRYPTION)
+            return 1;
+          else if (use == PK_USE_ENCRYPTION)
+            {
+              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 = (curvename
+                        && (!strcmp (curvename, "brainpoolP256r1")
+                            || !strcmp (curvename, "brainpoolP384r1")
+                            || !strcmp (curvename, "brainpoolP512r1")));
+
+              xfree (curve);
+              return result;
+            }
+          else
+            return 0;
 
        case PUBKEY_ALGO_ECDSA:
          {
index 0ddb8d7..013fd2f 100644 (file)
@@ -90,19 +90,16 @@ get_session_key (ctrl_t ctrl, PKT_pubkey_enc * k, DEK * dek)
       sk->pubkey_algo = k->pubkey_algo; /* We want a pubkey with this algo.  */
       if (!(rc = get_seckey (ctrl, 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));
-              rc = gpg_error (GPG_ERR_PUBKEY_ALGO);
-            }
-          else
-            rc = get_it (ctrl, k, dek, sk, k->keyid);
+          /* Print compliance warning.  */
+          if (!gnupg_pk_is_compliant (opt.compliance,
+                                      sk->pubkey_algo,
+                                      sk->pkey, nbits_from_pk (sk), NULL))
+            log_info (_("Note: key %s was not suitable for encryption"
+                        " in %s mode\n"),
+                      keystr_from_pk (sk),
+                      gnupg_compliance_option_string (opt.compliance));
+
+          rc = get_it (ctrl, k, dek, sk, k->keyid);
         }
     }
   else if (opt.skip_hidden_recipients)
@@ -131,17 +128,14 @@ 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;
-            }
+          /* Print compliance warning.  */
+          if (!gnupg_pk_is_compliant (opt.compliance,
+                                      sk->pubkey_algo,
+                                      sk->pkey, nbits_from_pk (sk), NULL))
+            log_info (_("Note: key %s was not suitable for encryption"
+                        " in %s mode\n"),
+                      keystr_from_pk (sk),
+                      gnupg_compliance_option_string (opt.compliance));
 
           rc = get_it (ctrl, k, dek, sk, keyid);
           if (!rc)
index 170ad5a..3de742a 100644 (file)
@@ -480,17 +480,19 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
                     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))
+                    /* Print compliance warning.  */
+                    if (! gnupg_pk_is_compliant (opt.compliance,
+                                                 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;
+                        char  kidstr[10+1];
+
+                        snprintf (kidstr, sizeof kidstr, "0x%08lX",
+                                  gpgsm_get_short_fingerprint (cert, NULL));
+                        log_info
+                          (_("Note: key %s was not suitable for encryption"
+                             " in %s mode\n"),
+                           kidstr,
+                           gnupg_compliance_option_string (opt.compliance));
                       }
 
                     /* Check that all certs are compliant with CO_DE_VS.  */