gpg,common: Move the compliance framework.
authorJustus Winter <justus@g10code.com>
Wed, 31 May 2017 12:33:45 +0000 (14:33 +0200)
committerJustus Winter <justus@g10code.com>
Thu, 1 Jun 2017 10:09:43 +0000 (12:09 +0200)
* common/Makefile.am (common_sources): Add new files.
* common/compliance.c: New file.  Move 'gnupg_pk_is_compliant' here,
and tweak it to not rely on types private to gpg.
* common/compliance.h: New file.  Move the compliance enum here.
* g10/keylist.c (print_compliance_flags): Adapt callsite.
* g10/main.h (gnupg_pk_is_compliant): Remove prototype.
* g10/misc.c (gnupg_pk_is_compliant): Remove function.
* g10/options.h (opt): Use the new compliance enum.
* sm/keylist.c (print_compliance_flags): Use the common functions.

Signed-off-by: Justus Winter <justus@g10code.com>
common/Makefile.am
common/compliance.c [new file with mode: 0644]
common/compliance.h [new file with mode: 0644]
g10/keylist.c
g10/main.h
g10/misc.c
g10/options.h
sm/keylist.c

index 83d82ac..fcbe7ea 100644 (file)
@@ -93,7 +93,8 @@ common_sources = \
        server-help.c server-help.h \
        name-value.c name-value.h \
        recsel.c recsel.h \
-       ksba-io-support.c ksba-io-support.h
+       ksba-io-support.c ksba-io-support.h \
+       compliance.c compliance.h
 
 
 if HAVE_W32_SYSTEM
diff --git a/common/compliance.c b/common/compliance.c
new file mode 100644 (file)
index 0000000..73c7ad7
--- /dev/null
@@ -0,0 +1,144 @@
+/* compliance.c - Functions for compliance modi
+ * Copyright (C) 2017 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <gcrypt.h>
+
+#include "openpgpdefs.h"
+#include "logging.h"
+#include "util.h"
+#include "compliance.h"
+
+/* Return true if ALGO with a key of KEYLENGTH is compliant to the
+ * give COMPLIANCE mode.  If KEY is not NULL, various bits of
+ * information will be extracted from it.  If CURVENAME is not NULL, it
+ * is assumed to be the already computed.  ALGO may be either an
+ * OpenPGP-style pubkey_algo_t, or a gcrypt-style enum gcry_pk_algos,
+ * both are compatible from the point of view of this function.  */
+int
+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_pgp5, is_elg_sign, is_ecc } algotype;
+  int result;
+
+  switch (algo)
+    {
+    case PUBKEY_ALGO_RSA:
+    case PUBKEY_ALGO_RSA_E:
+    case PUBKEY_ALGO_RSA_S:
+      algotype = is_rsa;
+      break;
+
+    case PUBKEY_ALGO_ELGAMAL_E:
+    case PUBKEY_ALGO_DSA:
+      algotype = is_pgp5;
+      break;
+
+    case PUBKEY_ALGO_ECDH:
+    case PUBKEY_ALGO_ECDSA:
+    case PUBKEY_ALGO_EDDSA:
+      algotype = is_ecc;
+      break;
+
+    case PUBKEY_ALGO_ELGAMAL:
+      algotype = is_elg_sign;
+      break;
+
+    default: /* Unknown.  */
+      return 0;
+    }
+
+  if (compliance == CO_DE_VS)
+    {
+      char *curve = NULL;
+
+      switch (algotype)
+        {
+        case is_pgp5:
+          result = 0;
+          break;
+
+        case is_rsa:
+          result = (keylength >= 2048);
+          break;
+
+        case is_ecc:
+          if (!curvename && key)
+            {
+              curve = openpgp_oid_to_str (key[0]);
+              curvename = openpgp_oid_to_curve (curve, 0);
+              if (!curvename)
+                curvename = curve;
+            }
+
+          result = (curvename
+                    && algo != PUBKEY_ALGO_EDDSA
+                    && (!strcmp (curvename, "brainpoolP256r1")
+                        || !strcmp (curvename, "brainpoolP384r1")
+                        || !strcmp (curvename, "brainpoolP512r1")));
+          break;
+
+        default:
+          result = 0;
+        }
+      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.  */
+    }
+
+  return result;
+}
+
+
+const char *
+gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance)
+{
+  switch (compliance)
+    {
+    case CO_GNUPG:
+      return "8";
+    case CO_RFC4880:
+    case CO_RFC2440:
+    case CO_PGP6:
+    case CO_PGP7:
+    case CO_PGP8:
+      log_assert (!"no status code assigned for this compliance mode");
+    case CO_DE_VS:
+      return "23";
+    }
+  log_assert (!"invalid compliance mode");
+}
diff --git a/common/compliance.h b/common/compliance.h
new file mode 100644 (file)
index 0000000..123bd1b
--- /dev/null
@@ -0,0 +1,47 @@
+/* compliance.h - Definitions for compliance modi
+ * Copyright (C) 2017 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GNUPG_COMMON_COMPLIANCE_H
+#define GNUPG_COMMON_COMPLIANCE_H
+
+#include <gcrypt.h>
+#include "openpgpdefs.h"
+
+enum gnupg_compliance_mode
+  {
+    CO_GNUPG, CO_RFC4880, CO_RFC2440,
+    CO_PGP6, CO_PGP7, CO_PGP8, CO_DE_VS
+  };
+
+int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
+                           gcry_mpi_t key[], unsigned int keylength,
+                           const char *curvename);
+const char *gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance);
+
+#endif /*GNUPG_COMMON_COMPLIANCE_H*/
index e2b8fef..4848bab 100644 (file)
@@ -44,6 +44,7 @@
 #include "../common/mbox-util.h"
 #include "../common/zb32.h"
 #include "tofu.h"
