diff options
author | Werner Koch <[email protected]> | 2021-06-02 09:03:55 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2021-06-02 09:03:55 +0000 |
commit | 4980fb3c6dde8c1dda975e8a36d6086c8456a631 (patch) | |
tree | d5a1dd07d15256549159f8a20b1617fc6ee7122a /sm/decrypt.c | |
parent | tests: Rename subdir gpgsm to cms and move sample dirs. (diff) | |
download | gnupg-4980fb3c6dde8c1dda975e8a36d6086c8456a631.tar.gz gnupg-4980fb3c6dde8c1dda975e8a36d6086c8456a631.zip |
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.
Diffstat (limited to 'sm/decrypt.c')
-rw-r--r-- | sm/decrypt.c | 82 |
1 files changed, 78 insertions, 4 deletions
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); |