diff options
author | Werner Koch <[email protected]> | 2009-10-02 14:57:55 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2009-10-02 14:57:55 +0000 |
commit | 71625f56fd98ab37bc05f1806b4b49a2e418ac37 (patch) | |
tree | 24d54f73a41c21241f7b99c3eee15374b1185df6 /g10/encr-data.c | |
parent | Fixed EOF detection for encrypted packets. (diff) | |
download | gnupg-71625f56fd98ab37bc05f1806b4b49a2e418ac37.tar.gz gnupg-71625f56fd98ab37bc05f1806b4b49a2e418ac37.zip |
Implement the server comamnd DECRYPT.
Use int instead of gnupg_fd_t in the server.
Comment fixes.
Rename encr-data.c -> decrypt-data.c
Diffstat (limited to 'g10/encr-data.c')
-rw-r--r-- | g10/encr-data.c | 446 |
1 files changed, 0 insertions, 446 deletions
diff --git a/g10/encr-data.c b/g10/encr-data.c deleted file mode 100644 index de26d0a4b..000000000 --- a/g10/encr-data.c +++ /dev/null @@ -1,446 +0,0 @@ -/* encr-data.c - process an encrypted data packet - * Copyright (C) 1998, 1999, 2000, 2001, 2005, - * 2006, 2009 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#include "gpg.h" -#include "util.h" -#include "packet.h" -#include "cipher.h" -#include "options.h" -#include "i18n.h" - - -static int mdc_decode_filter ( void *opaque, int control, IOBUF a, - byte *buf, size_t *ret_len); -static int decode_filter ( void *opaque, int control, IOBUF a, - byte *buf, size_t *ret_len); - -typedef struct decode_filter_context_s -{ - gcry_cipher_hd_t cipher_hd; - gcry_md_hd_t mdc_hash; - char defer[22]; - int defer_filled; - int eof_seen; - int refcount; - int partial; /* Working on a partial length packet. */ - size_t length; /* If !partial: Remaining bytes in the packet. */ -} *decode_filter_ctx_t; - - -/* Helper to release the decode context. */ -static void -release_dfx_context (decode_filter_ctx_t dfx) -{ - if (!dfx) - return; - - assert (dfx->refcount); - if ( !--dfx->refcount ) - { - gcry_cipher_close (dfx->cipher_hd); - dfx->cipher_hd = NULL; - gcry_md_close (dfx->mdc_hash); - dfx->mdc_hash = NULL; - xfree (dfx); - } -} - - - -/**************** - * Decrypt the data, specified by ED with the key DEK. - */ -int -decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek ) -{ - decode_filter_ctx_t dfx; - byte *p; - int rc=0, c, i; - byte temp[32]; - unsigned blocksize; - unsigned nprefix; - - dfx = xtrycalloc (1, sizeof *dfx); - if (!dfx) - return gpg_error_from_syserror (); - dfx->refcount = 1; - - if ( opt.verbose && !dek->algo_info_printed ) - { - if (!openpgp_cipher_test_algo (dek->algo)) - log_info (_("%s encrypted data\n"), - openpgp_cipher_algo_name (dek->algo)); - else - log_info (_("encrypted with unknown algorithm %d\n"), dek->algo ); - dek->algo_info_printed = 1; - } - rc = openpgp_cipher_test_algo (dek->algo); - if (rc) - goto leave; - blocksize = openpgp_cipher_get_algo_blklen (dek->algo); - if ( !blocksize || blocksize > 16 ) - log_fatal ("unsupported blocksize %u\n", blocksize ); - nprefix = blocksize; - if ( ed->len && ed->len < (nprefix+2) ) - BUG(); - - if ( ed->mdc_method ) - { - if (gcry_md_open (&dfx->mdc_hash, ed->mdc_method, 0 )) - BUG (); - if ( DBG_HASHING ) - gcry_md_start_debug (dfx->mdc_hash, "checkmdc"); - } - - rc = openpgp_cipher_open (&dfx->cipher_hd, dek->algo, - GCRY_CIPHER_MODE_CFB, - (GCRY_CIPHER_SECURE - | ((ed->mdc_method || dek->algo >= 100)? - 0 : GCRY_CIPHER_ENABLE_SYNC))); - if (rc) - { - /* We should never get an error here cause we already checked - * that the algorithm is available. */ - BUG(); - } - - - /* log_hexdump( "thekey", dek->key, dek->keylen );*/ - rc = gcry_cipher_setkey (dfx->cipher_hd, dek->key, dek->keylen); - if ( gpg_err_code (rc) == GPG_ERR_WEAK_KEY ) - { - log_info(_("WARNING: message was encrypted with" - " a weak key in the symmetric cipher.\n")); - rc=0; - } - else if( rc ) - { - log_error("key setup failed: %s\n", g10_errstr(rc) ); - goto leave; - } - - if (!ed->buf) - { - log_error(_("problem handling encrypted packet\n")); - goto leave; - } - - gcry_cipher_setiv (dfx->cipher_hd, NULL, 0); - - if ( ed->len ) - { - for (i=0; i < (nprefix+2) && ed->len; i++, ed->len-- ) - { - if ( (c=iobuf_get(ed->buf)) == -1 ) - break; - else - temp[i] = c; - } - } - else - { - for (i=0; i < (nprefix+2); i++ ) - if ( (c=iobuf_get(ed->buf)) == -1 ) - break; - else - temp[i] = c; - } - - gcry_cipher_decrypt (dfx->cipher_hd, temp, nprefix+2, NULL, 0); - gcry_cipher_sync (dfx->cipher_hd); - p = temp; - /* log_hexdump( "prefix", temp, nprefix+2 ); */ - if (dek->symmetric - && (p[nprefix-2] != p[nprefix] || p[nprefix-1] != p[nprefix+1]) ) - { - rc = gpg_error (GPG_ERR_BAD_KEY); - goto leave; - } - - if ( dfx->mdc_hash ) - gcry_md_write (dfx->mdc_hash, temp, nprefix+2); - - dfx->refcount++; - dfx->partial = ed->is_partial; - dfx->length = ed->len; - if ( ed->mdc_method ) - iobuf_push_filter ( ed->buf, mdc_decode_filter, dfx ); - else - iobuf_push_filter ( ed->buf, decode_filter, dfx ); - - proc_packets ( procctx, ed->buf ); - ed->buf = NULL; - if (dfx->eof_seen > 1 ) - rc = gpg_error (GPG_ERR_INV_PACKET); - else if ( ed->mdc_method ) - { - /* We used to let parse-packet.c handle the MDC packet but this - turned out to be a problem with compressed packets: With old - style packets there is no length information available and - the decompressor uses an implicit end. However we can't know - this implicit end beforehand (:-) and thus may feed the - decompressor with more bytes than actually needed. It would - be possible to unread the extra bytes but due to our weird - iobuf system any unread is non reliable due to filters - already popped off. The easy and sane solution is to care - about the MDC packet only here and never pass it to the - packet parser. Fortunatley the OpenPGP spec requires a - strict format for the MDC packet so that we know that 22 - bytes are appended. */ - int datalen = gcry_md_get_algo_dlen (ed->mdc_method); - - assert (dfx->cipher_hd); - assert (dfx->mdc_hash); - gcry_cipher_decrypt (dfx->cipher_hd, dfx->defer, 22, NULL, 0); - gcry_md_write (dfx->mdc_hash, dfx->defer, 2); - gcry_md_final (dfx->mdc_hash); - - if (dfx->defer[0] != '\xd3' || dfx->defer[1] != '\x14' ) - { - log_error("mdc_packet with invalid encoding\n"); - rc = gpg_error (GPG_ERR_INV_PACKET); - } - else if (datalen != 20 - || memcmp (gcry_md_read (dfx->mdc_hash, 0), - dfx->defer+2,datalen )) - rc = gpg_error (GPG_ERR_BAD_SIGNATURE); - /* log_printhex("MDC message:", dfx->defer, 22); */ - /* log_printhex("MDC calc:", gcry_md_read (dfx->mdc_hash,0), datalen); */ - } - - - leave: - release_dfx_context (dfx); - return rc; -} - - - -static int -mdc_decode_filter (void *opaque, int control, IOBUF a, - byte *buf, size_t *ret_len) -{ - decode_filter_ctx_t dfx = opaque; - size_t n, size = *ret_len; - int rc = 0; - int c; - - /* Note: We need to distinguish between a partial and a fixed length - packet. The first is the usual case as created by GPG. However - for short messages the format degrades to a fixed length packet - and other implementations might use fixed length as well. Only - looking for the EOF on fixed data works only if the encrypted - packet is not followed by other data. This used to be a long - standing bug which was fixed on 2009-10-02. */ - - if ( control == IOBUFCTRL_UNDERFLOW && dfx->eof_seen ) - { - *ret_len = 0; - rc = -1; - } - else if( control == IOBUFCTRL_UNDERFLOW ) - { - assert (a); - assert (size > 44); /* Our code requires at least this size. */ - - /* Get at least 22 bytes and put it ahead in the buffer. */ - if (dfx->partial) - { - for (n=22; n < 44; n++) - { - if ( (c = iobuf_get(a)) == -1 ) - break; - buf[n] = c; - } - } - else - { - for (n=22; n < 44 && dfx->length; n++, dfx->length--) - { - c = iobuf_get (a); - if (c == -1) - break; /* Premature EOF. */ - buf[n] = c; - } - } - if (n == 44) - { - /* We have enough stuff - flush the deferred stuff. */ - if ( !dfx->defer_filled ) /* First time. */ - { - memcpy (buf, buf+22, 22); - n = 22; - } - else - { - memcpy (buf, dfx->defer, 22); - } - /* Fill up the buffer. */ - if (dfx->partial) - { - for (; n < size; n++ ) - { - if ( (c = iobuf_get(a)) == -1 ) - { - dfx->eof_seen = 1; /* Normal EOF. */ - break; - } - buf[n] = c; - } - } - else - { - for (; n < size && dfx->length; n++, dfx->length--) - { - c = iobuf_get(a); - if (c == -1) - { - dfx->eof_seen = 3; /* Premature EOF. */ - break; - } - buf[n] = c; - } - if (!dfx->length) - dfx->eof_seen = 1; /* Normal EOF. */ - } - - /* Move the trailing 22 bytes back to the defer buffer. We - have at least 44 bytes thus a memmove is not needed. */ - n -= 22; - memcpy (dfx->defer, buf+n, 22 ); - dfx->defer_filled = 1; - } - else if ( !dfx->defer_filled ) /* EOF seen but empty defer buffer. */ - { - /* This is bad because it means an incomplete hash. */ - n -= 22; - memcpy (buf, buf+22, n ); - dfx->eof_seen = 2; /* EOF with incomplete hash. */ - } - else /* EOF seen (i.e. read less than 22 bytes). */ - { - memcpy (buf, dfx->defer, 22 ); - n -= 22; - memcpy (dfx->defer, buf+n, 22 ); - dfx->eof_seen = 1; /* Normal EOF. */ - } - - if ( n ) - { - if ( dfx->cipher_hd ) - gcry_cipher_decrypt (dfx->cipher_hd, buf, n, NULL, 0); - if ( dfx->mdc_hash ) - gcry_md_write (dfx->mdc_hash, buf, n); - } - else - { - assert ( dfx->eof_seen ); - rc = -1; /* Return EOF. */ - } - *ret_len = n; - } - else if ( control == IOBUFCTRL_FREE ) - { - release_dfx_context (dfx); - } - else if ( control == IOBUFCTRL_DESC ) - { - *(char**)buf = "mdc_decode_filter"; - } - return rc; -} - - -static int -decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) -{ - decode_filter_ctx_t fc = opaque; - size_t size = *ret_len; - size_t n; - int c, rc = 0; - - - if ( control == IOBUFCTRL_UNDERFLOW && fc->eof_seen ) - { - *ret_len = 0; - rc = -1; - } - else if ( control == IOBUFCTRL_UNDERFLOW ) - { - assert(a); - - if (fc->partial) - { - for (n=0; n < size; n++ ) - { - c = iobuf_get(a); - if (c == -1) - { - fc->eof_seen = 1; /* Normal EOF. */ - break; - } - buf[n] = c; - } - } - else - { - for (n=0; n < size && fc->length; n++, fc->length--) - { - c = iobuf_get(a); - if (c == -1) - { - fc->eof_seen = 3; /* Premature EOF. */ - break; - } - buf[n] = c; - } - if (!fc->length) - fc->eof_seen = 1; /* Normal EOF. */ - } - if (n) - { - if (fc->cipher_hd) - gcry_cipher_decrypt (fc->cipher_hd, buf, n, NULL, 0); - } - else - { - if (!fc->eof_seen) - fc->eof_seen = 1; - rc = -1; /* Return EOF. */ - } - *ret_len = n; - } - else if ( control == IOBUFCTRL_FREE ) - { - release_dfx_context (fc); - } - else if ( control == IOBUFCTRL_DESC ) - { - *(char**)buf = "decode_filter"; - } - return rc; -} - |