diff --git a/common/status.h b/common/status.h --- a/common/status.h +++ b/common/status.h @@ -141,6 +141,9 @@ 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 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -638,6 +638,17 @@ This indicates that a signature subpacket was seen. The format is the same as the "spk" record above. +*** DECRYPTION_COMPLIANCE_MODE + 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 + 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/keylist.c b/g10/keylist.c --- a/g10/keylist.c +++ b/g10/keylist.c @@ -1182,12 +1182,13 @@ if (pk->version == 5) { - es_fputs ("8", es_stdout); + es_fputs (gnupg_status_compliance_flag (CO_GNUPG), es_stdout); any++; } if (gnupg_pk_is_compliant (CO_DE_VS, pk, keylength, curvename)) { - es_fputs (any? " 23":"23", es_stdout); + es_fprintf (es_stdout, any ? " %s" : "%s", + gnupg_status_compliance_flag (CO_DE_VS)); any++; } } diff --git a/g10/main.h b/g10/main.h --- a/g10/main.h +++ b/g10/main.h @@ -128,6 +128,9 @@ int gnupg_pk_is_compliant (int compliance, PKT_public_key *pk, unsigned int keylength, const char *curvename); +int gnupg_cipher_is_compliant (int compliance, cipher_algo_t cipher); +int gnupg_digest_is_compliant (int compliance, digest_algo_t digest); +const char *gnupg_status_compliance_flag (int compliance); enum gcry_md_algos map_md_openpgp_to_gcry (digest_algo_t algo); int openpgp_md_test_algo (digest_algo_t algo); diff --git a/g10/mainproc.c b/g10/mainproc.c --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -599,6 +599,43 @@ 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, 0, 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 +2233,14 @@ } } + /* Compute compliance with CO_DE_VS. */ + if (pk && is_status_enabled () + && gnupg_pk_is_compliant (CO_DE_VS, pk, 0, 0) + && 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/g10/misc.c b/g10/misc.c --- a/g10/misc.c +++ b/g10/misc.c @@ -795,6 +795,79 @@ } +/* Return true if CIPHER is compliant to the give COMPLIANCE mode. */ +int +gnupg_cipher_is_compliant (int 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 (int 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 (int compliance) +{ + switch (compliance) + { + case CO_GNUPG: + return "8"; + case CO_RFC4880: + case CO_RFC2440: + case CO_PGP6: + case CO_PGP7: + case CO_PGP8: + log_assert (!"no status code assigned for this compliance mode"); + case CO_DE_VS: + return "23"; + } + log_assert (!"invalid compliance mode"); +} + + /* Explicit mapping of OpenPGP digest algos to Libgcrypt. */ /* FIXME: We do not yes use it everywhere. */ enum gcry_md_algos