summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/compliance.c72
-rw-r--r--common/compliance.h4
-rw-r--r--common/status.h3
-rw-r--r--doc/DETAILS11
-rw-r--r--g10/mainproc.c48
-rw-r--r--sm/decrypt.c25
-rw-r--r--sm/verify.c11
7 files changed, 171 insertions, 3 deletions
diff --git a/common/compliance.c b/common/compliance.c
index c0b69843b..80134d6b6 100644
--- a/common/compliance.c
+++ b/common/compliance.c
@@ -45,8 +45,8 @@ 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;
+ enum { is_rsa, is_dsa, is_pgp5, is_elg_sign, is_ecc } algotype;
+ int result = 0;
switch (algo)
{
@@ -56,8 +56,11 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
algotype = is_rsa;
break;
- case PUBKEY_ALGO_ELGAMAL_E:
case PUBKEY_ALGO_DSA:
+ algotype = is_dsa;
+ break;
+
+ case PUBKEY_ALGO_ELGAMAL_E:
algotype = is_pgp5;
break;
@@ -91,6 +94,16 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
|| keylength == 4096);
break;
+ case is_dsa:
+ if (key)
+ {
+ size_t L = gcry_mpi_get_nbits (key[0] /* p */);
+ size_t N = gcry_mpi_get_nbits (key[1] /* q */);
+ result = (L == 256
+ && (N == 2048 || N == 3072));
+ }
+ break;
+
case is_ecc:
if (!curvename && key)
{
@@ -126,6 +139,59 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
}
+/* Return true if CIPHER is compliant to the give COMPLIANCE mode. */
+int
+gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance, cipher_algo_t cipher)
+{
+ switch (compliance)
+ {
+ case CO_DE_VS:
+ switch (cipher)
+ {
+ case CIPHER_ALGO_AES:
+ case CIPHER_ALGO_AES192:
+ case CIPHER_ALGO_AES256:
+ case CIPHER_ALGO_3DES:
+ return 1;
+ default:
+ return 0;
+ }
+ log_assert (!"reached");
+
+ default:
+ return 0;
+ }
+
+ log_assert (!"reached");
+}
+
+
+/* Return true if DIGEST is compliant to the give COMPLIANCE mode. */
+int
+gnupg_digest_is_compliant (enum gnupg_compliance_mode compliance, digest_algo_t digest)
+{
+ switch (compliance)
+ {
+ case CO_DE_VS:
+ switch (digest)
+ {
+ case DIGEST_ALGO_SHA256:
+ case DIGEST_ALGO_SHA384:
+ case DIGEST_ALGO_SHA512:
+ return 1;
+ default:
+ return 0;
+ }
+ log_assert (!"reached");
+
+ default:
+ return 0;
+ }
+
+ log_assert (!"reached");
+}
+
+
const char *
gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance)
{
diff --git a/common/compliance.h b/common/compliance.h
index 123bd1b50..4f78ad42f 100644
--- a/common/compliance.h
+++ b/common/compliance.h
@@ -42,6 +42,10 @@ enum gnupg_compliance_mode
int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
gcry_mpi_t key[], unsigned int keylength,
const char *curvename);
+int gnupg_cipher_is_compliant (enum gnupg_compliance_mode compliance,
+ cipher_algo_t cipher);
+int gnupg_digest_is_compliant (enum gnupg_compliance_mode compliance,
+ digest_algo_t digest);
const char *gnupg_status_compliance_flag (enum gnupg_compliance_mode compliance);
#endif /*GNUPG_COMMON_COMPLIANCE_H*/
diff --git a/common/status.h b/common/status.h
index 8831a0f5f..0250a656f 100644
--- a/common/status.h
+++ b/common/status.h
@@ -141,6 +141,9 @@ enum
STATUS_TOFU_STATS_SHORT,
STATUS_TOFU_STATS_LONG,
+ STATUS_DECRYPTION_COMPLIANCE_MODE,
+ STATUS_VERIFICATION_COMPLIANCE_MODE,
+
STATUS_TRUNCATED,
STATUS_MOUNTPOINT,
STATUS_BLOCKDEV,
diff --git a/doc/DETAILS b/doc/DETAILS
index 1624315ff..01b5cf9c3 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -638,6 +638,17 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
This indicates that a signature subpacket was seen. The format is
the same as the "spk" record above.
+*** DECRYPTION_COMPLIANCE_MODE <flags>
+ Indicates that the current decryption operation is in compliance
+ with the given set of modes. "flags" is a space separated list of
+ numerical flags, see "Field 18 - Compliance flags" above.
+
+*** VERIFICATION_COMPLIANCE_MODE <flags>
+ Indicates that the current signature verification operation is in
+ compliance with the given set of modes. "flags" is a space
+ separated list of numerical flags, see "Field 18 - Compliance
+ flags" above.
+
** Key related
*** INV_RECP, INV_SGNR
The two similar status codes:
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 9500081d5..21ea6cafb 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -39,6 +39,7 @@
#include "photoid.h"
#include "../common/mbox-util.h"
#include "call-dirmngr.h"
+#include "../common/compliance.h"
/* Put an upper limit on nested packets. The 32 is an arbitrary
value, a much lower should actually be sufficient. */
@@ -599,6 +600,44 @@ proc_encrypted (CTX c, PACKET *pkt)
else if (!c->dek)
result = GPG_ERR_NO_SECKEY;
+ /* Compute compliance with CO_DE_VS. */
+ if (!result && is_status_enabled ()
+ /* Symmetric encryption voids compliance. */
+ && c->symkeys == 0
+ /* Overriding session key voids compliance. */
+ && opt.override_session_key == NULL
+ /* Check symmetric cipher. */
+ && gnupg_cipher_is_compliant (CO_DE_VS, c->dek->algo))
+ {
+ struct kidlist_item *i;
+ int compliant = 1;
+ PKT_public_key *pk = xmalloc (sizeof *pk);
+
+ log_assert (c->pkenc_list || !"where else did the session key come from!?");
+
+ /* Now check that every key used to encrypt the session key is
+ * compliant. */
+ for (i = c->pkenc_list; i && compliant; i = i->next)
+ {
+ memset (pk, 0, sizeof *pk);
+ pk->pubkey_algo = i->pubkey_algo;
+ if (get_pubkey (c->ctrl, pk, i->kid) != 0
+ || ! gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
+ nbits_from_pk (pk), NULL))
+ compliant = 0;
+ release_public_key_parts (pk);
+ }
+
+ xfree (pk);
+
+ if (compliant)
+ write_status_strings (STATUS_DECRYPTION_COMPLIANCE_MODE,
+ gnupg_status_compliance_flag (CO_DE_VS),
+ NULL);
+
+ }
+
+
if (!result)
result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek );
@@ -2196,6 +2235,15 @@ check_sig_and_print (CTX c, kbnode_t node)
}
}
+ /* Compute compliance with CO_DE_VS. */
+ if (pk && is_status_enabled ()
+ && gnupg_pk_is_compliant (CO_DE_VS, pk->pubkey_algo, pk->pkey,
+ nbits_from_pk (pk), NULL)
+ && gnupg_digest_is_compliant (CO_DE_VS, sig->digest_algo))
+ write_status_strings (STATUS_VERIFICATION_COMPLIANCE_MODE,
+ gnupg_status_compliance_flag (CO_DE_VS),
+ NULL);
+
free_public_key (pk);
pk = NULL;
release_kbnode( keyblock );
diff --git a/sm/decrypt.c b/sm/decrypt.c
index f8b01994c..aa621ddf3 100644
--- a/sm/decrypt.c
+++ b/sm/decrypt.c
@@ -32,6 +32,7 @@
#include "keydb.h"
#include "../common/i18n.h"
+#include "../common/compliance.h"
struct decrypt_filter_parm_s
{
@@ -325,6 +326,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
int algo, mode;
const char *algoid;
int any_key = 0;
+ int is_de_vs; /* Computed compliance with CO_DE_VS. */
audit_log (ctrl->audit, AUDIT_GOT_DATA);
@@ -356,6 +358,10 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
goto leave;
}
+ /* For CMS, CO_DE_VS demands CBC mode. */
+ is_de_vs = (mode == GCRY_CIPHER_MODE_CBC
+ && gnupg_cipher_is_compliant (CO_DE_VS, algo));
+
audit_log_i (ctrl->audit, AUDIT_DATA_CIPHER_ALGO, algo);
dfparm.algo = algo;
dfparm.mode = mode;
@@ -460,7 +466,21 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
desc = gpgsm_format_keydesc (cert);
+ /* Check that all certs are compliant with CO_DE_VS. */
+ if (is_de_vs)
+ {
+ unsigned int nbits;
+ int pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
+
+ is_de_vs = gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL,
+ nbits, NULL);
+ }
+
oops:
+ if (rc)
+ /* We cannot check compliance of certs that we
+ * don't have. */
+ is_de_vs = 0;
xfree (issuer);
xfree (serial);
ksba_cert_release (cert);
@@ -489,6 +509,11 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
ksba_writer_set_filter (writer,
decrypt_filter,
&dfparm);
+
+ if (is_de_vs)
+ gpgsm_status (ctrl, STATUS_DECRYPTION_COMPLIANCE_MODE,
+ gnupg_status_compliance_flag (CO_DE_VS));
+
}
audit_log_ok (ctrl->audit, AUDIT_RECP_RESULT, rc);
}
diff --git a/sm/verify.c b/sm/verify.c
index 7bdc68b80..e19c04e38 100644
--- a/sm/verify.c
+++ b/sm/verify.c
@@ -33,6 +33,7 @@
#include "keydb.h"
#include "../common/i18n.h"
+#include "../common/compliance.h"
static char *
strtimestamp_r (ksba_isotime_t atime)
@@ -631,6 +632,16 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
(verifyflags & VALIDATE_FLAG_CHAIN_MODEL)?
"0 chain": "0 shell");
+ /* Check compliance with CO_DE_VS. */
+ {
+ unsigned int nbits;
+ int pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
+
+ if (gnupg_pk_is_compliant (CO_DE_VS, pk_algo, NULL, nbits, NULL)
+ && gnupg_digest_is_compliant (CO_DE_VS, sigval_hash_algo))
+ gpgsm_status (ctrl, STATUS_VERIFICATION_COMPLIANCE_MODE,
+ gnupg_status_compliance_flag (CO_DE_VS));
+ }
next_signer:
rc = 0;