gpg,sm: Check compliance of the RNG.
authorWerner Koch <wk@gnupg.org>
Mon, 17 Jul 2017 13:52:26 +0000 (15:52 +0200)
committerWerner Koch <wk@gnupg.org>
Mon, 17 Jul 2017 13:53:16 +0000 (15:53 +0200)
* common/compliance.c (gnupg_rng_is_compliant): New.
* g10/call-agent.c (start_agent) [W32]: Check rng compliance.
* sm/call-agent.c (start_agent) [W32]: Ditto.
* g10/encrypt.c (encrypt_simple, encrypt_crypt): Check that the RNG is
compliant.
* sm/encrypt.c (gpgsm_encrypt): Ditto.
* g10/sign.c (do_sign): Ditto.
* sm/sign.c (gpgsm_sign): Ditto.
--

Under Windows we need to check that the Jitter RNG is active in de-vs
mode.  Under Linux this is not necessary because /dev/random can be
scrutinized and is believed to provide enough entropy.

Signed-off-by: Werner Koch <wk@gnupg.org>
common/compliance.c
common/compliance.h
g10/call-agent.c
g10/encrypt.c
g10/sign.c
sm/call-agent.c
sm/encrypt.c
sm/sign.c

index 8b91677..268ea4d 100644 (file)
@@ -466,6 +466,46 @@ gnupg_digest_is_allowed (enum gnupg_compliance_mode compliance, int producer,
 }
 
 
+/* Return True if the random number generator is compliant in
+ * COMPLIANCE mode.  */
+int
+gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance)
+{
+  static int result = -1;
+
+  if (result != -1)
+    ; /* Use cached result.  */
+  else if (compliance == CO_DE_VS)
+    {
+      /* In DE_VS mode under Windows we require that the JENT RNG
+       * is active.  */
+#ifdef HAVE_W32_SYSTEM
+# if GCRYPT_VERSION_NUMBER >= 0x010800
+      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;
+      else
+        result = 0;
+      gcry_free (buf);
+# else
+      result = 0;  /* No JENT - can't be compliant.  */
+# endif
+#else /*!HAVE_W32_SYSTEM*/
+      result = 1;  /* Not Windows - RNG is good.  */
+#endif /*!HAVE_W32_SYSTEM*/
+    }
+  else
+    result = 1;
+
+  return result;
+}
+
+
 const char *
 gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance)
 {
index d55bbf3..2076e79 100644 (file)
@@ -66,6 +66,8 @@ int gnupg_digest_is_compliant (enum gnupg_compliance_mode compliance,
 int gnupg_digest_is_allowed (enum gnupg_compliance_mode compliance,
                              int producer,
                              digest_algo_t digest);
+int gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance);
+
 const char *gnupg_status_compliance_flag (enum gnupg_compliance_mode
                                           compliance);
 
index 7b76933..3ad13e8 100644 (file)
@@ -281,6 +281,24 @@ start_agent (ctrl_t ctrl, int flag_for_card)
                   write_status_error ("set_pinentry_mode", rc);
                 }
             }
+
+          /* In DE_VS mode under Windows we require that the JENT RNG
+           * is active.  */
+#ifdef HAVE_W32_SYSTEM
+          if (!rc && opt.compliance == CO_DE_VS)
+            {
+              if (assuan_transact (agent_ctx, "GETINFO jent_active",
+                                   NULL, NULL, NULL, NULL, NULL, NULL))
+                {
+                  rc = gpg_error (GPG_ERR_FORBIDDEN);
+                  log_error (_("%s is not compliant with %s mode\n"),
+                             GPG_AGENT_NAME,
+                             gnupg_compliance_option_string (opt.compliance));
+                  write_status_error ("random-compliance", rc);
+                }
+            }
+#endif /*HAVE_W32_SYSTEM*/
+
         }
     }
 
index 4b21a61..c63ec88 100644 (file)
@@ -185,6 +185,16 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
   progress_filter_context_t *pfx;
   int do_compress = !!default_compress_algo();
 