+#include "../common/compliance.h"
 
 
 static void list_all (ctrl_t, int, int);
@@ -1180,14 +1181,19 @@ print_compliance_flags (PKT_public_key *pk,
 {
   int any = 0;
 
+  if (!keylength)
+    keylength = nbits_from_pk (pk);
+
   if (pk->version == 5)
     {
-      es_fputs ("8", es_stdout);
+      es_fputs (gnupg_status_compliance_flag (CO_GNUPG), es_stdout);
       any++;
     }
-  if (gnupg_pk_is_compliant (CO_DE_VS, pk, keylength, curvename))
+  if (gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
+                            keylength, curvename))
     {
-      es_fputs (any? " 23":"23", es_stdout);
+      es_fprintf (es_stdout, any ? " %s" : "%s",
+                 gnupg_status_compliance_flag (CO_DE_VS));
       any++;
     }
 }
index 129d746..c406113 100644 (file)
@@ -126,9 +126,6 @@ int openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use);
 int openpgp_pk_algo_usage ( int algo );
 const char *openpgp_pk_algo_name (pubkey_algo_t algo);
 
-int gnupg_pk_is_compliant (int compliance, PKT_public_key *pk,
-                           unsigned int keylength, const char *curvename);
-
 enum gcry_md_algos map_md_openpgp_to_gcry (digest_algo_t algo);
 int openpgp_md_test_algo (digest_algo_t algo);
 const char *openpgp_md_algo_name (int algo);
index bdd27cf..d485c94 100644 (file)
@@ -707,94 +707,6 @@ openpgp_pk_algo_name (pubkey_algo_t algo)
 }
 
 
