gpg: Report compliance with CO_DE_VS.

* common/compliance.c (gnupg_pk_is_compliant): Add DSA with certain
parameters.
(gnupg_cipher_is_compliant): New function.
(gnupg_digest_is_compliant): Likewise.
* common/compliance.h (gnupg_cipher_is_compliant): New prototype.
(gnupg_digest_is_compliant): Likewise.
* common/status.h (STATUS_DECRYPTION_COMPLIANCE_MODE): New status.
(STATUS_VERIFICATION_COMPLIANCE_MODE): Likewise.
* doc/DETAILS: Document the new status lines.
* g10/mainproc.c (proc_encrypted): Compute compliance with CO_DE_VS
and report that using the new status line.
(check_sig_and_print): Likewise.
* sm/decrypt.c (gpgsm_decrypt): Likewise.
* sm/verify.c (gpgsm_verify): Likewise.
--

When decrypting data and verifying signatures, report whether the
operations are in compliance with the criteria for data classified as
VS-NfD.  This information will be picked up by the frontend and
presented to the user.

GnuPG-bug-id: 3059
Signed-off-by: Justus Winter <justus@g10code.com>
This commit is contained in:
Justus Winter 2017-05-30 14:30:24 +02:00
parent 3b70f62423
commit be8ca88526
No known key found for this signature in database
GPG Key ID: DD1A52F9DA8C9020
7 changed files with 171 additions and 3 deletions

View File

@ -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)
{

View File

@ -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*/

View File

@ -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,

View File

@ -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:

View File

@ -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 );

View File

@ -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);
}

View File

@ -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;