1997-11-18 15:06:00 +01:00
|
|
|
/* mdfilter.c - filter data and calculate a message digest
|
2002-06-29 15:46:34 +02:00
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
1997-11-18 15:06:00 +01:00
|
|
|
*
|
1998-12-23 13:41:40 +01:00
|
|
|
* This file is part of GnuPG.
|
1997-11-18 15:06:00 +01:00
|
|
|
*
|
1998-12-23 13:41:40 +01:00
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
1997-11-18 15:06:00 +01:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2007-07-04 21:49:40 +02:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
1997-11-18 15:06:00 +01:00
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
1998-12-23 13:41:40 +01:00
|
|
|
* GnuPG is distributed in the hope that it will be useful,
|
1997-11-18 15:06:00 +01:00
|
|
|
* 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
|
2016-11-05 12:02:19 +01:00
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
1997-11-18 15:06:00 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
2023-07-25 05:02:26 +02:00
|
|
|
#include <npth.h>
|
1997-11-18 15:06:00 +01:00
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
#include "gpg.h"
|
2017-03-07 12:21:23 +01:00
|
|
|
#include "../common/status.h"
|
|
|
|
#include "../common/iobuf.h"
|
|
|
|
#include "../common/util.h"
|
1997-11-18 15:06:00 +01:00
|
|
|
#include "filter.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
1998-04-14 19:51:16 +02:00
|
|
|
* This filter is used to collect a message digest
|
1997-11-18 15:06:00 +01:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
md_filter( void *opaque, int control,
|
2006-04-19 13:26:11 +02:00
|
|
|
IOBUF a, byte *buf, size_t *ret_len)
|
1997-11-18 15:06:00 +01:00
|
|
|
{
|
|
|
|
size_t size = *ret_len;
|
|
|
|
md_filter_context_t *mfx = opaque;
|
1999-05-31 19:49:37 +02:00
|
|
|
int i, rc=0;
|
1997-11-18 15:06:00 +01:00
|
|
|
|
|
|
|
if( control == IOBUFCTRL_UNDERFLOW ) {
|
1997-11-24 12:04:11 +01:00
|
|
|
if( mfx->maxbuf_size && size > mfx->maxbuf_size )
|
1997-11-18 15:06:00 +01:00
|
|
|
size = mfx->maxbuf_size;
|
1999-05-31 19:49:37 +02:00
|
|
|
i = iobuf_read( a, buf, size );
|
|
|
|
if( i == -1 ) i = 0;
|
1999-05-19 16:12:26 +02:00
|
|
|
if( i ) {
|
2003-06-18 21:56:13 +02:00
|
|
|
gcry_md_write(mfx->md, buf, i );
|
1999-05-19 16:12:26 +02:00
|
|
|
if( mfx->md2 )
|
2003-06-18 21:56:13 +02:00
|
|
|
gcry_md_write(mfx->md2, buf, i );
|
1999-05-19 16:12:26 +02:00
|
|
|
}
|
1997-11-18 15:06:00 +01:00
|
|
|
else
|
|
|
|
rc = -1; /* eof */
|
|
|
|
*ret_len = i;
|
|
|
|
}
|
|
|
|
else if( control == IOBUFCTRL_DESC )
|
common: Fix iobuf API of filter function for alignment.
* common/iobuf.h (IOBUFCTRL_DESC): Change the call semantics.
* common/iobuf.c (iobuf_desc): Add the second argument DESC.
(print_chain, iobuf_close, do_open, iobuf_sockopen, iobuf_ioctl)
(iobuf_push_filter2, pop_filter, iobuf_write_temp): Change calls
of iobuf_desc.
(file_filter, file_es_filter, sock_filter, block_filter): Fill the
description.
* common/t-iobuf.c (every_other_filter, double_filter): Likewise.
* g10/armor.c, g10/cipher.c, g10/compress-bz2.c, g10/compress.c,
g10/decrypt-data.c, g10/encrypt.c, g10/mdfilter.c, g10/progress.c,
g10/textfilter.c: Likewise.
--
Newer GCC warns against possible alignment difference of pointers.
This change can silence those warnings.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2016-01-12 02:32:20 +01:00
|
|
|
mem2str (buf, "md_filter", *ret_len);
|
1997-11-18 15:06:00 +01:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
1997-11-24 12:04:11 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
free_md_filter_context( md_filter_context_t *mfx )
|
|
|
|
{
|
2006-04-19 13:26:11 +02:00
|
|
|
gcry_md_close(mfx->md);
|
|
|
|
gcry_md_close(mfx->md2);
|
1998-01-12 11:18:17 +01:00
|
|
|
mfx->md = NULL;
|
1999-05-19 16:12:26 +02:00
|
|
|
mfx->md2 = NULL;
|
1997-11-24 12:04:11 +01:00
|
|
|
mfx->maxbuf_size = 0;
|
|
|
|
}
|
2023-07-25 05:02:26 +02:00
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* Threaded implementation for hashing.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct md_thd_filter_context {
|
|
|
|
gcry_md_hd_t md;
|
|
|
|
npth_t thd;
|
|
|
|
/**/
|
|
|
|
npth_mutex_t mutex;
|
|
|
|
npth_cond_t cond;
|
|
|
|
size_t bufsize;
|
|
|
|
unsigned int produce : 1;
|
|
|
|
unsigned int consume : 1;
|
|
|
|
ssize_t written0;
|
|
|
|
ssize_t written1;
|
|
|
|
unsigned char buf[1];
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
lock_md (struct md_thd_filter_context *mfx)
|
|
|
|
{
|
|
|
|
int rc = npth_mutex_lock (&mfx->mutex);
|
|
|
|
if (rc)
|
|
|
|
log_fatal ("%s: failed to acquire mutex: %s\n", __func__,
|
|
|
|
gpg_strerror (gpg_error_from_errno (rc)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
unlock_md (struct md_thd_filter_context * mfx)
|
|
|
|
{
|
|
|
|
int rc = npth_mutex_unlock (&mfx->mutex);
|
|
|
|
if (rc)
|
|
|
|
log_fatal ("%s: failed to release mutex: %s\n", __func__,
|
|
|
|
gpg_strerror (gpg_error_from_errno (rc)));
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_buffer_to_hash (struct md_thd_filter_context *mfx,
|
|
|
|
unsigned char **r_buf, size_t *r_len)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
lock_md (mfx);
|
|
|
|
|
|
|
|
if ((mfx->consume == 0 && mfx->written0 < 0)
|
|
|
|
|| (mfx->consume != 0 && mfx->written1 < 0))
|
|
|
|
{
|
|
|
|
rc = npth_cond_wait (&mfx->cond, &mfx->mutex);
|
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
unlock_md (mfx);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mfx->consume == 0)
|
|
|
|
{
|
|
|
|
*r_buf = mfx->buf;
|
|
|
|
*r_len = mfx->written0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*r_buf = mfx->buf + mfx->bufsize;
|
|
|
|
*r_len = mfx->written1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock_md (mfx);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
put_buffer_to_recv (struct md_thd_filter_context *mfx)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
lock_md (mfx);
|
|
|
|
if (mfx->consume == 0)
|
|
|
|
{
|
|
|
|
mfx->written0 = -1;
|
|
|
|
mfx->consume = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mfx->written1 = -1;
|
|
|
|
mfx->consume = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = npth_cond_signal (&mfx->cond);
|
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
unlock_md (mfx);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock_md (mfx);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_buffer_to_fill (struct md_thd_filter_context *mfx,
|
|
|
|
unsigned char **r_buf, size_t len)
|
|
|
|
{
|
|
|
|
lock_md (mfx);
|
|
|
|
|
|
|
|
if (len > mfx->bufsize)
|
|
|
|
{
|
|
|
|
unlock_md (mfx);
|
|
|
|
return GPG_ERR_BUFFER_TOO_SHORT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mfx->produce == 0 && mfx->written0 >= 0)
|
|
|
|
|| (mfx->produce != 0 && mfx->written1 >= 0))
|
|
|
|
{
|
|
|
|
int rc = npth_cond_wait (&mfx->cond, &mfx->mutex);
|
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
unlock_md (mfx);
|
|
|
|
return gpg_error_from_errno (rc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mfx->produce == 0)
|
|
|
|
*r_buf = mfx->buf;
|
|
|
|
else
|
|
|
|
*r_buf = mfx->buf + mfx->bufsize;
|
|
|
|
unlock_md (mfx);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
put_buffer_to_send (struct md_thd_filter_context *mfx, size_t len)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
lock_md (mfx);
|
|
|
|
if (mfx->produce == 0)
|
|
|
|
{
|
|
|
|
mfx->written0 = len;
|
|
|
|
mfx->produce = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mfx->written1 = len;
|
|
|
|
mfx->produce = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = npth_cond_signal (&mfx->cond);
|
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
unlock_md (mfx);
|
|
|
|
return gpg_error_from_errno (rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
unlock_md (mfx);
|
|
|
|
|
|
|
|
/* Yield to the md_thread to let it compute the hash in parallel */
|
|
|
|
npth_usleep (0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void *
|
|
|
|
md_thread (void *arg)
|
|
|
|
{
|
|
|
|
struct md_thd_filter_context *mfx = arg;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
unsigned char *buf;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
if (get_buffer_to_hash (mfx, &buf, &len) < 0)
|
|
|
|
/* Error */
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
npth_unprotect ();
|
|
|
|
gcry_md_write (mfx->md, buf, len);
|
|
|
|
npth_protect ();
|
|
|
|
|
|
|
|
if (put_buffer_to_recv (mfx) < 0)
|
|
|
|
/* Error */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
md_thd_filter (void *opaque, int control,
|
|
|
|
IOBUF a, byte *buf, size_t *ret_len)
|
|
|
|
{
|
|
|
|
size_t size = *ret_len;
|
|
|
|
struct md_thd_filter_context **r_mfx = opaque;
|
|
|
|
struct md_thd_filter_context *mfx = *r_mfx;
|
|
|
|
int rc=0;
|
|
|
|
|
|
|
|
if (control == IOBUFCTRL_INIT)
|
|
|
|
{
|
|
|
|
npth_attr_t tattr;
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
n = 2 * iobuf_set_buffer_size (0) * 1024;
|
|
|
|
mfx = xtrymalloc (n + offsetof (struct md_thd_filter_context, buf));
|
|
|
|
if (!mfx)
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
*r_mfx = mfx;
|
|
|
|
mfx->bufsize = n / 2;
|
|
|
|
mfx->consume = mfx->produce = 0;
|
|
|
|
mfx->written0 = -1;
|
|
|
|
mfx->written1 = -1;
|
|
|
|
|
|
|
|
rc = npth_mutex_init (&mfx->mutex, NULL);
|
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
return gpg_error_from_errno (rc);
|
|
|
|
}
|
|
|
|
rc = npth_cond_init (&mfx->cond, NULL);
|
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
npth_mutex_destroy (&mfx->mutex);
|
|
|
|
return gpg_error_from_errno (rc);
|
|
|
|
}
|
|
|
|
rc = npth_attr_init (&tattr);
|
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
npth_cond_destroy (&mfx->cond);
|
|
|
|
npth_mutex_destroy (&mfx->mutex);
|
|
|
|
return gpg_error_from_errno (rc);
|
|
|
|
}
|
|
|
|
npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
|
|
|
|
rc = npth_create (&mfx->thd, &tattr, md_thread, mfx);
|
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
npth_cond_destroy (&mfx->cond);
|
|
|
|
npth_mutex_destroy (&mfx->mutex);
|
|
|
|
npth_attr_destroy (&tattr);
|
|
|
|
return gpg_error_from_errno (rc);
|
|
|
|
}
|
|
|
|
npth_attr_destroy (&tattr);
|
|
|
|
}
|
|
|
|
else if (control == IOBUFCTRL_UNDERFLOW)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned char *md_buf = NULL;
|
|
|
|
|
|
|
|
i = iobuf_read (a, buf, size);
|
|
|
|
if (i == -1)
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
rc = get_buffer_to_fill (mfx, &md_buf, i);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (i)
|
|
|
|
memcpy (md_buf, buf, i);
|
|
|
|
|
|
|
|
rc = put_buffer_to_send (mfx, i);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
npth_join (mfx->thd, NULL);
|
|
|
|
rc = -1; /* eof */
|
|
|
|
}
|
|
|
|
|
|
|
|
*ret_len = i;
|
|
|
|
}
|
|
|
|
else if (control == IOBUFCTRL_FREE)
|
|
|
|
{
|
|
|
|
npth_cond_destroy (&mfx->cond);
|
|
|
|
npth_mutex_destroy (&mfx->mutex);
|
|
|
|
xfree (mfx);
|
|
|
|
*r_mfx = NULL;
|
|
|
|
}
|
|
|
|
else if (control == IOBUFCTRL_DESC)
|
|
|
|
mem2str (buf, "md_thd_filter", *ret_len);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
md_thd_filter_set_md (struct md_thd_filter_context *mfx, gcry_md_hd_t md)
|
|
|
|
{
|
|
|
|
mfx->md = md;
|
|
|
|
}
|