+  if (!gnupg_rng_is_compliant (opt.compliance))
+    {
+      rc = gpg_error (GPG_ERR_FORBIDDEN);
+      log_error (_("%s is not compliant with %s mode\n"),
+                 "RNG",
+                 gnupg_compliance_option_string (opt.compliance));
+      write_status_error ("random-compliance", rc);
+      return rc;
+    }
+
   pfx = new_progress_context ();
   memset( &cfx, 0, sizeof cfx);
   memset( &zfx, 0, sizeof zfx);
@@ -626,6 +636,16 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
       goto leave;
     }
 
+  if (!gnupg_rng_is_compliant (opt.compliance))
+    {
+      rc = gpg_error (GPG_ERR_FORBIDDEN);
+      log_error (_("%s is not compliant with %s mode\n"),
+                 "RNG",
+                 gnupg_compliance_option_string (opt.compliance));
+      write_status_error ("random-compliance", rc);
+      goto leave;
+    }
+
   compliant = gnupg_cipher_is_compliant (CO_DE_VS, cfx.dek->algo,
                                          GCRY_CIPHER_MODE_CFB);
 
index 0ba1151..f7dd974 100644 (file)
@@ -299,6 +299,16 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
       goto leave;
     }
 
+  if (!gnupg_rng_is_compliant (opt.compliance))
+    {
+      err = gpg_error (GPG_ERR_FORBIDDEN);
+      log_error (_("%s is not compliant with %s mode\n"),
+                 "RNG",
+                 gnupg_compliance_option_string (opt.compliance));
+      write_status_error ("random-compliance", err);
+      goto leave;
+    }
+
   print_digest_algo_note (mdalgo);
   dp = gcry_md_read  (md, mdalgo);
   sig->digest_algo = mdalgo;
index 0e47c14..ba8fb12 100644 (file)
@@ -171,6 +171,25 @@ start_agent (ctrl_t ctrl)
                            str_pinentry_mode (opt.pinentry_mode),
                            gpg_strerror (rc));
             }
+
+          /* In DE_VS mode under Windows we require that the JENT RNG
+           * is active.  */
+#ifdef HAVE_W32_SYSTEM
+          if (!rc && opt.compliance == CO_DE_VS)
+            {
+              if (assuan_transact (agent_ctx, "GETINFO jent_active",
+                                   NULL, NULL, NULL, NULL, NULL, NULL))
+                {
+                  rc = gpg_error (GPG_ERR_FORBIDDEN);
+                  log_error (_("%s is not compliant with %s mode\n"),
+                             GPG_AGENT_NAME,
+                             gnupg_compliance_option_string (opt.compliance));
+                  gpgsm_status_with_error (ctrl, STATUS_ERROR,
+                                           "random-compliance", rc);
+                }
+            }
+#endif /*HAVE_W32_SYSTEM*/
+
         }
     }
 
index 9e3216a..7351932 100644 (file)
@@ -420,6 +420,17 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp)
       goto leave;
     }
 
+  if (!gnupg_rng_is_compliant (opt.compliance))
+    {
+      rc = gpg_error (GPG_ERR_FORBIDDEN);
+      log_error (_("%s is not compliant with %s mode\n"),
+                 "RNG",
+                 gnupg_compliance_option_string (opt.compliance));
+      gpgsm_status_with_error (ctrl, STATUS_ERROR,
+                               "random-compliance", rc);
+      goto leave;
+    }
+
   /* Create a session key */
   dek = xtrycalloc_secure (1, sizeof *dek);
   if (!dek)
index 7ba2319..1411501 100644 (file)
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -339,6 +339,17 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
       goto leave;
     }
 
+  if (!gnupg_rng_is_compliant (opt.compliance))
+    {
+      rc = gpg_error (GPG_ERR_FORBIDDEN);
+      log_error (_("%s is not compliant with %s mode\n"),
+                 "RNG",
+                 gnupg_compliance_option_string (opt.compliance));
+      gpgsm_status_with_error (ctrl, STATUS_ERROR,
+                               "random-compliance", rc);
+      goto leave;
+    }
+
   ctrl->pem_name = "SIGNED MESSAGE";
   rc = gnupg_ksba_create_writer
     (&b64writer, ((ctrl->create_pem? GNUPG_KSBA_IO_PEM : 0)