From 4980fb3c6dde8c1dda975e8a36d6086c8456a631 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 2 Jun 2021 11:03:55 +0200 Subject: sm: Support AES-GCM decryption. * tests/cms/samplemsgs/: Add sample messages. * sm/gpgsm.c (main): Use gpgrt_fcancel on decryption error. * sm/decrypt.c (decrypt_gcm_filter): New. (gpgsm_decrypt): Use this filter if requested. Check authtag. -- Note that the sample message pwri-sample.gcm.p7m is broken: The authtag is duplicated to the authEncryptedContentInfo. I used a temporary code during testing hack to that test message out. --- doc/DETAILS | 2 + sm/decrypt.c | 82 +++++++++++++++++++++++++++-- sm/gpgsm.c | 9 ++-- tests/cms/Makefile.am | 4 ++ tests/cms/samplemsgs/README | 6 +++ tests/cms/samplemsgs/pwri-sample.cbc-2.p7m | Bin 0 -> 346 bytes tests/cms/samplemsgs/pwri-sample.cbc.p7m | Bin 0 -> 350 bytes tests/cms/samplemsgs/pwri-sample.gcm.p7m | Bin 0 -> 375 bytes 8 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 tests/cms/samplemsgs/README create mode 100644 tests/cms/samplemsgs/pwri-sample.cbc-2.p7m create mode 100644 tests/cms/samplemsgs/pwri-sample.cbc.p7m create mode 100644 tests/cms/samplemsgs/pwri-sample.gcm.p7m diff --git a/doc/DETAILS b/doc/DETAILS index bbe2ad5d5..b5b1bb7d5 100644 --- a/doc/DETAILS +++ b/doc/DETAILS @@ -1665,6 +1665,8 @@ Description of some debug flags: ** List of useful RFCs - RFC-3447 :: PKCS #1: RSA Cryptography Specifications Version 2.1 - RFC-4880 :: OpenPGP + - RFC-5083 :: CMS - Authenticated-Enveloped-Data + - RFC-5084 :: CMS - AES-GCM - RFC-5280 :: X.509 PKI Certificate and CRL Profile - RFC-5652 :: CMS (STD0070) - RFC-6818 :: Updates to the X.509 PKI Certificate and CRL Profile diff --git a/sm/decrypt.c b/sm/decrypt.c index c5f073190..6b3dd6661 100644 --- a/sm/decrypt.c +++ b/sm/decrypt.c @@ -37,6 +37,15 @@ #include "../common/tlv.h" #include "../common/compliance.h" +/* We can provide an enum value which is only availabale with KSBA + * 1.6.0 so that we can compile even against older versions. Some + * calls will of course return an error in this case. This value is + * currently not used because the cipher mode is sufficient here. */ +/* #if KSBA_VERSION_NUMBER < 0x010600 /\* 1.6.0 *\/ */ +/* # define KSBA_CT_AUTHENVELOPED_DATA 10 */ +/* #endif */ + + struct decrypt_filter_parm_s { int algo; @@ -911,6 +920,14 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, goto leave; } + if (parm->mode == GCRY_CIPHER_MODE_GCM) + { + /* GCM mode really sucks in CMS. We need to know the AAD before + * we start decrypting but CMS puts the AAD after the content. + * Thus temporary files are required. Let's hope that no real + * messages with actual AAD are ever used. OCB Rules! */ + } + leave: xfree (seskey); return rc; @@ -1010,6 +1027,36 @@ decrypt_filter (void *arg, } +/* This is the GCM version of decrypt_filter. */ +static gpg_error_t +decrypt_gcm_filter (void *arg, + const void *inbuf, size_t inlen, size_t *inused, + void *outbuf, size_t maxoutlen, size_t *outlen) +{ + struct decrypt_filter_parm_s *parm = arg; + + if (!inlen) + return gpg_error (GPG_ERR_BUG); + + if (maxoutlen < parm->blklen) + return gpg_error (GPG_ERR_BUG); + + if (inlen > maxoutlen) + inlen = maxoutlen; + + *inused = inlen; + if (inlen) + { + gcry_cipher_decrypt (parm->hd, outbuf, inlen, inbuf, inlen); + *outlen = inlen; + parm->any_data = 1; + } + else + *outlen = 0; + return 0; +} + + /* Perform a decrypt operation. */ int @@ -1332,9 +1379,11 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) else { /* setup the bulk decrypter */ any_key = 1; - ksba_writer_set_filter (writer, - decrypt_filter, - &dfparm); + ksba_writer_set_filter + (writer, + dfparm.mode == GCRY_CIPHER_MODE_GCM? + decrypt_gcm_filter : decrypt_filter, + &dfparm); if (dfparm.is_de_vs && gnupg_gcrypt_is_compliant (CO_DE_VS)) @@ -1389,7 +1438,11 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) else if (stopreason == KSBA_SR_END_DATA) { ksba_writer_set_filter (writer, NULL, NULL); - if (dfparm.any_data) + if (dfparm.mode == GCRY_CIPHER_MODE_GCM) + { + /* Nothing yet to do. We wait for the ready event. */ + } + else if (dfparm.any_data ) { /* write the last block with padding removed */ int i, npadding = dfparm.lastblock[dfparm.blklen-1]; if (!npadding || npadding > dfparm.blklen) @@ -1415,7 +1468,28 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp) } } } + else if (stopreason == KSBA_SR_READY) + { + if (dfparm.mode == GCRY_CIPHER_MODE_GCM) + { + char *authtag; + size_t authtaglen; + rc = ksba_cms_get_message_digest (cms, 0, &authtag, &authtaglen); + if (rc) + { + log_error ("error getting authtag: %s\n", gpg_strerror (rc)); + goto leave; + } + if (DBG_CRYPTO) + log_printhex (authtag, authtaglen, "Authtag ...:"); + rc = gcry_cipher_checktag (dfparm.hd, authtag, authtaglen); + xfree (authtag); + if (rc) + log_error ("data is not authentic: %s\n", gpg_strerror (rc)); + goto leave; + } + } } while (stopreason != KSBA_SR_READY); diff --git a/sm/gpgsm.c b/sm/gpgsm.c index f488eb5e8..3c6fe9c76 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -2065,13 +2065,16 @@ main ( int argc, char **argv) set_binary (stdin); if (!argc) - gpgsm_decrypt (&ctrl, 0, fp); /* from stdin */ + err = gpgsm_decrypt (&ctrl, 0, fp); /* from stdin */ else if (argc == 1) - gpgsm_decrypt (&ctrl, open_read (*argv), fp); /* from file */ + err = gpgsm_decrypt (&ctrl, open_read (*argv), fp); /* from file */ else wrong_args ("--decrypt [filename]"); - es_fclose (fp); + if (err) + gpgrt_fcancel (fp); + else + es_fclose (fp); } break; diff --git a/tests/cms/Makefile.am b/tests/cms/Makefile.am index 03c7d8d21..bc86acba2 100644 --- a/tests/cms/Makefile.am +++ b/tests/cms/Makefile.am @@ -86,6 +86,10 @@ EXTRA_DIST = $(XTESTS) $(KEYS) $(CERTS) $(TEST_FILES) \ samplekeys/cert_g10code_pete1.pem \ samplekeys/cert_g10code_test1.pem \ samplekeys/cert_g10code_theo1.pem \ + samplemsgs/README \ + samplemsgs/pwri-sample.cbc.p7m \ + samplemsgs/pwri-sample.cbc-2.p7m \ + samplemsgs/pwri-sample.gcm.p7m \ text-1.txt text-2.txt text-3.txt \ text-1.osig.pem text-1.dsig.pem text-1.osig-bad.pem \ text-2.osig.pem text-2.osig-bad.pem \ diff --git a/tests/cms/samplemsgs/README b/tests/cms/samplemsgs/README new file mode 100644 index 000000000..a76b9457a --- /dev/null +++ b/tests/cms/samplemsgs/README @@ -0,0 +1,6 @@ +Sample messages for CMS symmetric encryption. +Password is "abc". + +pwri-sample.cbc.p7m - Using CBC Mode +pwri-sample.cbc-2.p7m - Using CBC with a different iteration count +pwri-sample.gcm.p7m - Using GCM (from a broken implementation) diff --git a/tests/cms/samplemsgs/pwri-sample.cbc-2.p7m b/tests/cms/samplemsgs/pwri-sample.cbc-2.p7m new file mode 100644 index 000000000..a417b7aca Binary files /dev/null and b/tests/cms/samplemsgs/pwri-sample.cbc-2.p7m differ diff --git a/tests/cms/samplemsgs/pwri-sample.cbc.p7m b/tests/cms/samplemsgs/pwri-sample.cbc.p7m new file mode 100644 index 000000000..ba208d2e3 Binary files /dev/null and b/tests/cms/samplemsgs/pwri-sample.cbc.p7m differ diff --git a/tests/cms/samplemsgs/pwri-sample.gcm.p7m b/tests/cms/samplemsgs/pwri-sample.gcm.p7m new file mode 100644 index 000000000..7cf1f8542 Binary files /dev/null and b/tests/cms/samplemsgs/pwri-sample.gcm.p7m differ -- cgit v1.2.3