From 90c514868ff5fcf6d39490d4874ac3a31ba9e85f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 28 Jan 2021 15:48:08 +0100 Subject: [PATCH] Include the library version in the compliance checks. * common/compliance.c (gnupg_gcrypt_is_compliant): New. (gnupg_rng_is_compliant): Also check library version. * g10/mainproc.c (proc_encrypted): Use new function. (check_sig_and_print): Ditto. * sm/decrypt.c (gpgsm_decrypt): Ditto. * sm/encrypt.c (gpgsm_encrypt): Ditto. * sm/verify.c (gpgsm_verify): Ditto -- This will eventually allow us to declare Libgcrypt 1.9 to be de-vs compliant. GnuPG can use this information then for its own checks. As of now GnuPG tests the version of the used library but that is a bit cumbersome to maintain. Signed-off-by: Werner Koch --- common/compliance.c | 78 ++++++++++++++++++++++++++++++++++++--------- common/compliance.h | 1 + g10/mainproc.c | 2 ++ sm/decrypt.c | 2 +- sm/encrypt.c | 2 +- sm/verify.c | 1 + 6 files changed, 69 insertions(+), 17 deletions(-) diff --git a/common/compliance.c b/common/compliance.c index 0c785799e..48eeb1fe7 100644 --- a/common/compliance.c +++ b/common/compliance.c @@ -496,23 +496,71 @@ gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance) ; /* 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 - char *buf; - const char *fields[5]; + /* We also check whether the library is at all compliant. */ + result = gnupg_gcrypt_is_compliant (compliance); - buf = gcry_get_config (0, "rng-type"); - if (buf - && split_fields_colon (buf, fields, DIM (fields)) >= 5 - && atoi (fields[4]) > 0) - result = 1; + /* In DE_VS mode under Windows we also require that the JENT RNG + * is active. Check it here. */ +#ifdef HAVE_W32_SYSTEM + if (result == 1) + { + char *buf; + const 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 + result = 1; + + return result; +} + + +/* Return true if the used Libgcrypt is compliant in COMPLIANCE + * mode. */ +int +gnupg_gcrypt_is_compliant (enum gnupg_compliance_mode compliance) +{ + static int result = -1; + + if (result != -1) + ; /* 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) + result = 1; /* Compliant version of Libgcrypt. */ + else if (is19orlater) + { + /* Libgcrypt might be nice enough to tell us whether it is + * compliant. */ + char *buf; + const char *fields[3]; + + buf = gcry_get_config (0, "compliance"); + if (buf + && split_fields_colon (buf, fields, DIM (fields)) >= 2 + && strstr (fields[1], "de-vs")) + result = 1; /* Compliant. */ + else + result = 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*/ + result = 0; /* Non-compliant version of Libgcrypt. */ } else result = 1; diff --git a/common/compliance.h b/common/compliance.h index 7c74da38a..2f7039206 100644 --- a/common/compliance.h +++ b/common/compliance.h @@ -73,6 +73,7 @@ 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); +int gnupg_gcrypt_is_compliant (enum gnupg_compliance_mode compliance); const char *gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance); diff --git a/g10/mainproc.c b/g10/mainproc.c index 08986a070..ca6c24323 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -688,6 +688,7 @@ proc_encrypted (CTX c, PACKET *pkt) /* Overriding session key voids compliance. */ && !opt.override_session_key /* Check symmetric cipher. */ + && gnupg_gcrypt_is_compliant (CO_DE_VS) && gnupg_cipher_is_compliant (CO_DE_VS, c->dek->algo, GCRY_CIPHER_MODE_CFB)) { @@ -2537,6 +2538,7 @@ check_sig_and_print (CTX c, kbnode_t node) /* Compute compliance with CO_DE_VS. */ if (pk && is_status_enabled () + && gnupg_gcrypt_is_compliant (CO_DE_VS) && gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, 0, pk->pkey, nbits_from_pk (pk), NULL) && gnupg_digest_is_compliant (CO_DE_VS, sig->digest_algo)) diff --git a/sm/decrypt.c b/sm/decrypt.c index 2d846335e..aa91b370d 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -925,7 +925,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) decrypt_filter, &dfparm); - if (is_de_vs) + if (is_de_vs && gnupg_gcrypt_is_compliant (CO_DE_VS)) gpgsm_status (ctrl, STATUS_DECRYPTION_COMPLIANCE_MODE, gnupg_status_compliance_flag (CO_DE_VS)); diff --git a/sm/encrypt.c b/sm/encrypt.c index 34a5e878b..fbd88b6cd 100644 --- a/sm/encrypt.c +++ b/sm/encrypt.c @@ -807,7 +807,7 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int data_fd, estream_t out_fp) } } - if (compliant) + if (compliant && gnupg_gcrypt_is_compliant (CO_DE_VS)) gpgsm_status (ctrl, STATUS_ENCRYPTION_COMPLIANCE_MODE, gnupg_status_compliance_flag (CO_DE_VS)); diff --git a/sm/verify.c b/sm/verify.c index 1575a1eb2..fe111c32a 100644 --- a/sm/verify.c +++ b/sm/verify.c @@ -516,6 +516,7 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp) /* Check compliance with CO_DE_VS. */ if (gnupg_pk_is_compliant (CO_DE_VS, pkalgo, pkalgoflags, NULL, nbits, NULL) + && gnupg_gcrypt_is_compliant (CO_DE_VS) && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo)) gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE, gnupg_status_compliance_flag (CO_DE_VS));