From e542c4af182d1c6d6ecb4dc902eb331889edb27f Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Tue, 2 Aug 2022 18:36:56 +0200 Subject: [PATCH] gpg: Make symmetric + pubkey encryption de-vs compliant. * g10/mainproc.c (proc_encrypted): Make symmetric + pubkey encryption de-vs compliant. * g10/mainproc.c (struct symlist_item): New. (struct mainproc_context): Add field symenc_list. (release_list): Free that list. (proc_symkey_enc): Record infos from symmetric session packet. (proc_encrypted): Check symkey packet algos -- The original check was too strong because it is in fact compliant to encrypt with a symmetric key and and public key. Thus decryption should issue a compliance status. In addition we now check that the cipher algorithms used to symmetrically encrypt the session key are all compliant. This is similar to our check for all public key encrypted session key packets. GnuPG-bug-id: 6119 Fixes-commit: b03fab09e188f7bb10237d4f20455e4026737e4e Backported from 2.2 Signed-off-by: Werner Koch --- g10/mainproc.c | 52 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/g10/mainproc.c b/g10/mainproc.c index af11877aa..0757fcd90 100644 --- a/g10/mainproc.c +++ b/g10/mainproc.c @@ -47,6 +47,16 @@ #define MAX_NESTING_DEPTH 32 +/* An object to build a list of symkey packet info. */ +struct symlist_item +{ + struct symlist_item *next; + int cipher_algo; + int cfb_mode; + int other_error; +}; + + /* * Object to hold the processing context. */ @@ -87,6 +97,7 @@ struct mainproc_context int trustletter; /* Temporary usage in list_node. */ ulong symkeys; /* Number of symmetrically encrypted session keys. */ struct pubkey_enc_list *pkenc_list; /* List of encryption packets. */ + struct symlist_item *symenc_list; /* List of sym. encryption packets. */ int seen_pkt_encrypted_aead; /* PKT_ENCRYPTED_AEAD packet seen. */ int seen_pkt_encrypted_mdc; /* PKT_ENCRYPTED_MDC packet seen. */ struct { @@ -136,6 +147,13 @@ release_list( CTX c ) c->pkenc_list = tmp; } c->pkenc_list = NULL; + while (c->symenc_list) + { + struct symlist_item *tmp = c->symenc_list->next; + xfree (c->symenc_list); + c->symenc_list = tmp; + } + c->symenc_list = NULL; c->list = NULL; c->any.data = 0; c->any.uncompress_failed = 0; @@ -460,6 +478,20 @@ proc_symkey_enc (CTX c, PACKET *pkt) } leave: + /* Record infos from the packet. */ + { + struct symlist_item *symitem; + symitem = xcalloc (1, sizeof *symitem); + if (enc) + { + symitem->cipher_algo = enc->cipher_algo; + symitem->cfb_mode = !enc->aead_algo; + } + else + symitem->other_error = 1; + symitem->next = c->symenc_list; + c->symenc_list = symitem; + } c->symkeys++; free_packet (pkt, NULL); } @@ -695,8 +727,6 @@ proc_encrypted (CTX c, PACKET *pkt) /* Compute compliance with CO_DE_VS. */ if (!result && is_status_enabled () - /* Symmetric encryption and asymmetric encryption voids compliance. */ - && (c->symkeys != !!c->pkenc_list ) /* Overriding session key voids compliance. */ && !opt.override_session_key /* Check symmetric cipher. */ @@ -705,14 +735,26 @@ proc_encrypted (CTX c, PACKET *pkt) GCRY_CIPHER_MODE_CFB)) { struct pubkey_enc_list *i; + struct symlist_item *si; int compliant = 1; PKT_public_key *pk = xmalloc (sizeof *pk); if ( !(c->pkenc_list || c->symkeys) ) log_debug ("%s: where else did the session key come from?\n", __func__); - /* Now check that every key used to encrypt the session key is - * compliant. */ + /* Check that all seen symmetric key packets use compliant + * algos. This is so that no non-compliant encrypted session + * key can be sneaked in. */ + for (si = c->symenc_list; si && compliant; si = si->next) + { + if (!si->cfb_mode + || !gnupg_cipher_is_compliant (CO_DE_VS, si->cipher_algo, + GCRY_CIPHER_MODE_CFB)) + compliant = 0; + } + + /* Check that every public key used to encrypt the session key + * is compliant. */ for (i = c->pkenc_list; i && compliant; i = i->next) { memset (pk, 0, sizeof *pk); @@ -836,7 +878,7 @@ proc_encrypted (CTX c, PACKET *pkt) /* If we concluded that the decryption was compliant, issue a - * compliance status before the thed end of decryption status. */ + * compliance status before the end of the decryption status. */ if (compliance_de_vs == (4|2|1)) { write_status_strings (STATUS_DECRYPTION_COMPLIANCE_MODE,