From a149afe338d61d86985c533cde5e7dbcd31e8698 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 17 Jul 2017 15:52:26 +0200 Subject: [PATCH] gpg,sm: Check compliance of the RNG. * 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 --- common/compliance.c | 40 ++++++++++++++++++++++++++++++++++++++++ common/compliance.h | 2 ++ g10/call-agent.c | 18 ++++++++++++++++++ g10/encrypt.c | 20 ++++++++++++++++++++ g10/sign.c | 10 ++++++++++ sm/call-agent.c | 19 +++++++++++++++++++ sm/encrypt.c | 11 +++++++++++ sm/sign.c | 11 +++++++++++ 8 files changed, 131 insertions(+) diff --git a/common/compliance.c b/common/compliance.c index 8b9167758..268ea4dbf 100644 --- a/common/compliance.c +++ b/common/compliance.c @@ -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) { diff --git a/common/compliance.h b/common/compliance.h index d55bbf3ac..2076e79cb 100644 --- a/common/compliance.h +++ b/common/compliance.h @@ -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); diff --git a/g10/call-agent.c b/g10/call-agent.c index 7b769332e..3ad13e874 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -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*/ + } } diff --git a/g10/encrypt.c b/g10/encrypt.c index 4b21a6178..c63ec8838 100644 --- a/g10/encrypt.c +++ b/g10/encrypt.c @@ -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); diff --git a/g10/sign.c b/g10/sign.c index 0ba115188..f7dd974fe 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -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; diff --git a/sm/call-agent.c b/sm/call-agent.c index 0e47c1448..ba8fb122b 100644 --- a/sm/call-agent.c +++ b/sm/call-agent.c @@ -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*/ + } } diff --git a/sm/encrypt.c b/sm/encrypt.c index 9e3216a79..73519325e 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -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) diff --git a/sm/sign.c b/sm/sign.c index 7ba231939..14115017d 100644 --- 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)