summaryrefslogtreecommitdiff
path: root/common/compliance.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/compliance.c')
-rw-r--r--common/compliance.c135
1 files changed, 114 insertions, 21 deletions
diff --git a/common/compliance.c b/common/compliance.c
index e77b1af..1cda1ec 100644
--- a/common/compliance.c
+++ b/common/compliance.c
@@ -40,6 +40,38 @@
static int initialized;
static int module;
+
+/* Return the address of a compliance cache variable for COMPLIANCE.
+ * If no such variable exists NULL is returned. FOR_RNG returns the
+ * cache variable for the RNG compliance check. */
+static int *
+get_compliance_cache (enum gnupg_compliance_mode compliance, int for_rng)
+{
+ static int r_gnupg = -1, s_gnupg = -1;
+ static int r_rfc4880 = -1, s_rfc4880 = -1;
+ static int r_rfc2440 = -1, s_rfc2440 = -1;
+ static int r_pgp6 = -1, s_pgp6 = -1;
+ static int r_pgp7 = -1, s_pgp7 = -1;
+ static int r_pgp8 = -1, s_pgp8 = -1;
+ static int r_de_vs = -1, s_de_vs = -1;
+
+ int *ptr = NULL;
+
+ switch (compliance)
+ {
+ case CO_GNUPG: ptr = for_rng? &r_gnupg : &s_gnupg ; break;
+ case CO_RFC4880: ptr = for_rng? &r_rfc4880 : &s_rfc4880; break;
+ case CO_RFC2440: ptr = for_rng? &r_rfc2440 : &s_rfc2440; break;
+ case CO_PGP6: ptr = for_rng? &r_pgp6 : &s_pgp6 ; break;
+ case CO_PGP7: ptr = for_rng? &r_pgp7 : &s_pgp7 ; break;
+ case CO_PGP8: ptr = for_rng? &r_pgp8 : &s_pgp8 ; break;
+ case CO_DE_VS: ptr = for_rng? &r_de_vs : &s_de_vs ; break;
+ }
+
+ return ptr;
+}
+
+
/* Initializes the module. Must be called with the current
* GNUPG_MODULE_NAME. Checks a few invariants, and tunes the policies
* for the given module. */
@@ -386,7 +418,8 @@ gnupg_cipher_is_allowed (enum gnupg_compliance_mode compliance, int producer,
|| mode == GCRY_CIPHER_MODE_CFB);
case GNUPG_MODULE_NAME_GPGSM:
return (mode == GCRY_CIPHER_MODE_NONE
- || mode == GCRY_CIPHER_MODE_CBC);
+ || mode == GCRY_CIPHER_MODE_CBC
+ || (mode == GCRY_CIPHER_MODE_GCM && !producer));
}
log_assert (!"reached");
@@ -490,34 +523,94 @@ gnupg_digest_is_allowed (enum gnupg_compliance_mode compliance, int producer,
int
gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance)
{
- static int result = -1;
+ int *result;
+ int res;
- if (result != -1)
- ; /* Use cached result. */
+ result = get_compliance_cache (compliance, 1);
+
+ if (result && *result != -1)
+ res = *result; /* Use cached result. */
else if (compliance == CO_DE_VS)
{
- /* In DE_VS mode under Windows we require that the JENT RNG
- * is active. */
+ /* We also check whether the library is at all compliant. */
+ res = gnupg_gcrypt_is_compliant (compliance);
+
+ /* In DE_VS mode under Windows we also require that the JENT RNG
+ * is active. Check it here. */
#ifdef HAVE_W32_SYSTEM
- char *buf;
- char *fields[5];
-
- buf = gcry_get_config (0, "rng-type");
- if (buf
- && split_fields_colon (buf, fields, DIM (fields)) >= 5
- && atoi (fields[4]) > 0)
- result = 1;
+ if (res == 1)
+ {
+ char *buf;
+ char *fields[5];
+
+ buf = gcry_get_config (0, "rng-type");
+ if (buf
+ && split_fields_colon (buf, fields, DIM (fields)) >= 5
+ && atoi (fields[4]) > 0)
+ ; /* Field 5 > 0 := Jent is active. */
+ else
+ result = 0; /* Force non-compliance. */
+ gcry_free (buf);
+ }
+#endif /*HAVE_W32_SYSTEM*/
+ }
+ else
+ res = 1;
+
+ if (result)
+ *result = res;
+
+ return res;
+}
+
+
+/* Return true if the used Libgcrypt is compliant in COMPLIANCE
+ * mode. */
+int
+gnupg_gcrypt_is_compliant (enum gnupg_compliance_mode compliance)
+{
+ int *result;
+ int res;
+
+ result = get_compliance_cache (compliance, 0);
+
+ if (result && *result != -1)
+ res = *result; /* Use cached result. */
+ else if (compliance == CO_DE_VS)
+ {
+ int is19orlater = !!gcry_check_version ("1.9.0");
+
+ /* A compliant version of GnuPG requires Libgcrypt >= 1.8.1 and
+ * less than 1.9.0. Version 1.9.0 requires a re-evaluation and
+ * can thus not be used for de-vs. */
+ if (gcry_check_version ("1.8.1") && !is19orlater)
+ res = 1; /* Compliant version of Libgcrypt. */
+ else if (is19orlater)
+ {
+ /* Libgcrypt might be nice enough to tell us whether it is
+ * compliant. */
+ char *buf;
+ char *fields[3];
+
+ buf = gcry_get_config (0, "compliance");
+ if (buf
+ && split_fields_colon (buf, fields, DIM (fields)) >= 2
+ && strstr (fields[1], "de-vs"))
+ res = 1; /* Compliant. */
+ else
+ res = 0; /* Non-compliant. */
+ gcry_free (buf);
+ }
else
- result = 0;
- gcry_free (buf);
-#else /*!HAVE_W32_SYSTEM*/
- result = 1; /* Not Windows - RNG is good. */
-#endif /*!HAVE_W32_SYSTEM*/
+ res = 0; /* Non-compliant version of Libgcrypt. */
}
else
- result = 1;
+ res = 1;
- return result;
+ if (result)
+ *result = res;
+
+ return res;
}