-/* Return true if PK is compliant to the give COMPLIANCE mode.  If
- * KEYLENGTH and CURVENAME are not 0/NULL the are assumed to be the
- * already computed values from PK.  */
-int
-gnupg_pk_is_compliant (int compliance, PKT_public_key *pk,
-                       unsigned int keylength, const char *curvename)
-{
-  enum { is_rsa, is_pgp5, is_elg_sign, is_ecc } algotype;
-  int result;
-
-  switch (pk->pubkey_algo)
-    {
-    case PUBKEY_ALGO_RSA:
-    case PUBKEY_ALGO_RSA_E:
-    case PUBKEY_ALGO_RSA_S:
-      algotype = is_rsa;
-      break;
-
-    case PUBKEY_ALGO_ELGAMAL_E:
-    case PUBKEY_ALGO_DSA:
-      algotype = is_pgp5;
-      break;
-
-    case PUBKEY_ALGO_ECDH:
-    case PUBKEY_ALGO_ECDSA:
-    case PUBKEY_ALGO_EDDSA:
-      algotype = is_ecc;
-      break;
-
-    case PUBKEY_ALGO_ELGAMAL:
-      algotype = is_elg_sign;
-      break;
-
-    default: /* Unknown.  */
-      return 0;
-    }
-
-  if (compliance == CO_DE_VS)
-    {
-      char *curve = NULL;
-
-      switch (algotype)
-        {
-        case is_pgp5:
-          result = 0;
-          break;
-
-        case is_rsa:
-          if (!keylength)
-            keylength = nbits_from_pk (pk);
-          result = (keylength >= 2048);
-          break;
-
-        case is_ecc:
-          if (!curvename)
-            {
-              curve = openpgp_oid_to_str (pk->pkey[0]);
-              curvename = openpgp_oid_to_curve (curve, 0);
-              if (!curvename)
-                curvename = curve;
-            }
-
-          result = (curvename
-                    && pk->pubkey_algo != PUBKEY_ALGO_EDDSA
-                    && (!strcmp (curvename, "brainpoolP256r1")
-                        || !strcmp (curvename, "brainpoolP384r1")
-                        || !strcmp (curvename, "brainpoolP512r1")));
-          break;
-
-        default:
-          result = 0;
-        }
-      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.  */
-    }
-
-  return result;
-}
-
-
 /* Explicit mapping of OpenPGP digest algos to Libgcrypt.  */
 /* FIXME: We do not yes use it everywhere.  */
 enum gcry_md_algos
index c634f0f..8d1d93e 100644 (file)
@@ -28,6 +28,7 @@
 #include "packet.h"
 #include "tofu.h"
 #include "../common/session-env.h"
+#include "../common/compliance.h"
 
 #ifndef EXTERN_UNLESS_MAIN_MODULE
 /* Norcraft can't cope with common symbols */
@@ -139,11 +140,7 @@ struct
     } trust_model;
   enum tofu_policy tofu_default_policy;
   int force_ownertrust;
-  enum
-    {
-      CO_GNUPG, CO_RFC4880, CO_RFC2440,
-      CO_PGP6, CO_PGP7, CO_PGP8, CO_DE_VS
-    } compliance;
+  enum gnupg_compliance_mode compliance;
   enum
     {
       KF_DEFAULT, KF_NONE, KF_SHORT, KF_LONG, KF_0xSHORT, KF_0xLONG
index 13de45d..abec049 100644 (file)
@@ -36,6 +36,7 @@
 #include "../kbx/keybox.h" /* for KEYBOX_FLAG_* */
 #include "../common/i18n.h"
 #include "../common/tlv.h"
+#include "../common/compliance.h"
 
 struct list_external_parm_s
 {
@@ -351,8 +352,8 @@ email_kludge (const char *name)
 static void
 print_compliance_flags (int algo, unsigned int nbits, estream_t fp)
 {
-  if (algo == GCRY_PK_RSA && nbits >= 2048)
-    es_fputs ("23", fp);
+  if (gnupg_pk_is_compliant (CO_DE_VS, algo, NULL, nbits, NULL))
+    es_fputs (gnupg_status_compliance_flag (CO_DE_VS), fp);
 }