1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00

This commit was manufactured by cvs2svn to create branch

'GNUPG-1-9-BRANCH'.
This commit is contained in:
Repo Admin 2003-06-05 07:14:21 +00:00
parent a3d4ac6f3e
commit 7250331472
77 changed files with 58548 additions and 0 deletions

8238
g10/ChangeLog Normal file

File diff suppressed because it is too large Load diff

123
g10/Makefile.am Normal file
View file

@ -0,0 +1,123 @@
# Copyright (C) 1998, 1999, 2000, 2001, 2002,
# 2003 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 2 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
## Process this file with automake to produce Makefile.in
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
EXTRA_DIST = options.skel
# it seems that we can't use this with automake 1.5
#OMIT_DEPENDENCIES = zlib.h zconf.h
libexecdir = @libexecdir@/@PACKAGE@
if ! HAVE_DOSISH_SYSTEM
AM_CFLAGS = -DGNUPG_LIBEXECDIR="\"$(libexecdir)\""
endif
needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a
#noinst_PROGRAMS = gpgd
bin_PROGRAMS = gpg gpgv
common_source = \
global.h \
build-packet.c \
compress.c \
filter.h \
free-packet.c \
getkey.c \
keydb.c keydb.h \
keyring.c keyring.h \
seskey.c \
kbnode.c \
main.h \
mainproc.c \
armor.c \
mdfilter.c \
textfilter.c \
progress.c \
misc.c \
options.h \
openfile.c \
keyid.c \
packet.h \
parse-packet.c \
comment.c \
status.c \
status.h \
plaintext.c \
sig-check.c \
keylist.c \
signal.c
gpg_SOURCES = g10.c \
$(common_source) \
pkclist.c \
skclist.c \
pubkey-enc.c \
passphrase.c \
seckey-cert.c \
encr-data.c \
cipher.c \
encode.c \
sign.c \
verify.c \
revoke.c \
decrypt.c \
keyedit.c \
dearmor.c \
import.c \
export.c \
trustdb.c \
trustdb.h \
tdbdump.c \
tdbio.c \
tdbio.h \
delkey.c \
keygen.c \
pipemode.c \
helptext.c \
keyserver.c \
keyserver-internal.h \
photoid.c photoid.h \
exec.c exec.h
gpgv_SOURCES = gpgv.c \
$(common_source) \
verify.c
#gpgd_SOURCES = gpgd.c \
# ks-proto.h \
# ks-proto.c \
# ks-db.c \
# ks-db.h \
# $(common_source)
LDADD = $(needed_libs) @INTLLIBS@ @CAPLIBS@ @ZLIBS@
# gpg gets LIBOBJS to add in mkdtemp if the platform doesn't have it
gpg_LDADD = @LIBOBJS@ $(LDADD) @DLLIBS@ @EGDLIBS@
$(PROGRAMS): $(needed_libs)
install-data-local:
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
$(INSTALL_DATA) $(srcdir)/options.skel \
$(DESTDIR)$(pkgdatadir)/options.skel
@set -e;\
if test -f $(DESTDIR)$(bindir)/gpgm ; then \
echo "removing obsolete gpgm binary" ; \
rm $(DESTDIR)$(bindir)/gpgm ; \
fi

1336
g10/armor.c Normal file

File diff suppressed because it is too large Load diff

1196
g10/build-packet.c Normal file

File diff suppressed because it is too large Load diff

152
g10/cipher.c Normal file
View file

@ -0,0 +1,152 @@
/* cipher.c - En-/De-ciphering filter
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "errors.h"
#include "iobuf.h"
#include "memory.h"
#include "util.h"
#include "filter.h"
#include "packet.h"
#include "options.h"
#include "main.h"
#include "status.h"
#define MIN_PARTIAL_SIZE 512
static void
write_header( cipher_filter_context_t *cfx, IOBUF a )
{
PACKET pkt;
PKT_encrypted ed;
byte temp[18];
unsigned blocksize;
unsigned nprefix;
blocksize = cipher_get_blocksize( cfx->dek->algo );
if( blocksize < 8 || blocksize > 16 )
log_fatal("unsupported blocksize %u\n", blocksize );
memset( &ed, 0, sizeof ed );
ed.len = cfx->datalen;
ed.extralen = blocksize+2;
ed.new_ctb = !ed.len && !RFC1991;
if( cfx->dek->use_mdc ) {
ed.mdc_method = DIGEST_ALGO_SHA1;
cfx->mdc_hash = md_open( DIGEST_ALGO_SHA1, 0 );
if ( DBG_HASHING )
md_start_debug( cfx->mdc_hash, "creatmdc" );
}
{
char buf[20];
sprintf (buf, "%d %d", ed.mdc_method, cfx->dek->algo);
write_status_text (STATUS_BEGIN_ENCRYPTION, buf);
}
init_packet( &pkt );
pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED;
pkt.pkt.encrypted = &ed;
if( build_packet( a, &pkt ))
log_bug("build_packet(ENCR_DATA) failed\n");
nprefix = blocksize;
randomize_buffer( temp, nprefix, 1 );
temp[nprefix] = temp[nprefix-2];
temp[nprefix+1] = temp[nprefix-1];
print_cipher_algo_note( cfx->dek->algo );
cfx->cipher_hd = cipher_open( cfx->dek->algo,
cfx->dek->use_mdc? CIPHER_MODE_CFB
: CIPHER_MODE_AUTO_CFB, 1 );
/* log_hexdump( "thekey", cfx->dek->key, cfx->dek->keylen );*/
cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
cipher_setiv( cfx->cipher_hd, NULL, 0 );
/* log_hexdump( "prefix", temp, nprefix+2 ); */
if( cfx->mdc_hash ) /* hash the "IV" */
md_write( cfx->mdc_hash, temp, nprefix+2 );
cipher_encrypt( cfx->cipher_hd, temp, temp, nprefix+2);
cipher_sync( cfx->cipher_hd );
iobuf_write(a, temp, nprefix+2);
cfx->header=1;
}
/****************
* This filter is used to en/de-cipher data with a conventional algorithm
*/
int
cipher_filter( void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len)
{
size_t size = *ret_len;
cipher_filter_context_t *cfx = opaque;
int rc=0;
if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */
rc = -1; /* not yet used */
}
else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
assert(a);
if( !cfx->header ) {
write_header( cfx, a );
}
if( cfx->mdc_hash )
md_write( cfx->mdc_hash, buf, size );
cipher_encrypt( cfx->cipher_hd, buf, buf, size);
if( iobuf_write( a, buf, size ) )
rc = G10ERR_WRITE_FILE;
}
else if( control == IOBUFCTRL_FREE ) {
if( cfx->mdc_hash ) {
byte *hash;
int hashlen = md_digest_length( md_get_algo( cfx->mdc_hash ) );
byte temp[22];
assert( hashlen == 20 );
/* we must hash the prefix of the MDC packet here */
temp[0] = 0xd3;
temp[1] = 0x14;
md_putc( cfx->mdc_hash, temp[0] );
md_putc( cfx->mdc_hash, temp[1] );
md_final( cfx->mdc_hash );
hash = md_read( cfx->mdc_hash, 0 );
memcpy(temp+2, hash, 20);
cipher_encrypt( cfx->cipher_hd, temp, temp, 22 );
md_close( cfx->mdc_hash ); cfx->mdc_hash = NULL;
if( iobuf_write( a, temp, 22 ) )
log_error("writing MDC packet failed\n" );
}
cipher_close(cfx->cipher_hd);
}
else if( control == IOBUFCTRL_DESC ) {
*(char**)buf = "cipher_filter";
}
return rc;
}

324
g10/compress.c Normal file
View file

@ -0,0 +1,324 @@
/* compress.c - compress filter
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <zlib.h>
#ifdef __riscos__
# include "zlib-riscos.h"
#endif
#include "util.h"
#include "memory.h"
#include "packet.h"
#include "filter.h"
#include "main.h"
#include "options.h"
static void
init_compress( compress_filter_context_t *zfx, z_stream *zs )
{
int rc;
int level;
#ifdef __riscos__
static int zlib_initialized = 0;
if (!zlib_initialized)
zlib_initialized = riscos_load_module("ZLib", zlib_path, 1);
#endif
if( opt.compress >= 0 && opt.compress <= 9 )
level = opt.compress;
else if( opt.compress == -1 )
level = Z_DEFAULT_COMPRESSION;
else if( opt.compress == 10 ) /* remove this ! */
level = 0;
else {
log_error("invalid compression level; using default level\n");
level = Z_DEFAULT_COMPRESSION;
}
if( (rc = zfx->algo == 1? deflateInit2( zs, level, Z_DEFLATED,
-13, 8, Z_DEFAULT_STRATEGY)
: deflateInit( zs, level )
) != Z_OK ) {
log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
rc == Z_MEM_ERROR ? "out of core" :
rc == Z_VERSION_ERROR ? "invalid lib version" :
"unknown error" );
}
zfx->outbufsize = 8192;
zfx->outbuf = m_alloc( zfx->outbufsize );
}
static int
do_compress( compress_filter_context_t *zfx, z_stream *zs, int flush, IOBUF a )
{
int zrc;
unsigned n;
do {
#ifndef __riscos__
zs->next_out = zfx->outbuf;
#else /* __riscos__ */
zs->next_out = (Bytef *) zfx->outbuf;
#endif /* __riscos__ */
zs->avail_out = zfx->outbufsize;
if( DBG_FILTER )
log_debug("enter deflate: avail_in=%u, avail_out=%u, flush=%d\n",
(unsigned)zs->avail_in, (unsigned)zs->avail_out, flush );
zrc = deflate( zs, flush );
if( zrc == Z_STREAM_END && flush == Z_FINISH )
;
else if( zrc != Z_OK ) {
if( zs->msg )
log_fatal("zlib deflate problem: %s\n", zs->msg );
else
log_fatal("zlib deflate problem: rc=%d\n", zrc );
}
n = zfx->outbufsize - zs->avail_out;
if( DBG_FILTER )
log_debug("leave deflate: "
"avail_in=%u, avail_out=%u, n=%u, zrc=%d\n",
(unsigned)zs->avail_in, (unsigned)zs->avail_out,
(unsigned)n, zrc );
if( iobuf_write( a, zfx->outbuf, n ) ) {
log_debug("deflate: iobuf_write failed\n");
return G10ERR_WRITE_FILE;
}
} while( zs->avail_in || (flush == Z_FINISH && zrc != Z_STREAM_END) );
return 0;
}
static void
init_uncompress( compress_filter_context_t *zfx, z_stream *zs )
{
int rc;
/****************
* PGP uses a windowsize of 13 bits. Using a negative value for
* it forces zlib not to expect a zlib header. This is a
* undocumented feature Peter Gutmann told me about.
*
* We must use 15 bits for the inflator because CryptoEx uses 15
* bits thus the output would get scrambled w/o error indication
* if we would use 13 bits. For the uncompressing this does not
* matter at all.
*/
if( (rc = zfx->algo == 1? inflateInit2( zs, -15)
: inflateInit( zs )) != Z_OK ) {
log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
rc == Z_MEM_ERROR ? "out of core" :
rc == Z_VERSION_ERROR ? "invalid lib version" :
"unknown error" );
}
zfx->inbufsize = 2048;
zfx->inbuf = m_alloc( zfx->inbufsize );
zs->avail_in = 0;
}
static int
do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
IOBUF a, size_t *ret_len )
{
int zrc;
int rc=0;
size_t n;
int nread, count;
int refill = !zs->avail_in;
if( DBG_FILTER )
log_debug("begin inflate: avail_in=%u, avail_out=%u, inbuf=%u\n",
(unsigned)zs->avail_in, (unsigned)zs->avail_out,
(unsigned)zfx->inbufsize );
do {
if( zs->avail_in < zfx->inbufsize && refill ) {
n = zs->avail_in;
if( !n )
#ifndef __riscos__
zs->next_in = zfx->inbuf;
#else /* __riscos__ */
zs->next_in = (Bytef *) zfx->inbuf;
#endif /* __riscos__ */
count = zfx->inbufsize - n;
nread = iobuf_read( a, zfx->inbuf + n, count );
if( nread == -1 ) nread = 0;
n += nread;
/* If we use the undocumented feature to suppress
* the zlib header, we have to give inflate an
* extra dummy byte to read */
if( nread < count && zfx->algo == 1 ) {
*(zfx->inbuf + n) = 0xFF; /* is it really needed ? */
zfx->algo1hack = 1;
n++;
}
zs->avail_in = n;
}
refill = 1;
if( DBG_FILTER )
log_debug("enter inflate: avail_in=%u, avail_out=%u\n",
(unsigned)zs->avail_in, (unsigned)zs->avail_out);
#ifdef Z_SYNC_FLUSH
zrc = inflate( zs, Z_SYNC_FLUSH );
#else
zrc = inflate( zs, Z_PARTIAL_FLUSH );
#endif
if( DBG_FILTER )
log_debug("leave inflate: avail_in=%u, avail_out=%u, zrc=%d\n",
(unsigned)zs->avail_in, (unsigned)zs->avail_out, zrc);
if( zrc == Z_STREAM_END )
rc = -1; /* eof */
else if( zrc != Z_OK && zrc != Z_BUF_ERROR ) {
if( zs->msg )
log_fatal("zlib inflate problem: %s\n", zs->msg );
else
log_fatal("zlib inflate problem: rc=%d\n", zrc );
}
} while( zs->avail_out && zrc != Z_STREAM_END && zrc != Z_BUF_ERROR );
*ret_len = zfx->outbufsize - zs->avail_out;
if( DBG_FILTER )
log_debug("do_uncompress: returning %u bytes\n", (unsigned)*ret_len );
return rc;
}
int
compress_filter( void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len)
{
size_t size = *ret_len;
compress_filter_context_t *zfx = opaque;
z_stream *zs = zfx->opaque;
int rc=0;
if( control == IOBUFCTRL_UNDERFLOW ) {
if( !zfx->status ) {
zs = zfx->opaque = m_alloc_clear( sizeof *zs );
init_uncompress( zfx, zs );
zfx->status = 1;
}
#ifndef __riscos__
zs->next_out = buf;
#else /* __riscos__ */
zs->next_out = (Bytef *) buf;
#endif /* __riscos__ */
zs->avail_out = size;
zfx->outbufsize = size; /* needed only for calculation */
rc = do_uncompress( zfx, zs, a, ret_len );
}
else if( control == IOBUFCTRL_FLUSH ) {
if( !zfx->status ) {
PACKET pkt;
PKT_compressed cd;
if( !zfx->algo )
zfx->algo = DEFAULT_COMPRESS_ALGO;
if( zfx->algo != 1 && zfx->algo != 2 )
BUG();
memset( &cd, 0, sizeof cd );
cd.len = 0;
cd.algorithm = zfx->algo;
init_packet( &pkt );
pkt.pkttype = PKT_COMPRESSED;
pkt.pkt.compressed = &cd;
if( build_packet( a, &pkt ))
log_bug("build_packet(PKT_COMPRESSED) failed\n");
zs = zfx->opaque = m_alloc_clear( sizeof *zs );
init_compress( zfx, zs );
zfx->status = 2;
}
#ifndef __riscos__
zs->next_in = buf;
#else /* __riscos__ */
zs->next_in = (Bytef *) buf;
#endif /* __riscos__ */
zs->avail_in = size;
rc = do_compress( zfx, zs, Z_NO_FLUSH, a );
}
else if( control == IOBUFCTRL_FREE ) {
if( zfx->status == 1 ) {
inflateEnd(zs);
m_free(zs);
zfx->opaque = NULL;
m_free(zfx->outbuf); zfx->outbuf = NULL;
}
else if( zfx->status == 2 ) {
#ifndef __riscos__
zs->next_in = buf;
#else /* __riscos__ */
zs->next_in = (Bytef *) buf;
#endif /* __riscos__ */
zs->avail_in = 0;
do_compress( zfx, zs, Z_FINISH, a );
deflateEnd(zs);
m_free(zs);
zfx->opaque = NULL;
m_free(zfx->outbuf); zfx->outbuf = NULL;
}
if (zfx->release)
zfx->release (zfx);
}
else if( control == IOBUFCTRL_DESC )
*(char**)buf = "compress_filter";
return rc;
}
static void
release_context (compress_filter_context_t *ctx)
{
m_free (ctx);
}
/****************
* Handle a compressed packet
*/
int
handle_compressed( void *procctx, PKT_compressed *cd,
int (*callback)(IOBUF, void *), void *passthru )
{
compress_filter_context_t *cfx;
int rc;
if( cd->algorithm < 1 || cd->algorithm > 2 )
return G10ERR_COMPR_ALGO;
cfx = m_alloc_clear (sizeof *cfx);
cfx->algo = cd->algorithm;
cfx->release = release_context;
iobuf_push_filter( cd->buf, compress_filter, cfx );
if( callback )
rc = callback(cd->buf, passthru );
else
rc = proc_packets(procctx, cd->buf);
cd->buf = NULL;
return rc;
}

141
g10/decrypt.c Normal file
View file

@ -0,0 +1,141 @@
/* decrypt.c - verify signed data
* Copyright (C) 1998,1999,2000,2001,2002,2003 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
#include "memory.h"
#include "util.h"
#include "main.h"
#include "status.h"
#include "i18n.h"
/****************
* Assume that the input is an encrypted message and decrypt
* (and if signed, verify the signature on) it.
* This command differs from the default operation, as it never
* writes to the filename which is included in the file and it
* rejects files which don't begin with an encrypted message.
*/
int
decrypt_message( const char *filename )
{
IOBUF fp;
armor_filter_context_t afx;
progress_filter_context_t pfx;
int rc;
int no_out=0;
/* open the message file */
fp = iobuf_open(filename);
if( !fp ) {
log_error(_("can't open `%s'\n"), print_fname_stdin(filename));
return G10ERR_OPEN_FILE;
}
handle_progress (&pfx, fp, filename);
if( !opt.no_armor ) {
if( use_armor_filter( fp ) ) {
memset( &afx, 0, sizeof afx);
iobuf_push_filter( fp, armor_filter, &afx );
}
}
if( !opt.outfile ) {
no_out = 1;
opt.outfile = "-";
}
rc = proc_encryption_packets( NULL, fp );
if( no_out )
opt.outfile = NULL;
iobuf_close(fp);
return rc;
}
void
decrypt_messages(int nfiles, char **files)
{
IOBUF fp;
armor_filter_context_t afx;
progress_filter_context_t pfx;
char *p, *output = NULL;
int rc = 0;
if (opt.outfile)
{
log_error(_("--output doesn't work for this command\n"));
return;
}
while (nfiles--)
{
print_file_status(STATUS_FILE_START, *files, 3);
output = make_outfile_name(*files);
if (!output)
goto next_file;
fp = iobuf_open(*files);
if (!fp)
{
log_error(_("can't open `%s'\n"), print_fname_stdin(*files));
goto next_file;
}
handle_progress (&pfx, fp, *files);
if (!opt.no_armor)
{
if (use_armor_filter(fp))
{
memset(&afx, 0, sizeof afx);
iobuf_push_filter(fp, armor_filter, &afx);
}
}
rc = proc_packets(NULL, fp);
iobuf_close(fp);
if (rc)
log_error("%s: decryption failed: %s\n", print_fname_stdin(*files),
g10_errstr(rc));
p = get_last_passphrase();
set_next_passphrase(p);
m_free (p);
next_file:
/* Note that we emit file_done even after an error. */
write_status( STATUS_FILE_DONE );
m_free(output);
files++;
}
set_next_passphrase(NULL);
}

811
g10/encode.c Normal file
View file

@ -0,0 +1,811 @@
/* encode.c - encode data
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
* 2003 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
#include "memory.h"
#include "util.h"
#include "main.h"
#include "filter.h"
#include "trustdb.h"
#include "i18n.h"
#include "status.h"
static int encode_simple( const char *filename, int mode, int compat );
static int write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out );
/****************
* Encode FILENAME with only the symmetric cipher. Take input from
* stdin if FILENAME is NULL.
*/
int
encode_symmetric( const char *filename )
{
int compat = 1;
#if 0
/* We don't want to use it because older gnupg version can't
handle it and we can presume that a lot of scripts are running
with the expert mode set. Some time in the future we might
want to allow for it. */
if ( opt.expert )
compat = 0; /* PGP knows how to handle this mode. */
#endif
return encode_simple( filename, 1, compat );
}
/****************
* Encode FILENAME as a literal data packet only. Take input from
* stdin if FILENAME is NULL.
*/
int
encode_store( const char *filename )
{
return encode_simple( filename, 0, 1 );
}
static void
encode_sesskey( DEK *dek, DEK **ret_dek, byte *enckey )
{
CIPHER_HANDLE hd;
DEK *c;
byte buf[33];
assert ( dek->keylen < 32 );
c = m_alloc_clear( sizeof *c );
c->keylen = dek->keylen;
c->algo = dek->algo;
make_session_key( c );
/*log_hexdump( "thekey", c->key, c->keylen );*/
buf[0] = c->algo;
memcpy( buf + 1, c->key, c->keylen );
hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 );
cipher_setkey( hd, dek->key, dek->keylen );
cipher_setiv( hd, NULL, 0 );
cipher_encrypt( hd, buf, buf, c->keylen + 1 );
cipher_close( hd );
memcpy( enckey, buf, c->keylen + 1 );
wipememory( buf, sizeof buf ); /* burn key */
*ret_dek = c;
}
/* We try very hard to use a MDC */
static int
use_mdc(PK_LIST pk_list,int algo)
{
/* --force-mdc overrides --disable-mdc */
if(opt.force_mdc)
return 1;
if(opt.disable_mdc)
return 0;
/* Do the keys really support MDC? */
if(select_mdc_from_pklist(pk_list))
return 1;
/* The keys don't support MDC, so now we do a bit of a hack - if any
of the AESes or TWOFISH are in the prefs, we assume that the user
can handle a MDC. This is valid for PGP 7, which can handle MDCs
though it will not generate them. 2440bis allows this, by the
way. */
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
CIPHER_ALGO_AES,NULL)==CIPHER_ALGO_AES)
return 1;
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
CIPHER_ALGO_AES192,NULL)==CIPHER_ALGO_AES192)
return 1;
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
CIPHER_ALGO_AES256,NULL)==CIPHER_ALGO_AES256)
return 1;
if(select_algo_from_prefs(pk_list,PREFTYPE_SYM,
CIPHER_ALGO_TWOFISH,NULL)==CIPHER_ALGO_TWOFISH)
return 1;
/* Last try. Use MDC for the modern ciphers. */
if(cipher_get_blocksize(algo)!=8)
return 1;
return 0; /* No MDC */
}
static int
encode_simple( const char *filename, int mode, int compat )
{
IOBUF inp, out;
PACKET pkt;
DEK *dek = NULL;
PKT_plaintext *pt = NULL;
STRING2KEY *s2k = NULL;
byte enckey[33];
int rc = 0;
int seskeylen = 0;
u32 filesize;
cipher_filter_context_t cfx;
armor_filter_context_t afx;
compress_filter_context_t zfx;
text_filter_context_t tfx;
progress_filter_context_t pfx;
int do_compress = opt.compress && !RFC1991;
memset( &cfx, 0, sizeof cfx);
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
memset( &tfx, 0, sizeof tfx);
init_packet(&pkt);
/* prepare iobufs */
if( !(inp = iobuf_open(filename)) ) {
log_error(_("%s: can't open: %s\n"), filename? filename: "[stdin]",
strerror(errno) );
return G10ERR_OPEN_FILE;
}
handle_progress (&pfx, inp, filename);
if( opt.textmode )
iobuf_push_filter( inp, text_filter, &tfx );
/* Due the the fact that we use don't use an IV to encrypt the
session key we can't use the new mode with RFC1991 because
it has no S2K salt. RFC1991 always uses simple S2K. */
if ( RFC1991 && !compat )
compat = 1;
cfx.dek = NULL;
if( mode ) {
s2k = m_alloc_clear( sizeof *s2k );
s2k->mode = RFC1991? 0:opt.s2k_mode;
s2k->hash_algo = opt.s2k_digest_algo;
cfx.dek = passphrase_to_dek( NULL, 0,
default_cipher_algo(), s2k, 2,
NULL, NULL);
if( !cfx.dek || !cfx.dek->keylen ) {
rc = G10ERR_PASSPHRASE;
m_free(cfx.dek);
m_free(s2k);
iobuf_close(inp);
log_error(_("error creating passphrase: %s\n"), g10_errstr(rc) );
return rc;
}
if (!compat && s2k->mode != 1 && s2k->mode != 3) {
compat = 1;
log_info (_("can't use a symmetric ESK packet "
"due to the S2K mode\n"));
}
if ( !compat ) {
seskeylen = cipher_get_keylen( default_cipher_algo() ) / 8;
encode_sesskey( cfx.dek, &dek, enckey );
m_free( cfx.dek ); cfx.dek = dek;
}
cfx.dek->use_mdc=use_mdc(NULL,cfx.dek->algo);
}
if (opt.compress == -1 && cfx.dek && cfx.dek->use_mdc &&
is_file_compressed(filename, &rc))
{
if (opt.verbose)
log_info(_("`%s' already compressed\n"), filename);
do_compress = 0;
}
if( rc || (rc = open_outfile( filename, opt.armor? 1:0, &out )) ) {
iobuf_cancel(inp);
m_free(cfx.dek);
m_free(s2k);
return rc;
}
if( opt.armor )
iobuf_push_filter( out, armor_filter, &afx );
#ifdef ENABLE_COMMENT_PACKETS
else {
write_comment( out, "#created by GNUPG v" VERSION " ("
PRINTABLE_OS_NAME ")");
if( opt.comment_string )
write_comment( out, opt.comment_string );
}
#endif
if( s2k && !RFC1991 ) {
PKT_symkey_enc *enc = m_alloc_clear( sizeof *enc + seskeylen + 1 );
enc->version = 4;
enc->cipher_algo = cfx.dek->algo;
enc->s2k = *s2k;
if ( !compat && seskeylen ) {
enc->seskeylen = seskeylen + 1; /* algo id */
memcpy( enc->seskey, enckey, seskeylen + 1 );
}
pkt.pkttype = PKT_SYMKEY_ENC;
pkt.pkt.symkey_enc = enc;
if( (rc = build_packet( out, &pkt )) )
log_error("build symkey packet failed: %s\n", g10_errstr(rc) );
m_free(enc);
}
if (!opt.no_literal) {
/* setup the inner packet */
if( filename || opt.set_filename ) {
char *s = make_basename( opt.set_filename ? opt.set_filename
: filename,
iobuf_get_real_fname( inp ) );
pt = m_alloc( sizeof *pt + strlen(s) - 1 );
pt->namelen = strlen(s);
memcpy(pt->name, s, pt->namelen );
m_free(s);
}
else { /* no filename */
pt = m_alloc( sizeof *pt - 1 );
pt->namelen = 0;
}
}
/* Note that PGP 5 has problems decrypting symmetrically encrypted
data if the file length is in the inner packet. It works when
only partial length headers are use. In the past, we always
used partial body length here, but since PGP 2, PGP 6, and PGP
7 need the file length, and nobody should be using PGP 5
nowadays anyway, this is now set to the file length. Note also
that this only applies to the RFC-1991 style symmetric
messages, and not the RFC-2440 style. PGP 6 and 7 work with
either partial length or fixed length with the new style
messages. */
if (filename && *filename && !(*filename == '-' && !filename[1])
&& !opt.textmode ) {
off_t tmpsize;
if ( !(tmpsize = iobuf_get_filelength(inp)) )
log_info(_("%s: WARNING: empty file\n"), filename );
/* We can't encode the length of very large files because
OpenPGP uses only 32 bit for file sizes. So if the the
size of a file is larger than 2^32 minus some bytes for
packet headers, we switch to partial length encoding. */
if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
filesize = tmpsize;
else
filesize = 0;
}
else
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
if (!opt.no_literal) {
pt->timestamp = make_timestamp();
pt->mode = opt.textmode? 't' : 'b';
pt->len = filesize;
pt->new_ctb = !pt->len && !RFC1991;
pt->buf = inp;
pkt.pkttype = PKT_PLAINTEXT;
pkt.pkt.plaintext = pt;
cfx.datalen = filesize && !do_compress ? calc_packet_length( &pkt ) : 0;
}
else
{
cfx.datalen = filesize && !do_compress ? filesize : 0;
pkt.pkttype = 0;
pkt.pkt.generic = NULL;
}
/* register the cipher filter */
if( mode )
iobuf_push_filter( out, cipher_filter, &cfx );
/* register the compress filter */
if( do_compress )
{
if (cfx.dek && cfx.dek->use_mdc)
zfx.new_ctb = 1;
zfx.algo=default_compress_algo();
iobuf_push_filter( out, compress_filter, &zfx );
}
/* do the work */
if (!opt.no_literal) {
if( (rc = build_packet( out, &pkt )) )
log_error("build_packet failed: %s\n", g10_errstr(rc) );
}
else {
/* user requested not to create a literal packet,
* so we copy the plain data */
byte copy_buffer[4096];
int bytes_copied;
while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
rc = G10ERR_WRITE_FILE;
log_error("copying input to output failed: %s\n", g10_errstr(rc) );
break;
}
wipememory(copy_buffer, 4096); /* burn buffer */
}
/* finish the stuff */
iobuf_close(inp);
if (rc)
iobuf_cancel(out);
else {
iobuf_close(out); /* fixme: check returncode */
if (mode)
write_status( STATUS_END_ENCRYPTION );
}
if (pt)
pt->buf = NULL;
free_packet(&pkt);
m_free(cfx.dek);
m_free(s2k);
return rc;
}
/****************
* Encrypt the file with the given userids (or ask if none
* is supplied).
*/
int
encode_crypt( const char *filename, STRLIST remusr )
{
IOBUF inp = NULL, out = NULL;
PACKET pkt;
PKT_plaintext *pt = NULL;
int rc = 0, rc2 = 0;
u32 filesize;
cipher_filter_context_t cfx;
armor_filter_context_t afx;
compress_filter_context_t zfx;
text_filter_context_t tfx;
progress_filter_context_t pfx;
PK_LIST pk_list,work_list;
int do_compress = opt.compress && !RFC1991;
memset( &cfx, 0, sizeof cfx);
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
memset( &tfx, 0, sizeof tfx);
init_packet(&pkt);
if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) )
return rc;
if(PGP2) {
for(work_list=pk_list; work_list; work_list=work_list->next)
if(!(is_RSA(work_list->pk->pubkey_algo) &&
nbits_from_pk(work_list->pk)<=2048))
{
log_info(_("you can only encrypt to RSA keys of 2048 bits or "
"less in --pgp2 mode\n"));
compliance_failure();
break;
}
}
/* prepare iobufs */
if( !(inp = iobuf_open(filename)) ) {
log_error(_("can't open %s: %s\n"), filename? filename: "[stdin]",
strerror(errno) );
rc = G10ERR_OPEN_FILE;
goto leave;
}
else if( opt.verbose )
log_info(_("reading from `%s'\n"), filename? filename: "[stdin]");
handle_progress (&pfx, inp, filename);
if( opt.textmode )
iobuf_push_filter( inp, text_filter, &tfx );
if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) )
goto leave;
if( opt.armor )
iobuf_push_filter( out, armor_filter, &afx );
#ifdef ENABLE_COMMENT_PACKETS
else {
write_comment( out, "#created by GNUPG v" VERSION " ("
PRINTABLE_OS_NAME ")");
if( opt.comment_string )
write_comment( out, opt.comment_string );
}
#endif
/* create a session key */
cfx.dek = m_alloc_secure_clear (sizeof *cfx.dek);
if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
cfx.dek->algo = select_algo_from_prefs(pk_list,PREFTYPE_SYM,-1,NULL);
/* The only way select_algo_from_prefs can fail here is when
mixing v3 and v4 keys, as v4 keys have an implicit
preference entry for 3DES, and the pk_list cannot be empty.
In this case, use 3DES anyway as it's the safest choice -
perhaps the v3 key is being used in an OpenPGP
implementation and we know that the implementation behind
any v4 key can handle 3DES. */
if( cfx.dek->algo == -1 ) {
cfx.dek->algo = CIPHER_ALGO_3DES;
if( PGP2 ) {
log_info(_("unable to use the IDEA cipher for all of the keys "
"you are encrypting to.\n"));
compliance_failure();
}
}
}
else {
if(!opt.expert &&
select_algo_from_prefs(pk_list,PREFTYPE_SYM,
opt.def_cipher_algo,NULL)!=opt.def_cipher_algo)
log_info(_("forcing symmetric cipher %s (%d) "
"violates recipient preferences\n"),
cipher_algo_to_string(opt.def_cipher_algo),
opt.def_cipher_algo);
cfx.dek->algo = opt.def_cipher_algo;
}
cfx.dek->use_mdc=use_mdc(pk_list,cfx.dek->algo);
/* Only do the is-file-already-compressed check if we are using a
MDC. This forces compressed files to be re-compressed if we do
not have a MDC to give some protection against chosen
ciphertext attacks. */
if (opt.compress == -1 && cfx.dek->use_mdc &&
is_file_compressed(filename, &rc2) )
{
if (opt.verbose)
log_info(_("`%s' already compressed\n"), filename);
do_compress = 0;
}
if (rc2)
{
rc = rc2;
goto leave;
}
make_session_key( cfx.dek );
if( DBG_CIPHER )
log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
rc = write_pubkey_enc_from_list( pk_list, cfx.dek, out );
if( rc )
goto leave;
if (!opt.no_literal) {
/* setup the inner packet */
if( filename || opt.set_filename ) {
char *s = make_basename( opt.set_filename ? opt.set_filename
: filename,
iobuf_get_real_fname( inp ) );
pt = m_alloc( sizeof *pt + strlen(s) - 1 );
pt->namelen = strlen(s);
memcpy(pt->name, s, pt->namelen );
m_free(s);
}
else { /* no filename */
pt = m_alloc( sizeof *pt - 1 );
pt->namelen = 0;
}
}
if (filename && *filename && !(*filename == '-' && !filename[1])
&& !opt.textmode ) {
off_t tmpsize;
if ( !(tmpsize = iobuf_get_filelength(inp)) )
log_info(_("%s: WARNING: empty file\n"), filename );
/* We can't encode the length of very large files because
OpenPGP uses only 32 bit for file sizes. So if the the
size of a file is larger than 2^32 minus some bytes for
packet headers, we switch to partial length encoding. */
if ( tmpsize < (IOBUF_FILELENGTH_LIMIT - 65536) )
filesize = tmpsize;
else
filesize = 0;
}
else
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
if (!opt.no_literal) {
pt->timestamp = make_timestamp();
pt->mode = opt.textmode ? 't' : 'b';
pt->len = filesize;
pt->new_ctb = !pt->len && !RFC1991;
pt->buf = inp;
pkt.pkttype = PKT_PLAINTEXT;
pkt.pkt.plaintext = pt;
cfx.datalen = filesize && !do_compress? calc_packet_length( &pkt ) : 0;
}
else
cfx.datalen = filesize && !do_compress ? filesize : 0;
/* register the cipher filter */
iobuf_push_filter( out, cipher_filter, &cfx );
/* register the compress filter */
if( do_compress ) {
int compr_algo = opt.def_compress_algo;
if(compr_algo==-1)
{
if((compr_algo=
select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1)
compr_algo=DEFAULT_COMPRESS_ALGO;
/* Theoretically impossible to get here since uncompressed
is implicit. */
}
else if(!opt.expert &&
select_algo_from_prefs(pk_list,PREFTYPE_ZIP,
compr_algo,NULL)!=compr_algo)
log_info(_("forcing compression algorithm %s (%d) "
"violates recipient preferences\n"),
compress_algo_to_string(compr_algo),compr_algo);
/* algo 0 means no compression */
if( compr_algo )
{
if (cfx.dek && cfx.dek->use_mdc)
zfx.new_ctb = 1;
zfx.algo = compr_algo;
iobuf_push_filter( out, compress_filter, &zfx );
}
}
/* do the work */
if (!opt.no_literal) {
if( (rc = build_packet( out, &pkt )) )
log_error("build_packet failed: %s\n", g10_errstr(rc) );
}
else {
/* user requested not to create a literal packet, so we copy
the plain data */
byte copy_buffer[4096];
int bytes_copied;
while ((bytes_copied = iobuf_read(inp, copy_buffer, 4096)) != -1)
if (iobuf_write(out, copy_buffer, bytes_copied) == -1) {
rc = G10ERR_WRITE_FILE;
log_error("copying input to output failed: %s\n",
g10_errstr(rc) );
break;
}
wipememory(copy_buffer, 4096); /* burn buffer */
}
/* finish the stuff */
leave:
iobuf_close(inp);
if( rc )
iobuf_cancel(out);
else {
iobuf_close(out); /* fixme: check returncode */
write_status( STATUS_END_ENCRYPTION );
}
if( pt )
pt->buf = NULL;
free_packet(&pkt);
m_free(cfx.dek);
release_pk_list( pk_list );
return rc;
}
/****************
* Filter to do a complete public key encryption.
*/
int
encrypt_filter( void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len)
{
size_t size = *ret_len;
encrypt_filter_context_t *efx = opaque;
int rc=0;
if( control == IOBUFCTRL_UNDERFLOW ) { /* decrypt */
BUG(); /* not used */
}
else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
if( !efx->header_okay ) {
efx->cfx.dek = m_alloc_secure_clear( sizeof *efx->cfx.dek );
if( !opt.def_cipher_algo ) { /* try to get it from the prefs */
efx->cfx.dek->algo =
select_algo_from_prefs(efx->pk_list,PREFTYPE_SYM,-1,NULL);
if( efx->cfx.dek->algo == -1 ) {
/* because 3DES is implicitly in the prefs, this can only
* happen if we do not have any public keys in the list */
efx->cfx.dek->algo = DEFAULT_CIPHER_ALGO;
}
}
else {
if(!opt.expert &&
select_algo_from_prefs(efx->pk_list,PREFTYPE_SYM,
opt.def_cipher_algo,
NULL)!=opt.def_cipher_algo)
log_info(_("forcing symmetric cipher %s (%d) "
"violates recipient preferences\n"),
cipher_algo_to_string(opt.def_cipher_algo),
opt.def_cipher_algo);
efx->cfx.dek->algo = opt.def_cipher_algo;
}
efx->cfx.dek->use_mdc = use_mdc(efx->pk_list,efx->cfx.dek->algo);
make_session_key( efx->cfx.dek );
if( DBG_CIPHER )
log_hexdump("DEK is: ",
efx->cfx.dek->key, efx->cfx.dek->keylen );
rc = write_pubkey_enc_from_list( efx->pk_list, efx->cfx.dek, a );
if( rc )
return rc;
iobuf_push_filter( a, cipher_filter, &efx->cfx );
efx->header_okay = 1;
}
rc = iobuf_write( a, buf, size );
}
else if( control == IOBUFCTRL_FREE ) {
}
else if( control == IOBUFCTRL_DESC ) {
*(char**)buf = "encrypt_filter";
}
return rc;
}
/****************
* Write pubkey-enc packets from the list of PKs to OUT.
*/
static int
write_pubkey_enc_from_list( PK_LIST pk_list, DEK *dek, IOBUF out )
{
PACKET pkt;
PKT_public_key *pk;
PKT_pubkey_enc *enc;
int rc;
for( ; pk_list; pk_list = pk_list->next ) {
MPI frame;
pk = pk_list->pk;
print_pubkey_algo_note( pk->pubkey_algo );
enc = m_alloc_clear( sizeof *enc );
enc->pubkey_algo = pk->pubkey_algo;
keyid_from_pk( pk, enc->keyid );
enc->throw_keyid = (opt.throw_keyid || (pk_list->flags&1));
if(opt.throw_keyid && (PGP2 || PGP6 || PGP7 || PGP8))
{
log_info(_("you may not use %s while in %s mode\n"),
"--throw-keyid",compliance_option_string());
compliance_failure();
}
/* Okay, what's going on: We have the session key somewhere in
* the structure DEK and want to encode this session key in
* an integer value of n bits. pubkey_nbits gives us the
* number of bits we have to use. We then encode the session
* key in some way and we get it back in the big intger value
* FRAME. Then we use FRAME, the public key PK->PKEY and the
* algorithm number PK->PUBKEY_ALGO and pass it to pubkey_encrypt
* which returns the encrypted value in the array ENC->DATA.
* This array has a size which depends on the used algorithm
* (e.g. 2 for ElGamal). We don't need frame anymore because we
* have everything now in enc->data which is the passed to
* build_packet()
*/
frame = encode_session_key( dek, pubkey_nbits( pk->pubkey_algo,
pk->pkey ) );
rc = pubkey_encrypt( pk->pubkey_algo, enc->data, frame, pk->pkey );
mpi_free( frame );
if( rc )
log_error("pubkey_encrypt failed: %s\n", g10_errstr(rc) );
else {
if( opt.verbose ) {
char *ustr = get_user_id_string_printable (enc->keyid);
log_info(_("%s/%s encrypted for: \"%s\"\n"),
pubkey_algo_to_string(enc->pubkey_algo),
cipher_algo_to_string(dek->algo), ustr );
m_free(ustr);
}
/* and write it */
init_packet(&pkt);
pkt.pkttype = PKT_PUBKEY_ENC;
pkt.pkt.pubkey_enc = enc;
rc = build_packet( out, &pkt );
if( rc )
log_error("build_packet(pubkey_enc) failed: %s\n", g10_errstr(rc));
}
free_pubkey_enc(enc);
if( rc )
return rc;
}
return 0;
}
void
encode_crypt_files(int nfiles, char **files, STRLIST remusr)
{
int rc = 0;
if (opt.outfile)
{
log_error(_("--output doesn't work for this command\n"));
return;
}
if (!nfiles)
{
char line[2048];
unsigned int lno = 0;
while ( fgets(line, DIM(line), stdin) )
{
lno++;
if (!*line || line[strlen(line)-1] != '\n')
{
log_error("input line %u too long or missing LF\n", lno);
return;
}
line[strlen(line)-1] = '\0';
print_file_status(STATUS_FILE_START, line, 2);
if ( (rc = encode_crypt(line, remusr)) )
log_error("%s: encryption failed: %s\n",
print_fname_stdin(line), g10_errstr(rc) );
write_status( STATUS_FILE_DONE );
}
}
else
{
while (nfiles--)
{
print_file_status(STATUS_FILE_START, *files, 2);
if ( (rc = encode_crypt(*files, remusr)) )
log_error("%s: encryption failed: %s\n",
print_fname_stdin(*files), g10_errstr(rc) );
write_status( STATUS_FILE_DONE );
files++;
}
}
}

619
g10/exec.c Normal file
View file

@ -0,0 +1,619 @@
/* exec.c - generic call-a-program code
* Copyright (C) 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifndef EXEC_TEMPFILE_ONLY
#include <sys/wait.h>
#endif
#ifdef HAVE_DOSISH_SYSTEM
#include <windows.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "options.h"
#include "memory.h"
#include "i18n.h"
#include "iobuf.h"
#include "util.h"
#include "exec.h"
#ifdef NO_EXEC
int exec_write(struct exec_info **info,const char *program,
const char *args_in,const char *name,int writeonly,int binary)
{
log_error(_("no remote program execution supported\n"));
return G10ERR_GENERAL;
}
int exec_read(struct exec_info *info) { return G10ERR_GENERAL; }
int exec_finish(struct exec_info *info) { return G10ERR_GENERAL; }
int set_exec_path(const char *path,int method) { return G10ERR_GENERAL; }
#else /* ! NO_EXEC */
#ifndef HAVE_MKDTEMP
char *mkdtemp(char *template);
#endif
#if defined (__MINGW32__)
/* This is a nicer system() for windows that waits for programs to
return before returning control to the caller. I hate helpful
computers. */
static int win_system(const char *command)
{
PROCESS_INFORMATION pi;
STARTUPINFO si;
char *string;
/* We must use a copy of the command as CreateProcess modifies this
argument. */
string=m_strdup(command);
memset(&pi,0,sizeof(pi));
memset(&si,0,sizeof(si));
si.cb=sizeof(si);
if(!CreateProcess(NULL,string,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi))
return -1;
/* Wait for the child to exit */
WaitForSingleObject(pi.hProcess,INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
m_free(string);
return 0;
}
#endif
/* method==0 to replace current $PATH, and 1 to append to current
$PATH. */
int set_exec_path(const char *path,int method)
{
char *p,*curpath=NULL;
size_t curlen=0;
if(method==1 && (curpath=getenv("PATH")))
curlen=strlen(curpath)+1;
p=m_alloc(5+curlen+strlen(path)+1);
strcpy(p,"PATH=");
if(curpath)
{
strcat(p,curpath);
strcat(p,":");
}
strcat(p,path);
if(DBG_EXTPROG)
log_debug("set_exec_path method %d: %s\n",method,p);
/* Notice that path is never freed. That is intentional due to the
way putenv() works. This leaks a few bytes if we call
set_exec_path multiple times. */
if(putenv(p)!=0)
return G10ERR_GENERAL;
else
return 0;
}
/* Makes a temp directory and filenames */
static int make_tempdir(struct exec_info *info)
{
char *tmp=opt.temp_dir,*namein=info->name,*nameout;
if(!namein)
namein=info->binary?"tempin" EXTSEP_S "bin":"tempin" EXTSEP_S "txt";
nameout=info->binary?"tempout" EXTSEP_S "bin":"tempout" EXTSEP_S "txt";
/* Make up the temp dir and files in case we need them */
if(tmp==NULL)
{
#if defined (__MINGW32__)
tmp=m_alloc(256);
if(GetTempPath(256,tmp)==0)
strcpy(tmp,"c:\\windows\\temp");
else
{
int len=strlen(tmp);
/* GetTempPath may return with \ on the end */
while(len>0 && tmp[len-1]=='\\')
{
tmp[len-1]='\0';
len--;
}
}
#else /* More unixish systems */
tmp=getenv("TMPDIR");
if(tmp==NULL)
{
tmp=getenv("TMP");
if(tmp==NULL)
{
#ifdef __riscos__
tmp="<Wimp$ScrapDir>.GnuPG";
mkdir(tmp,0700); /* Error checks occur later on */
#else
tmp="/tmp";
#endif
}
}
#endif
}
info->tempdir=m_alloc(strlen(tmp)+strlen(DIRSEP_S)+10+1);
sprintf(info->tempdir,"%s" DIRSEP_S "gpg-XXXXXX",tmp);
#if defined (__MINGW32__)
m_free(tmp);
#endif
if(mkdtemp(info->tempdir)==NULL)
log_error(_("can't create directory `%s': %s\n"),
info->tempdir,strerror(errno));
else
{
info->madedir=1;
info->tempfile_in=m_alloc(strlen(info->tempdir)+
strlen(DIRSEP_S)+strlen(namein)+1);
sprintf(info->tempfile_in,"%s" DIRSEP_S "%s",info->tempdir,namein);
if(!info->writeonly)
{
info->tempfile_out=m_alloc(strlen(info->tempdir)+
strlen(DIRSEP_S)+strlen(nameout)+1);
sprintf(info->tempfile_out,"%s" DIRSEP_S "%s",info->tempdir,nameout);
}
}
return info->madedir?0:G10ERR_GENERAL;
}
/* Expands %i and %o in the args to the full temp files within the
temp directory. */
static int expand_args(struct exec_info *info,const char *args_in)
{
const char *ch=args_in;
unsigned int size,len;
info->use_temp_files=0;
info->keep_temp_files=0;
if(DBG_EXTPROG)
log_debug("expanding string \"%s\"\n",args_in);
size=100;
info->command=m_alloc(size);
len=0;
info->command[0]='\0';
while(*ch!='\0')
{
if(*ch=='%')
{
char *append=NULL;
ch++;
switch(*ch)
{
case 'O':
info->keep_temp_files=1;
/* fall through */
case 'o': /* out */
if(!info->madedir)
{
if(make_tempdir(info))
goto fail;
}
append=info->tempfile_out;
info->use_temp_files=1;
break;
case 'I':
info->keep_temp_files=1;
/* fall through */
case 'i': /* in */
if(!info->madedir)
{
if(make_tempdir(info))
goto fail;
}
append=info->tempfile_in;
info->use_temp_files=1;
break;
case '%':
append="%";
break;
}
if(append)
{
size_t applen=strlen(append);
if(applen+len>size-1)
{
if(applen<100)
applen=100;
size+=applen;
info->command=m_realloc(info->command,size);
}
strcat(info->command,append);
len+=strlen(append);
}
}
else
{
if(len==size-1) /* leave room for the \0 */
{
size+=100;
info->command=m_realloc(info->command,size);
}
info->command[len++]=*ch;
info->command[len]='\0';
}
ch++;
}
if(DBG_EXTPROG)
log_debug("args expanded to \"%s\", use %d, keep %d\n",
info->command,info->use_temp_files,info->keep_temp_files);
return 0;
fail:
m_free(info->command);
info->command=NULL;
return G10ERR_GENERAL;
}
/* Either handles the tempfile creation, or the fork/exec. If it
returns ok, then info->tochild is a FILE * that can be written to.
The rules are: if there are no args, then it's a fork/exec/pipe.
If there are args, but no tempfiles, then it's a fork/exec/pipe via
shell -c. If there are tempfiles, then it's a system. */
int exec_write(struct exec_info **info,const char *program,
const char *args_in,const char *name,int writeonly,int binary)
{
int ret=G10ERR_GENERAL;
if(opt.exec_disable && !opt.no_perm_warn)
{
log_info(_("external program calls are disabled due to unsafe "
"options file permissions\n"));
return ret;
}
#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
/* There should be no way to get to this spot while still carrying
setuid privs. Just in case, bomb out if we are. */
if(getuid()!=geteuid())
BUG();
#endif
if(program==NULL && args_in==NULL)
BUG();
*info=m_alloc_clear(sizeof(struct exec_info));
if(name)
(*info)->name=m_strdup(name);
(*info)->binary=binary;
(*info)->writeonly=writeonly;
/* Expand the args, if any */
if(args_in && expand_args(*info,args_in))
goto fail;
#ifdef EXEC_TEMPFILE_ONLY
if(!(*info)->use_temp_files)
{
log_error(_("this platform requires temp files when calling external "
"programs\n"));
goto fail;
}
#else /* !EXEC_TEMPFILE_ONLY */
/* If there are no args, or there are args, but no temp files, we
can use fork/exec/pipe */
if(args_in==NULL || (*info)->use_temp_files==0)
{
int to[2],from[2];
if(pipe(to)==-1)
goto fail;
if(pipe(from)==-1)
{
close(to[0]);
close(to[1]);
goto fail;
}
if(((*info)->child=fork())==-1)
{
close(to[0]);
close(to[1]);
close(from[0]);
close(from[1]);
goto fail;
}
if((*info)->child==0)
{
char *shell=getenv("SHELL");
if(shell==NULL)
shell="/bin/sh";
/* I'm the child */
/* If the program isn't going to respond back, they get to
keep their stdout/stderr */
if(!(*info)->writeonly)
{
/* implied close of STDERR */
if(dup2(STDOUT_FILENO,STDERR_FILENO)==-1)
_exit(1);
/* implied close of STDOUT */
close(from[0]);
if(dup2(from[1],STDOUT_FILENO)==-1)
_exit(1);
}
/* implied close of STDIN */
close(to[1]);
if(dup2(to[0],STDIN_FILENO)==-1)
_exit(1);
if(args_in==NULL)
{
if(DBG_EXTPROG)
log_debug("execlp: %s\n",program);
execlp(program,program,(void *)NULL);
}
else
{
if(DBG_EXTPROG)
log_debug("execlp: %s -c %s\n",shell,(*info)->command);
execlp(shell,shell,"-c",(*info)->command,(void *)NULL);
}
/* If we get this far the exec failed. Clean up and return. */
log_error(_("unable to execute %s \"%s\": %s\n"),
args_in==NULL?"program":"shell",
args_in==NULL?program:shell,
strerror(errno));
/* This mimics the POSIX sh behavior - 127 means "not found"
from the shell. */
if(errno==ENOENT)
_exit(127);
_exit(1);
}
/* I'm the parent */
close(to[0]);
(*info)->tochild=fdopen(to[1],binary?"wb":"w");
if((*info)->tochild==NULL)
{
close(to[1]);
ret=G10ERR_WRITE_FILE;
goto fail;
}
close(from[1]);
(*info)->fromchild=iobuf_fdopen(from[0],"r");
if((*info)->fromchild==NULL)
{
close(from[0]);
ret=G10ERR_READ_FILE;
goto fail;
}
/* fd iobufs are cached?! */
iobuf_ioctl((*info)->fromchild,3,1,NULL);
return 0;
}
#endif /* !EXEC_TEMPFILE_ONLY */
if(DBG_EXTPROG)
log_debug("using temp file `%s'\n",(*info)->tempfile_in);
/* It's not fork/exec/pipe, so create a temp file */
(*info)->tochild=fopen((*info)->tempfile_in,binary?"wb":"w");
if((*info)->tochild==NULL)
{
log_error(_("can't create `%s': %s\n"),
(*info)->tempfile_in,strerror(errno));
ret=G10ERR_WRITE_FILE;
goto fail;
}
ret=0;
fail:
return ret;
}
int exec_read(struct exec_info *info)
{
int ret=G10ERR_GENERAL;
fclose(info->tochild);
info->tochild=NULL;
if(info->use_temp_files)
{
if(DBG_EXTPROG)
log_debug("system() command is %s\n",info->command);
#if defined (__MINGW32__)
info->progreturn=win_system(info->command);
#else
info->progreturn=system(info->command);
#endif
if(info->progreturn==-1)
{
log_error(_("system error while calling external program: %s\n"),
strerror(errno));
info->progreturn=127;
goto fail;
}
#if defined(WIFEXITED) && defined(WEXITSTATUS)
if(WIFEXITED(info->progreturn))
info->progreturn=WEXITSTATUS(info->progreturn);
else
{
log_error(_("unnatural exit of external program\n"));
info->progreturn=127;
goto fail;
}
#else
/* If we don't have the macros, do the best we can. */
info->progreturn = (info->progreturn & 0xff00) >> 8;
#endif
/* 127 is the magic value returned from system() to indicate
that the shell could not be executed, or from /bin/sh to
indicate that the program could not be executed. */
if(info->progreturn==127)
{
log_error(_("unable to execute external program\n"));
goto fail;
}
if(!info->writeonly)
{
info->fromchild=iobuf_open(info->tempfile_out);
if(info->fromchild==NULL)
{
log_error(_("unable to read external program response: %s\n"),
strerror(errno));
ret=G10ERR_READ_FILE;
goto fail;
}
/* Do not cache this iobuf on close */
iobuf_ioctl(info->fromchild,3,1,NULL);
}
}
ret=0;
fail:
return ret;
}
int exec_finish(struct exec_info *info)
{
int ret=info->progreturn;
if(info->fromchild)
iobuf_close(info->fromchild);
if(info->tochild)
fclose(info->tochild);
#ifndef EXEC_TEMPFILE_ONLY
if(info->child>0)
{
if(waitpid(info->child,&info->progreturn,0)!=0 &&
WIFEXITED(info->progreturn))
ret=WEXITSTATUS(info->progreturn);
else
{
log_error(_("unnatural exit of external program\n"));
ret=127;
}
}
#endif
if(info->madedir && !info->keep_temp_files)
{
if(info->tempfile_in)
{
if(unlink(info->tempfile_in)==-1)
log_info(_("WARNING: unable to remove tempfile (%s) `%s': %s\n"),
"in",info->tempfile_in,strerror(errno));
}
if(info->tempfile_out)
{
if(unlink(info->tempfile_out)==-1)
log_info(_("WARNING: unable to remove tempfile (%s) `%s': %s\n"),
"out",info->tempfile_out,strerror(errno));
}
if(rmdir(info->tempdir)==-1)
log_info(_("WARNING: unable to remove temp directory `%s': %s\n"),
info->tempdir,strerror(errno));
}
m_free(info->command);
m_free(info->name);
m_free(info->tempdir);
m_free(info->tempfile_in);
m_free(info->tempfile_out);
m_free(info);
return ret;
}
#endif /* ! NO_EXEC */

43
g10/exec.h Normal file
View file

@ -0,0 +1,43 @@
/* exec.h
* Copyright (C) 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef _EXEC_H_
#define _EXEC_H_
#include <unistd.h>
#include <stdio.h>
#include "iobuf.h"
struct exec_info
{
int progreturn,binary,writeonly,madedir,use_temp_files,keep_temp_files;
pid_t child;
FILE *tochild;
IOBUF fromchild;
char *command,*name,*tempdir,*tempfile_in,*tempfile_out;
};
int exec_write(struct exec_info **info,const char *program,
const char *args_in,const char *name,int writeonly,int binary);
int exec_read(struct exec_info *info);
int exec_finish(struct exec_info *info);
int set_exec_path(const char *path,int method);
#endif /* !_EXEC_H_ */

396
g10/export.c Normal file
View file

@ -0,0 +1,396 @@
/* export.c
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "keydb.h"
#include "memory.h"
#include "util.h"
#include "main.h"
#include "i18n.h"
static int do_export( STRLIST users, int secret, unsigned int options );
static int do_export_stream( IOBUF out, STRLIST users, int secret,
KBNODE *keyblock_out, unsigned int options,
int *any );
int
parse_export_options(char *str,unsigned int *options)
{
struct parse_options export_opts[]=
{
{"include-non-rfc",EXPORT_INCLUDE_NON_RFC},
{"include-local-sigs",EXPORT_INCLUDE_LOCAL_SIGS},
{"include-attributes",EXPORT_INCLUDE_ATTRIBUTES},
{"include-sensitive-revkeys",EXPORT_INCLUDE_SENSITIVE_REVKEYS},
{NULL,0}
/* add tags for include revoked and disabled? */
};
return parse_options(str,options,export_opts);
}
/****************
* Export the public keys (to standard out or --output).
* Depending on opt.armor the output is armored.
* options are defined in main.h.
* If USERS is NULL, the complete ring will be exported. */
int
export_pubkeys( STRLIST users, unsigned int options )
{
return do_export( users, 0, options );
}
/****************
* Export to an already opened stream; return -1 if no keys have
* been exported
*/
int
export_pubkeys_stream( IOBUF out, STRLIST users,
KBNODE *keyblock_out, unsigned int options )
{
int any, rc;
rc = do_export_stream( out, users, 0, keyblock_out, options, &any );
if( !rc && !any )
rc = -1;
return rc;
}
int
export_seckeys( STRLIST users )
{
return do_export( users, 1, 0 );
}
int
export_secsubkeys( STRLIST users )
{
return do_export( users, 2, 0 );
}
static int
do_export( STRLIST users, int secret, unsigned int options )
{
IOBUF out = NULL;
int any, rc;
armor_filter_context_t afx;
compress_filter_context_t zfx;
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
rc = open_outfile( NULL, 0, &out );
if( rc )
return rc;
if( opt.armor ) {
afx.what = secret?5:1;
iobuf_push_filter( out, armor_filter, &afx );
}
if( opt.compress_keys && opt.compress )
iobuf_push_filter( out, compress_filter, &zfx );
rc = do_export_stream( out, users, secret, NULL, options, &any );
if( rc || !any )
iobuf_cancel(out);
else
iobuf_close(out);
return rc;
}
/* If keyblock_out is non-NULL, AND the exit code is zero, then it
contains a pointer to the first keyblock found and exported. No
other keyblocks are exported. The caller must free it. */
static int
do_export_stream( IOBUF out, STRLIST users, int secret,
KBNODE *keyblock_out, unsigned int options, int *any )
{
int rc = 0;
PACKET pkt;
KBNODE keyblock = NULL;
KBNODE kbctx, node;
size_t ndesc, descindex;
KEYDB_SEARCH_DESC *desc = NULL;
KEYDB_HANDLE kdbhd;
STRLIST sl;
*any = 0;
init_packet( &pkt );
kdbhd = keydb_new (secret);
if (!users) {
ndesc = 1;
desc = m_alloc_clear ( ndesc * sizeof *desc);
desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
}
else {
for (ndesc=0, sl=users; sl; sl = sl->next, ndesc++)
;
desc = m_alloc ( ndesc * sizeof *desc);
for (ndesc=0, sl=users; sl; sl = sl->next) {
if (classify_user_id (sl->d, desc+ndesc))
ndesc++;
else
log_error (_("key `%s' not found: %s\n"),
sl->d, g10_errstr (G10ERR_INV_USER_ID));
}
/* it would be nice to see which of the given users did
actually match one in the keyring. To implement this we
need to have a found flag for each entry in desc and to set
this we must check all those entries after a match to mark
all matched one - currently we stop at the first match. To
do this we need an extra flag to enable this feature so */
}
while (!(rc = keydb_search2 (kdbhd, desc, ndesc, &descindex))) {
int sha1_warned=0,skip_until_subkey=0;
u32 sk_keyid[2];
if (!users)
desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
/* read the keyblock */
rc = keydb_get_keyblock (kdbhd, &keyblock );
if( rc ) {
log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
goto leave;
}
/* do not export keys which are incompatible with rfc2440 */
if( !(options&EXPORT_INCLUDE_NON_RFC) &&
(node = find_kbnode( keyblock, PKT_PUBLIC_KEY )) ) {
PKT_public_key *pk = node->pkt->pkt.public_key;
if( pk->version == 3 && pk->pubkey_algo > 3 ) {
log_info(_("key %08lX: not a rfc2440 key - skipped\n"),
(ulong)keyid_from_pk( pk, NULL) );
continue;
}
}
node=find_kbnode( keyblock, PKT_SECRET_KEY );
if(node)
{
PKT_secret_key *sk=node->pkt->pkt.secret_key;
keyid_from_sk(sk,sk_keyid);
/* we can't apply GNU mode 1001 on an unprotected key */
if( secret == 2 && !sk->is_protected )
{
log_info(_("key %08lX: not protected - skipped\n"),
(ulong)sk_keyid[1]);
continue;
}
/* no v3 keys with GNU mode 1001 */
if( secret == 2 && sk->version == 3 )
{
log_info(_("key %08lX: PGP 2.x style key - skipped\n"),
(ulong)sk_keyid[1]);
continue;
}
}
/* and write it */
for( kbctx=NULL; (node = walk_kbnode( keyblock, &kbctx, 0 )); ) {
if( skip_until_subkey )
{
if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype==PKT_SECRET_SUBKEY)
skip_until_subkey=0;
else
continue;
}
/* don't export any comment packets but those in the
* secret keyring */
if( !secret && node->pkt->pkttype == PKT_COMMENT )
continue;
/* make sure that ring_trust packets never get exported */
if (node->pkt->pkttype == PKT_RING_TRUST)
continue;
/* If exact is set, then we only export what was requested
(plus the primary key, if the user didn't specifically
request it) */
if(desc[descindex].exact
&& (node->pkt->pkttype==PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype==PKT_SECRET_SUBKEY))
{
u32 kid[2];
byte fpr[MAX_FINGERPRINT_LEN];
size_t fprlen;
switch(desc[descindex].mode)
{
case KEYDB_SEARCH_MODE_SHORT_KID:
case KEYDB_SEARCH_MODE_LONG_KID:
if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
keyid_from_pk(node->pkt->pkt.public_key,kid);
else
keyid_from_sk(node->pkt->pkt.secret_key,kid);
break;
case KEYDB_SEARCH_MODE_FPR16:
case KEYDB_SEARCH_MODE_FPR20:
case KEYDB_SEARCH_MODE_FPR:
if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
fingerprint_from_pk(node->pkt->pkt.public_key,
fpr,&fprlen);
else
fingerprint_from_sk(node->pkt->pkt.secret_key,
fpr,&fprlen);
break;
default:
break;
}
switch(desc[descindex].mode)
{
case KEYDB_SEARCH_MODE_SHORT_KID:
if (desc[descindex].u.kid[1] != kid[1])
skip_until_subkey=1;
break;
case KEYDB_SEARCH_MODE_LONG_KID:
if (desc[descindex].u.kid[0] != kid[0]
|| desc[descindex].u.kid[1] != kid[1])
skip_until_subkey=1;
break;
case KEYDB_SEARCH_MODE_FPR16:
if (memcmp (desc[descindex].u.fpr, fpr, 16))
skip_until_subkey=1;
break;
case KEYDB_SEARCH_MODE_FPR20:
case KEYDB_SEARCH_MODE_FPR:
if (memcmp (desc[descindex].u.fpr, fpr, 20))
skip_until_subkey=1;
break;
default:
break;
}
if(skip_until_subkey)
continue;
}
if( node->pkt->pkttype == PKT_SIGNATURE ) {
/* do not export packets which are marked as not exportable */
if( !(options&EXPORT_INCLUDE_LOCAL_SIGS) &&
!node->pkt->pkt.signature->flags.exportable )
continue; /* not exportable */
/* Do not export packets with a "sensitive" revocation
key unless the user wants us to. Note that we do
export these when issuing the actual revocation (see
revoke.c). */
if( !(options&EXPORT_INCLUDE_SENSITIVE_REVKEYS) &&
node->pkt->pkt.signature->revkey ) {
int i;
for(i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
if(node->pkt->pkt.signature->revkey[i]->class & 0x40)
break;
if(i<node->pkt->pkt.signature->numrevkeys)
continue;
}
}
/* Don't export attribs? */
if( !(options&EXPORT_INCLUDE_ATTRIBUTES) &&
node->pkt->pkttype == PKT_USER_ID &&
node->pkt->pkt.user_id->attrib_data ) {
/* Skip until we get to something that is not an attrib
or a signature on an attrib */
while(kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE) {
kbctx=kbctx->next;
}
continue;
}
if( secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY ) {
/* we don't want to export the secret parts of the
* primary key, this is done by using GNU protection mode 1001
*/
int save_mode = node->pkt->pkt.secret_key->protect.s2k.mode;
node->pkt->pkt.secret_key->protect.s2k.mode = 1001;
rc = build_packet( out, node->pkt );
node->pkt->pkt.secret_key->protect.s2k.mode = save_mode;
}
else {
/* Warn the user if the secret key or any of the secret
subkeys are protected with SHA1 and we have
simple_sk_checksum set. */
if(!sha1_warned && opt.simple_sk_checksum &&
(node->pkt->pkttype==PKT_SECRET_KEY ||
node->pkt->pkttype==PKT_SECRET_SUBKEY) &&
node->pkt->pkt.secret_key->protect.sha1chk)
{
/* I hope this warning doesn't confuse people. */
log_info(_("WARNING: secret key %08lX does not have a "
"simple SK checksum\n"),(ulong)sk_keyid[1]);
sha1_warned=1;
}
rc = build_packet( out, node->pkt );
}
if( rc ) {
log_error("build_packet(%d) failed: %s\n",
node->pkt->pkttype, g10_errstr(rc) );
rc = G10ERR_WRITE_FILE;
goto leave;
}
}
++*any;
if(keyblock_out)
{
*keyblock_out=keyblock;
break;
}
}
if( rc == -1 )
rc = 0;
leave:
m_free(desc);
keydb_release (kdbhd);
if(rc || keyblock_out==NULL)
release_kbnode( keyblock );
if( !*any )
log_info(_("WARNING: nothing exported\n"));
return rc;
}

154
g10/filter.h Normal file
View file

@ -0,0 +1,154 @@
/* filter.h
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_FILTER_H
#define G10_FILTER_H
#include "types.h"
#include "cipher.h"
typedef struct {
MD_HANDLE md; /* catch all */
MD_HANDLE md2; /* if we want to calculate an alternate hash */
size_t maxbuf_size;
} md_filter_context_t;
typedef struct {
/* these fields may be initialized */
int what; /* what kind of armor headers to write */
int only_keyblocks; /* skip all headers but ".... key block" */
const char *hdrlines; /* write these headerlines */
/* these fileds must be initialized to zero */
int no_openpgp_data; /* output flag: "No valid OpenPGP data found" */
/* the following fields must be initialized to zero */
int inp_checked; /* set if the input has been checked */
int inp_bypass; /* set if the input is not armored */
int in_cleartext; /* clear text message */
int not_dash_escaped; /* clear text is not dash escaped */
int hashes; /* detected hash algorithms */
int faked; /* we are faking a literal data packet */
int truncated; /* number of truncated lines */
int qp_detected;
int pgp2mode;
byte *buffer; /* malloced buffer */
unsigned buffer_size; /* and size of this buffer */
unsigned buffer_len; /* used length of the buffer */
unsigned buffer_pos; /* read position */
byte radbuf[4];
int idx, idx2;
u32 crc;
int status; /* an internal state flag */
int cancel;
int any_data; /* any valid armored data seen */
int pending_lf; /* used together with faked */
} armor_filter_context_t;
struct unarmor_pump_s;
typedef struct unarmor_pump_s *UnarmorPump;
struct compress_filter_context_s {
int status;
void *opaque; /* (used for z_stream) */
byte *inbuf;
unsigned inbufsize;
byte *outbuf;
unsigned outbufsize;
int algo; /* compress algo */
int algo1hack;
int new_ctb;
void (*release)(struct compress_filter_context_s*);
};
typedef struct compress_filter_context_s compress_filter_context_t;
typedef struct {
DEK *dek;
u32 datalen;
CIPHER_HANDLE cipher_hd;
int header;
MD_HANDLE mdc_hash;
byte enchash[20];
int create_mdc; /* flag will be set by the cipher filter */
} cipher_filter_context_t;
typedef struct {
byte *buffer; /* malloced buffer */
unsigned buffer_size; /* and size of this buffer */
unsigned buffer_len; /* used length of the buffer */
unsigned buffer_pos; /* read position */
int truncated; /* number of truncated lines */
int not_dash_escaped;
int escape_from;
MD_HANDLE md;
int pending_lf;
int pending_esc;
} text_filter_context_t;
typedef struct {
char *what; /* description */
u32 last_time; /* last time reported */
unsigned long last; /* last amount reported */
unsigned long offset; /* current amount */
unsigned long total; /* total amount */
} progress_filter_context_t;
/* encrypt_filter_context_t defined in main.h */
/*-- mdfilter.c --*/
int md_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len);
void free_md_filter_context( md_filter_context_t *mfx );
/*-- armor.c --*/
int use_armor_filter( IOBUF a );
int armor_filter( void *opaque, int control,
IOBUF chain, byte *buf, size_t *ret_len);
UnarmorPump unarmor_pump_new (void);
void unarmor_pump_release (UnarmorPump x);
int unarmor_pump (UnarmorPump x, int c);
/*-- compress.c --*/
int compress_filter( void *opaque, int control,
IOBUF chain, byte *buf, size_t *ret_len);
/*-- cipher.c --*/
int cipher_filter( void *opaque, int control,
IOBUF chain, byte *buf, size_t *ret_len);
/*-- textfilter.c --*/
int text_filter( void *opaque, int control,
IOBUF chain, byte *buf, size_t *ret_len);
int copy_clearsig_text( IOBUF out, IOBUF inp, MD_HANDLE md,
int escape_dash, int escape_from, int pgp2mode );
/*-- progress.c --*/
int progress_filter (void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len);
void handle_progress (progress_filter_context_t *pfx,
IOBUF inp, const char *name);
#endif /*G10_FILTER_H*/

542
g10/free-packet.c Normal file
View file

@ -0,0 +1,542 @@
/* free-packet.c - cleanup stuff for packets
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "packet.h"
#include "iobuf.h"
#include "mpi.h"
#include "util.h"
#include "cipher.h"
#include "memory.h"
#include "options.h"
void
free_symkey_enc( PKT_symkey_enc *enc )
{
m_free(enc);
}
void
free_pubkey_enc( PKT_pubkey_enc *enc )
{
int n, i;
n = pubkey_get_nenc( enc->pubkey_algo );
if( !n )
mpi_free(enc->data[0]);
for(i=0; i < n; i++ )
mpi_free( enc->data[i] );
m_free(enc);
}
void
free_seckey_enc( PKT_signature *sig )
{
int n, i;
n = pubkey_get_nsig( sig->pubkey_algo );
if( !n )
mpi_free(sig->data[0]);
for(i=0; i < n; i++ )
mpi_free( sig->data[i] );
m_free(sig->revkey);
m_free(sig->hashed);
m_free(sig->unhashed);
m_free(sig);
}
void
release_public_key_parts( PKT_public_key *pk )
{
int n, i;
n = pubkey_get_npkey( pk->pubkey_algo );
if( !n )
mpi_free(pk->pkey[0]);
for(i=0; i < n; i++ ) {
mpi_free( pk->pkey[i] );
pk->pkey[i] = NULL;
}
if (pk->prefs) {
m_free (pk->prefs);
pk->prefs = NULL;
}
if (pk->user_id) {
free_user_id (pk->user_id);
pk->user_id = NULL;
}
if (pk->revkey) {
m_free(pk->revkey);
pk->revkey=NULL;
pk->numrevkeys=0;
}
}
void
free_public_key( PKT_public_key *pk )
{
release_public_key_parts( pk );
m_free(pk);
}
static subpktarea_t *
cp_subpktarea (subpktarea_t *s )
{
subpktarea_t *d;
if( !s )
return NULL;
d = m_alloc (sizeof (*d) + s->size - 1 );
d->size = s->size;
d->len = s->len;
memcpy (d->data, s->data, s->len);
return d;
}
/*
* Return a copy of the preferences
*/
prefitem_t *
copy_prefs (const prefitem_t *prefs)
{
size_t n;
prefitem_t *new;
if (!prefs)
return NULL;
for (n=0; prefs[n].type; n++)
;
new = m_alloc ( sizeof (*new) * (n+1));
for (n=0; prefs[n].type; n++) {
new[n].type = prefs[n].type;
new[n].value = prefs[n].value;
}
new[n].type = PREFTYPE_NONE;
new[n].value = 0;
return new;
}
PKT_public_key *
copy_public_key ( PKT_public_key *d, PKT_public_key *s)
{
int n, i;
if( !d )
d = m_alloc(sizeof *d);
memcpy( d, s, sizeof *d );
d->user_id = scopy_user_id (s->user_id);
d->prefs = copy_prefs (s->prefs);
n = pubkey_get_npkey( s->pubkey_algo );
if( !n )
d->pkey[0] = mpi_copy(s->pkey[0]);
else {
for(i=0; i < n; i++ )
d->pkey[i] = mpi_copy( s->pkey[i] );
}
if( !s->revkey && s->numrevkeys )
BUG();
if( s->numrevkeys ) {
d->revkey = m_alloc(sizeof(struct revocation_key)*s->numrevkeys);
memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
}
else
d->revkey = NULL;
return d;
}
/****************
* Replace all common parts of a sk by the one from the public key.
* This is a hack and a better solution will be to just store the real secret
* parts somewhere and don't duplicate all the other stuff.
*/
void
copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
{
sk->expiredate = pk->expiredate;
sk->pubkey_algo = pk->pubkey_algo;
sk->pubkey_usage= pk->pubkey_usage;
sk->req_usage = pk->req_usage;
sk->req_algo = pk->req_algo;
sk->has_expired = pk->has_expired;
sk->is_revoked = pk->is_revoked;
sk->is_valid = pk->is_valid;
sk->main_keyid[0]= pk->main_keyid[0];
sk->main_keyid[1]= pk->main_keyid[1];
sk->keyid[0] = pk->keyid[0];
sk->keyid[1] = pk->keyid[1];
}
PKT_signature *
copy_signature( PKT_signature *d, PKT_signature *s )
{
int n, i;
if( !d )
d = m_alloc(sizeof *d);
memcpy( d, s, sizeof *d );
n = pubkey_get_nsig( s->pubkey_algo );
if( !n )
d->data[0] = mpi_copy(s->data[0]);
else {
for(i=0; i < n; i++ )
d->data[i] = mpi_copy( s->data[i] );
}
d->hashed = cp_subpktarea (s->hashed);
d->unhashed = cp_subpktarea (s->unhashed);
if(s->numrevkeys)
{
d->revkey=NULL;
d->numrevkeys=0;
parse_revkeys(d);
}
return d;
}
/*
* shallow copy of the user ID
*/
PKT_user_id *
scopy_user_id (PKT_user_id *s)
{
if (s)
s->ref++;
return s;
}
void
release_secret_key_parts( PKT_secret_key *sk )
{
int n, i;
n = pubkey_get_nskey( sk->pubkey_algo );
if( !n )
mpi_free(sk->skey[0]);
for(i=0; i < n; i++ ) {
mpi_free( sk->skey[i] );
sk->skey[i] = NULL;
}
}
void
free_secret_key( PKT_secret_key *sk )
{
release_secret_key_parts( sk );
m_free(sk);
}
PKT_secret_key *
copy_secret_key( PKT_secret_key *d, PKT_secret_key *s )
{
int n, i;
if( !d )
d = m_alloc(sizeof *d);
memcpy( d, s, sizeof *d );
n = pubkey_get_nskey( s->pubkey_algo );
if( !n )
d->skey[0] = mpi_copy(s->skey[0]);
else {
for(i=0; i < n; i++ )
d->skey[i] = mpi_copy( s->skey[i] );
}
return d;
}
void
free_comment( PKT_comment *rem )
{
m_free(rem);
}
void
free_attributes(PKT_user_id *uid)
{
m_free(uid->attribs);
m_free(uid->attrib_data);
uid->attribs=NULL;
uid->attrib_data=NULL;
uid->attrib_len=0;
}
void
free_user_id (PKT_user_id *uid)
{
assert (uid->ref > 0);
if (--uid->ref)
return;
free_attributes(uid);
m_free (uid->prefs);
m_free (uid->namehash);
m_free (uid);
}
void
free_compressed( PKT_compressed *zd )
{
if( zd->buf ) { /* have to skip some bytes */
/* don't have any information about the length, so
* we assume this is the last packet */
while( iobuf_read( zd->buf, NULL, 1<<30 ) != -1 )
;
}
m_free(zd);
}
void
free_encrypted( PKT_encrypted *ed )
{
if( ed->buf ) { /* have to skip some bytes */
if( iobuf_in_block_mode(ed->buf) ) {
while( iobuf_read( ed->buf, NULL, 1<<30 ) != -1 )
;
}
else {
while( ed->len ) { /* skip the packet */
int n = iobuf_read( ed->buf, NULL, ed->len );
if( n == -1 )
ed->len = 0;
else
ed->len -= n;
}
}
}
m_free(ed);
}
void
free_plaintext( PKT_plaintext *pt )
{
if( pt->buf ) { /* have to skip some bytes */
if( iobuf_in_block_mode(pt->buf) ) {
while( iobuf_read( pt->buf, NULL, 1<<30 ) != -1 )
;
}
else {
while( pt->len ) { /* skip the packet */
int n = iobuf_read( pt->buf, NULL, pt->len );
if( n == -1 )
pt->len = 0;
else
pt->len -= n;
}
}
}
m_free(pt);
}
/****************
* Free the packet in pkt.
*/
void
free_packet( PACKET *pkt )
{
if( !pkt || !pkt->pkt.generic )
return;
if( DBG_MEMORY )
log_debug("free_packet() type=%d\n", pkt->pkttype );
switch( pkt->pkttype ) {
case PKT_SIGNATURE:
free_seckey_enc( pkt->pkt.signature );
break;
case PKT_PUBKEY_ENC:
free_pubkey_enc( pkt->pkt.pubkey_enc );
break;
case PKT_SYMKEY_ENC:
free_symkey_enc( pkt->pkt.symkey_enc );
break;
case PKT_PUBLIC_KEY:
case PKT_PUBLIC_SUBKEY:
free_public_key( pkt->pkt.public_key );
break;
case PKT_SECRET_KEY:
case PKT_SECRET_SUBKEY:
free_secret_key( pkt->pkt.secret_key );
break;
case PKT_COMMENT:
free_comment( pkt->pkt.comment );
break;
case PKT_USER_ID:
free_user_id( pkt->pkt.user_id );
break;
case PKT_COMPRESSED:
free_compressed( pkt->pkt.compressed);
break;
case PKT_ENCRYPTED:
case PKT_ENCRYPTED_MDC:
free_encrypted( pkt->pkt.encrypted );
break;
case PKT_PLAINTEXT:
free_plaintext( pkt->pkt.plaintext );
break;
default:
m_free( pkt->pkt.generic );
break;
}
pkt->pkt.generic = NULL;
}
/****************
* returns 0 if they match.
*/
int
cmp_public_keys( PKT_public_key *a, PKT_public_key *b )
{
int n, i;
if( a->timestamp != b->timestamp )
return -1;
if( a->version < 4 && a->expiredate != b->expiredate )
return -1;
if( a->pubkey_algo != b->pubkey_algo )
return -1;
n = pubkey_get_npkey( b->pubkey_algo );
if( !n )
return -1; /* can't compare due to unknown algorithm */
for(i=0; i < n; i++ ) {
if( mpi_cmp( a->pkey[i], b->pkey[i] ) )
return -1;
}
return 0;
}
/****************
* Returns 0 if they match.
* We only compare the public parts.
*/
int
cmp_secret_keys( PKT_secret_key *a, PKT_secret_key *b )
{
int n, i;
if( a->timestamp != b->timestamp )
return -1;
if( a->version < 4 && a->expiredate != b->expiredate )
return -1;
if( a->pubkey_algo != b->pubkey_algo )
return -1;
n = pubkey_get_npkey( b->pubkey_algo );
if( !n )
return -1; /* can't compare due to unknown algorithm */
for(i=0; i < n; i++ ) {
if( mpi_cmp( a->skey[i], b->skey[i] ) )
return -1;
}
return 0;
}
/****************
* Returns 0 if they match.
*/
int
cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
{
int n, i;
if( pk->timestamp != sk->timestamp )
return -1;
if( pk->version < 4 && pk->expiredate != sk->expiredate )
return -1;
if( pk->pubkey_algo != sk->pubkey_algo )
return -1;
n = pubkey_get_npkey( pk->pubkey_algo );
if( !n )
return -1; /* can't compare due to unknown algorithm */
for(i=0; i < n; i++ ) {
if( mpi_cmp( pk->pkey[i] , sk->skey[i] ) )
return -1;
}
return 0;
}
int
cmp_signatures( PKT_signature *a, PKT_signature *b )
{
int n, i;
if( a->keyid[0] != b->keyid[0] )
return -1;
if( a->keyid[1] != b->keyid[1] )
return -1;
if( a->pubkey_algo != b->pubkey_algo )
return -1;
n = pubkey_get_nsig( a->pubkey_algo );
if( !n )
return -1; /* can't compare due to unknown algorithm */
for(i=0; i < n; i++ ) {
if( mpi_cmp( a->data[i] , b->data[i] ) )
return -1;
}
return 0;
}
/****************
* Returns: true if the user ids do not match
*/
int
cmp_user_ids( PKT_user_id *a, PKT_user_id *b )
{
int res=1;
if( a == b )
return 0;
if( a->attrib_data && b->attrib_data )
{
res = a->attrib_len - b->attrib_len;
if( !res )
res = memcmp( a->attrib_data, b->attrib_data, a->attrib_len );
}
else if( !a->attrib_data && !b->attrib_data )
{
res = a->len - b->len;
if( !res )
res = memcmp( a->name, b->name, a->len );
}
return res;
}

3137
g10/g10.c Normal file

File diff suppressed because it is too large Load diff

2611
g10/getkey.c Normal file

File diff suppressed because it is too large Load diff

396
g10/gpgv.c Normal file
View file

@ -0,0 +1,396 @@
/* gpgv.c - The GnuPG signature verify utility
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#ifdef HAVE_DOSISH_SYSTEM
#include <fcntl.h> /* for setmode() */
#endif
#define INCLUDED_BY_MAIN_MODULE 1
#include "packet.h"
#include "iobuf.h"
#include "memory.h"
#include "util.h"
#include "main.h"
#include "options.h"
#include "keydb.h"
#include "trustdb.h"
#include "mpi.h"
#include "cipher.h"
#include "filter.h"
#include "ttyio.h"
#include "i18n.h"
#include "status.h"
#include "g10defs.h"
enum cmd_and_opt_values { aNull = 0,
oQuiet = 'q',
oVerbose = 'v',
oBatch = 500,
oKeyring,
oIgnoreTimeConflict,
oStatusFD,
oLoggerFD,
oHomedir,
aTest };
static ARGPARSE_OPTS opts[] = {
{ 301, NULL, 0, N_("@\nOptions:\n ") },
{ oVerbose, "verbose", 0, N_("verbose") },
{ oQuiet, "quiet", 0, N_("be somewhat more quiet") },
{ oKeyring, "keyring" ,2, N_("take the keys from this keyring")},
{ oIgnoreTimeConflict, "ignore-time-conflict", 0,
N_("make timestamp conflicts only a warning") },
{ oStatusFD, "status-fd" ,1, N_("|FD|write status info to this FD") },
{ oLoggerFD, "logger-fd",1, "@" },
{ oHomedir, "homedir", 2, "@" }, /* defaults to "~/.gnupg" */
{0} };
int g10_errors_seen = 0;
#ifdef __riscos__
RISCOS_GLOBAL_STATICS("GnuPG (gpgv) Heap")
#endif /* __riscos__ */
const char *
strusage( int level )
{
const char *p;
switch( level ) {
case 11: p = "gpgv (GnuPG)";
break;
case 13: p = VERSION; break;
case 17: p = PRINTABLE_OS_NAME; break;
case 19: p =
_("Please report bugs to <gnupg-bugs@gnu.org>.\n");
break;
case 1:
case 40: p =
_("Usage: gpgv [options] [files] (-h for help)");
break;
case 41: p =
_("Syntax: gpg [options] [files]\n"
"Check signatures against known trusted keys\n");
break;
default: p = default_strusage(level);
}
return p;
}
static void
i18n_init(void)
{
#ifdef USE_SIMPLE_GETTEXT
set_gettext_file( PACKAGE );
#else
#ifdef ENABLE_NLS
#ifdef HAVE_LC_MESSAGES
setlocale( LC_TIME, "" );
setlocale( LC_MESSAGES, "" );
#else
setlocale( LC_ALL, "" );
#endif
bindtextdomain( PACKAGE, G10_LOCALEDIR );
textdomain( PACKAGE );
#endif
#endif
}
int
main( int argc, char **argv )
{
ARGPARSE_ARGS pargs;
int rc=0;
STRLIST sl;
STRLIST nrings=NULL;
unsigned configlineno;
#ifdef __riscos__
riscos_global_defaults();
#endif /* __riscos__ */
log_set_name("gpgv");
init_signals();
i18n_init();
opt.command_fd = -1; /* no command fd */
opt.pgp2_workarounds = 1;
opt.keyserver_options.auto_key_retrieve = 1;
opt.trust_model = TM_ALWAYS;
opt.batch = 1;
#if defined (__MINGW32__)
opt.homedir = read_w32_registry_string( NULL, "Software\\GNU\\GnuPG", "HomeDir" );
#else
opt.homedir = getenv("GNUPGHOME");
#endif
if( !opt.homedir || !*opt.homedir ) {
opt.homedir = GNUPG_HOMEDIR;
}
tty_no_terminal(1);
tty_batchmode(1);
disable_dotlock();
set_native_charset (NULL); /* Try to auto set the character set */
pargs.argc = &argc;
pargs.argv = &argv;
pargs.flags= 1; /* do not remove the args */
while( optfile_parse( NULL, NULL, &configlineno, &pargs, opts) ) {
switch( pargs.r_opt ) {
case oQuiet: opt.quiet = 1; break;
case oVerbose: g10_opt_verbose++;
opt.verbose++; opt.list_sigs=1; break;
case oKeyring: append_to_strlist( &nrings, pargs.r.ret_str); break;
case oStatusFD: set_status_fd( pargs.r.ret_int ); break;
case oLoggerFD: log_set_logfile( NULL, pargs.r.ret_int ); break;
case oHomedir: opt.homedir = pargs.r.ret_str; break;
case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
default : pargs.err = 2; break;
}
}
if( log_get_errorcount(0) )
g10_exit(2);
g10_opt_homedir = opt.homedir;
if( opt.verbose > 1 )
set_packet_list_mode(1);
if( !nrings ) /* no keyring given: use default one */
keydb_add_resource ("trustedkeys" EXTSEP_S "gpg", 0, 0);
for(sl = nrings; sl; sl = sl->next )
keydb_add_resource (sl->d, 0, 0 );
FREE_STRLIST(nrings);
if( (rc = verify_signatures( argc, argv ) ))
log_error("verify signatures failed: %s\n", g10_errstr(rc) );
/* cleanup */
g10_exit(0);
return 8; /*NEVER REACHED*/
}
void
g10_exit( int rc )
{
rc = rc? rc : log_get_errorcount(0)? 2 :
g10_errors_seen? 1 : 0;
exit(rc );
}
/* Stub:
* We have to override the trustcheck from pkclist.c becuase
* this utility assumes that all keys in the keyring are trustworthy
*/
int
check_signatures_trust( PKT_signature *sig )
{
return 0;
}
/* Stub:
* We don't have the trustdb , so we have to provide some stub functions
* instead
*/
int
cache_disabled_value(PKT_public_key *pk)
{
return 0;
}
int
get_validity_info (PKT_public_key *pk, PKT_user_id *uid)
{
return '?';
}
unsigned int
get_validity (PKT_public_key *pk, PKT_user_id *uid)
{
return 0;
}
const char *
trust_value_to_string (unsigned int value)
{
return "err";
}
/* Stub: */
int
get_ownertrust_info (PKT_public_key *pk)
{
return '?';
}
unsigned int
get_ownertrust (PKT_public_key *pk)
{
return TRUST_UNKNOWN;
}
/* Stub:
* Because we only work with trusted keys, it does not make sense to
* get them from a keyserver
*/
int
keyserver_import_keyid( u32 *keyid, void *dummy )
{
return -1;
}
/* Stub:
* No encryption here but mainproc links to these functions.
*/
int
get_session_key( PKT_pubkey_enc *k, DEK *dek )
{
return G10ERR_GENERAL;
}
/* Stub: */
int
get_override_session_key( DEK *dek, const char *string )
{
return G10ERR_GENERAL;
}
/* Stub: */
int
decrypt_data( void *procctx, PKT_encrypted *ed, DEK *dek )
{
return G10ERR_GENERAL;
}
/* Stub:
* No interactive commnds, so we don't need the helptexts
*/
void
display_online_help( const char *keyword )
{
}
/* Stub:
* We don't use secret keys, but getkey.c links to this
*/
int
check_secret_key( PKT_secret_key *sk, int n )
{
return G10ERR_GENERAL;
}
/* Stub:
* No secret key, so no passphrase needed
*/
DEK *
passphrase_to_dek( u32 *keyid, int pubkey_algo,
int cipher_algo, STRING2KEY *s2k, int mode,
const char *tmp, int *canceled)
{
if (canceled)
*canceled = 0;
return NULL;
}
/* Stubs to avoid linking to photoid.c */
void show_photos(const struct user_attribute *attrs,int count,PKT_public_key *pk) {}
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len) {return 0;}
char *image_type_to_string(byte type,int string) {return NULL;}
/* Stubs to void linking to ../cipher/cipher.c */
int string_to_cipher_algo( const char *string ) { return 0; }
const char *cipher_algo_to_string( int algo ) { return "?";}
void disable_cipher_algo( int algo ) {}
int check_cipher_algo( int algo ) { return -1;}
unsigned int cipher_get_keylen( int algo ) { return 0; }
unsigned int cipher_get_blocksize( int algo ) {return 0;}
CIPHER_HANDLE cipher_open( int algo, int mode, int secure ) { return NULL;}
void cipher_close( CIPHER_HANDLE c ) {}
int cipher_setkey( CIPHER_HANDLE c, byte *key, unsigned keylen ) { return -1;}
void cipher_setiv( CIPHER_HANDLE c, const byte *iv, unsigned ivlen ){}
void cipher_encrypt( CIPHER_HANDLE c, byte *outbuf,
byte *inbuf, unsigned nbytes ) {}
void cipher_decrypt( CIPHER_HANDLE c, byte *outbuf,
byte *inbuf, unsigned nbytes ) {}
void cipher_sync( CIPHER_HANDLE c ) {}
/* Stubs to avoid linking to ../cipher/random.c */
void random_dump_stats(void) {}
int quick_random_gen( int onoff ) { return -1;}
void randomize_buffer( byte *buffer, size_t length, int level ) {}
int random_is_faked() { return -1;}
byte *get_random_bits( size_t nbits, int level, int secure ) { return NULL;}
void set_random_seed_file( const char *name ) {}
void update_random_seed_file() {}
void fast_random_poll() {}
/* Stubs to avoid linking of ../cipher/primegen.c */
void register_primegen_progress ( void (*cb)( void *, int), void *cb_data ) {}
MPI generate_secret_prime( unsigned nbits ) { return NULL;}
MPI generate_public_prime( unsigned nbits ) { return NULL;}
MPI generate_elg_prime( int mode, unsigned pbits, unsigned qbits,
MPI g, MPI **ret_factors ) { return NULL;}
/* Do not link to ../cipher/rndlinux.c */
void rndlinux_constructor(void) {}
/* Stubs to avoid linking to ../util/ttyio.c */
int tty_batchmode( int onoff ) { return 0; }
void tty_printf( const char *fmt, ... ) { }
void tty_print_string( byte *p, size_t n ) { }
void tty_print_utf8_string( byte *p, size_t n ) {}
void tty_print_utf8_string2( byte *p, size_t n, size_t max_n ) {}
char *tty_get( const char *prompt ) { return NULL;}
char *tty_get_hidden( const char *prompt ) {return NULL; }
void tty_kill_prompt(void) {}
int tty_get_answer_is_yes( const char *prompt ) {return 0;}
int tty_no_terminal(int onoff) {return 0;}
/* We do not do any locking, so use these stubs here */
void disable_dotlock(void) {}
DOTLOCK create_dotlock( const char *file_to_lock ) { return NULL; }
int make_dotlock( DOTLOCK h, long timeout ) { return 0;}
int release_dotlock( DOTLOCK h ) {return 0;}
void remove_lockfiles(void) {}

1879
g10/import.c Normal file

File diff suppressed because it is too large Load diff

399
g10/kbnode.c Normal file
View file

@ -0,0 +1,399 @@
/* kbnode.c - keyblock node utility functions
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#include "memory.h"
#include "packet.h"
#include "keydb.h"
#define USE_UNUSED_NODES 1
static KBNODE unused_nodes;
static KBNODE
alloc_node(void)
{
KBNODE n;
n = unused_nodes;
if( n )
unused_nodes = n->next;
else
n = m_alloc( sizeof *n );
n->next = NULL;
n->pkt = NULL;
n->flag = 0;
n->private_flag=0;
n->recno = 0;
return n;
}
static void
free_node( KBNODE n )
{
if( n ) {
#if USE_UNUSED_NODES
n->next = unused_nodes;
unused_nodes = n;
#else
m_free( n );
#endif
}
}
KBNODE
new_kbnode( PACKET *pkt )
{
KBNODE n = alloc_node();
n->pkt = pkt;
return n;
}
KBNODE
clone_kbnode( KBNODE node )
{
KBNODE n = alloc_node();
n->pkt = node->pkt;
n->private_flag = node->private_flag | 2; /* mark cloned */
return n;
}
void
release_kbnode( KBNODE n )
{
KBNODE n2;
while( n ) {
n2 = n->next;
if( !is_cloned_kbnode(n) ) {
free_packet( n->pkt );
m_free( n->pkt );
}
free_node( n );
n = n2;
}
}
/****************
* Delete NODE.
* Note: This only works with walk_kbnode!!
*/
void
delete_kbnode( KBNODE node )
{
node->private_flag |= 1;
}
/****************
* Append NODE to ROOT. ROOT must exist!
*/
void
add_kbnode( KBNODE root, KBNODE node )
{
KBNODE n1;
for(n1=root; n1->next; n1 = n1->next)
;
n1->next = node;
}
/****************
* Insert NODE into the list after root but before a packet which is not of
* type PKTTYPE
* (only if PKTTYPE != 0)
*/
void
insert_kbnode( KBNODE root, KBNODE node, int pkttype )
{
if( !pkttype ) {
node->next = root->next;
root->next = node;
}
else {
KBNODE n1;
for(n1=root; n1->next; n1 = n1->next)
if( pkttype != n1->next->pkt->pkttype ) {
node->next = n1->next;
n1->next = node;
return;
}
/* no such packet, append */
node->next = NULL;
n1->next = node;
}
}
/****************
* Find the previous node (if PKTTYPE = 0) or the previous node
* with pkttype PKTTYPE in the list starting with ROOT of NODE.
*/
KBNODE
find_prev_kbnode( KBNODE root, KBNODE node, int pkttype )
{
KBNODE n1;
for (n1=NULL; root && root != node; root = root->next ) {
if (!pkttype ||root->pkt->pkttype == pkttype)
n1 = root;
}
return n1;
}
/****************
* Ditto, but find the next packet. The behaviour is trivial if
* PKTTYPE is 0 but if it is specified, the next node with a packet
* of this type is returned. The function has some knowledge about
* the valid ordering of packets: e.g. if the next signature packet
* is requested, the function will not return one if it encounters
* a user-id.
*/
KBNODE
find_next_kbnode( KBNODE node, int pkttype )
{
for( node=node->next ; node; node = node->next ) {
if( !pkttype )
return node;
else if( pkttype == PKT_USER_ID
&& ( node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_SECRET_KEY ) )
return NULL;
else if( pkttype == PKT_SIGNATURE
&& ( node->pkt->pkttype == PKT_USER_ID
|| node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_SECRET_KEY ) )
return NULL;
else if( node->pkt->pkttype == pkttype )
return node;
}
return NULL;
}
KBNODE
find_kbnode( KBNODE node, int pkttype )
{
for( ; node; node = node->next ) {
if( node->pkt->pkttype == pkttype )
return node;
}
return NULL;
}
/****************
* Walk through a list of kbnodes. This function returns
* the next kbnode for each call; before using the function the first
* time, the caller must set CONTEXT to NULL (This has simply the effect
* to start with ROOT).
*/
KBNODE
walk_kbnode( KBNODE root, KBNODE *context, int all )
{
KBNODE n;
do {
if( !*context ) {
*context = root;
n = root;
}
else {
n = (*context)->next;
*context = n;
}
} while( !all && n && is_deleted_kbnode(n) );
return n;
}
void
clear_kbnode_flags( KBNODE n )
{
for( ; n; n = n->next ) {
n->flag = 0;
}
}
/****************
* Commit changes made to the kblist at ROOT. Note that ROOT my change,
* and it is therefore passed by reference.
* The function has the effect of removing all nodes marked as deleted.
* returns true if any node has been changed
*/
int
commit_kbnode( KBNODE *root )
{
KBNODE n, nl;
int changed = 0;
for( n = *root, nl=NULL; n; n = nl->next ) {
if( is_deleted_kbnode(n) ) {
if( n == *root )
*root = nl = n->next;
else
nl->next = n->next;
if( !is_cloned_kbnode(n) ) {
free_packet( n->pkt );
m_free( n->pkt );
}
free_node( n );
changed = 1;
}
else
nl = n;
}
return changed;
}
void
remove_kbnode( KBNODE *root, KBNODE node )
{
KBNODE n, nl;
for( n = *root, nl=NULL; n; n = nl->next ) {
if( n == node ) {
if( n == *root )
*root = nl = n->next;
else
nl->next = n->next;
if( !is_cloned_kbnode(n) ) {
free_packet( n->pkt );
m_free( n->pkt );
}
free_node( n );
}
else
nl = n;
}
}
/****************
* Move NODE behind right after WHERE or to the beginning if WHERE is NULL.
*/
void
move_kbnode( KBNODE *root, KBNODE node, KBNODE where )
{
KBNODE tmp, prev;
if( !root || !*root || !node )
return; /* sanity check */
for( prev = *root; prev && prev->next != node; prev = prev->next )
;
if( !prev )
return; /* node is not in the list */
if( !where ) { /* move node before root */
if( node == *root ) /* move to itself */
return;
prev->next = node->next;
node->next = *root;
*root = node;
return;
}
/* move it after where */
if( node == where )
return;
tmp = node->next;
node->next = where->next;
where->next = node;
prev->next = tmp;
}
void
dump_kbnode( KBNODE node )
{
for(; node; node = node->next ) {
const char *s;
switch( node->pkt->pkttype ) {
case 0: s="empty"; break;
case PKT_PUBLIC_KEY: s="public-key"; break;
case PKT_SECRET_KEY: s="secret-key"; break;
case PKT_SECRET_SUBKEY: s= "secret-subkey"; break;
case PKT_PUBKEY_ENC: s="public-enc"; break;
case PKT_SIGNATURE: s="signature"; break;
case PKT_ONEPASS_SIG: s="onepass-sig"; break;
case PKT_USER_ID: s="user-id"; break;
case PKT_PUBLIC_SUBKEY: s="public-subkey"; break;
case PKT_COMMENT: s="comment"; break;
case PKT_RING_TRUST: s="trust"; break;
case PKT_PLAINTEXT: s="plaintext"; break;
case PKT_COMPRESSED: s="compressed"; break;
case PKT_ENCRYPTED: s="encrypted"; break;
case PKT_GPG_CONTROL: s="gpg-control"; break;
default: s="unknown"; break;
}
fprintf(stderr, "node %p %02x/%02x type=%s",
node, node->flag, node->private_flag, s);
if( node->pkt->pkttype == PKT_USER_ID ) {
PKT_user_id *uid = node->pkt->pkt.user_id;
fputs(" \"", stderr);
print_string( stderr, uid->name, uid->len, 0 );
fprintf (stderr, "\" %c%c%c%c\n",
uid->is_expired? 'e':'.',
uid->is_revoked? 'r':'.',
uid->created? 'v':'.',
uid->is_primary? 'p':'.' );
}
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
fprintf(stderr, " class=%02x keyid=%08lX ts=%lu\n",
node->pkt->pkt.signature->sig_class,
(ulong)node->pkt->pkt.signature->keyid[1],
(ulong)node->pkt->pkt.signature->timestamp);
}
else if( node->pkt->pkttype == PKT_GPG_CONTROL ) {
fprintf(stderr, " ctrl=%d len=%u\n",
node->pkt->pkt.gpg_control->control,
(unsigned int)node->pkt->pkt.gpg_control->datalen);
}
else if( node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
PKT_public_key *pk = node->pkt->pkt.public_key;
fprintf(stderr, " keyid=%08lX a=%d u=%d %c%c%c%c\n",
(ulong)keyid_from_pk( pk, NULL ),
pk->pubkey_algo, pk->pubkey_usage,
pk->has_expired? 'e':'.',
pk->is_revoked? 'r':'.',
pk->is_valid? 'v':'.',
pk->mdc_feature? 'm':'.');
}
else
fputs("\n", stderr);
}
}

724
g10/keydb.c Normal file
View file

@ -0,0 +1,724 @@
/* keydb.c - key database dispatcher
* Copyright (C) 2001, 2002, 2003 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "util.h"
#include "options.h"
#include "main.h" /*try_make_homedir ()*/
#include "packet.h"
#include "keyring.h"
#include "keydb.h"
#include "i18n.h"
static int active_handles;
typedef enum {
KEYDB_RESOURCE_TYPE_NONE = 0,
KEYDB_RESOURCE_TYPE_KEYRING
} KeydbResourceType;
#define MAX_KEYDB_RESOURCES 40
struct resource_item {
KeydbResourceType type;
union {
KEYRING_HANDLE kr;
} u;
void *token;
int secret;
};
static struct resource_item all_resources[MAX_KEYDB_RESOURCES];
static int used_resources;
static void *primary_keyring=NULL;
struct keydb_handle {
int locked;
int found;
int current;
int used; /* items in active */
struct resource_item active[MAX_KEYDB_RESOURCES];
};
static int lock_all (KEYDB_HANDLE hd);
static void unlock_all (KEYDB_HANDLE hd);
/*
* Register a resource (which currently may only be a keyring file).
* The first keyring which is added by this function is
* created if it does not exist.
* Note: this function may be called before secure memory is
* available.
* Flag 1 == force
* Flag 2 == default
*/
int
keydb_add_resource (const char *url, int flags, int secret)
{
static int any_secret, any_public;
const char *resname = url;
IOBUF iobuf = NULL;
char *filename = NULL;
int force=(flags&1);
int rc = 0;
KeydbResourceType rt = KEYDB_RESOURCE_TYPE_NONE;
void *token;
/* Do we have an URL?
* gnupg-ring:filename := this is a plain keyring
* filename := See what is is, but create as plain keyring.
*/
if (strlen (resname) > 11) {
if (!strncmp( resname, "gnupg-ring:", 11) ) {
rt = KEYDB_RESOURCE_TYPE_KEYRING;
resname += 11;
}
#if !defined(HAVE_DRIVE_LETTERS) && !defined(__riscos__)
else if (strchr (resname, ':')) {
log_error ("invalid key resource URL `%s'\n", url );
rc = G10ERR_GENERAL;
goto leave;
}
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
}
if (*resname != DIRSEP_C ) { /* do tilde expansion etc */
if (strchr(resname, DIRSEP_C) )
filename = make_filename (resname, NULL);
else
filename = make_filename (opt.homedir, resname, NULL);
}
else
filename = m_strdup (resname);
if (!force)
force = secret? !any_secret : !any_public;
/* see whether we can determine the filetype */
if (rt == KEYDB_RESOURCE_TYPE_NONE) {
FILE *fp = fopen( filename, "rb" );
if (fp) {
u32 magic;
if (fread( &magic, 4, 1, fp) == 1 ) {
if (magic == 0x13579ace || magic == 0xce9a5713)
; /* GDBM magic - no more support */
else
rt = KEYDB_RESOURCE_TYPE_KEYRING;
}
else /* maybe empty: assume ring */
rt = KEYDB_RESOURCE_TYPE_KEYRING;
fclose( fp );
}
else /* no file yet: create ring */
rt = KEYDB_RESOURCE_TYPE_KEYRING;
}
switch (rt) {
case KEYDB_RESOURCE_TYPE_NONE:
log_error ("unknown type of key resource `%s'\n", url );
rc = G10ERR_GENERAL;
goto leave;
case KEYDB_RESOURCE_TYPE_KEYRING:
if (access(filename, F_OK))
{ /* file does not exist */
mode_t oldmask;
char *last_slash_in_filename;
if (!force)
{
rc = G10ERR_OPEN_FILE;
goto leave;
}
last_slash_in_filename = strrchr (filename, DIRSEP_C);
*last_slash_in_filename = 0;
if (access(filename, F_OK))
{ /* On the first time we try to create the default
homedir and check again. */
static int tried;
if (!tried)
{
tried = 1;
try_make_homedir (filename);
}
if (access (filename, F_OK))
{
rc = G10ERR_OPEN_FILE;
*last_slash_in_filename = DIRSEP_C;
goto leave;
}
}
*last_slash_in_filename = DIRSEP_C;
oldmask=umask(077);
iobuf = iobuf_create (filename);
umask(oldmask);
if (!iobuf)
{
log_error ( _("error creating keyring `%s': %s\n"),
filename, strerror(errno));
rc = G10ERR_OPEN_FILE;
goto leave;
}
if (!opt.quiet)
log_info (_("keyring `%s' created\n"), filename);
iobuf_close (iobuf);
iobuf = NULL;
/* must invalidate that ugly cache */
iobuf_ioctl (NULL, 2, 0, (char*)filename);
} /* end file creation */
if(keyring_register_filename (filename, secret, &token))
{
if (used_resources >= MAX_KEYDB_RESOURCES)
rc = G10ERR_RESOURCE_LIMIT;
else
{
if(flags&2)
primary_keyring=token;
all_resources[used_resources].type = rt;
all_resources[used_resources].u.kr = NULL; /* Not used here */
all_resources[used_resources].token = token;
all_resources[used_resources].secret = secret;
used_resources++;
}
}
else
{
/* This keyring was already registered, so ignore it.
However, we can still mark it as primary even if it was
already registered. */
if(flags&2)
primary_keyring=token;
}
break;
default:
log_error ("resource type of `%s' not supported\n", url);
rc = G10ERR_GENERAL;
goto leave;
}
/* fixme: check directory permissions and print a warning */
leave:
if (rc)
log_error ("keyblock resource `%s': %s\n", filename, g10_errstr(rc));
else if (secret)
any_secret = 1;
else
any_public = 1;
m_free (filename);
return rc;
}
KEYDB_HANDLE
keydb_new (int secret)
{
KEYDB_HANDLE hd;
int i, j;
hd = m_alloc_clear (sizeof *hd);
hd->found = -1;
assert (used_resources <= MAX_KEYDB_RESOURCES);
for (i=j=0; i < used_resources; i++)
{
if (!all_resources[i].secret != !secret)
continue;
switch (all_resources[i].type)
{
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
hd->active[j].type = all_resources[i].type;
hd->active[j].token = all_resources[i].token;
hd->active[j].secret = all_resources[i].secret;
hd->active[j].u.kr = keyring_new (all_resources[i].token, secret);
if (!hd->active[j].u.kr) {
m_free (hd);
return NULL; /* fixme: release all previously allocated handles*/
}
j++;
break;
}
}
hd->used = j;
active_handles++;
return hd;
}
void
keydb_release (KEYDB_HANDLE hd)
{
int i;
if (!hd)
return;
assert (active_handles > 0);
active_handles--;
unlock_all (hd);
for (i=0; i < hd->used; i++) {
switch (hd->active[i].type) {
case KEYDB_RESOURCE_TYPE_NONE:
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
keyring_release (hd->active[i].u.kr);
break;
}
}
m_free (hd);
}
/*
* Return the name of the current resource. This is function first
* looks for the last found found, then for the current search
* position, and last returns the first available resource. The
* returned string is only valid as long as the handle exists. This
* function does only return NULL if no handle is specified, in all
* other error cases an empty string is returned.
*/
const char *
keydb_get_resource_name (KEYDB_HANDLE hd)
{
int idx;
const char *s = NULL;
if (!hd)
return NULL;
if ( hd->found >= 0 && hd->found < hd->used)
idx = hd->found;
else if ( hd->current >= 0 && hd->current < hd->used)
idx = hd->current;
else
idx = 0;
switch (hd->active[idx].type) {
case KEYDB_RESOURCE_TYPE_NONE:
s = NULL;
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
s = keyring_get_resource_name (hd->active[idx].u.kr);
break;
}
return s? s: "";
}
static int
lock_all (KEYDB_HANDLE hd)
{
int i, rc = 0;
for (i=0; !rc && i < hd->used; i++) {
switch (hd->active[i].type) {
case KEYDB_RESOURCE_TYPE_NONE:
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_lock (hd->active[i].u.kr, 1);
break;
}
}
if (rc) {
/* revert the already set locks */
for (i--; i >= 0; i--) {
switch (hd->active[i].type) {
case KEYDB_RESOURCE_TYPE_NONE:
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
keyring_lock (hd->active[i].u.kr, 0);
break;
}
}
}
else
hd->locked = 1;
return rc;
}
static void
unlock_all (KEYDB_HANDLE hd)
{
int i;
if (!hd->locked)
return;
for (i=hd->used-1; i >= 0; i--) {
switch (hd->active[i].type) {
case KEYDB_RESOURCE_TYPE_NONE:
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
keyring_lock (hd->active[i].u.kr, 0);
break;
}
}
hd->locked = 0;
}
/*
* Return the last found keyring. Caller must free it.
* The returned keyblock has the kbode flag bit 0 set for the node with
* the public key used to locate the keyblock or flag bit 1 set for
* the user ID node.
*/
int
keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
{
int rc = 0;
if (!hd)
return G10ERR_INV_ARG;
if ( hd->found < 0 || hd->found >= hd->used)
return -1; /* nothing found */
switch (hd->active[hd->found].type) {
case KEYDB_RESOURCE_TYPE_NONE:
rc = G10ERR_GENERAL; /* oops */
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
break;
}
return rc;
}
/*
* update the current keyblock with KB
*/
int
keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb)
{
int rc = 0;
if (!hd)
return G10ERR_INV_ARG;
if ( hd->found < 0 || hd->found >= hd->used)
return -1; /* nothing found */
if( opt.dry_run )
return 0;
rc = lock_all (hd);
if (rc)
return rc;
switch (hd->active[hd->found].type) {
case KEYDB_RESOURCE_TYPE_NONE:
rc = G10ERR_GENERAL; /* oops */
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_update_keyblock (hd->active[hd->found].u.kr, kb);
break;
}
unlock_all (hd);
return rc;
}
/*
* Insert a new KB into one of the resources.
*/
int
keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb)
{
int rc = -1;
int idx;
if (!hd)
return G10ERR_INV_ARG;
if( opt.dry_run )
return 0;
if ( hd->found >= 0 && hd->found < hd->used)
idx = hd->found;
else if ( hd->current >= 0 && hd->current < hd->used)
idx = hd->current;
else
return G10ERR_GENERAL;
rc = lock_all (hd);
if (rc)
return rc;
switch (hd->active[idx].type) {
case KEYDB_RESOURCE_TYPE_NONE:
rc = G10ERR_GENERAL; /* oops */
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
break;
}
unlock_all (hd);
return rc;
}
/*
* The current keyblock will be deleted.
*/
int
keydb_delete_keyblock (KEYDB_HANDLE hd)
{
int rc = -1;
if (!hd)
return G10ERR_INV_ARG;
if ( hd->found < 0 || hd->found >= hd->used)
return -1; /* nothing found */
if( opt.dry_run )
return 0;
rc = lock_all (hd);
if (rc)
return rc;
switch (hd->active[hd->found].type) {
case KEYDB_RESOURCE_TYPE_NONE:
rc = G10ERR_GENERAL; /* oops */
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_delete_keyblock (hd->active[hd->found].u.kr);
break;
}
unlock_all (hd);
return rc;
}
/*
* Locate the default writable key resource, so that the next
* operation (which is only relevant for inserts) will be done on this
* resource.
*/
int
keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved)
{
int rc;
if (!hd)
return G10ERR_INV_ARG;
rc = keydb_search_reset (hd); /* this does reset hd->current */
if (rc)
return rc;
/* If we have a primary set, try that one first */
if(primary_keyring)
{
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
{
if(hd->active[hd->current].token==primary_keyring)
{
if(keyring_is_writable (hd->active[hd->current].token))
return 0;
else
break;
}
}
rc = keydb_search_reset (hd); /* this does reset hd->current */
if (rc)
return rc;
}
for ( ; hd->current >= 0 && hd->current < hd->used; hd->current++)
{
switch (hd->active[hd->current].type)
{
case KEYDB_RESOURCE_TYPE_NONE:
BUG();
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
if (keyring_is_writable (hd->active[hd->current].token))
return 0; /* found (hd->current is set to it) */
break;
}
}
return -1;
}
/*
* Rebuild the caches of all key resources.
*/
void
keydb_rebuild_caches (void)
{
int i, rc;
for (i=0; i < used_resources; i++)
{
if (all_resources[i].secret)
continue;
switch (all_resources[i].type)
{
case KEYDB_RESOURCE_TYPE_NONE: /* ignore */
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_rebuild_cache (all_resources[i].token);
if (rc)
log_error (_("failed to rebuild keyring cache: %s\n"),
g10_errstr (rc));
break;
}
}
}
/*
* Start the next search on this handle right at the beginning
*/
int
keydb_search_reset (KEYDB_HANDLE hd)
{
int i, rc = 0;
if (!hd)
return G10ERR_INV_ARG;
hd->current = 0;
hd->found = -1;
/* and reset all resources */
for (i=0; !rc && i < hd->used; i++) {
switch (hd->active[i].type) {
case KEYDB_RESOURCE_TYPE_NONE:
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_search_reset (hd->active[i].u.kr);
break;
}
}
return rc;
}
/*
* Search through all keydb resources, starting at the current position,
* for a keyblock which contains one of the keys described in the DESC array.
*/
int
keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex)
{
int rc = -1;
if (!hd)
return G10ERR_INV_ARG;
while (rc == -1 && hd->current >= 0 && hd->current < hd->used) {
switch (hd->active[hd->current].type) {
case KEYDB_RESOURCE_TYPE_NONE:
BUG(); /* we should never see it here */
break;
case KEYDB_RESOURCE_TYPE_KEYRING:
rc = keyring_search (hd->active[hd->current].u.kr, desc,
ndesc, descindex);
break;
}
if (rc == -1) /* EOF -> switch to next resource */
hd->current++;
else if (!rc)
hd->found = hd->current;
}
return rc;
}
int
keydb_search_first (KEYDB_HANDLE hd)
{
KEYDB_SEARCH_DESC desc;
memset (&desc, 0, sizeof desc);
desc.mode = KEYDB_SEARCH_MODE_FIRST;
return keydb_search (hd, &desc, 1);
}
int
keydb_search_next (KEYDB_HANDLE hd)
{
KEYDB_SEARCH_DESC desc;
memset (&desc, 0, sizeof desc);
desc.mode = KEYDB_SEARCH_MODE_NEXT;
return keydb_search (hd, &desc, 1);
}
int
keydb_search_kid (KEYDB_HANDLE hd, u32 *kid)
{
KEYDB_SEARCH_DESC desc;
memset (&desc, 0, sizeof desc);
desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
desc.u.kid[0] = kid[0];
desc.u.kid[1] = kid[1];
return keydb_search (hd, &desc, 1);
}
int
keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr)
{
KEYDB_SEARCH_DESC desc;
memset (&desc, 0, sizeof desc);
desc.mode = KEYDB_SEARCH_MODE_FPR;
memcpy (desc.u.fpr, fpr, MAX_FINGERPRINT_LEN);
return keydb_search (hd, &desc, 1);
}

278
g10/keydb.h Normal file
View file

@ -0,0 +1,278 @@
/* keydb.h - Key database
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_KEYDB_H
#define G10_KEYDB_H
#include "types.h"
#include "global.h"
#include "packet.h"
#include "cipher.h"
/* What qualifies as a certification (rather than a signature?) */
#define IS_CERT(s) (IS_KEY_SIG(s) || IS_UID_SIG(s) || IS_SUBKEY_SIG(s) \
|| IS_KEY_REV(s) || IS_UID_REV(s) || IS_SUBKEY_REV(s))
#define IS_SIG(s) (!IS_CERT(s))
#define IS_KEY_SIG(s) ((s)->sig_class == 0x1f)
#define IS_UID_SIG(s) (((s)->sig_class & ~3) == 0x10)
#define IS_SUBKEY_SIG(s) ((s)->sig_class == 0x18)
#define IS_KEY_REV(s) ((s)->sig_class == 0x20)
#define IS_UID_REV(s) ((s)->sig_class == 0x30)
#define IS_SUBKEY_REV(s) ((s)->sig_class == 0x28)
struct getkey_ctx_s;
typedef struct getkey_ctx_s *GETKEY_CTX;
/****************
* A Keyblock is all packets which form an entire certificate;
* i.e. the public key, certificate, trust packets, user ids,
* signatures, and subkey.
*
* This structure is also used to bind arbitrary packets together.
*/
struct kbnode_struct {
KBNODE next;
PACKET *pkt;
int flag;
int private_flag;
ulong recno; /* used while updating the trustdb */
};
#define is_deleted_kbnode(a) ((a)->private_flag & 1)
#define is_cloned_kbnode(a) ((a)->private_flag & 2)
enum resource_type {
rt_UNKNOWN = 0,
rt_RING = 1
};
/****************
* A data structre to hold information about the external position
* of a keyblock.
*/
struct keyblock_pos_struct {
int resno; /* resource number */
enum resource_type rt;
off_t offset; /* position information */
unsigned count; /* length of the keyblock in packets */
IOBUF fp; /* used by enum_keyblocks */
int secret; /* working on a secret keyring */
PACKET *pkt; /* ditto */
int valid;
};
typedef struct keyblock_pos_struct KBPOS;
/* structure to hold a couple of public key certificates */
typedef struct pk_list *PK_LIST;
struct pk_list {
PK_LIST next;
PKT_public_key *pk;
int flags; /* flag bit 1==throw_keyid */
};
/* structure to hold a couple of secret key certificates */
typedef struct sk_list *SK_LIST;
struct sk_list {
SK_LIST next;
PKT_secret_key *sk;
int mark; /* not used */
};
/* structure to collect all information which can be used to
* identify a public key */
typedef struct pubkey_find_info *PUBKEY_FIND_INFO;
struct pubkey_find_info {
u32 keyid[2];
unsigned nbits;
byte pubkey_algo;
byte fingerprint[MAX_FINGERPRINT_LEN];
char userid[1];
};
typedef struct keydb_handle *KEYDB_HANDLE;
typedef enum {
KEYDB_SEARCH_MODE_NONE,
KEYDB_SEARCH_MODE_EXACT,
KEYDB_SEARCH_MODE_SUBSTR,
KEYDB_SEARCH_MODE_MAIL,
KEYDB_SEARCH_MODE_MAILSUB,
KEYDB_SEARCH_MODE_MAILEND,
KEYDB_SEARCH_MODE_WORDS,
KEYDB_SEARCH_MODE_SHORT_KID,
KEYDB_SEARCH_MODE_LONG_KID,
KEYDB_SEARCH_MODE_FPR16,
KEYDB_SEARCH_MODE_FPR20,
KEYDB_SEARCH_MODE_FPR,
KEYDB_SEARCH_MODE_FIRST,
KEYDB_SEARCH_MODE_NEXT
} KeydbSearchMode;
struct keydb_search_desc {
KeydbSearchMode mode;
int (*skipfnc)(void *,u32*);
void *skipfncvalue;
union {
const char *name;
char fpr[MAX_FINGERPRINT_LEN];
u32 kid[2];
} u;
int exact;
};
/*-- keydb.c --*/
/*
Flag 1 == force
Flag 2 == default
*/
int keydb_add_resource (const char *url, int flags, int secret);
KEYDB_HANDLE keydb_new (int secret);
void keydb_release (KEYDB_HANDLE hd);
const char *keydb_get_resource_name (KEYDB_HANDLE hd);
int keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
int keydb_update_keyblock (KEYDB_HANDLE hd, KBNODE kb);
int keydb_insert_keyblock (KEYDB_HANDLE hd, KBNODE kb);
int keydb_delete_keyblock (KEYDB_HANDLE hd);
int keydb_locate_writable (KEYDB_HANDLE hd, const char *reserved);
void keydb_rebuild_caches (void);
int keydb_search_reset (KEYDB_HANDLE hd);
#define keydb_search(a,b,c) keydb_search2((a),(b),(c),NULL)
int keydb_search2 (KEYDB_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex);
int keydb_search_first (KEYDB_HANDLE hd);
int keydb_search_next (KEYDB_HANDLE hd);
int keydb_search_kid (KEYDB_HANDLE hd, u32 *kid);
int keydb_search_fpr (KEYDB_HANDLE hd, const byte *fpr);
/*-- pkclist.c --*/
void show_revocation_reason( PKT_public_key *pk, int mode );
int check_signatures_trust( PKT_signature *sig );
void release_pk_list( PK_LIST pk_list );
int build_pk_list( STRLIST rcpts, PK_LIST *ret_pk_list, unsigned use );
int algo_available( preftype_t preftype, int algo, void *hint );
int select_algo_from_prefs( PK_LIST pk_list, int preftype,
int request, void *hint );
int select_mdc_from_pklist (PK_LIST pk_list);
/*-- skclist.c --*/
void release_sk_list( SK_LIST sk_list );
int build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list,
int unlock, unsigned use );
/*-- passphrase.h --*/
int have_static_passphrase(void);
void read_passphrase_from_fd( int fd );
void passphrase_clear_cache ( u32 *keyid, int algo );
DEK *passphrase_to_dek( u32 *keyid, int pubkey_algo,
int cipher_algo, STRING2KEY *s2k, int mode,
const char *tryagain_text, int *canceled);
void set_next_passphrase( const char *s );
char *get_last_passphrase(void);
/*-- getkey.c --*/
int classify_user_id( const char *name, KEYDB_SEARCH_DESC *desc);
void cache_public_key( PKT_public_key *pk );
void getkey_disable_caches(void);
int get_pubkey( PKT_public_key *pk, u32 *keyid );
int get_pubkey_fast ( PKT_public_key *pk, u32 *keyid );
KBNODE get_pubkeyblock( u32 *keyid );
int get_pubkey_byname( PKT_public_key *pk, const char *name,
KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd,
int include_disabled );
int get_pubkey_bynames( GETKEY_CTX *rx, PKT_public_key *pk,
STRLIST names, KBNODE *ret_keyblock );
int get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock );
void get_pubkey_end( GETKEY_CTX ctx );
int get_seckey( PKT_secret_key *sk, u32 *keyid );
int get_primary_seckey( PKT_secret_key *sk, u32 *keyid );
int get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint,
size_t fprint_len );
int get_pubkey_byfprint_fast (PKT_public_key *pk,
const byte *fprint, size_t fprint_len);
int get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
size_t fprint_len );
int get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid );
int seckey_available( u32 *keyid );
int get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock );
int get_seckey_bynames( GETKEY_CTX *rx, PKT_secret_key *sk,
STRLIST names, KBNODE *ret_keyblock );
int get_seckey_byfprint( PKT_secret_key *sk,
const byte *fprint, size_t fprint_len);
int get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock );
void get_seckey_end( GETKEY_CTX ctx );
int enum_secret_keys( void **context, PKT_secret_key *sk,
int with_subkeys, int with_spm );
void merge_keys_and_selfsig( KBNODE keyblock );
char*get_user_id_string( u32 *keyid );
char*get_user_id_string_printable( u32 *keyid );
char*get_long_user_id_string( u32 *keyid );
char*get_user_id( u32 *keyid, size_t *rn );
char*get_user_id_printable( u32 *keyid );
KEYDB_HANDLE get_ctx_handle(GETKEY_CTX ctx);
/*-- keyid.c --*/
int pubkey_letter( int algo );
u32 keyid_from_sk( PKT_secret_key *sk, u32 *keyid );
u32 keyid_from_pk( PKT_public_key *pk, u32 *keyid );
u32 keyid_from_sig( PKT_signature *sig, u32 *keyid );
u32 keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid );
byte *namehash_from_uid(PKT_user_id *uid);
unsigned nbits_from_pk( PKT_public_key *pk );
unsigned nbits_from_sk( PKT_secret_key *sk );
const char *datestr_from_pk( PKT_public_key *pk );
const char *datestr_from_sk( PKT_secret_key *sk );
const char *datestr_from_sig( PKT_signature *sig );
const char *expirestr_from_pk( PKT_public_key *pk );
const char *expirestr_from_sk( PKT_secret_key *sk );
const char *expirestr_from_sig( PKT_signature *sig );
const char *colon_strtime (u32 t);
const char *colon_datestr_from_pk (PKT_public_key *pk);
const char *colon_datestr_from_sk (PKT_secret_key *sk);
const char *colon_datestr_from_sig (PKT_signature *sig);
const char *colon_expirestr_from_sig (PKT_signature *sig);
byte *fingerprint_from_sk( PKT_secret_key *sk, byte *buf, size_t *ret_len );
byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len );
/*-- kbnode.c --*/
KBNODE new_kbnode( PACKET *pkt );
KBNODE clone_kbnode( KBNODE node );
void release_kbnode( KBNODE n );
void delete_kbnode( KBNODE node );
void add_kbnode( KBNODE root, KBNODE node );
void insert_kbnode( KBNODE root, KBNODE node, int pkttype );
void move_kbnode( KBNODE *root, KBNODE node, KBNODE where );
void remove_kbnode( KBNODE *root, KBNODE node );
KBNODE find_prev_kbnode( KBNODE root, KBNODE node, int pkttype );
KBNODE find_next_kbnode( KBNODE node, int pkttype );
KBNODE find_kbnode( KBNODE node, int pkttype );
KBNODE walk_kbnode( KBNODE root, KBNODE *context, int all );
void clear_kbnode_flags( KBNODE n );
int commit_kbnode( KBNODE *root );
void dump_kbnode( KBNODE node );
#endif /*G10_KEYDB_H*/

3672
g10/keyedit.c Normal file

File diff suppressed because it is too large Load diff

2523
g10/keygen.c Normal file

File diff suppressed because it is too large Load diff

518
g10/keyid.c Normal file
View file

@ -0,0 +1,518 @@
/* keyid.c - key ID and fingerprint handling
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <assert.h>
#include "util.h"
#include "main.h"
#include "packet.h"
#include "options.h"
#include "mpi.h"
#include "keydb.h"
#include "i18n.h"
int
pubkey_letter( int algo )
{
switch( algo ) {
case PUBKEY_ALGO_RSA: return 'R' ;
case PUBKEY_ALGO_RSA_E: return 'r' ;
case PUBKEY_ALGO_RSA_S: return 's' ;
case PUBKEY_ALGO_ELGAMAL_E: return 'g';
case PUBKEY_ALGO_ELGAMAL: return 'G' ;
case PUBKEY_ALGO_DSA: return 'D' ;
default: return '?';
}
}
static MD_HANDLE
do_fingerprint_md( PKT_public_key *pk )
{
MD_HANDLE md;
unsigned n;
unsigned nb[PUBKEY_MAX_NPKEY];
unsigned nn[PUBKEY_MAX_NPKEY];
byte *pp[PUBKEY_MAX_NPKEY];
int i;
int npkey = pubkey_get_npkey( pk->pubkey_algo );
md = md_open( pk->version < 4 ? DIGEST_ALGO_RMD160 : DIGEST_ALGO_SHA1, 0);
n = pk->version < 4 ? 8 : 6;
for(i=0; i < npkey; i++ ) {
nb[i] = mpi_get_nbits(pk->pkey[i]);
pp[i] = mpi_get_buffer( pk->pkey[i], nn+i, NULL );
n += 2 + nn[i];
}
md_putc( md, 0x99 ); /* ctb */
md_putc( md, n >> 8 ); /* 2 byte length header */
md_putc( md, n );
if( pk->version < 4 )
md_putc( md, 3 );
else
md_putc( md, 4 );
{ u32 a = pk->timestamp;
md_putc( md, a >> 24 );
md_putc( md, a >> 16 );
md_putc( md, a >> 8 );
md_putc( md, a );
}
if( pk->version < 4 ) {
u16 a;
if( pk->expiredate )
a = (u16)((pk->expiredate - pk->timestamp) / 86400L);
else
a = 0;
md_putc( md, a >> 8 );
md_putc( md, a );
}
md_putc( md, pk->pubkey_algo );
for(i=0; i < npkey; i++ ) {
md_putc( md, nb[i]>>8);
md_putc( md, nb[i] );
md_write( md, pp[i], nn[i] );
m_free(pp[i]);
}
md_final( md );
return md;
}
static MD_HANDLE
do_fingerprint_md_sk( PKT_secret_key *sk )
{
PKT_public_key pk;
int npkey = pubkey_get_npkey( sk->pubkey_algo ); /* npkey is correct! */
int i;
pk.pubkey_algo = sk->pubkey_algo;
pk.version = sk->version;
pk.timestamp = sk->timestamp;
pk.expiredate = sk->expiredate;
pk.pubkey_algo = sk->pubkey_algo;
for( i=0; i < npkey; i++ )
pk.pkey[i] = sk->skey[i];
return do_fingerprint_md( &pk );
}
/****************
* Get the keyid from the secret key and put it into keyid
* if this is not NULL. Return the 32 low bits of the keyid.
*/
u32
keyid_from_sk( PKT_secret_key *sk, u32 *keyid )
{
u32 lowbits;
u32 dummy_keyid[2];
if( !keyid )
keyid = dummy_keyid;
if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
lowbits = pubkey_get_npkey(sk->pubkey_algo) ?
mpi_get_keyid( sk->skey[0], keyid ) : 0; /* take n */
}
else {
const byte *dp;
MD_HANDLE md;
md = do_fingerprint_md_sk(sk);
dp = md_read( md, 0 );
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
lowbits = keyid[1];
md_close(md);
}
return lowbits;
}
/****************
* Get the keyid from the public key and put it into keyid
* if this is not NULL. Return the 32 low bits of the keyid.
*/
u32
keyid_from_pk( PKT_public_key *pk, u32 *keyid )
{
u32 lowbits;
u32 dummy_keyid[2];
if( !keyid )
keyid = dummy_keyid;
if( pk->keyid[0] || pk->keyid[1] ) {
keyid[0] = pk->keyid[0];
keyid[1] = pk->keyid[1];
lowbits = keyid[1];
}
else if( pk->version < 4 && is_RSA(pk->pubkey_algo) ) {
lowbits = pubkey_get_npkey(pk->pubkey_algo) ?
mpi_get_keyid( pk->pkey[0], keyid ) : 0 ; /* from n */
pk->keyid[0] = keyid[0];
pk->keyid[1] = keyid[1];
}
else {
const byte *dp;
MD_HANDLE md;
md = do_fingerprint_md(pk);
dp = md_read( md, 0 );
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
lowbits = keyid[1];
md_close(md);
pk->keyid[0] = keyid[0];
pk->keyid[1] = keyid[1];
}
return lowbits;
}
/****************
* Get the keyid from the fingerprint. This function is simple for most
* keys, but has to do a keylookup for old stayle keys.
*/
u32
keyid_from_fingerprint( const byte *fprint, size_t fprint_len, u32 *keyid )
{
u32 dummy_keyid[2];
if( !keyid )
keyid = dummy_keyid;
if( fprint_len != 20 ) {
/* This is special as we have to lookup the key first */
PKT_public_key pk;
int rc;
memset( &pk, 0, sizeof pk );
rc = get_pubkey_byfprint( &pk, fprint, fprint_len );
if( rc ) {
log_error("Oops: keyid_from_fingerprint: no pubkey\n");
keyid[0] = 0;
keyid[1] = 0;
}
else
keyid_from_pk( &pk, keyid );
}
else {
const byte *dp = fprint;
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
}
return keyid[1];
}
u32
keyid_from_sig( PKT_signature *sig, u32 *keyid )
{
if( keyid ) {
keyid[0] = sig->keyid[0];
keyid[1] = sig->keyid[1];
}
return sig->keyid[1];
}
byte *
namehash_from_uid(PKT_user_id *uid)
{
if(uid->namehash==NULL)
{
uid->namehash=m_alloc(20);
if(uid->attrib_data)
rmd160_hash_buffer(uid->namehash,uid->attrib_data,uid->attrib_len);
else
rmd160_hash_buffer(uid->namehash,uid->name,uid->len);
}
return uid->namehash;
}
/****************
* return the number of bits used in the pk
*/
unsigned
nbits_from_pk( PKT_public_key *pk )
{
return pubkey_nbits( pk->pubkey_algo, pk->pkey );
}
/****************
* return the number of bits used in the sk
*/
unsigned
nbits_from_sk( PKT_secret_key *sk )
{
return pubkey_nbits( sk->pubkey_algo, sk->skey );
}
static const char *
mk_datestr (char *buffer, time_t atime)
{
struct tm *tp;
if ( atime < 0 ) /* 32 bit time_t and after 2038-01-19 */
strcpy (buffer, "????" "-??" "-??"); /* mark this as invalid */
else {
tp = gmtime (&atime);
sprintf (buffer,"%04d-%02d-%02d",
1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
}
return buffer;
}
/****************
* return a string with the creation date of the pk
* Note: this is alloced in a static buffer.
* Format is: yyyy-mm-dd
*/
const char *
datestr_from_pk( PKT_public_key *pk )
{
static char buffer[11+5];
time_t atime = pk->timestamp;
return mk_datestr (buffer, atime);
}
const char *
datestr_from_sk( PKT_secret_key *sk )
{
static char buffer[11+5];
time_t atime = sk->timestamp;
return mk_datestr (buffer, atime);
}
const char *
datestr_from_sig( PKT_signature *sig )
{
static char buffer[11+5];
time_t atime = sig->timestamp;
return mk_datestr (buffer, atime);
}
const char *
expirestr_from_pk( PKT_public_key *pk )
{
static char buffer[11+5];
time_t atime;
if( !pk->expiredate )
return _("never ");
atime = pk->expiredate;
return mk_datestr (buffer, atime);
}
const char *
expirestr_from_sk( PKT_secret_key *sk )
{
static char buffer[11+5];
time_t atime;
if( !sk->expiredate )
return _("never ");
atime = sk->expiredate;
return mk_datestr (buffer, atime);
}
const char *
expirestr_from_sig( PKT_signature *sig )
{
static char buffer[11+5];
time_t atime;
if(!sig->expiredate)
return _("never ");
atime=sig->expiredate;
return mk_datestr (buffer, atime);
}
const char *
colon_strtime (u32 t)
{
if (!t)
return "";
if (opt.fixed_list_mode) {
static char buf[15];
sprintf (buf, "%lu", (ulong)t);
return buf;
}
return strtimestamp(t);
}
const char *
colon_datestr_from_pk (PKT_public_key *pk)
{
if (opt.fixed_list_mode) {
static char buf[15];
sprintf (buf, "%lu", (ulong)pk->timestamp);
return buf;
}
return datestr_from_pk (pk);
}
const char *
colon_datestr_from_sk (PKT_secret_key *sk)
{
if (opt.fixed_list_mode) {
static char buf[15];
sprintf (buf, "%lu", (ulong)sk->timestamp);
return buf;
}
return datestr_from_sk (sk);
}
const char *
colon_datestr_from_sig (PKT_signature *sig)
{
if (opt.fixed_list_mode) {
static char buf[15];
sprintf (buf, "%lu", (ulong)sig->timestamp);
return buf;
}
return datestr_from_sig (sig);
}
const char *
colon_expirestr_from_sig (PKT_signature *sig)
{
if(!sig->expiredate)
return "";
if (opt.fixed_list_mode) {
static char buf[15];
sprintf (buf, "%lu", (ulong)sig->expiredate);
return buf;
}
return expirestr_from_sig (sig);
}
/**************** .
* Return a byte array with the fingerprint for the given PK/SK
* The length of the array is returned in ret_len. Caller must free
* the array or provide an array of length MAX_FINGERPRINT_LEN.
*/
byte *
fingerprint_from_pk( PKT_public_key *pk, byte *array, size_t *ret_len )
{
byte *p, *buf;
const byte *dp;
size_t len;
unsigned int n;
if( pk->version < 4 && is_RSA(pk->pubkey_algo) ) {
/* RSA in version 3 packets is special */
MD_HANDLE md;
md = md_open( DIGEST_ALGO_MD5, 0);
if( pubkey_get_npkey( pk->pubkey_algo ) > 1 ) {
p = buf = mpi_get_buffer( pk->pkey[0], &n, NULL );
md_write( md, p, n );
m_free(buf);
p = buf = mpi_get_buffer( pk->pkey[1], &n, NULL );
md_write( md, p, n );
m_free(buf);
}
md_final(md);
if( !array )
array = m_alloc( 16 );
len = 16;
memcpy(array, md_read(md, DIGEST_ALGO_MD5), 16 );
md_close(md);
}
else {
MD_HANDLE md;
md = do_fingerprint_md(pk);
dp = md_read( md, 0 );
len = md_digest_length( md_get_algo( md ) );
assert( len <= MAX_FINGERPRINT_LEN );
if( !array )
array = m_alloc( len );
memcpy(array, dp, len );
pk->keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
pk->keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
md_close(md);
}
*ret_len = len;
return array;
}
byte *
fingerprint_from_sk( PKT_secret_key *sk, byte *array, size_t *ret_len )
{
byte *p, *buf;
const char *dp;
size_t len;
unsigned n;
if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
/* RSA in version 3 packets is special */
MD_HANDLE md;
md = md_open( DIGEST_ALGO_MD5, 0);
if( pubkey_get_npkey( sk->pubkey_algo ) > 1 ) {
p = buf = mpi_get_buffer( sk->skey[0], &n, NULL );
md_write( md, p, n );
m_free(buf);
p = buf = mpi_get_buffer( sk->skey[1], &n, NULL );
md_write( md, p, n );
m_free(buf);
}
md_final(md);
if( !array )
array = m_alloc( 16 );
len = 16;
memcpy(array, md_read(md, DIGEST_ALGO_MD5), 16 );
md_close(md);
}
else {
MD_HANDLE md;
md = do_fingerprint_md_sk(sk);
dp = md_read( md, 0 );
len = md_digest_length( md_get_algo( md ) );
assert( len <= MAX_FINGERPRINT_LEN );
if( !array )
array = m_alloc( len );
memcpy(array, dp, len );
md_close(md);
}
*ret_len = len;
return array;
}

1287
g10/keylist.c Normal file

File diff suppressed because it is too large Load diff

1573
g10/keyring.c Normal file

File diff suppressed because it is too large Load diff

46
g10/keyring.h Normal file
View file

@ -0,0 +1,46 @@
/* keyring.h - Keyring operations
* Copyright (C) 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef GPG_KEYRING_H
#define GPG_KEYRING_H 1
#include "global.h"
typedef struct keyring_handle *KEYRING_HANDLE;
int keyring_register_filename (const char *fname, int secret, void **ptr);
int keyring_is_writable (void *token);
KEYRING_HANDLE keyring_new (void *token, int secret);
void keyring_release (KEYRING_HANDLE hd);
const char *keyring_get_resource_name (KEYRING_HANDLE hd);
int keyring_lock (KEYRING_HANDLE hd, int yes);
int keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb);
int keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb);
int keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb);
int keyring_locate_writable (KEYRING_HANDLE hd);
int keyring_delete_keyblock (KEYRING_HANDLE hd);
int keyring_search_reset (KEYRING_HANDLE hd);
int keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex);
int keyring_rebuild_cache (void *);
#endif /*GPG_KEYRING_H*/

1378
g10/keyserver.c Normal file

File diff suppressed because it is too large Load diff

241
g10/main.h Normal file
View file

@ -0,0 +1,241 @@
/* main.h
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_MAIN_H
#define G10_MAIN_H
#include "types.h"
#include "iobuf.h"
#include "mpi.h"
#include "cipher.h"
#include "keydb.h"
/* It could be argued that the default cipher should be 3DES rather
than CAST5, and the default compression should be 0
(i.e. uncompressed) rather than 1 (zip). */
#define DEFAULT_CIPHER_ALGO CIPHER_ALGO_CAST5
#define DEFAULT_DIGEST_ALGO DIGEST_ALGO_SHA1
#define DEFAULT_COMPRESS_ALGO 1
typedef struct {
int header_okay;
PK_LIST pk_list;
cipher_filter_context_t cfx;
} encrypt_filter_context_t;
struct groupitem
{
char *name;
STRLIST values;
struct groupitem *next;
};
/*-- g10.c --*/
extern int g10_errors_seen;
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
void g10_exit(int rc) __attribute__ ((noreturn));
#else
void g10_exit(int rc);
#endif
void print_pubkey_algo_note( int algo );
void print_cipher_algo_note( int algo );
void print_digest_algo_note( int algo );
/*-- armor.c --*/
char *make_radix64_string( const byte *data, size_t len );
/*-- misc.c --*/
void trap_unaligned(void);
int disable_core_dumps(void);
u16 checksum_u16( unsigned n );
u16 checksum( byte *p, unsigned n );
u16 checksum_mpi( MPI a );
u32 buffer_to_u32( const byte *buffer );
const byte *get_session_marker( size_t *rlen );
int openpgp_cipher_test_algo( int algo );
int openpgp_pk_test_algo( int algo, unsigned int usage_flags );
int openpgp_pk_algo_usage ( int algo );
int openpgp_md_test_algo( int algo );
#ifdef USE_IDEA
void idea_cipher_warn( int show );
#else
#define idea_cipher_warn(a)
#endif
struct expando_args
{
PKT_public_key *pk;
PKT_secret_key *sk;
byte imagetype;
};
char *pct_expando(const char *string,struct expando_args *args);
int hextobyte( const char *s );
void deprecated_warning(const char *configname,unsigned int configlineno,
const char *option,const char *repl1,const char *repl2);
const char *compress_algo_to_string(int algo);
int string_to_compress_algo(const char *string);
int check_compress_algo(int algo);
int default_cipher_algo(void);
int default_compress_algo(void);
const char *compliance_option_string(void);
void compliance_failure(void);
struct parse_options
{
char *name;
unsigned int bit;
};
int parse_options(char *str,unsigned int *options,struct parse_options *opts);
/*-- helptext.c --*/
void display_online_help( const char *keyword );
/*-- encode.c --*/
int encode_symmetric( const char *filename );
int encode_store( const char *filename );
int encode_crypt( const char *filename, STRLIST remusr );
void encode_crypt_files(int nfiles, char **files, STRLIST remusr);
int encrypt_filter( void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len);
/*-- sign.c --*/
int complete_sig( PKT_signature *sig, PKT_secret_key *sk, MD_HANDLE md );
int sign_file( STRLIST filenames, int detached, STRLIST locusr,
int do_encrypt, STRLIST remusr, const char *outfile );
int clearsign_file( const char *fname, STRLIST locusr, const char *outfile );
int sign_symencrypt_file (const char *fname, STRLIST locusr);
/*-- sig-check.c --*/
int check_revocation_keys (PKT_public_key *pk, PKT_signature *sig);
int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig );
int check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
int *is_selfsig, u32 *r_expiredate, int *r_expired );
/*-- delkey.c --*/
int delete_keys( STRLIST names, int secret, int allow_both );
/*-- keyedit.c --*/
void keyedit_menu( const char *username, STRLIST locusr, STRLIST cmds,
int sign_mode );
void show_basic_key_info (KBNODE keyblock);
/*-- keygen.c --*/
u32 ask_expire_interval(int object);
u32 ask_expiredate(void);
void generate_keypair( const char *fname );
int keygen_set_std_prefs (const char *string,int personal);
PKT_user_id *keygen_get_std_prefs (void);
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
int keygen_upd_std_prefs( PKT_signature *sig, void *opaque );
int keygen_add_revkey(PKT_signature *sig, void *opaque);
int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );
/*-- openfile.c --*/
int overwrite_filep( const char *fname );
char *make_outfile_name( const char *iname );
char *ask_outfile_name( const char *name, size_t namelen );
int open_outfile( const char *iname, int mode, IOBUF *a );
IOBUF open_sigfile( const char *iname, progress_filter_context_t *pfx );
void try_make_homedir( const char *fname );
/*-- seskey.c --*/
void make_session_key( DEK *dek );
MPI encode_session_key( DEK *dek, unsigned nbits );
MPI encode_md_value( int pubkey_algo, MD_HANDLE md,
int hash_algo, unsigned nbits, int v3compathack );
/*-- comment.c --*/
KBNODE make_comment_node( const char *s );
KBNODE make_mpi_comment_node( const char *s, MPI a );
/*-- import.c --*/
int parse_import_options(char *str,unsigned int *options);
void import_keys( char **fnames, int nnames,
void *stats_hd, unsigned int options );
int import_keys_stream( IOBUF inp,
void *stats_hd, unsigned int options );
void *import_new_stats_handle (void);
void import_release_stats_handle (void *p);
void import_print_stats (void *hd);
int collapse_uids( KBNODE *keyblock );
/*-- export.c --*/
int parse_export_options(char *str,unsigned int *options);
int export_pubkeys( STRLIST users, unsigned int options );
int export_pubkeys_stream( IOBUF out, STRLIST users,
KBNODE *keyblock_out, unsigned int options );
int export_seckeys( STRLIST users );
int export_secsubkeys( STRLIST users );
/* dearmor.c --*/
int dearmor_file( const char *fname );
int enarmor_file( const char *fname );
/*-- revoke.c --*/
struct revocation_reason_info;
int gen_revoke( const char *uname );
int gen_desig_revoke( const char *uname );
int revocation_reason_build_cb( PKT_signature *sig, void *opaque );
struct revocation_reason_info *
ask_revocation_reason( int key_rev, int cert_rev, int hint );
void release_revocation_reason_info( struct revocation_reason_info *reason );
/*-- keylist.c --*/
void public_key_list( STRLIST list );
void secret_key_list( STRLIST list );
void reorder_keyblock (KBNODE keyblock);
void list_keyblock( KBNODE keyblock, int secret, int fpr, void *opaque );
void print_fingerprint (PKT_public_key *pk, PKT_secret_key *sk, int mode);
void show_policy_url(PKT_signature *sig,int indent,int mode);
void show_notation(PKT_signature *sig,int indent,int mode);
void dump_attribs(const PKT_user_id *uid,
PKT_public_key *pk,PKT_secret_key *sk);
void set_attrib_fd(int fd);
void print_seckey_info (PKT_secret_key *sk);
void print_pubkey_info (PKT_public_key *pk);
/*-- verify.c --*/
void print_file_status( int status, const char *name, int what );
int verify_signatures( int nfiles, char **files );
int verify_files( int nfiles, char **files );
/*-- decrypt.c --*/
int decrypt_message( const char *filename );
void decrypt_messages(int nfiles, char **files);
/*-- plaintext.c --*/
int hash_datafiles( MD_HANDLE md, MD_HANDLE md2,
STRLIST files, const char *sigfilename, int textmode );
/*-- pipemode.c --*/
void run_in_pipemode (void);
/*-- signal.c --*/
void init_signals(void);
void pause_on_sigusr( int which );
void block_all_signals(void);
void unblock_all_signals(void);
#endif /*G10_MAIN_H*/

1681
g10/mainproc.c Normal file

File diff suppressed because it is too large Load diff

678
g10/misc.c Normal file
View file

@ -0,0 +1,678 @@
/* misc.c - miscellaneous functions
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
#include <asm/sysinfo.h>
#include <asm/unistd.h>
#endif
#ifdef HAVE_SETRLIMIT
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
#include "util.h"
#include "main.h"
#include "photoid.h"
#include "options.h"
#include "i18n.h"
const char *g10m_revision_string(int);
const char *g10c_revision_string(int);
const char *g10u_revision_string(int);
#ifdef __GNUC__
volatile
#endif
void
pull_in_libs(void)
{
g10m_revision_string(0);
g10c_revision_string(0);
g10u_revision_string(0);
}
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
static int
setsysinfo(unsigned long op, void *buffer, unsigned long size,
int *start, void *arg, unsigned long flag)
{
return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
}
void
trap_unaligned(void)
{
unsigned int buf[2];
buf[0] = SSIN_UACPROC;
buf[1] = UAC_SIGBUS | UAC_NOPRINT;
setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
}
#else
void
trap_unaligned(void)
{ /* dummy */
}
#endif
int
disable_core_dumps()
{
#ifdef HAVE_DOSISH_SYSTEM
return 0;
#else
#ifdef HAVE_SETRLIMIT
struct rlimit limit;
limit.rlim_cur = 0;
limit.rlim_max = 0;
if( !setrlimit( RLIMIT_CORE, &limit ) )
return 0;
if( errno != EINVAL && errno != ENOSYS )
log_fatal(_("can't disable core dumps: %s\n"), strerror(errno) );
#endif
return 1;
#endif
}
u16
checksum_u16( unsigned n )
{
u16 a;
a = (n >> 8) & 0xff;
a += n & 0xff;
return a;
}
u16
checksum( byte *p, unsigned n )
{
u16 a;
for(a=0; n; n-- )
a += *p++;
return a;
}
u16
checksum_mpi( MPI a )
{
u16 csum;
byte *buffer;
unsigned nbytes;
unsigned nbits;
buffer = mpi_get_buffer( a, &nbytes, NULL );
nbits = mpi_get_nbits(a);
csum = checksum_u16( nbits );
csum += checksum( buffer, nbytes );
m_free( buffer );
return csum;
}
u32
buffer_to_u32( const byte *buffer )
{
unsigned long a;
a = *buffer << 24;
a |= buffer[1] << 16;
a |= buffer[2] << 8;
a |= buffer[3];
return a;
}
static void
no_exp_algo(void)
{
static int did_note = 0;
if( !did_note ) {
did_note = 1;
log_info(_("Experimental algorithms should not be used!\n"));
}
}
void
print_pubkey_algo_note( int algo )
{
if( algo >= 100 && algo <= 110 )
no_exp_algo();
}
void
print_cipher_algo_note( int algo )
{
if( algo >= 100 && algo <= 110 )
no_exp_algo();
else if( algo == CIPHER_ALGO_3DES
|| algo == CIPHER_ALGO_CAST5
|| algo == CIPHER_ALGO_BLOWFISH
|| algo == CIPHER_ALGO_TWOFISH
|| algo == CIPHER_ALGO_RIJNDAEL
|| algo == CIPHER_ALGO_RIJNDAEL192
|| algo == CIPHER_ALGO_RIJNDAEL256
)
;
else {
static int did_note = 0;
if( !did_note ) {
did_note = 1;
log_info(_("this cipher algorithm is deprecated; "
"please use a more standard one!\n"));
}
}
}
void
print_digest_algo_note( int algo )
{
if( algo >= 100 && algo <= 110 )
no_exp_algo();
}
/* Return a string which is used as a kind of process ID */
const byte *
get_session_marker( size_t *rlen )
{
static byte marker[SIZEOF_UNSIGNED_LONG*2];
static int initialized;
if ( !initialized ) {
volatile ulong aa, bb; /* we really want the uninitialized value */
ulong a, b;
initialized = 1;
/* also this marker is guessable it is not easy to use this
* for a faked control packet because an attacker does not
* have enough control about the time the verification does
* take place. Of course, we can add just more random but
* than we need the random generator even for verification
* tasks - which does not make sense. */
a = aa ^ (ulong)getpid();
b = bb ^ (ulong)time(NULL);
memcpy( marker, &a, SIZEOF_UNSIGNED_LONG );
memcpy( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );
}
*rlen = sizeof(marker);
return marker;
}
/****************
* Wrapper around the libgcrypt function with addional checks on
* openPGP contraints for the algo ID.
*/
int
openpgp_cipher_test_algo( int algo )
{
if( algo < 0 || algo > 110 )
return G10ERR_CIPHER_ALGO;
return check_cipher_algo(algo);
}
int
openpgp_pk_test_algo( int algo, unsigned int usage_flags )
{
if( algo < 0 || algo > 110 )
return G10ERR_PUBKEY_ALGO;
return check_pubkey_algo2( algo, usage_flags );
}
int
openpgp_pk_algo_usage ( int algo )
{
int use = 0;
/* they are hardwired in gpg 1.0 */
switch ( algo ) {
case PUBKEY_ALGO_RSA:
use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC;
break;
case PUBKEY_ALGO_RSA_E:
use = PUBKEY_USAGE_ENC;
break;
case PUBKEY_ALGO_RSA_S:
use = PUBKEY_USAGE_SIG;
break;
case PUBKEY_ALGO_ELGAMAL_E:
use = PUBKEY_USAGE_ENC;
break;
case PUBKEY_ALGO_DSA:
use = PUBKEY_USAGE_SIG;
break;
case PUBKEY_ALGO_ELGAMAL:
use = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC;
break;
default:
break;
}
return use;
}
int
openpgp_md_test_algo( int algo )
{
if( algo < 0 || algo > 110 )
return G10ERR_DIGEST_ALGO;
return check_digest_algo(algo);
}
#ifdef USE_IDEA
/* Special warning for the IDEA cipher */
void
idea_cipher_warn(int show)
{
static int warned=0;
if(!warned || show)
{
log_info(_("the IDEA cipher plugin is not present\n"));
log_info(_("please see http://www.gnupg.org/why-not-idea.html "
"for more information\n"));
warned=1;
}
}
#endif
/* Expand %-strings. Returns a string which must be m_freed. Returns
NULL if the string cannot be expanded (too large). */
char *
pct_expando(const char *string,struct expando_args *args)
{
const char *ch=string;
int idx=0,maxlen=0,done=0;
u32 pk_keyid[2]={0,0},sk_keyid[2]={0,0};
char *ret=NULL;
if(args->pk)
keyid_from_pk(args->pk,pk_keyid);
if(args->sk)
keyid_from_sk(args->sk,sk_keyid);
if(!args->pk && args->sk)
keyid_from_sk(args->sk,pk_keyid);
while(*ch!='\0')
{
char *str=NULL;
if(!done)
{
/* 8192 is way bigger than we'll need here */
if(maxlen>=8192)
goto fail;
maxlen+=1024;
ret=m_realloc(ret,maxlen);
}
done=0;
if(*ch=='%')
{
switch(*(ch+1))
{
case 's': /* short key id */
if(idx+8<maxlen)
{
sprintf(&ret[idx],"%08lX",(ulong)sk_keyid[1]);
idx+=8;
done=1;
}
break;
case 'S': /* long key id */
if(idx+16<maxlen)
{
sprintf(&ret[idx],"%08lX%08lX",
(ulong)sk_keyid[0],(ulong)sk_keyid[1]);
idx+=16;
done=1;
}
break;
case 'k': /* short key id */
if(idx+8<maxlen)
{
sprintf(&ret[idx],"%08lX",(ulong)pk_keyid[1]);
idx+=8;
done=1;
}
break;
case 'K': /* long key id */
if(idx+16<maxlen)
{
sprintf(&ret[idx],"%08lX%08lX",
(ulong)pk_keyid[0],(ulong)pk_keyid[1]);
idx+=16;
done=1;
}
break;
case 'f': /* fingerprint */
{
byte array[MAX_FINGERPRINT_LEN];
size_t len;
int i;
if(args->pk)
fingerprint_from_pk(args->pk,array,&len);
else
memset(array,0, (len=MAX_FINGERPRINT_LEN));
if(idx+(len*2)<maxlen)
{
for(i=0;i<len;i++)
{
sprintf(&ret[idx],"%02X",array[i]);
idx+=2;
}
done=1;
}
}
break;
case 't': /* e.g. "jpg" */
str=image_type_to_string(args->imagetype,0);
/* fall through */
case 'T': /* e.g. "image/jpeg" */
if(str==NULL)
str=image_type_to_string(args->imagetype,2);
if(idx+strlen(str)<maxlen)
{
strcpy(&ret[idx],str);
idx+=strlen(str);
done=1;
}
break;
case '%':
if(idx+1<maxlen)
{
ret[idx++]='%';
ret[idx]='\0';
done=1;
}
break;
/* Any unknown %-keys (like %i, %o, %I, and %O) are
passed through for later expansion. Note this also
handles the case where the last character in the
string is a '%' - the terminating \0 will end up here
and properly terminate the string. */
default:
if(idx+2<maxlen)
{
ret[idx++]='%';
ret[idx++]=*(ch+1);
ret[idx]='\0';
done=1;
}
break;
}
if(done)
ch++;
}
else
{
if(idx+1<maxlen)
{
ret[idx++]=*ch;
ret[idx]='\0';
done=1;
}
}
if(done)
ch++;
}
return ret;
fail:
m_free(ret);
return NULL;
}
int
hextobyte( const char *s )
{
int c;
if( *s >= '0' && *s <= '9' )
c = 16 * (*s - '0');
else if( *s >= 'A' && *s <= 'F' )
c = 16 * (10 + *s - 'A');
else if( *s >= 'a' && *s <= 'f' )
c = 16 * (10 + *s - 'a');
else
return -1;
s++;
if( *s >= '0' && *s <= '9' )
c += *s - '0';
else if( *s >= 'A' && *s <= 'F' )
c += 10 + *s - 'A';
else if( *s >= 'a' && *s <= 'f' )
c += 10 + *s - 'a';
else
return -1;
return c;
}
void
deprecated_warning(const char *configname,unsigned int configlineno,
const char *option,const char *repl1,const char *repl2)
{
if(configname)
{
if(strncmp("--",option,2)==0)
option+=2;
if(strncmp("--",repl1,2)==0)
repl1+=2;
log_info(_("%s:%d: deprecated option \"%s\"\n"),
configname,configlineno,option);
}
else
log_info(_("WARNING: \"%s\" is a deprecated option\n"),option);
log_info(_("please use \"%s%s\" instead\n"),repl1,repl2);
}
const char *
compress_algo_to_string(int algo)
{
const char *s="?";
switch(algo)
{
case 0:
s="Uncompressed";
break;
case 1:
s="ZIP";
break;
case 2:
s="ZLIB";
break;
}
return s;
}
int
string_to_compress_algo(const char *string)
{
if(ascii_strcasecmp(string,"uncompressed")==0)
return 0;
else if(ascii_strcasecmp(string,"zip")==0)
return 1;
else if(ascii_strcasecmp(string,"zlib")==0)
return 2;
else if(ascii_strcasecmp(string,"z0")==0)
return 0;
else if(ascii_strcasecmp(string,"z1")==0)
return 1;
else if(ascii_strcasecmp(string,"z2")==0)
return 2;
else
return -1;
}
int
check_compress_algo(int algo)
{
if(algo>=0 && algo<=2)
return 0;
return G10ERR_COMPR_ALGO;
}
int
default_cipher_algo(void)
{
if(opt.def_cipher_algo)
return opt.def_cipher_algo;
else if(opt.personal_cipher_prefs)
return opt.personal_cipher_prefs[0].value;
else
return opt.s2k_cipher_algo;
}
/* There is no default_digest_algo function, but see
sign.c:hash_for */
int
default_compress_algo(void)
{
if(opt.def_compress_algo!=-1)
return opt.def_compress_algo;
else if(opt.personal_compress_prefs)
return opt.personal_compress_prefs[0].value;
else
return DEFAULT_COMPRESS_ALGO;
}
const char *
compliance_option_string(void)
{
switch(opt.compliance)
{
case CO_RFC2440:
return "--openpgp";
case CO_PGP2:
return "--pgp2";
case CO_PGP6:
return "--pgp6";
case CO_PGP7:
return "--pgp7";
case CO_PGP8:
return "--pgp8";
default:
return "???";
}
}
static const char *
compliance_string(void)
{
switch(opt.compliance)
{
case CO_RFC2440:
return "OpenPGP";
case CO_PGP2:
return "PGP 2.x";
case CO_PGP6:
return "PGP 6.x";
case CO_PGP7:
return "PGP 7.x";
case CO_PGP8:
return "PGP 8.x";
default:
return "???";
}
}
void
compliance_failure(void)
{
log_info(_("this message may not be usable by %s\n"),compliance_string());
opt.compliance=CO_GNUPG;
}
int
parse_options(char *str,unsigned int *options,struct parse_options *opts)
{
char *tok;
while((tok=strsep(&str," ,")))
{
int i,rev=0;
if(tok[0]=='\0')
continue;
if(ascii_strncasecmp("no-",tok,3)==0)
{
rev=1;
tok+=3;
}
for(i=0;opts[i].name;i++)
{
if(ascii_strcasecmp(opts[i].name,tok)==0)
{
if(rev)
*options&=~opts[i].bit;
else
*options|=opts[i].bit;
break;
}
}
if(!opts[i].name)
return 0;
}
return 1;
}

389
g10/openfile.c Normal file
View file

@ -0,0 +1,389 @@
/* openfile.c
* Copyright (C) 1998, 1999, 2000, 2001, 2003 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "util.h"
#include "memory.h"
#include "ttyio.h"
#include "options.h"
#include "main.h"
#include "status.h"
#include "i18n.h"
#ifdef USE_ONLY_8DOT3
#define SKELEXT ".skl"
#else
#define SKELEXT EXTSEP_S "skel"
#endif
#if defined (HAVE_DRIVE_LETTERS) || defined (__riscos__)
#define CMP_FILENAME(a,b) ascii_strcasecmp( (a), (b) )
#else
#define CMP_FILENAME(a,b) strcmp( (a), (b) )
#endif
#ifdef MKDIR_TAKES_ONE_ARG
#undef mkdir
#define mkdir(a,b) mkdir(a)
#endif
/* FIXME: Implement opt.interactive. */
/****************
* Check whether FNAME exists and ask if it's okay to overwrite an
* existing one.
* Returns: True: it's okay to overwrite or the file does not exist
* False: Do not overwrite
*/
int
overwrite_filep( const char *fname )
{
if( !fname || (*fname == '-' && !fname[1]) )
return 1; /* writing to stdout is always okay */
if( access( fname, F_OK ) )
return 1; /* does not exist */
#ifndef HAVE_DOSISH_SYSTEM
if ( !strcmp ( fname, "/dev/null" ) )
return 1; /* does not do any harm */
#endif
/* fixme: add some backup stuff in case of overwrite */
if( opt.answer_yes )
return 1;
if( opt.answer_no || opt.batch )
return 0; /* do not overwrite */
tty_printf(_("File `%s' exists. "), fname);
if( cpr_get_answer_is_yes("openfile.overwrite.okay",
_("Overwrite (y/N)? ")) )
return 1;
return 0;
}
/****************
* Strip know extensions from iname and return a newly allocated
* filename. Return NULL if we can't do that.
*/
char *
make_outfile_name( const char *iname )
{
size_t n;
if( (!iname || (*iname=='-' && !iname[1]) ))
return m_strdup("-");
n = strlen(iname);
if( n > 4 && ( !CMP_FILENAME(iname+n-4, EXTSEP_S "gpg")
|| !CMP_FILENAME(iname+n-4, EXTSEP_S "pgp")
|| !CMP_FILENAME(iname+n-4, EXTSEP_S "sig")
|| !CMP_FILENAME(iname+n-4, EXTSEP_S "asc") ) ) {
char *buf = m_strdup( iname );
buf[n-4] = 0;
return buf;
}
else if( n > 5 && !CMP_FILENAME(iname+n-5, EXTSEP_S "sign") ) {
char *buf = m_strdup( iname );
buf[n-5] = 0;
return buf;
}
log_info(_("%s: unknown suffix\n"), iname );
return NULL;
}
/****************
* Ask for a outputfilename and use the given one as default.
* Return NULL if no file has been given or it is not possible to
* ask the user.
*/
char *
ask_outfile_name( const char *name, size_t namelen )
{
size_t n;
const char *s;
char *prompt;
char *fname;
char *defname;
if( opt.batch )
return NULL;
s = _("Enter new filename");
n = strlen(s) + namelen + 10;
defname = name && namelen? make_printable_string( name, namelen, 0): NULL;
prompt = m_alloc(n);
if( defname )
sprintf(prompt, "%s [%s]: ", s, defname );
else
sprintf(prompt, "%s: ", s );
fname = cpr_get("openfile.askoutname", prompt );
cpr_kill_prompt();
m_free(prompt);
if( !*fname ) {
m_free( fname ); fname = NULL;
fname = defname; defname = NULL;
}
m_free(defname);
if (fname)
trim_spaces (fname);
return fname;
}
/****************
* Make an output filename for the inputfile INAME.
* Returns an IOBUF and an errorcode
* Mode 0 = use ".gpg"
* 1 = use ".asc"
* 2 = use ".sig"
*/
int
open_outfile( const char *iname, int mode, IOBUF *a )
{
int rc = 0;
*a = NULL;
if( (!iname || (*iname=='-' && !iname[1])) && !opt.outfile ) {
if( !(*a = iobuf_create(NULL)) ) {
log_error(_("%s: can't open: %s\n"), "[stdout]", strerror(errno) );
rc = G10ERR_CREATE_FILE;
}
else if( opt.verbose )
log_info(_("writing to stdout\n"));
}
else {
char *buf = NULL;
const char *name;
if( opt.dry_run )
name = "/dev/null";
else if( opt.outfile )
name = opt.outfile;
else {
#ifdef USE_ONLY_8DOT3
if (opt.mangle_dos_filenames)
{
/* It is quite common DOS system to have only one dot in a
* a filename So if we have something like this, we simple
* replace the suffix execpt in cases where the suffix is
* larger than 3 characters and not the same as.
* We should really map the filenames to 8.3 but this tends to
* be more complicated and is probaly a duty of the filesystem
*/
char *dot;
const char *newsfx = mode==1 ? ".asc" :
mode==2 ? ".sig" : ".gpg";
buf = m_alloc(strlen(iname)+4+1);
strcpy(buf,iname);
dot = strchr(buf, '.' );
if ( dot && dot > buf && dot[1] && strlen(dot) <= 4
&& CMP_FILENAME(newsfx, dot) )
{
strcpy(dot, newsfx );
}
else if ( dot && !dot[1] ) /* don't duplicate a dot */
strcpy( dot, newsfx+1 );
else
strcat ( buf, newsfx );
}
if (!buf)
#endif /* USE_ONLY_8DOT3 */
{
buf = m_alloc(strlen(iname)+4+1);
strcpy(stpcpy(buf,iname), mode==1 ? EXTSEP_S "asc" :
mode==2 ? EXTSEP_S "sig" : EXTSEP_S "gpg");
}
name = buf;
}
rc = 0;
while( !overwrite_filep (name) )
{
char *tmp = ask_outfile_name (NULL, 0);
if ( !tmp || !*tmp )
{
m_free (tmp);
rc = G10ERR_FILE_EXISTS;
break;
}
m_free (buf);
name = buf = tmp;
}
if( !rc )
{
if( !(*a = iobuf_create( name )) )
{
log_error(_("%s: can't create: %s\n"), name, strerror(errno) );
rc = G10ERR_CREATE_FILE;
}
else if( opt.verbose )
log_info(_("writing to `%s'\n"), name );
}
m_free(buf);
}
return rc;
}
/****************
* Try to open a file without the extension ".sig" or ".asc"
* Return NULL if such a file is not available.
*/
IOBUF
open_sigfile( const char *iname, progress_filter_context_t *pfx )
{
IOBUF a = NULL;
size_t len;
if( iname && !(*iname == '-' && !iname[1]) ) {
len = strlen(iname);
if( len > 4 && ( !strcmp(iname + len - 4, EXTSEP_S "sig")
|| ( len > 5 && !strcmp(iname + len - 5, EXTSEP_S "sign") )
|| !strcmp(iname + len - 4, EXTSEP_S "asc")) ) {
char *buf;
buf = m_strdup(iname);
buf[len-(buf[len-1]=='n'?5:4)] = 0 ;
a = iobuf_open( buf );
if( a && opt.verbose )
log_info(_("assuming signed data in `%s'\n"), buf );
if (a && pfx)
handle_progress (pfx, a, buf);
m_free(buf);
}
}
return a;
}
/****************
* Copy the option file skeleton to the given directory.
*/
static void
copy_options_file( const char *destdir )
{
const char *datadir = GNUPG_DATADIR;
char *fname;
FILE *src, *dst;
int linefeeds=0;
int c;
mode_t oldmask;
int esc = 0;
int any_option = 0;
if( opt.dry_run )
return;
fname = m_alloc( strlen(datadir) + strlen(destdir) + 15 );
strcpy(stpcpy(fname, datadir), DIRSEP_S "options" SKELEXT );
src = fopen( fname, "r" );
if( !src ) {
log_error(_("%s: can't open: %s\n"), fname, strerror(errno) );
m_free(fname);
return;
}
strcpy(stpcpy(fname, destdir), DIRSEP_S "gpg" EXTSEP_S "conf" );
oldmask=umask(077);
dst = fopen( fname, "w" );
umask(oldmask);
if( !dst ) {
log_error(_("%s: can't create: %s\n"), fname, strerror(errno) );
fclose( src );
m_free(fname);
return;
}
while( (c=getc(src)) != EOF ) {
if( linefeeds < 3 ) {
if( c == '\n' )
linefeeds++;
}
else {
putc( c, dst );
if (c== '\n')
esc = 1;
else if (esc == 1) {
if (c == ' ' || c == '\t')
;
else if (c == '#')
esc = 2;
else
any_option = 1;
}
}
}
fclose( dst );
fclose( src );
log_info(_("new configuration file `%s' created\n"), fname );
if (any_option)
log_info (_("WARNING: options in `%s'"
" are not yet active during this run\n"),
fname);
m_free(fname);
}
void
try_make_homedir( const char *fname )
{
const char *defhome = GNUPG_HOMEDIR;
/* Create the directory only if the supplied directory name
* is the same as the default one. This way we avoid to create
* arbitrary directories when a non-default homedirectory is used.
* To cope with HOME, we do compare only the suffix if we see that
* the default homedir does start with a tilde.
*/
if( opt.dry_run || opt.no_homedir_creation )
return;
if ( ( *defhome == '~'
&& ( strlen(fname) >= strlen (defhome+1)
&& !strcmp(fname+strlen(fname)-strlen(defhome+1),
defhome+1 ) ))
|| ( *defhome != '~'
&& !compare_filenames( fname, defhome ) )
) {
if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) )
log_fatal( _("%s: can't create directory: %s\n"),
fname, strerror(errno) );
else if( !opt.quiet )
log_info( _("%s: directory created\n"), fname );
copy_options_file( fname );
/* log_info(_("you have to start GnuPG again, " */
/* "so it can read the new configuration file\n") ); */
/* g10_exit(1); */
}
}

241
g10/options.h Normal file
View file

@ -0,0 +1,241 @@
/* options.h
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
* 2003 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_OPTIONS_H
#define G10_OPTIONS_H
#include <types.h>
#include "main.h"
#include "packet.h"
#undef ENABLE_COMMENT_PACKETS /* don't create comment packets */
#ifndef EXTERN_UNLESS_MAIN_MODULE
/* Norcraft can't cope with common symbols */
#if defined (__riscos__) && !defined (INCLUDED_BY_MAIN_MODULE)
#define EXTERN_UNLESS_MAIN_MODULE extern
#else
#define EXTERN_UNLESS_MAIN_MODULE
#endif
#endif
EXTERN_UNLESS_MAIN_MODULE
struct {
int verbose;
int quiet;
unsigned debug;
int armor;
int compress;
char *outfile;
int dry_run;
int list_only;
int textmode;
int expert;
int ask_sig_expire;
int ask_cert_expire;
int batch; /* run in batch mode */
int answer_yes; /* answer yes on most questions */
int answer_no; /* answer no on most questions */
int check_sigs; /* check key signatures */
int with_colons;
int with_key_data;
int with_fingerprint; /* opt --with-fingerprint active */
int fingerprint; /* list fingerprints */
int list_sigs; /* list signatures */
int no_armor;
int list_packets; /* list-packets mode: 1=normal, 2=invoked by command*/
int def_cipher_algo;
int force_v3_sigs;
int force_v4_certs;
int force_mdc;
int disable_mdc;
int def_digest_algo;
int cert_digest_algo;
int def_compress_algo;
const char *def_secret_key;
char *def_recipient;
int def_recipient_self;
int def_cert_check_level;
int sk_comments;
int no_version;
int marginals_needed;
int completes_needed;
int max_cert_depth;
const char *homedir;
char *display; /* 5 options to be passed to the gpg-agent */
char *ttyname;
char *ttytype;
char *lc_ctype;
char *lc_messages;
int skip_verify;
int compress_keys;
int compress_sigs;
/* TM_CLASSIC must be zero to accomodate trustdbs generated before
we started storing the trust model inside the trustdb. */
enum {TM_CLASSIC=0, TM_PGP=1, TM_ALWAYS, TM_AUTO} trust_model;
unsigned int force_ownertrust;
enum
{
CO_GNUPG=0, CO_RFC2440, CO_RFC1991, CO_PGP2, CO_PGP6, CO_PGP7, CO_PGP8
} compliance;
int pgp2_workarounds;
unsigned int emulate_bugs; /* bug emulation flags EMUBUG_xxxx */
int shm_coprocess;
const char *set_filename;
const char *comment_string;
int throw_keyid;
const char *photo_viewer;
int s2k_mode;
int s2k_digest_algo;
int s2k_cipher_algo;
int simple_sk_checksum; /* create the deprecated rfc2440 secret
key protection*/
int not_dash_escaped;
int escape_from;
int lock_once;
char *keyserver_uri;
char *keyserver_scheme;
char *keyserver_host;
char *keyserver_port;
char *keyserver_opaque;
struct
{
int verbose;
int include_revoked;
int include_disabled;
int include_subkeys;
int honor_http_proxy;
int broken_http_proxy;
int use_temp_files;
int keep_temp_files;
int fake_v3_keyids;
int auto_key_retrieve;
int try_dns_srv;
unsigned int import_options;
unsigned int export_options;
STRLIST other;
} keyserver_options;
int exec_disable;
int exec_path_set;
unsigned int import_options;
unsigned int export_options;
unsigned int list_options;
unsigned int verify_options;
char *def_preference_list;
prefitem_t *personal_cipher_prefs;
prefitem_t *personal_digest_prefs;
prefitem_t *personal_compress_prefs;
int no_perm_warn;
int no_mdc_warn;
char *temp_dir;
int no_encrypt_to;
int interactive;
STRLIST sig_notation_data;
STRLIST cert_notation_data;
STRLIST sig_policy_url;
STRLIST cert_policy_url;
int use_embedded_filename;
int allow_non_selfsigned_uid;
int allow_freeform_uid;
int no_literal;
ulong set_filesize;
int fast_list_mode;
int fixed_list_mode;
int ignore_time_conflict;
int ignore_valid_from;
int ignore_crc_error;
int ignore_mdc_error;
int command_fd;
const char *override_session_key;
int show_session_key;
int use_agent;
const char *gpg_agent_info;
int merge_only;
int try_all_secrets;
int no_expensive_trust_checks;
int no_sig_cache;
int no_sig_create_check;
int no_auto_check_trustdb;
int preserve_permissions;
int no_homedir_creation;
struct groupitem *grouplist;
int strict;
int mangle_dos_filenames;
int enable_progress_filter;
} opt;
#define EMUBUG_MDENCODE 4
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
#define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CIPHER_VALUE 4 /* debug cipher handling */
/* (may reveal sensitive data) */
#define DBG_FILTER_VALUE 8 /* debug internal filter handling */
#define DBG_IOBUF_VALUE 16 /* debug iobuf stuff */
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
#define DBG_CACHE_VALUE 64 /* debug the cacheing */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_TRUST_VALUE 256 /* debug the trustdb */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
#define DBG_EXTPROG_VALUE 1024 /* debug external program calls */
#define DBG_PACKET (opt.debug & DBG_PACKET_VALUE)
#define DBG_FILTER (opt.debug & DBG_FILTER_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_TRUST (opt.debug & DBG_TRUST_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
#define GNUPG (opt.compliance==CO_GNUPG)
#define RFC1991 (opt.compliance==CO_RFC1991 || opt.compliance==CO_PGP2)
#define RFC2440 (opt.compliance==CO_RFC2440)
#define PGP2 (opt.compliance==CO_PGP2)
#define PGP6 (opt.compliance==CO_PGP6)
#define PGP7 (opt.compliance==CO_PGP7)
#define PGP8 (opt.compliance==CO_PGP8)
/* Various option flags */
#define IMPORT_ALLOW_LOCAL_SIGS 1
#define IMPORT_REPAIR_PKS_SUBKEY_BUG 2
#define IMPORT_FAST_IMPORT 4
#define IMPORT_SK2PK 8
#define EXPORT_INCLUDE_NON_RFC 1
#define EXPORT_INCLUDE_LOCAL_SIGS 2
#define EXPORT_INCLUDE_ATTRIBUTES 4
#define EXPORT_INCLUDE_SENSITIVE_REVKEYS 8
#define LIST_SHOW_PHOTOS 1
#define LIST_SHOW_POLICY 2
#define LIST_SHOW_NOTATION 4
#define LIST_SHOW_KEYRING 8
#define LIST_SHOW_VALIDITY 16
#define LIST_SHOW_LONG_KEYID 32
#define VERIFY_SHOW_PHOTOS 1
#define VERIFY_SHOW_POLICY 2
#define VERIFY_SHOW_NOTATION 4
#endif /*G10_OPTIONS_H*/

208
g10/options.skel Normal file
View file

@ -0,0 +1,208 @@
# These first three lines are not copied to the gpg.conf file in
# the users home directory.
# $Id$
# Options for GnuPG
# Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This file is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Unless you specify which option file to use (with the command line
# option "--options filename"), GnuPG uses the file ~/.gnupg/gpg.conf
# by default.
#
# An options file can contain any long options which are available in
# GnuPG. If the first non white space character of a line is a '#',
# this line is ignored. Empty lines are also ignored.
#
# See the man page for a list of options.
# Uncomment the following option to get rid of the copyright notice
#no-greeting
# If you have more than 1 secret key in your keyring, you may want to
# uncomment the following option and set your preferred keyid.
#default-key 621CC013
# If you do not pass a recipient to gpg, it will ask for one. Using
# this option you can encrypt to a default key. Key validation will
# not be done in this case. The second form uses the default key as
# default recipient.
#default-recipient some-user-id
#default-recipient-self
# By default GnuPG creates version 3 signatures for data files. This
# is not strictly OpenPGP compliant but PGP 6 and most versions of PGP
# 7 require them. To disable this behavior, you may use this option
# or --openpgp.
#no-force-v3-sigs
# Because some mailers change lines starting with "From " to ">From "
# it is good to handle such lines in a special way when creating
# cleartext signatures; all other PGP versions do it this way too.
# To enable full OpenPGP compliance you may want to use this option.
#no-escape-from-lines
# If you do not use the Latin-1 (ISO-8859-1) charset, you should tell
# GnuPG which is the native character set. Please check the man page
# for supported character sets. This character set is only used for
# metadata and not for the actual message which does not undergo any
# translation. Note that future version of GnuPG will change to UTF-8
# as default character set.
#charset utf-8
# Group names may be defined like this:
# group mynames = paige 0x12345678 joe patti
#
# Any time "mynames" is a recipient (-r or --recipient), it will be
# expanded to the names "paige", "joe", and "patti", and the key ID
# "0x12345678". Note there is only one level of expansion - you
# cannot make an group that points to another group. Note also that
# if there are spaces in the recipient name, this will appear as two
# recipients. In these cases it is better to use the key ID.
#group mynames = paige 0x12345678 joe patti
# Some old Windows platforms require 8.3 filenames. If your system
# can handle long filenames, uncomment this.
#no-mangle-dos-filenames
# Lock the file only once for the lifetime of a process. If you do
# not define this, the lock will be obtained and released every time
# it is needed - normally this is not needed.
#lock-once
# GnuPG can send and receive keys to and from a keyserver. These
# servers can be HKP, email, or LDAP (if GnuPG is built with LDAP
# support).
#
# Example HKP keyserver:
# x-hkp://pgp.mit.edu
#
# Example email keyserver:
# mailto:pgp-public-keys@keys.nl.pgp.net
#
# Example LDAP keyservers:
# ldap://pgp.surfnet.nl:11370
# ldap://keyserver.pgp.com
#
# Regular URL syntax applies, and you can set an alternate port
# through the usual method:
# x-hkp://keyserver.example.net:22742
#
# If you have problems connecting to a HKP server through a buggy http
# proxy, you can use keyserver option broken-http-proxy (see below),
# but first you should make sure that you have read the man page
# regarding proxies (keyserver option honor-http-proxy)
#
# Most users just set the name and type of their preferred keyserver.
# Most servers do synchronize with each other and DNS round-robin may
# give you a quasi-random server each time.
#keyserver x-hkp://pgp.mit.edu
#keyserver mailto:pgp-public-keys@keys.nl.pgp.net
#keyserver ldap://pgp.surfnet.nl:11370
#keyserver ldap://keyserver.pgp.com
# Common options for keyserver functions:
#
# include-disabled = when searching, include keys marked as "disabled"
# on the keyserver (not all keyservers support this).
#
# no-include-revoked = when searching, do not include keys marked as
# "revoked" on the keyserver.
#
# verbose = show more information as the keys are fetched.
# Can be used more than once to increase the amount
# of information shown.
#
# use-temp-files = use temporary files instead of a pipe to talk to the
# keyserver. Some platforms (Win32 for one) always
# have this on.
#
# keep-temp-files = do not delete temporary files after using them
# (really only useful for debugging)
#
# honor-http-proxy = if the keyserver uses HTTP, honor the http_proxy
# environment variable
#
# broken-http-proxy = try to work around a buggy HTTP proxy
#
# auto-key-retrieve = automatically fetch keys as needed from the keyserver
# when verifying signatures or when importing keys that
# have been revoked by a revocation key that is not
# present on the keyring.
#
# no-include-attributes = do not include attribute IDs (aka "photo IDs")
# when sending keys to the keyserver.
#keyserver-options auto-key-retrieve
# Uncomment this line to display photo user IDs in key listings and
# when a signature from a key with a photo is verified.
#show-photos
# Use this program to display photo user IDs
#
# %i is expanded to a temporary file that contains the photo.
# %I is the same as %i, but the file isn't deleted afterwards by GnuPG.
# %k is expanded to the key ID of the key.
# %K is expanded to the long OpenPGP key ID of the key.
# %t is expanded to the extension of the image (e.g. "jpg").
# %T is expanded to the MIME type of the image (e.g. "image/jpeg").
# %f is expanded to the fingerprint of the key.
# %% is %, of course.
#
# If %i or %I are not present, then the photo is supplied to the
# viewer on standard input. If your platform supports it, standard
# input is the best way to do this as it avoids the time and effort in
# generating and then cleaning up a secure temp file.
#
# The default program is "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin"
# On Mac OS X and Windows, the default is to use your regular JPEG image
# viewer.
#
# Some other viewers:
# photo-viewer "qiv %i"
# photo-viewer "ee %i"
# photo-viewer "display -title 'KeyID 0x%k'"
#
# This one saves a copy of the photo ID in your home directory:
# photo-viewer "cat > ~/photoid-for-key-%k.%t"
#
# Use your MIME handler to view photos:
# photo-viewer "metamail -q -d -b -c %T -s 'KeyID 0x%k' -f GnuPG"
# Passphrase agent
#
# We support the old experimental passphrase agent protocol as well as
# the new Assuan based one (currently available in the "newpg" package
# at ftp.gnupg.org/gcrypt/alpha/aegypten/). To make use of the agent,
# you have to run an agent as daemon and use the option
#
# use-agent
#
# which tries to use the agent but will fallback to the regular mode
# if there is a problem connecting to the agent. The normal way to
# locate the agent is by looking at the environment variable
# GPG_AGENT_INFO which should have been set during gpg-agent startup.
# In certain situations the use of this variable is not possible, thus
# the option
#
# --gpg-agent-info=<path>:<pid>:1
#
# may be used to override it.

510
g10/packet.h Normal file
View file

@ -0,0 +1,510 @@
/* packet.h - packet definitions
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_PACKET_H
#define G10_PACKET_H
#include "types.h"
#include "iobuf.h"
#include "mpi.h"
#include "cipher.h"
#include "filter.h"
#include "global.h"
#define DEBUG_PARSE_PACKET 1
typedef enum {
PKT_NONE =0,
PKT_PUBKEY_ENC =1, /* public key encrypted packet */
PKT_SIGNATURE =2, /* secret key encrypted packet */
PKT_SYMKEY_ENC =3, /* session key packet (OpenPGP)*/
PKT_ONEPASS_SIG =4, /* one pass sig packet (OpenPGP)*/
PKT_SECRET_KEY =5, /* secret key */
PKT_PUBLIC_KEY =6, /* public key */
PKT_SECRET_SUBKEY =7, /* secret subkey (OpenPGP) */
PKT_COMPRESSED =8, /* compressed data packet */
PKT_ENCRYPTED =9, /* conventional encrypted data */
PKT_MARKER =10, /* marker packet (OpenPGP) */
PKT_PLAINTEXT =11, /* plaintext data with filename and mode */
PKT_RING_TRUST =12, /* keyring trust packet */
PKT_USER_ID =13, /* user id packet */
PKT_PUBLIC_SUBKEY =14, /* public subkey (OpenPGP) */
PKT_OLD_COMMENT =16, /* comment packet from an OpenPGP draft */
PKT_ATTRIBUTE =17, /* PGP's attribute packet */
PKT_ENCRYPTED_MDC =18, /* integrity protected encrypted data */
PKT_MDC =19, /* manipulation detection code packet */
PKT_COMMENT =61, /* new comment packet (private) */
PKT_GPG_CONTROL =63 /* internal control packet */
} pkttype_t;
typedef struct packet_struct PACKET;
/* PKT_GPG_CONTROL types */
typedef enum {
CTRLPKT_CLEARSIGN_START = 1,
CTRLPKT_PIPEMODE = 2,
CTRLPKT_PLAINTEXT_MARK =3
} ctrlpkttype_t;
typedef enum {
PREFTYPE_NONE = 0,
PREFTYPE_SYM = 1,
PREFTYPE_HASH = 2,
PREFTYPE_ZIP = 3
} preftype_t;
typedef struct {
byte type;
byte value;
} prefitem_t;
typedef struct {
int mode;
byte hash_algo;
byte salt[8];
u32 count;
} STRING2KEY;
typedef struct {
byte version;
byte cipher_algo; /* cipher algorithm used */
STRING2KEY s2k;
byte seskeylen; /* keylength in byte or 0 for no seskey */
byte seskey[1];
} PKT_symkey_enc;
typedef struct {
u32 keyid[2]; /* 64 bit keyid */
byte version;
byte pubkey_algo; /* algorithm used for public key scheme */
byte throw_keyid;
MPI data[PUBKEY_MAX_NENC];
} PKT_pubkey_enc;
typedef struct {
u32 keyid[2]; /* 64 bit keyid */
byte sig_class; /* sig classification */
byte digest_algo; /* algorithm used for digest */
byte pubkey_algo; /* algorithm used for public key scheme */
byte last; /* a stupid flag */
} PKT_onepass_sig;
typedef struct {
size_t size; /* allocated */
size_t len; /* used */
byte data[1];
} subpktarea_t;
struct revocation_key {
byte class;
byte algid;
byte fpr[MAX_FINGERPRINT_LEN];
};
typedef struct {
ulong local_id; /* internal use, valid if > 0 */
struct {
unsigned checked:1; /* signature has been checked */
unsigned valid:1; /* signature is good (if checked is set) */
unsigned unknown_critical:1;
unsigned exportable:1;
unsigned revocable:1;
unsigned policy_url:1; /* Policy URL is present */
unsigned notation:1; /* At least one notation is present */
unsigned expired:1;
} flags;
u32 keyid[2]; /* 64 bit keyid */
u32 timestamp; /* signature made */
u32 expiredate; /* expires at this date or 0 if not at all */
byte version;
byte sig_class; /* sig classification, append for MD calculation*/
byte pubkey_algo; /* algorithm used for public key scheme */
/* (PUBKEY_ALGO_xxx) */
byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */
byte trust_depth;
byte trust_value;
const byte *trust_regexp;
struct revocation_key **revkey;
int numrevkeys;
subpktarea_t *hashed; /* all subpackets with hashed data (v4 only) */
subpktarea_t *unhashed; /* ditto for unhashed data */
byte digest_start[2]; /* first 2 bytes of the digest */
MPI data[PUBKEY_MAX_NSIG];
} PKT_signature;
#define ATTRIB_IMAGE 1
/* This is the cooked form of attributes */
struct user_attribute {
byte type;
const byte *data;
u32 len;
};
typedef struct {
int ref; /* reference counter */
int len; /* length of the name */
struct user_attribute *attribs;
int numattribs;
byte *attrib_data; /* if this is not NULL, the packet is an attribute */
unsigned long attrib_len;
byte *namehash;
int help_key_usage;
u32 help_key_expire;
int help_full_count;
int help_marginal_count;
int is_primary; /* 2 if set via the primary flag, 1 if calculated */
int is_revoked;
int is_expired;
u32 expiredate; /* expires at this date or 0 if not at all */
prefitem_t *prefs; /* list of preferences (may be NULL)*/
int mdc_feature;
int ks_modify;
u32 created; /* according to the self-signature */
byte selfsigversion;
char name[1];
} PKT_user_id;
/****************
* Note about the pkey/skey elements: We assume that the secret keys
* has the same elemts as the public key at the begin of the array, so
* that npkey < nskey and it is possible to compare the secret and
* public keys by comparing the first npkey elements of pkey againts skey.
*/
typedef struct {
u32 timestamp; /* key made */
u32 expiredate; /* expires at this date or 0 if not at all */
u32 max_expiredate; /* must not expire past this date */
byte hdrbytes; /* number of header bytes */
byte version;
byte selfsigversion; /* highest version of all of the self-sigs */
byte pubkey_algo; /* algorithm used for public key scheme */
byte pubkey_usage; /* for now only used to pass it to getkey() */
byte req_usage; /* hack to pass a request to getkey() */
byte req_algo; /* Ditto */
u32 has_expired; /* set to the expiration date if expired */
int is_revoked; /* key has been revoked */
int is_valid; /* key (especially subkey) is valid */
int dont_cache; /* do not cache this */
ulong local_id; /* internal use, valid if > 0 */
u32 main_keyid[2]; /* keyid of the primary key */
u32 keyid[2]; /* calculated by keyid_from_pk() */
byte is_primary;
byte is_disabled; /* 0 for unset, 1 for enabled, 2 for disabled. */
prefitem_t *prefs; /* list of preferences (may be NULL) */
int mdc_feature; /* mdc feature set */
PKT_user_id *user_id; /* if != NULL: found by that uid */
struct revocation_key *revkey;
int numrevkeys;
u32 trust_timestamp;
byte trust_depth;
byte trust_value;
const byte *trust_regexp;
MPI pkey[PUBKEY_MAX_NPKEY];
} PKT_public_key;
/* Evaluates as true if the pk is disabled, and false if it isn't. If
there is no disable value cached, fill one in. */
#define pk_is_disabled(a) (((a)->is_disabled)?((a)->is_disabled==2):(cache_disabled_value((a))))
typedef struct {
u32 timestamp; /* key made */
u32 expiredate; /* expires at this date or 0 if not at all */
u32 max_expiredate; /* must not expire past this date */
byte hdrbytes; /* number of header bytes */
byte version;
byte pubkey_algo; /* algorithm used for public key scheme */
byte pubkey_usage;
byte req_usage;
byte req_algo;
u32 has_expired; /* set to the expiration date if expired */
int is_revoked; /* key has been revoked */
int is_valid; /* key (especially subkey) is valid */
u32 main_keyid[2]; /* keyid of the primary key */
u32 keyid[2];
byte is_primary;
byte is_protected; /* The secret info is protected and must */
/* be decrypted before use, the protected */
/* MPIs are simply (void*) pointers to memory */
/* and should never be passed to a mpi_xxx() */
struct {
byte algo; /* cipher used to protect the secret information*/
byte sha1chk; /* SHA1 is used instead of a 16 bit checksum */
STRING2KEY s2k;
byte ivlen; /* used length of the iv */
byte iv[16]; /* initialization vector for CFB mode */
} protect;
MPI skey[PUBKEY_MAX_NSKEY];
u16 csum; /* checksum */
} PKT_secret_key;
typedef struct {
int len; /* length of data */
char data[1];
} PKT_comment;
typedef struct {
u32 len; /* reserved */
byte new_ctb;
byte algorithm;
IOBUF buf; /* IOBUF reference */
} PKT_compressed;
typedef struct {
u32 len; /* length of encrypted data */
int extralen; /* this is (blocksize+2) */
byte new_ctb; /* uses a new CTB */
byte mdc_method; /* > 0: integrity protected encrypted data packet */
IOBUF buf; /* IOBUF reference */
} PKT_encrypted;
typedef struct {
byte hash[20];
} PKT_mdc;
typedef struct {
unsigned int trustval;
unsigned int sigcache;
} PKT_ring_trust;
typedef struct {
u32 len; /* length of encrypted data */
IOBUF buf; /* IOBUF reference */
byte new_ctb;
byte is_partial; /* partial length encoded */
int mode;
u32 timestamp;
int namelen;
char name[1];
} PKT_plaintext;
typedef struct {
int control;
size_t datalen;
char data[1];
} PKT_gpg_control;
/* combine all packets into a union */
struct packet_struct {
pkttype_t pkttype;
union {
void *generic;
PKT_symkey_enc *symkey_enc; /* PKT_SYMKEY_ENC */
PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */
PKT_onepass_sig *onepass_sig; /* PKT_ONEPASS_SIG */
PKT_signature *signature; /* PKT_SIGNATURE */
PKT_public_key *public_key; /* PKT_PUBLIC_[SUB)KEY */
PKT_secret_key *secret_key; /* PKT_SECRET_[SUB]KEY */
PKT_comment *comment; /* PKT_COMMENT */
PKT_user_id *user_id; /* PKT_USER_ID */
PKT_compressed *compressed; /* PKT_COMPRESSED */
PKT_encrypted *encrypted; /* PKT_ENCRYPTED[_MDC] */
PKT_mdc *mdc; /* PKT_MDC */
PKT_ring_trust *ring_trust; /* PKT_RING_TRUST */
PKT_plaintext *plaintext; /* PKT_PLAINTEXT */
PKT_gpg_control *gpg_control; /* PKT_GPG_CONTROL */
} pkt;
};
#define init_packet(a) do { (a)->pkttype = 0; \
(a)->pkt.generic = NULL; \
} while(0)
typedef enum {
SIGSUBPKT_TEST_CRITICAL=-3,
SIGSUBPKT_LIST_UNHASHED=-2,
SIGSUBPKT_LIST_HASHED =-1,
SIGSUBPKT_NONE = 0,
SIGSUBPKT_SIG_CREATED = 2, /* signature creation time */
SIGSUBPKT_SIG_EXPIRE = 3, /* signature expiration time */
SIGSUBPKT_EXPORTABLE = 4, /* exportable */
SIGSUBPKT_TRUST = 5, /* trust signature */
SIGSUBPKT_REGEXP = 6, /* regular expression */
SIGSUBPKT_REVOCABLE = 7, /* revocable */
SIGSUBPKT_KEY_EXPIRE = 9, /* key expiration time */
SIGSUBPKT_ARR =10, /* additional recipient request */
SIGSUBPKT_PREF_SYM =11, /* preferred symmetric algorithms */
SIGSUBPKT_REV_KEY =12, /* revocation key */
SIGSUBPKT_ISSUER =16, /* issuer key ID */
SIGSUBPKT_NOTATION =20, /* notation data */
SIGSUBPKT_PREF_HASH =21, /* preferred hash algorithms */
SIGSUBPKT_PREF_COMPR =22, /* preferred compression algorithms */
SIGSUBPKT_KS_FLAGS =23, /* key server preferences */
SIGSUBPKT_PREF_KS =24, /* preferred key server */
SIGSUBPKT_PRIMARY_UID =25, /* primary user id */
SIGSUBPKT_POLICY =26, /* policy URL */
SIGSUBPKT_KEY_FLAGS =27, /* key flags */
SIGSUBPKT_SIGNERS_UID =28, /* signer's user id */
SIGSUBPKT_REVOC_REASON =29, /* reason for revocation */
SIGSUBPKT_FEATURES =30, /* feature flags */
SIGSUBPKT_FLAG_CRITICAL=128
} sigsubpkttype_t;
/*-- mainproc.c --*/
int proc_packets( void *ctx, IOBUF a );
int proc_signature_packets( void *ctx, IOBUF a,
STRLIST signedfiles, const char *sigfile );
int proc_encryption_packets( void *ctx, IOBUF a );
int list_packets( IOBUF a );
/*-- parse-packet.c --*/
int set_packet_list_mode( int mode );
#if DEBUG_PARSE_PACKET
int dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid,
const char* file, int lineno );
int dbg_parse_packet( IOBUF inp, PACKET *ret_pkt,
const char* file, int lineno );
int dbg_copy_all_packets( IOBUF inp, IOBUF out,
const char* file, int lineno );
int dbg_copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff,
const char* file, int lineno );
int dbg_skip_some_packets( IOBUF inp, unsigned n,
const char* file, int lineno );
#define search_packet( a,b,c,d ) \
dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ )
#define parse_packet( a, b ) \
dbg_parse_packet( (a), (b), __FILE__, __LINE__ )
#define copy_all_packets( a,b ) \
dbg_copy_all_packets((a),(b), __FILE__, __LINE__ )
#define copy_some_packets( a,b,c ) \
dbg_copy_some_packets((a),(b),(c), __FILE__, __LINE__ )
#define skip_some_packets( a,b ) \
dbg_skip_some_packets((a),(b), __FILE__, __LINE__ )
#else
int search_packet( IOBUF inp, PACKET *pkt, off_t *retpos, int with_uid );
int parse_packet( IOBUF inp, PACKET *ret_pkt);
int copy_all_packets( IOBUF inp, IOBUF out );
int copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff );
int skip_some_packets( IOBUF inp, unsigned n );
#endif
const byte *enum_sig_subpkt ( const subpktarea_t *subpkts,
sigsubpkttype_t reqtype,
size_t *ret_n, int *start, int *critical );
const byte *parse_sig_subpkt ( const subpktarea_t *buffer,
sigsubpkttype_t reqtype,
size_t *ret_n );
const byte *parse_sig_subpkt2 ( PKT_signature *sig,
sigsubpkttype_t reqtype,
size_t *ret_n );
int parse_one_sig_subpkt( const byte *buffer, size_t n, int type );
void parse_revkeys(PKT_signature *sig);
int parse_attribute_subpkts(PKT_user_id *uid);
void make_attribute_uidname(PKT_user_id *uid, size_t max_namelen);
PACKET *create_gpg_control ( ctrlpkttype_t type,
const byte *data,
size_t datalen );
/*-- build-packet.c --*/
int build_packet( IOBUF inp, PACKET *pkt );
u32 calc_packet_length( PACKET *pkt );
void hash_public_key( MD_HANDLE md, PKT_public_key *pk );
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen );
void build_sig_subpkt_from_sig( PKT_signature *sig );
int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
void build_attribute_subpkt(PKT_user_id *uid,byte type,
const void *buf,u32 buflen,
const void *header,u32 headerlen);
/*-- free-packet.c --*/
void free_symkey_enc( PKT_symkey_enc *enc );
void free_pubkey_enc( PKT_pubkey_enc *enc );
void free_seckey_enc( PKT_signature *enc );
int digest_algo_from_sig( PKT_signature *sig );
void release_public_key_parts( PKT_public_key *pk );
void free_public_key( PKT_public_key *key );
void release_secret_key_parts( PKT_secret_key *sk );
void free_secret_key( PKT_secret_key *sk );
void free_attributes(PKT_user_id *uid);
void free_user_id( PKT_user_id *uid );
void free_comment( PKT_comment *rem );
void free_packet( PACKET *pkt );
prefitem_t *copy_prefs (const prefitem_t *prefs);
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
void copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk );
PKT_secret_key *copy_secret_key( PKT_secret_key *d, PKT_secret_key *s );
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
PKT_user_id *scopy_user_id (PKT_user_id *sd );
int cmp_public_keys( PKT_public_key *a, PKT_public_key *b );
int cmp_secret_keys( PKT_secret_key *a, PKT_secret_key *b );
int cmp_signatures( PKT_signature *a, PKT_signature *b );
int cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk );
int cmp_user_ids( PKT_user_id *a, PKT_user_id *b );
/*-- sig-check.c --*/
int signature_check( PKT_signature *sig, MD_HANDLE digest );
int signature_check2( PKT_signature *sig, MD_HANDLE digest,
u32 *r_expiredate, int *r_expired );
/*-- seckey-cert.c --*/
int is_secret_key_protected( PKT_secret_key *sk );
int check_secret_key( PKT_secret_key *sk, int retries );
int protect_secret_key( PKT_secret_key *sk, DEK *dek );
/*-- pubkey-enc.c --*/
int get_session_key( PKT_pubkey_enc *k, DEK *dek );
int get_override_session_key( DEK *dek, const char *string );
/*-- compress.c --*/
int handle_compressed( void *ctx, PKT_compressed *cd,
int (*callback)(IOBUF, void *), void *passthru );
/*-- encr-data.c --*/
int decrypt_data( void *ctx, PKT_encrypted *ed, DEK *dek );
/*-- plaintext.c --*/
int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
int nooutput, int clearsig );
int ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
const char *inname, int textmode );
/*-- comment.c --*/
int write_comment( IOBUF out, const char *s );
/*-- sign.c --*/
int make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
PKT_user_id *uid, PKT_public_key *subpk,
PKT_secret_key *sk, int sigclass, int digest_algo,
int sigversion, u32 timestamp, u32 duration,
int (*mksubpkt)(PKT_signature *, void *),
void *opaque );
int update_keysig_packet( PKT_signature **ret_sig,
PKT_signature *orig_sig,
PKT_public_key *pk,
PKT_user_id *uid,
PKT_public_key *subpk,
PKT_secret_key *sk,
int (*mksubpkt)(PKT_signature *, void *),
void *opaque );
/*-- keygen.c --*/
PKT_user_id *generate_user_id(void);
#endif /*G10_PACKET_H*/

2281
g10/parse-packet.c Normal file

File diff suppressed because it is too large Load diff

1238
g10/passphrase.c Normal file

File diff suppressed because it is too large Load diff

333
g10/photoid.c Normal file
View file

@ -0,0 +1,333 @@
/* photoid.c - photo ID handling code
* Copyright (C) 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#ifdef __MINGW32__
# include <windows.h>
# ifndef VER_PLATFORM_WIN32_WINDOWS
# define VER_PLATFORM_WIN32_WINDOWS 1
# endif
#endif
#include "packet.h"
#include "status.h"
#include "exec.h"
#include "keydb.h"
#include "util.h"
#include "i18n.h"
#include "iobuf.h"
#include "memory.h"
#include "options.h"
#include "main.h"
#include "photoid.h"
/* Generate a new photo id packet, or return NULL if canceled */
PKT_user_id *generate_photo_id(PKT_public_key *pk)
{
PKT_user_id *uid;
int error=1,i;
unsigned int len;
char *filename=NULL;
byte *photo=NULL;
byte header[16];
IOBUF file;
header[0]=0x10; /* little side of photo header length */
header[1]=0; /* big side of photo header length */
header[2]=1; /* 1 == version of photo header */
header[3]=1; /* 1 == JPEG */
for(i=4;i<16;i++) /* The reserved bytes */
header[i]=0;
#define EXTRA_UID_NAME_SPACE 71
uid=m_alloc_clear(sizeof(*uid)+71);
printf(_("\nPick an image to use for your photo ID. "
"The image must be a JPEG file.\n"
"Remember that the image is stored within your public key. "
"If you use a\n"
"very large picture, your key will become very large as well!\n"
"Keeping the image close to 240x288 is a good size to use.\n"));
while(photo==NULL)
{
printf("\n");
m_free(filename);
filename=cpr_get("photoid.jpeg.add",
_("Enter JPEG filename for photo ID: "));
if(strlen(filename)==0)
goto scram;
file=iobuf_open(filename);
if(!file)
{
log_error(_("Unable to open photo \"%s\": %s\n"),
filename,strerror(errno));
continue;
}
len=iobuf_get_filelength(file);
if(len>6144)
{
printf("This JPEG is really large (%d bytes) !\n",len);
if(!cpr_get_answer_is_yes("photoid.jpeg.size",
_("Are you sure you want to use it (y/N)? ")))
{
iobuf_close(file);
continue;
}
}
photo=m_alloc(len);
iobuf_read(file,photo,len);
iobuf_close(file);
/* Is it a JPEG? */
if(photo[0]!=0xFF || photo[1]!=0xD8 ||
photo[6]!='J' || photo[7]!='F' || photo[8]!='I' || photo[9]!='F')
{
log_error(_("\"%s\" is not a JPEG file\n"),filename);
m_free(photo);
photo=NULL;
continue;
}
/* Build the packet */
build_attribute_subpkt(uid,1,photo,len,header,16);
parse_attribute_subpkts(uid);
make_attribute_uidname(uid, EXTRA_UID_NAME_SPACE);
/* Showing the photo is not safe when noninteractive since the
"user" may not be able to dismiss a viewer window! */
if(opt.command_fd==-1)
{
show_photos(uid->attribs,uid->numattribs,pk,NULL);
switch(cpr_get_answer_yes_no_quit("photoid.jpeg.okay",
_("Is this photo correct (y/N/q)? ")))
{
case -1:
goto scram;
case 0:
free_attributes(uid);
m_free(photo);
photo=NULL;
continue;
}
}
}
error=0;
uid->ref=1;
scram:
m_free(filename);
m_free(photo);
if(error)
{
free_attributes(uid);
m_free(uid);
return NULL;
}
return uid;
}
/* Returns 0 for error, 1 for valid */
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len)
{
u16 headerlen;
if(attr->len<3)
return 0;
/* For historical reasons (i.e. "oops!"), the header length is
little endian. */
headerlen=(attr->data[1]<<8) | attr->data[0];
if(headerlen>attr->len)
return 0;
if(type && attr->len>=4)
{
if(attr->data[2]==1) /* header version 1 */
*type=attr->data[3];
else
*type=0;
}
*len=attr->len-headerlen;
if(*len==0)
return 0;
return 1;
}
/* style==0 for extension, 1 for name, 2 for MIME type. Remember that
the "name" style string could be used in a user ID name field, so
make sure it is not too big (see parse-packet.c:parse_attribute).
Extensions should be 3 characters long for the best cross-platform
compatibility. */
char *image_type_to_string(byte type,int style)
{
char *string;
switch(type)
{
case 1: /* jpeg */
if(style==0)
string="jpg";
else if(style==1)
string="jpeg";
else
string="image/jpeg";
break;
default:
if(style==0)
string="bin";
else if(style==1)
string="unknown";
else
string="image/x-unknown";
break;
}
return string;
}
#if !defined(FIXED_PHOTO_VIEWER) && !defined(DISABLE_PHOTO_VIEWER)
static const char *get_default_photo_command(void)
{
#if defined(__MINGW32__)
OSVERSIONINFO osvi;
memset(&osvi,0,sizeof(osvi));
osvi.dwOSVersionInfoSize=sizeof(osvi);
GetVersionEx(&osvi);
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
return "start /w %i";
else
return "cmd /c start /w %i";
#elif defined(__APPLE__)
/* OS X. This really needs more than just __APPLE__. */
return "open %I";
#elif defined(__riscos__)
return "Filer_Run %I";
#else
return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
#endif
}
#endif
void show_photos(const struct user_attribute *attrs,
int count,PKT_public_key *pk,PKT_secret_key *sk)
{
#ifndef DISABLE_PHOTO_VIEWER
int i;
struct expando_args args;
u32 len;
u32 kid[2]={0,0};
memset(&args,0,sizeof(args));
args.pk=pk;
args.sk=sk;
if(pk)
keyid_from_pk(pk,kid);
else if(sk)
keyid_from_sk(sk,kid);
for(i=0;i<count;i++)
if(attrs[i].type==ATTRIB_IMAGE &&
parse_image_header(&attrs[i],&args.imagetype,&len))
{
char *command,*name;
struct exec_info *spawn;
int offset=attrs[i].len-len;
#ifdef FIXED_PHOTO_VIEWER
opt.photo_viewer=FIXED_PHOTO_VIEWER;
#else
if(!opt.photo_viewer)
opt.photo_viewer=get_default_photo_command();
#endif
/* make command grow */
command=pct_expando(opt.photo_viewer,&args);
if(!command)
goto fail;
name=m_alloc(16+strlen(EXTSEP_S)+
strlen(image_type_to_string(args.imagetype,0))+1);
/* Make the filename. Notice we are not using the image
encoding type for more than cosmetics. Most external image
viewers can handle a multitude of types, and even if one
cannot understand a particular type, we have no way to know
which. The spec permits this, by the way. -dms */
#ifdef USE_ONLY_8DOT3
sprintf(name,"%08lX" EXTSEP_S "%s",(ulong)kid[1],
image_type_to_string(args.imagetype,0));
#else
sprintf(name,"%08lX%08lX" EXTSEP_S "%s",(ulong)kid[0],(ulong)kid[1],
image_type_to_string(args.imagetype,0));
#endif
if(exec_write(&spawn,NULL,command,name,1,1)!=0)
{
m_free(name);
goto fail;
}
#ifdef __riscos__
riscos_set_filetype_by_mimetype(spawn->tempfile_in,
image_type_to_string(args.imagetype,2));
#endif
m_free(name);
fwrite(&attrs[i].data[offset],attrs[i].len-offset,1,spawn->tochild);
if(exec_read(spawn)!=0)
{
exec_finish(spawn);
goto fail;
}
if(exec_finish(spawn)!=0)
goto fail;
}
return;
fail:
log_error(_("unable to display photo ID!\n"));
#endif
}

34
g10/photoid.h Normal file
View file

@ -0,0 +1,34 @@
/* photoid.h
* Copyright (C) 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
/* Photo ID functions */
#ifndef _PHOTOID_H_
#define _PHOTOID_H_
#include "packet.h"
PKT_user_id *generate_photo_id(PKT_public_key *pk);
int parse_image_header(const struct user_attribute *attr,byte *type,u32 *len);
char *image_type_to_string(byte type,int style);
void show_photos(const struct user_attribute *attrs,
int count,PKT_public_key *pk,PKT_secret_key *sk);
#endif /* !_PHOTOID_H_ */

1376
g10/pkclist.c Normal file

File diff suppressed because it is too large Load diff

446
g10/plaintext.c Normal file
View file

@ -0,0 +1,446 @@
/* plaintext.c - process plaintext packets
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#ifdef HAVE_DOSISH_SYSTEM
#include <fcntl.h> /* for setmode() */
#endif
#include "util.h"
#include "memory.h"
#include "options.h"
#include "packet.h"
#include "ttyio.h"
#include "filter.h"
#include "main.h"
#include "status.h"
#include "i18n.h"
/****************
* Handle a plaintext packet. If MFX is not NULL, update the MDs
* Note: we should use the filter stuff here, but we have to add some
* easy mimic to set a read limit, so we calculate only the
* bytes from the plaintext.
*/
int
handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx,
int nooutput, int clearsig )
{
char *fname = NULL;
FILE *fp = NULL;
int rc = 0;
int c;
int convert = pt->mode == 't';
#ifdef __riscos__
int filetype = 0xfff;
#endif
/* create the filename as C string */
if( nooutput )
;
else if( opt.outfile ) {
fname = m_alloc( strlen( opt.outfile ) + 1);
strcpy(fname, opt.outfile );
}
else if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) ) {
log_info(_("data not saved; use option \"--output\" to save it\n"));
nooutput = 1;
}
else if( !opt.use_embedded_filename ) {
fname = make_outfile_name( iobuf_get_real_fname(pt->buf) );
if( !fname )
fname = ask_outfile_name( pt->name, pt->namelen );
if( !fname ) {
rc = G10ERR_CREATE_FILE;
goto leave;
}
}
else {
fname = make_printable_string( pt->name, pt->namelen, 0 );
}
if( nooutput )
;
else if( !*fname || (*fname=='-' && !fname[1])) {
/* no filename or "-" given; write to stdout */
fp = stdout;
#ifdef HAVE_DOSISH_SYSTEM
setmode ( fileno(fp) , O_BINARY );
#endif
}
else {
while( !overwrite_filep (fname) ) {
char *tmp = ask_outfile_name (NULL, 0);
if ( !tmp || !*tmp ) {
m_free (tmp);
rc = G10ERR_CREATE_FILE;
goto leave;
}
m_free (fname);
fname = tmp;
}
}
#ifndef __riscos__
if( fp || nooutput )
;
else if( !(fp = fopen(fname,"wb")) ) {
log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
rc = G10ERR_CREATE_FILE;
goto leave;
}
#else /* __riscos__ */
/* Convert all '.' in fname to '/' -- we don't create directories! */
for( c=0; fname[c]; ++c )
if( fname[c] == '.' )
fname[c] = '/';
if( fp || nooutput )
;
else {
fp = fopen(fname,"wb");
if( !fp ) {
log_error(_("error creating `%s': %s\n"), fname, strerror(errno) );
rc = G10ERR_CREATE_FILE;
if (errno == 106)
log_info("Do output file and input file have the same name?\n");
goto leave;
}
/* If there's a ,xxx extension in the embedded filename,
use that, else check whether the user input (in fname)
has a ,xxx appended, then use that in preference */
if( (c = riscos_get_filetype_from_string( pt->name,
pt->namelen )) != -1 )
filetype = c;
if( (c = riscos_get_filetype_from_string( fname,
strlen(fname) )) != -1 )
filetype = c;
riscos_set_filetype_by_number(fname, filetype);
}
#endif /* __riscos__ */
if( !pt->is_partial ) {
/* we have an actual length (which might be zero). */
assert( !clearsig );
if( convert ) { /* text mode */
for( ; pt->len; pt->len-- ) {
if( (c = iobuf_get(pt->buf)) == -1 ) {
log_error("Problem reading source (%u bytes remaining)\n",
(unsigned)pt->len);
rc = G10ERR_READ_FILE;
goto leave;
}
if( mfx->md )
md_putc(mfx->md, c );
#ifndef HAVE_DOSISH_SYSTEM
if( c == '\r' ) /* convert to native line ending */
continue; /* fixme: this hack might be too simple */
#endif
if( fp ) {
if( putc( c, fp ) == EOF ) {
log_error("Error writing to `%s': %s\n",
fname, strerror(errno) );
rc = G10ERR_WRITE_FILE;
goto leave;
}
}
}
}
else { /* binary mode */
byte *buffer = m_alloc( 32768 );
while( pt->len ) {
int len = pt->len > 32768 ? 32768 : pt->len;
len = iobuf_read( pt->buf, buffer, len );
if( len == -1 ) {
log_error("Problem reading source (%u bytes remaining)\n",
(unsigned)pt->len);
rc = G10ERR_READ_FILE;
m_free( buffer );
goto leave;
}
if( mfx->md )
md_write( mfx->md, buffer, len );
if( fp ) {
if( fwrite( buffer, 1, len, fp ) != len ) {
log_error("Error writing to `%s': %s\n",
fname, strerror(errno) );
rc = G10ERR_WRITE_FILE;
m_free( buffer );
goto leave;
}
}
pt->len -= len;
}
m_free( buffer );
}
}
else if( !clearsig ) {
if( convert ) { /* text mode */
while( (c = iobuf_get(pt->buf)) != -1 ) {
if( mfx->md )
md_putc(mfx->md, c );
#ifndef HAVE_DOSISH_SYSTEM
if( convert && c == '\r' )
continue; /* fixme: this hack might be too simple */
#endif
if( fp ) {
if( putc( c, fp ) == EOF ) {
log_error("Error writing to `%s': %s\n",
fname, strerror(errno) );
rc = G10ERR_WRITE_FILE;
goto leave;
}
}
}
}
else { /* binary mode */
byte *buffer = m_alloc( 32768 );
int eof;
for( eof=0; !eof; ) {
/* Why do we check for len < 32768:
* If we won't, we would practically read 2 EOFs but
* the first one has already popped the block_filter
* off and therefore we don't catch the boundary.
* So, always assume EOF if iobuf_read returns less bytes
* then requested */
int len = iobuf_read( pt->buf, buffer, 32768 );
if( len == -1 )
break;
if( len < 32768 )
eof = 1;
if( mfx->md )
md_write( mfx->md, buffer, len );
if( fp ) {
if( fwrite( buffer, 1, len, fp ) != len ) {
log_error("Error writing to `%s': %s\n",
fname, strerror(errno) );
rc = G10ERR_WRITE_FILE;
m_free( buffer );
goto leave;
}
}
}
m_free( buffer );
}
pt->buf = NULL;
}
else { /* clear text signature - don't hash the last cr,lf */
int state = 0;
while( (c = iobuf_get(pt->buf)) != -1 ) {
if( fp ) {
if( putc( c, fp ) == EOF ) {
log_error("Error writing to `%s': %s\n",
fname, strerror(errno) );
rc = G10ERR_WRITE_FILE;
goto leave;
}
}
if( !mfx->md )
continue;
if( state == 2 ) {
md_putc(mfx->md, '\r' );
md_putc(mfx->md, '\n' );
state = 0;
}
if( !state ) {
if( c == '\r' )
state = 1;
else if( c == '\n' )
state = 2;
else
md_putc(mfx->md, c );
}
else if( state == 1 ) {
if( c == '\n' )
state = 2;
else {
md_putc(mfx->md, '\r' );
if( c == '\r' )
state = 1;
else {
state = 0;
md_putc(mfx->md, c );
}
}
}
}
pt->buf = NULL;
}
if( fp && fp != stdout && fclose(fp) ) {
log_error("Error closing `%s': %s\n", fname, strerror(errno) );
fp = NULL;
rc = G10ERR_WRITE_FILE;
goto leave;
}
fp = NULL;
leave:
if( fp && fp != stdout )
fclose(fp);
m_free(fname);
return rc;
}
static void
do_hash( MD_HANDLE md, MD_HANDLE md2, IOBUF fp, int textmode )
{
text_filter_context_t tfx;
int c;
if( textmode ) {
memset( &tfx, 0, sizeof tfx);
iobuf_push_filter( fp, text_filter, &tfx );
}
if( md2 ) { /* work around a strange behaviour in pgp2 */
/* It seems that at least PGP5 converts a single CR to a CR,LF too */
int lc = -1;
while( (c = iobuf_get(fp)) != -1 ) {
if( c == '\n' && lc == '\r' )
md_putc(md2, c);
else if( c == '\n' ) {
md_putc(md2, '\r');
md_putc(md2, c);
}
else if( c != '\n' && lc == '\r' ) {
md_putc(md2, '\n');
md_putc(md2, c);
}
else
md_putc(md2, c);
if( md )
md_putc(md, c );
lc = c;
}
}
else {
while( (c = iobuf_get(fp)) != -1 ) {
if( md )
md_putc(md, c );
}
}
}
/****************
* Ask for the detached datafile and calculate the digest from it.
* INFILE is the name of the input file.
*/
int
ask_for_detached_datafile( MD_HANDLE md, MD_HANDLE md2,
const char *inname, int textmode )
{
progress_filter_context_t pfx;
char *answer = NULL;
IOBUF fp;
int rc = 0;
fp = open_sigfile( inname, &pfx ); /* open default file */
if( !fp && !opt.batch ) {
int any=0;
tty_printf(_("Detached signature.\n"));
do {
m_free(answer);
answer = cpr_get("detached_signature.filename",
_("Please enter name of data file: "));
cpr_kill_prompt();
if( any && !*answer ) {
rc = G10ERR_READ_FILE;
goto leave;
}
fp = iobuf_open(answer);
if( !fp && errno == ENOENT ) {
tty_printf("No such file, try again or hit enter to quit.\n");
any++;
}
else if( !fp ) {
log_error("can't open `%s': %s\n", answer, strerror(errno) );
rc = G10ERR_READ_FILE;
goto leave;
}
} while( !fp );
}
if( !fp ) {
if( opt.verbose )
log_info(_("reading stdin ...\n"));
fp = iobuf_open( NULL );
assert(fp);
}
do_hash( md, md2, fp, textmode );
iobuf_close(fp);
leave:
m_free(answer);
return rc;
}
/****************
* Hash the given files and append the hash to hash context md.
* If FILES is NULL, hash stdin.
*/
int
hash_datafiles( MD_HANDLE md, MD_HANDLE md2, STRLIST files,
const char *sigfilename, int textmode )
{
progress_filter_context_t pfx;
IOBUF fp;
STRLIST sl;
if( !files ) {
/* check whether we can open the signed material */
fp = open_sigfile( sigfilename, &pfx );
if( fp ) {
do_hash( md, md2, fp, textmode );
iobuf_close(fp);
return 0;
}
log_error (_("no signed data\n"));
return G10ERR_OPEN_FILE;
}
for (sl=files; sl; sl = sl->next ) {
fp = iobuf_open( sl->d );
if( !fp ) {
log_error(_("can't open signed data `%s'\n"),
print_fname_stdin(sl->d));
return G10ERR_OPEN_FILE;
}
handle_progress (&pfx, fp, sl->d);
do_hash( md, md2, fp, textmode );
iobuf_close(fp);
}
return 0;
}

117
g10/progress.c Normal file
View file

@ -0,0 +1,117 @@
/* progress.c
* Copyright (C) 2003 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include "iobuf.h"
#include "filter.h"
#include "status.h"
#include "util.h"
#include "options.h"
/****************
* The filter is used to report progress to the user.
*/
int
progress_filter (void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len)
{
int rc = 0;
progress_filter_context_t *pfx = opaque;
if (control == IOBUFCTRL_INIT)
{
char buffer[50];
pfx->last = 0;
pfx->offset = 0;
pfx->last_time = make_timestamp ();
sprintf (buffer, "%.20s ? %lu %lu",
pfx->what? pfx->what : "?",
pfx->offset,
pfx->total);
write_status_text (STATUS_PROGRESS, buffer);
}
else if (control == IOBUFCTRL_UNDERFLOW)
{
u32 timestamp = make_timestamp ();
int len = iobuf_read (a, buf, *ret_len);
if (len >= 0)
{
pfx->offset += len;
*ret_len = len;
}
else
{
*ret_len = 0;
rc = -1;
}
if ((len == -1 && pfx->offset != pfx->last)
|| timestamp - pfx->last_time > 0)
{
char buffer[50];
sprintf (buffer, "%.20s ? %lu %lu",
pfx->what? pfx->what : "?",
pfx->offset,
pfx->total);
write_status_text (STATUS_PROGRESS, buffer);
pfx->last = pfx->offset;
pfx->last_time = timestamp;
}
}
else if (control == IOBUFCTRL_FREE)
{
/* Note, that we must always dealloc resources of a filter
within the filter handler and not anywhere else. (We set it
to NULL and check all uses just in case.) */
m_free (pfx->what);
pfx->what = NULL;
}
else if (control == IOBUFCTRL_DESC)
*(char**)buf = "progress_filter";
return rc;
}
void
handle_progress (progress_filter_context_t *pfx, IOBUF inp, const char *name)
{
off_t filesize = 0;
if (!opt.enable_progress_filter)
return;
if (!is_status_enabled ())
return;
if (name && *name && !(*name == '-' && !name[1]))
filesize = iobuf_get_filelength (inp);
else if (opt.set_filesize)
filesize = opt.set_filesize;
/* register the progress filter */
pfx->what = m_strdup (name ? name : "stdin");
pfx->total = filesize;
iobuf_push_filter (inp, progress_filter, pfx);
}

690
g10/revoke.c Normal file
View file

@ -0,0 +1,690 @@
/* revoke.c
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <ctype.h>
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "keydb.h"
#include "memory.h"
#include "util.h"
#include "main.h"
#include "ttyio.h"
#include "status.h"
#include "i18n.h"
struct revocation_reason_info {
int code;
char *desc;
};
int
revocation_reason_build_cb( PKT_signature *sig, void *opaque )
{
struct revocation_reason_info *reason = opaque;
char *ud = NULL;
byte *buffer;
size_t buflen = 1;
if(!reason)
return 0;
if( reason->desc ) {
ud = native_to_utf8( reason->desc );
buflen += strlen(ud);
}
buffer = m_alloc( buflen );
*buffer = reason->code;
if( ud ) {
memcpy(buffer+1, ud, strlen(ud) );
m_free( ud );
}
build_sig_subpkt( sig, SIGSUBPKT_REVOC_REASON, buffer, buflen );
m_free( buffer );
return 0;
}
/* Outputs a minimal pk (as defined by 2440) from a keyblock. A
minimal pk consists of the public key packet and a user ID. We try
and pick a user ID that has a uid signature, and include it if
possible. */
static int
export_minimal_pk(IOBUF out,KBNODE keyblock,
PKT_signature *revsig,PKT_signature *revkey)
{
KBNODE node;
PACKET pkt;
PKT_user_id *uid=NULL;
PKT_signature *selfsig=NULL;
u32 keyid[2];
int rc;
node=find_kbnode(keyblock,PKT_PUBLIC_KEY);
if(!node)
{
log_error(_("key incomplete\n"));
return G10ERR_GENERAL;
}
keyid_from_pk(node->pkt->pkt.public_key,keyid);
pkt=*node->pkt;
rc=build_packet(out,&pkt);
if(rc)
{
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
return rc;
}
init_packet(&pkt);
pkt.pkttype=PKT_SIGNATURE;
/* the revocation itself, if any. 2440 likes this to come first. */
if(revsig)
{
pkt.pkt.signature=revsig;
rc=build_packet(out,&pkt);
if(rc)
{
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
return rc;
}
}
/* If a revkey in a 1F sig is present, include it too */
if(revkey)
{
pkt.pkt.signature=revkey;
rc=build_packet(out,&pkt);
if(rc)
{
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
return rc;
}
}
while(!selfsig)
{
KBNODE signode;
node=find_next_kbnode(node,PKT_USER_ID);
if(!node)
{
/* We're out of user IDs - none were self-signed. */
if(uid)
break;
else
{
log_error(_("key %08lX incomplete\n"),(ulong)keyid[1]);
return G10ERR_GENERAL;
}
}
if(node->pkt->pkt.user_id->attrib_data)
continue;
uid=node->pkt->pkt.user_id;
signode=node;
while((signode=find_next_kbnode(signode,PKT_SIGNATURE)))
{
if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
IS_UID_SIG(signode->pkt->pkt.signature))
{
selfsig=signode->pkt->pkt.signature;
break;
}
}
}
pkt.pkttype=PKT_USER_ID;
pkt.pkt.user_id=uid;
rc=build_packet(out,&pkt);
if(rc)
{
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
return rc;
}
if(selfsig)
{
pkt.pkttype=PKT_SIGNATURE;
pkt.pkt.signature=selfsig;
rc=build_packet(out,&pkt);
if(rc)
{
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
return rc;
}
}
return 0;
}
/****************
* Generate a revocation certificate for UNAME via a designated revoker
*/
int
gen_desig_revoke( const char *uname )
{
int rc = 0;
armor_filter_context_t afx;
PKT_public_key *pk = NULL;
PKT_secret_key *sk = NULL;
PKT_signature *sig = NULL;
IOBUF out = NULL;
struct revocation_reason_info *reason = NULL;
KEYDB_HANDLE kdbhd;
KEYDB_SEARCH_DESC desc;
KBNODE keyblock=NULL,node;
u32 keyid[2];
int i,any=0;
if( opt.batch ) {
log_error(_("sorry, can't do this in batch mode\n"));
return G10ERR_GENERAL;
}
memset( &afx, 0, sizeof afx);
kdbhd = keydb_new (0);
classify_user_id (uname, &desc);
rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
if (rc) {
log_error (_("key `%s' not found: %s\n"),uname, g10_errstr (rc));
goto leave;
}
rc = keydb_get_keyblock (kdbhd, &keyblock );
if( rc ) {
log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
goto leave;
}
/* To parse the revkeys */
merge_keys_and_selfsig(keyblock);
/* get the key from the keyblock */
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
if( !node )
BUG ();
pk=node->pkt->pkt.public_key;
keyid_from_pk(pk,keyid);
/* Are we a designated revoker for this key? */
if(!pk->revkey && pk->numrevkeys)
BUG();
for(i=0;i<pk->numrevkeys;i++)
{
if(sk)
free_secret_key(sk);
sk=m_alloc_clear(sizeof(*sk));
rc=get_seckey_byfprint(sk,pk->revkey[i].fpr,MAX_FINGERPRINT_LEN);
/* We have the revocation key */
if(!rc)
{
PKT_signature *revkey = NULL;
any = 1;
print_pubkey_info (pk);
tty_printf ("\n");
tty_printf (_("To be revoked by:\n"));
print_seckey_info (sk);
if(pk->revkey[i].class&0x40)
tty_printf(_("(This is a sensitive revocation key)\n"));
tty_printf("\n");
if( !cpr_get_answer_is_yes("gen_desig_revoke.okay",
_("Create a revocation certificate for this key? ")) )
continue;
/* get the reason for the revocation (this is always v4) */
reason = ask_revocation_reason( 1, 0, 1 );
if( !reason )
continue;
rc = check_secret_key( sk, 0 );
if( rc )
continue;
if( !opt.armor )
tty_printf(_("ASCII armored output forced.\n"));
if( (rc = open_outfile( NULL, 0, &out )) )
goto leave;
afx.what = 1;
afx.hdrlines = "Comment: A revocation certificate should follow\n";
iobuf_push_filter( out, armor_filter, &afx );
/* create it */
rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
0, 0, 0,
revocation_reason_build_cb, reason );
if( rc ) {
log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
goto leave;
}
/* Spit out a minimal pk as well, since otherwise there is
no way to know which key to attach this revocation to.
Also include the direct key signature that contains
this revocation key. We're allowed to include
sensitive revocation keys along with a revocation, as
this may be the only time the recipient has seen it.
Note that this means that if we have multiple different
sensitive revocation keys in a given direct key
signature, we're going to include them all here. This
is annoying, but the good outweighs the bad, since
without including this a sensitive revoker can't really
do their job. People should not include multiple
sensitive revocation keys in one signature: 2440 says
"Note that it may be appropriate to isolate this
subpacket within a separate signature so that it is not
combined with other subpackets that need to be
exported." -dms */
while(!revkey)
{
KBNODE signode;
signode=find_next_kbnode(node,PKT_SIGNATURE);
if(!signode)
break;
node=signode;
if(keyid[0]==signode->pkt->pkt.signature->keyid[0] &&
keyid[1]==signode->pkt->pkt.signature->keyid[1] &&
IS_KEY_SIG(signode->pkt->pkt.signature))
{
int j;
for(j=0;j<signode->pkt->pkt.signature->numrevkeys;j++)
{
if(pk->revkey[i].class==
signode->pkt->pkt.signature->revkey[j]->class &&
pk->revkey[i].algid==
signode->pkt->pkt.signature->revkey[j]->algid &&
memcmp(pk->revkey[i].fpr,
signode->pkt->pkt.signature->revkey[j]->fpr,
MAX_FINGERPRINT_LEN)==0)
{
revkey=signode->pkt->pkt.signature;
break;
}
}
}
}
if(!revkey)
BUG();
rc=export_minimal_pk(out,keyblock,sig,revkey);
if(rc)
goto leave;
/* and issue a usage notice */
tty_printf(_("Revocation certificate created.\n"));
break;
}
}
if(!any)
log_error(_("no revocation keys found for `%s'\n"),uname);
leave:
if( pk )
free_public_key( pk );
if( sk )
free_secret_key( sk );
if( sig )
free_seckey_enc( sig );
if( rc )
iobuf_cancel(out);
else
iobuf_close(out);
release_revocation_reason_info( reason );
return rc;
}
/****************
* Generate a revocation certificate for UNAME
*/
int
gen_revoke( const char *uname )
{
int rc = 0;
armor_filter_context_t afx;
PACKET pkt;
PKT_secret_key *sk; /* used as pointer into a kbnode */
PKT_public_key *pk = NULL;
PKT_signature *sig = NULL;
u32 sk_keyid[2];
IOBUF out = NULL;
KBNODE keyblock = NULL, pub_keyblock = NULL;
KBNODE node;
KEYDB_HANDLE kdbhd;
struct revocation_reason_info *reason = NULL;
KEYDB_SEARCH_DESC desc;
if( opt.batch ) {
log_error(_("sorry, can't do this in batch mode\n"));
return G10ERR_GENERAL;
}
memset( &afx, 0, sizeof afx);
init_packet( &pkt );
/* search the userid:
* We don't want the whole getkey stuff here but the entire keyblock
*/
kdbhd = keydb_new (1);
classify_user_id (uname, &desc);
rc = desc.mode? keydb_search (kdbhd, &desc, 1) : G10ERR_INV_USER_ID;
if (rc) {
log_error (_("secret key `%s' not found: %s\n"),
uname, g10_errstr (rc));
goto leave;
}
rc = keydb_get_keyblock (kdbhd, &keyblock );
if( rc ) {
log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
goto leave;
}
/* get the keyid from the keyblock */
node = find_kbnode( keyblock, PKT_SECRET_KEY );
if( !node )
BUG ();
/* fixme: should make a function out of this stuff,
* it's used all over the source */
sk = node->pkt->pkt.secret_key;
keyid_from_sk( sk, sk_keyid );
print_seckey_info (sk);
pk = m_alloc_clear( sizeof *pk );
/* FIXME: We should get the public key direct from the secret one */
pub_keyblock=get_pubkeyblock(sk_keyid);
if(!pub_keyblock)
{
log_error(_("no corresponding public key: %s\n"), g10_errstr(rc) );
goto leave;
}
node=find_kbnode(pub_keyblock,PKT_PUBLIC_KEY);
if(!node)
BUG();
pk=node->pkt->pkt.public_key;
if( cmp_public_secret_key( pk, sk ) ) {
log_error(_("public key does not match secret key!\n") );
rc = G10ERR_GENERAL;
goto leave;
}
tty_printf("\n");
if( !cpr_get_answer_is_yes("gen_revoke.okay",
_("Create a revocation certificate for this key? ")) ){
rc = 0;
goto leave;
}
if(sk->version>=4 || opt.force_v4_certs) {
/* get the reason for the revocation */
reason = ask_revocation_reason( 1, 0, 1 );
if( !reason ) { /* user decided to cancel */
rc = 0;
goto leave;
}
}
switch( is_secret_key_protected( sk ) ) {
case -1:
log_error(_("unknown protection algorithm\n"));
rc = G10ERR_PUBKEY_ALGO;
break;
case 0:
tty_printf(_("NOTE: This key is not protected!\n"));
break;
default:
rc = check_secret_key( sk, 0 );
break;
}
if( rc )
goto leave;
if( !opt.armor )
tty_printf(_("ASCII armored output forced.\n"));
if( (rc = open_outfile( NULL, 0, &out )) )
goto leave;
afx.what = 1;
afx.hdrlines = "Comment: A revocation certificate should follow\n";
iobuf_push_filter( out, armor_filter, &afx );
/* create it */
rc = make_keysig_packet( &sig, pk, NULL, NULL, sk, 0x20, 0,
opt.force_v4_certs?4:0, 0, 0,
revocation_reason_build_cb, reason );
if( rc ) {
log_error(_("make_keysig_packet failed: %s\n"), g10_errstr(rc));
goto leave;
}
if(PGP2 || PGP6 || PGP7 || PGP8)
{
/* Use a minimal pk for PGPx mode, since PGP can't import bare
revocation certificates. */
rc=export_minimal_pk(out,pub_keyblock,sig,NULL);
if(rc)
goto leave;
}
else
{
init_packet( &pkt );
pkt.pkttype = PKT_SIGNATURE;
pkt.pkt.signature = sig;
rc = build_packet( out, &pkt );
if( rc ) {
log_error(_("build_packet failed: %s\n"), g10_errstr(rc) );
goto leave;
}
}
/* and issue a usage notice */
tty_printf(_("Revocation certificate created.\n\n"
"Please move it to a medium which you can hide away; if Mallory gets\n"
"access to this certificate he can use it to make your key unusable.\n"
"It is smart to print this certificate and store it away, just in case\n"
"your media become unreadable. But have some caution: The print system of\n"
"your machine might store the data and make it available to others!\n"));
leave:
if( sig )
free_seckey_enc( sig );
release_kbnode( keyblock );
release_kbnode( pub_keyblock );
keydb_release (kdbhd);
if( rc )
iobuf_cancel(out);
else
iobuf_close(out);
release_revocation_reason_info( reason );
return rc;
}
struct revocation_reason_info *
ask_revocation_reason( int key_rev, int cert_rev, int hint )
{
int code=-1;
char *description = NULL;
struct revocation_reason_info *reason;
const char *text_0 = _("No reason specified");
const char *text_1 = _("Key has been compromised");
const char *text_2 = _("Key is superseded");
const char *text_3 = _("Key is no longer used");
const char *text_4 = _("User ID is no longer valid");
const char *code_text = NULL;
do {
code=-1;
m_free(description);
description = NULL;
tty_printf(_("Please select the reason for the revocation:\n"));
tty_printf( " 0 = %s\n", text_0 );
if( key_rev )
tty_printf(" 1 = %s\n", text_1 );
if( key_rev )
tty_printf(" 2 = %s\n", text_2 );
if( key_rev )
tty_printf(" 3 = %s\n", text_3 );
if( cert_rev )
tty_printf(" 4 = %s\n", text_4 );
tty_printf( " Q = %s\n", _("Cancel") );
if( hint )
tty_printf(_("(Probably you want to select %d here)\n"), hint );
while(code==-1) {
int n;
char *answer = cpr_get("ask_revocation_reason.code",
_("Your decision? "));
trim_spaces( answer );
cpr_kill_prompt();
if( *answer == 'q' || *answer == 'Q')
return NULL; /* cancel */
if( hint && !*answer )
n = hint;
else if(!isdigit( *answer ) )
n = -1;
else
n = atoi(answer);
m_free(answer);
if( n == 0 ) {
code = 0x00; /* no particular reason */
code_text = text_0;
}
else if( key_rev && n == 1 ) {
code = 0x02; /* key has been compromised */
code_text = text_1;
}
else if( key_rev && n == 2 ) {
code = 0x01; /* key is superseded */
code_text = text_2;
}
else if( key_rev && n == 3 ) {
code = 0x03; /* key is no longer used */
code_text = text_3;
}
else if( cert_rev && n == 4 ) {
code = 0x20; /* uid is no longer valid */
code_text = text_4;
}
else
tty_printf(_("Invalid selection.\n"));
}
tty_printf(_("Enter an optional description; "
"end it with an empty line:\n") );
for(;;) {
char *answer = cpr_get("ask_revocation_reason.text", "> " );
trim_trailing_ws( answer, strlen(answer) );
cpr_kill_prompt();
if( !*answer ) {
m_free(answer);
break;
}
{
char *p = make_printable_string( answer, strlen(answer), 0 );
m_free(answer);
answer = p;
}
if( !description )
description = m_strdup(answer);
else {
char *p = m_alloc( strlen(description) + strlen(answer) + 2 );
strcpy(stpcpy(stpcpy( p, description),"\n"),answer);
m_free(description);
description = p;
}
m_free(answer);
}
tty_printf(_("Reason for revocation: %s\n"), code_text );
if( !description )
tty_printf(_("(No description given)\n") );
else
tty_printf("%s\n", description );
} while( !cpr_get_answer_is_yes("ask_revocation_reason.okay",
_("Is this okay? ")) );
reason = m_alloc( sizeof *reason );
reason->code = code;
reason->desc = description;
return reason;
}
void
release_revocation_reason_info( struct revocation_reason_info *reason )
{
if( reason ) {
m_free( reason->desc );
m_free( reason );
}
}

400
g10/seckey-cert.c Normal file
View file

@ -0,0 +1,400 @@
/* seckey-cert.c - secret key certificate packet handling
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#include "memory.h"
#include "packet.h"
#include "mpi.h"
#include "keydb.h"
#include "cipher.h"
#include "main.h"
#include "options.h"
#include "i18n.h"
#include "status.h"
static int
do_check( PKT_secret_key *sk, const char *tryagain_text, int mode,
int *canceled )
{
byte *buffer;
u16 csum=0;
int i, res;
unsigned nbytes;
if( sk->is_protected ) { /* remove the protection */
DEK *dek = NULL;
u32 keyid[4]; /* 4! because we need two of them */
CIPHER_HANDLE cipher_hd=NULL;
PKT_secret_key *save_sk;
if( sk->protect.s2k.mode == 1001 ) {
log_info(_("secret key parts are not available\n"));
return G10ERR_GENERAL;
}
if( sk->protect.algo == CIPHER_ALGO_NONE )
BUG();
if( check_cipher_algo( sk->protect.algo ) ) {
log_info(_("protection algorithm %d%s is not supported\n"),
sk->protect.algo,sk->protect.algo==1?" (IDEA)":"" );
if (sk->protect.algo==CIPHER_ALGO_IDEA)
{
write_status (STATUS_RSA_OR_IDEA);
idea_cipher_warn (0);
}
return G10ERR_CIPHER_ALGO;
}
keyid_from_sk( sk, keyid );
keyid[2] = keyid[3] = 0;
if( !sk->is_primary ) {
keyid[2] = sk->main_keyid[0];
keyid[3] = sk->main_keyid[1];
}
dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo,
&sk->protect.s2k, mode,
tryagain_text, canceled );
if (!dek && canceled && *canceled)
return G10ERR_GENERAL;
cipher_hd = cipher_open( sk->protect.algo,
CIPHER_MODE_AUTO_CFB, 1);
cipher_setkey( cipher_hd, dek->key, dek->keylen );
m_free(dek);
save_sk = copy_secret_key( NULL, sk );
cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
csum = 0;
if( sk->version >= 4 ) {
int ndata;
byte *p, *data;
u16 csumc = 0;
i = pubkey_get_npkey(sk->pubkey_algo);
assert( mpi_is_opaque( sk->skey[i] ) );
p = mpi_get_opaque( sk->skey[i], &ndata );
if ( ndata > 1 )
csumc = p[ndata-2] << 8 | p[ndata-1];
data = m_alloc_secure( ndata );
cipher_decrypt( cipher_hd, data, p, ndata );
mpi_free( sk->skey[i] ); sk->skey[i] = NULL ;
p = data;
if (sk->protect.sha1chk) {
/* This is the new SHA1 checksum method to detect
tampering with the key as used by the Klima/Rosa
attack */
sk->csum = 0;
csum = 1;
if( ndata < 20 )
log_error("not enough bytes for SHA-1 checksum\n");
else {
MD_HANDLE h = md_open (DIGEST_ALGO_SHA1, 1);
if (!h)
BUG(); /* algo not available */
md_write (h, data, ndata - 20);
md_final (h);
if (!memcmp (md_read (h, DIGEST_ALGO_SHA1),
data + ndata - 20, 20) ) {
/* digest does match. We have to keep the old
style checksum in sk->csum, so that the
test used for unprotected keys does work.
This test gets used when we are adding new
keys. */
sk->csum = csum = checksum (data, ndata-20);
}
md_close (h);
}
}
else {
if( ndata < 2 ) {
log_error("not enough bytes for checksum\n");
sk->csum = 0;
csum = 1;
}
else {
csum = checksum( data, ndata-2);
sk->csum = data[ndata-2] << 8 | data[ndata-1];
if ( sk->csum != csum ) {
/* This is a PGP 7.0.0 workaround */
sk->csum = csumc; /* take the encrypted one */
}
}
}
/* must check it here otherwise the mpi_read_xx would fail
because the length may have an arbitrary value */
if( sk->csum == csum ) {
for( ; i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
nbytes = ndata;
sk->skey[i] = mpi_read_from_buffer(p, &nbytes, 1 );
ndata -= nbytes;
p += nbytes;
}
/* Note: at this point ndata should be 2 for a simple
checksum or 20 for the sha1 digest */
}
m_free(data);
}
else {
for(i=pubkey_get_npkey(sk->pubkey_algo);
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
byte *p;
int ndata;
unsigned int dummy;
assert (mpi_is_opaque (sk->skey[i]));
p = mpi_get_opaque (sk->skey[i], &ndata);
assert (ndata >= 2);
assert (ndata == ((p[0] << 8 | p[1]) + 7)/8 + 2);
buffer = m_alloc_secure (ndata);
cipher_sync (cipher_hd);
buffer[0] = p[0];
buffer[1] = p[1];
cipher_decrypt (cipher_hd, buffer+2, p+2, ndata-2);
csum += checksum (buffer, ndata);
mpi_free (sk->skey[i]);
dummy = ndata;
sk->skey[i] = mpi_read_from_buffer (buffer, &dummy, 1);
assert (sk->skey[i]);
m_free (buffer);
/* csum += checksum_mpi (sk->skey[i]); */
}
}
cipher_close( cipher_hd );
/* now let's see whether we have used the right passphrase */
if( csum != sk->csum ) {
copy_secret_key( sk, save_sk );
passphrase_clear_cache ( keyid, sk->pubkey_algo );
free_secret_key( save_sk );
return G10ERR_BAD_PASS;
}
/* the checksum may fail, so we also check the key itself */
res = pubkey_check_secret_key( sk->pubkey_algo, sk->skey );
if( res ) {
copy_secret_key( sk, save_sk );
passphrase_clear_cache ( keyid, sk->pubkey_algo );
free_secret_key( save_sk );
return G10ERR_BAD_PASS;
}
free_secret_key( save_sk );
sk->is_protected = 0;
}
else { /* not protected, assume it is okay if the checksum is okay */
csum = 0;
for(i=pubkey_get_npkey(sk->pubkey_algo);
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
csum += checksum_mpi( sk->skey[i] );
}
if( csum != sk->csum )
return G10ERR_CHECKSUM;
}
return 0;
}
/****************
* Check the secret key
* Ask up to 3 (or n) times for a correct passphrase
* If n is negative, disable the key info prompt and make n=abs(n)
*/
int
check_secret_key( PKT_secret_key *sk, int n )
{
int rc = G10ERR_BAD_PASS;
int i,mode;
if(n<0)
{
n=abs(n);
mode=1;
}
else
mode=0;
if( n < 1 )
n = (opt.batch && !opt.use_agent)? 1 : 3; /* use the default value */
for(i=0; i < n && rc == G10ERR_BAD_PASS; i++ ) {
int canceled = 0;
const char *tryagain = NULL;
if (i) {
tryagain = N_("Invalid passphrase; please try again");
log_info (_("%s ...\n"), _(tryagain));
}
rc = do_check( sk, tryagain, mode, &canceled );
if( rc == G10ERR_BAD_PASS && is_status_enabled() ) {
u32 kid[2];
char buf[50];
keyid_from_sk( sk, kid );
sprintf(buf, "%08lX%08lX", (ulong)kid[0], (ulong)kid[1]);
write_status_text( STATUS_BAD_PASSPHRASE, buf );
}
if( have_static_passphrase() || canceled)
break;
}
if( !rc )
write_status( STATUS_GOOD_PASSPHRASE );
return rc;
}
/****************
* check whether the secret key is protected.
* Returns: 0 not protected, -1 on error or the protection algorithm
*/
int
is_secret_key_protected( PKT_secret_key *sk )
{
return sk->is_protected? sk->protect.algo : 0;
}
/****************
* Protect the secret key with the passphrase from DEK
*/
int
protect_secret_key( PKT_secret_key *sk, DEK *dek )
{
int i,j, rc = 0;
byte *buffer;
unsigned nbytes;
u16 csum;
if( !dek )
return 0;
if( !sk->is_protected ) { /* okay, apply the protection */
CIPHER_HANDLE cipher_hd=NULL;
if( check_cipher_algo( sk->protect.algo ) )
rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
else {
print_cipher_algo_note( sk->protect.algo );
cipher_hd = cipher_open( sk->protect.algo,
CIPHER_MODE_AUTO_CFB, 1 );
if( cipher_setkey( cipher_hd, dek->key, dek->keylen ) )
log_info(_("WARNING: Weak key detected"
" - please change passphrase again.\n"));
sk->protect.ivlen = cipher_get_blocksize( sk->protect.algo );
assert( sk->protect.ivlen <= DIM(sk->protect.iv) );
if( sk->protect.ivlen != 8 && sk->protect.ivlen != 16 )
BUG(); /* yes, we are very careful */
randomize_buffer(sk->protect.iv, sk->protect.ivlen, 1);
cipher_setiv( cipher_hd, sk->protect.iv, sk->protect.ivlen );
if( sk->version >= 4 ) {
byte *bufarr[PUBKEY_MAX_NSKEY];
unsigned narr[PUBKEY_MAX_NSKEY];
unsigned nbits[PUBKEY_MAX_NSKEY];
int ndata=0;
byte *p, *data;
for(j=0, i = pubkey_get_npkey(sk->pubkey_algo);
i < pubkey_get_nskey(sk->pubkey_algo); i++, j++ ) {
assert( !mpi_is_opaque( sk->skey[i] ) );
bufarr[j] = mpi_get_buffer( sk->skey[i], &narr[j], NULL );
nbits[j] = mpi_get_nbits( sk->skey[i] );
ndata += narr[j] + 2;
}
for( ; j < PUBKEY_MAX_NSKEY; j++ )
bufarr[j] = NULL;
ndata += opt.simple_sk_checksum? 2 : 20; /* for checksum */
data = m_alloc_secure( ndata );
p = data;
for(j=0; j < PUBKEY_MAX_NSKEY && bufarr[j]; j++ ) {
p[0] = nbits[j] >> 8 ;
p[1] = nbits[j];
p += 2;
memcpy(p, bufarr[j], narr[j] );
p += narr[j];
m_free(bufarr[j]);
}
if (opt.simple_sk_checksum) {
log_info (_("generating the deprecated 16-bit checksum"
" for secret key protection\n"));
csum = checksum( data, ndata-2);
sk->csum = csum;
*p++ = csum >> 8;
*p++ = csum;
sk->protect.sha1chk = 0;
}
else {
MD_HANDLE h = md_open (DIGEST_ALGO_SHA1, 1);
if (!h)
BUG(); /* algo not available */
md_write (h, data, ndata - 20);
md_final (h);
memcpy (p, md_read (h, DIGEST_ALGO_SHA1), 20);
p += 20;
md_close (h);
sk->csum = csum = 0;
sk->protect.sha1chk = 1;
}
assert( p == data+ndata );
cipher_encrypt( cipher_hd, data, data, ndata );
for(i = pubkey_get_npkey(sk->pubkey_algo);
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
mpi_free( sk->skey[i] );
sk->skey[i] = NULL;
}
i = pubkey_get_npkey(sk->pubkey_algo);
sk->skey[i] = mpi_set_opaque(NULL, data, ndata );
}
else {
csum = 0;
for(i=pubkey_get_npkey(sk->pubkey_algo);
i < pubkey_get_nskey(sk->pubkey_algo); i++ ) {
byte *data;
unsigned int nbits;
csum += checksum_mpi (sk->skey[i]);
buffer = mpi_get_buffer( sk->skey[i], &nbytes, NULL );
cipher_sync (cipher_hd);
assert ( !mpi_is_opaque (sk->skey[i]) );
data = m_alloc (nbytes+2);
nbits = mpi_get_nbits (sk->skey[i]);
assert (nbytes == (nbits + 7)/8);
data[0] = nbits >> 8;
data[1] = nbits;
cipher_encrypt (cipher_hd, data+2, buffer, nbytes);
m_free( buffer );
mpi_free (sk->skey[i]);
sk->skey[i] = mpi_set_opaque (NULL, data, nbytes+2);
}
sk->csum = csum;
}
sk->is_protected = 1;
cipher_close( cipher_hd );
}
}
return rc;
}

625
g10/sig-check.c Normal file
View file

@ -0,0 +1,625 @@
/* sig-check.c - Check a signature
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#include "packet.h"
#include "memory.h"
#include "mpi.h"
#include "keydb.h"
#include "cipher.h"
#include "main.h"
#include "status.h"
#include "i18n.h"
#include "options.h"
struct cmp_help_context_s {
PKT_signature *sig;
MD_HANDLE md;
};
static int do_check( PKT_public_key *pk, PKT_signature *sig,
MD_HANDLE digest, int *r_expired );
/****************
* Check the signature which is contained in SIG.
* The MD_HANDLE should be currently open, so that this function
* is able to append some data, before finalizing the digest.
*/
int
signature_check( PKT_signature *sig, MD_HANDLE digest )
{
u32 dummy;
int dum2;
return signature_check2( sig, digest, &dummy, &dum2 );
}
int
signature_check2( PKT_signature *sig, MD_HANDLE digest,
u32 *r_expiredate, int *r_expired )
{
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
int rc=0;
*r_expiredate = 0;
/* Sanity check that the md has a context for the hash that the
sig is expecting. This can happen if a onepass sig header does
not match the actual sig, and also if the clearsign "Hash:"
header is missing or does not match the actual sig. */
if(!md_algo_present(digest,sig->digest_algo)) {
log_info(_("WARNING: signature digest conflict in message\n"));
rc=G10ERR_GENERAL;
}
else if( get_pubkey( pk, sig->keyid ) )
rc = G10ERR_NO_PUBKEY;
else if(!pk->is_valid && !pk->is_primary)
rc=G10ERR_BAD_PUBKEY; /* you cannot have a good sig from an
invalid subkey */
else {
*r_expiredate = pk->expiredate;
rc = do_check( pk, sig, digest, r_expired );
}
free_public_key( pk );
if( !rc && sig->sig_class < 2 && is_status_enabled() ) {
/* This signature id works best with DLP algorithms because
* they use a random parameter for every signature. Instead of
* this sig-id we could have also used the hash of the document
* and the timestamp, but the drawback of this is, that it is
* not possible to sign more than one identical document within
* one second. Some remote batch processing applications might
* like this feature here */
MD_HANDLE md;
u32 a = sig->timestamp;
int i, nsig = pubkey_get_nsig( sig->pubkey_algo );
byte *p, *buffer;
md = md_open( DIGEST_ALGO_RMD160, 0);
md_putc( digest, sig->pubkey_algo );
md_putc( digest, sig->digest_algo );
md_putc( digest, (a >> 24) & 0xff );
md_putc( digest, (a >> 16) & 0xff );
md_putc( digest, (a >> 8) & 0xff );
md_putc( digest, a & 0xff );
for(i=0; i < nsig; i++ ) {
unsigned n = mpi_get_nbits( sig->data[i]);
md_putc( md, n>>8);
md_putc( md, n );
p = mpi_get_buffer( sig->data[i], &n, NULL );
md_write( md, p, n );
m_free(p);
}
md_final( md );
p = make_radix64_string( md_read( md, 0 ), 20 );
buffer = m_alloc( strlen(p) + 60 );
sprintf( buffer, "%s %s %lu",
p, strtimestamp( sig->timestamp ), (ulong)sig->timestamp );
write_status_text( STATUS_SIG_ID, buffer );
m_free(buffer);
m_free(p);
md_close(md);
}
return rc;
}
/****************
* This function gets called by pubkey_verify() if the algorithm needs it.
*/
static int
cmp_help( void *opaque, MPI result )
{
#if 0 /* we do not use this anymore */
int rc=0, i, j, c, old_enc;
byte *dp;
const byte *asn;
size_t mdlen, asnlen;
struct cmp_help_context_s *ctx = opaque;
PKT_signature *sig = ctx->sig;
MD_HANDLE digest = ctx->md;
old_enc = 0;
for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) {
if( !j ) {
if( !i && c != 1 )
break;
else if( i && c == 0xff )
; /* skip the padding */
else if( i && !c )
j++;
else
break;
}
else if( ++j == 18 && c != 1 )
break;
else if( j == 19 && c == 0 ) {
old_enc++;
break;
}
}
if( old_enc ) {
log_error("old encoding scheme is not supported\n");
return G10ERR_GENERAL;
}
if( (rc=check_digest_algo(sig->digest_algo)) )
return rc; /* unsupported algo */
asn = md_asn_oid( sig->digest_algo, &asnlen, &mdlen );
for(i=mdlen,j=asnlen-1; (c=mpi_getbyte(result, i)) != -1 && j >= 0;
i++, j-- )
if( asn[j] != c )
break;
if( j != -1 || mpi_getbyte(result, i) )
return G10ERR_BAD_PUBKEY; /* ASN is wrong */
for(i++; (c=mpi_getbyte(result, i)) != -1; i++ )
if( c != 0xff )
break;
i++;
if( c != sig->digest_algo || mpi_getbyte(result, i) ) {
/* Padding or leading bytes in signature is wrong */
return G10ERR_BAD_PUBKEY;
}
if( mpi_getbyte(result, mdlen-1) != sig->digest_start[0]
|| mpi_getbyte(result, mdlen-2) != sig->digest_start[1] ) {
/* Wrong key used to check the signature */
return G10ERR_BAD_PUBKEY;
}
dp = md_read( digest, sig->digest_algo );
for(i=mdlen-1; i >= 0; i--, dp++ ) {
if( mpi_getbyte( result, i ) != *dp )
return G10ERR_BAD_SIGN;
}
return 0;
#else
return -1;
#endif
}
static int
do_check_messages( PKT_public_key *pk, PKT_signature *sig, int *r_expired )
{
u32 cur_time;
*r_expired = 0;
if( pk->version == 4 && pk->pubkey_algo == PUBKEY_ALGO_ELGAMAL_E ) {
log_info(_("key %08lX: this is a PGP generated "
"ElGamal key which is NOT secure for signatures!\n"),
(ulong)keyid_from_pk(pk,NULL));
return G10ERR_PUBKEY_ALGO;
}
if( pk->timestamp > sig->timestamp ) {
ulong d = pk->timestamp - sig->timestamp;
log_info( d==1
? _("public key %08lX is %lu second newer than the signature\n")
: _("public key %08lX is %lu seconds newer than the signature\n"),
(ulong)keyid_from_pk(pk,NULL),d );
if( !opt.ignore_time_conflict )
return G10ERR_TIME_CONFLICT; /* pubkey newer than signature */
}
cur_time = make_timestamp();
if( pk->timestamp > cur_time ) {
ulong d = pk->timestamp - cur_time;
log_info( d==1 ? _("key %08lX has been created %lu second "
"in future (time warp or clock problem)\n")
: _("key %08lX has been created %lu seconds "
"in future (time warp or clock problem)\n"),
(ulong)keyid_from_pk(pk,NULL),d );
if( !opt.ignore_time_conflict )
return G10ERR_TIME_CONFLICT;
}
if( pk->expiredate && pk->expiredate < cur_time ) {
char buf[11];
if (opt.verbose) {
u32 tmp_kid[2];
keyid_from_pk( pk, tmp_kid );
log_info(_("NOTE: signature key %08lX expired %s\n"),
(ulong)tmp_kid[1], asctimestamp( pk->expiredate ) );
}
/* SIGEXPIRED is deprecated. Use KEYEXPIRED. */
sprintf(buf,"%lu",(ulong)pk->expiredate);
write_status_text(STATUS_KEYEXPIRED,buf);
write_status(STATUS_SIGEXPIRED);
*r_expired = 1;
}
return 0;
}
static int
do_check( PKT_public_key *pk, PKT_signature *sig, MD_HANDLE digest,
int *r_expired )
{
MPI result = NULL;
int rc=0;
struct cmp_help_context_s ctx;
if( (rc=do_check_messages(pk,sig,r_expired)) )
return rc;
if( (rc=check_digest_algo(sig->digest_algo)) )
return rc;
if( (rc=check_pubkey_algo(sig->pubkey_algo)) )
return rc;
/* make sure the digest algo is enabled (in case of a detached signature)*/
md_enable( digest, sig->digest_algo );
/* complete the digest */
if( sig->version >= 4 )
md_putc( digest, sig->version );
md_putc( digest, sig->sig_class );
if( sig->version < 4 ) {
u32 a = sig->timestamp;
md_putc( digest, (a >> 24) & 0xff );
md_putc( digest, (a >> 16) & 0xff );
md_putc( digest, (a >> 8) & 0xff );
md_putc( digest, a & 0xff );
}
else {
byte buf[6];
size_t n;
md_putc( digest, sig->pubkey_algo );
md_putc( digest, sig->digest_algo );
if( sig->hashed ) {
n = sig->hashed->len;
md_putc (digest, (n >> 8) );
md_putc (digest, n );
md_write (digest, sig->hashed->data, n);
n += 6;
}
else {
/* Two octets for the (empty) length of the hashed
section. */
md_putc (digest, 0);
md_putc (digest, 0);
n = 6;
}
/* add some magic */
buf[0] = sig->version;
buf[1] = 0xff;
buf[2] = n >> 24;
buf[3] = n >> 16;
buf[4] = n >> 8;
buf[5] = n;
md_write( digest, buf, 6 );
}
md_final( digest );
result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo,
mpi_get_nbits(pk->pkey[0]), 0 );
if (!result)
return G10ERR_GENERAL;
ctx.sig = sig;
ctx.md = digest;
rc = pubkey_verify( pk->pubkey_algo, result, sig->data, pk->pkey,
cmp_help, &ctx );
mpi_free( result );
if( (opt.emulate_bugs & EMUBUG_MDENCODE)
&& rc == G10ERR_BAD_SIGN && is_ELGAMAL(pk->pubkey_algo) ) {
/* In this case we try again because old GnuPG versions didn't encode
* the hash right. There is no problem with DSA however */
result = encode_md_value( pk->pubkey_algo, digest, sig->digest_algo,
mpi_get_nbits(pk->pkey[0]), (sig->version < 5) );
if (!result)
rc = G10ERR_GENERAL;
else {
ctx.sig = sig;
ctx.md = digest;
rc = pubkey_verify( pk->pubkey_algo, result, sig->data, pk->pkey,
cmp_help, &ctx );
}
}
if( !rc && sig->flags.unknown_critical ) {
log_info(_("assuming bad signature from key %08lX due to an unknown critical bit\n"),(ulong)keyid_from_pk(pk,NULL));
rc = G10ERR_BAD_SIGN;
}
return rc;
}
static void
hash_uid_node( KBNODE unode, MD_HANDLE md, PKT_signature *sig )
{
PKT_user_id *uid = unode->pkt->pkt.user_id;
assert( unode->pkt->pkttype == PKT_USER_ID );
if( uid->attrib_data ) {
if( sig->version >=4 ) {
byte buf[5];
buf[0] = 0xd1; /* packet of type 17 */
buf[1] = uid->attrib_len >> 24; /* always use 4 length bytes */
buf[2] = uid->attrib_len >> 16;
buf[3] = uid->attrib_len >> 8;
buf[4] = uid->attrib_len;
md_write( md, buf, 5 );
}
md_write( md, uid->attrib_data, uid->attrib_len );
}
else {
if( sig->version >=4 ) {
byte buf[5];
buf[0] = 0xb4; /* indicates a userid packet */
buf[1] = uid->len >> 24; /* always use 4 length bytes */
buf[2] = uid->len >> 16;
buf[3] = uid->len >> 8;
buf[4] = uid->len;
md_write( md, buf, 5 );
}
md_write( md, uid->name, uid->len );
}
}
static void
cache_sig_result ( PKT_signature *sig, int result )
{
if ( !result ) {
sig->flags.checked = 1;
sig->flags.valid = 1;
}
else if ( result == G10ERR_BAD_SIGN ) {
sig->flags.checked = 1;
sig->flags.valid = 0;
}
else {
sig->flags.checked = 0;
sig->flags.valid = 0;
}
}
/* Check the revocation keys to see if any of them have revoked our
pk. sig is the revocation sig. pk is the key it is on. This code
will need to be modified if gpg ever becomes multi-threaded. Note
that this guarantees that a designated revocation sig will never be
considered valid unless it is actually valid, as well as being
issued by a revocation key in a valid direct signature. Note that
this is written so that a revoked revoker can still issue
revocations: i.e. If A revokes B, but A is revoked, B is still
revoked. I'm not completely convinced this is the proper behavior,
but it matches how PGP does it. -dms */
/* Returns 0 if sig is valid (i.e. pk is revoked), non-0 if not
revoked */
int
check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
{
static int busy=0;
int i,rc=G10ERR_GENERAL;
assert(IS_KEY_REV(sig));
assert((sig->keyid[0]!=pk->keyid[0]) || (sig->keyid[0]!=pk->keyid[1]));
if(busy)
{
/* return -1 (i.e. not revoked), but mark the pk as uncacheable
as we don't really know its revocation status until it is
checked directly. */
pk->dont_cache=1;
return rc;
}
busy=1;
/* printf("looking at %08lX with a sig from %08lX\n",(ulong)pk->keyid[1],
(ulong)sig->keyid[1]); */
/* is the issuer of the sig one of our revokers? */
if( !pk->revkey && pk->numrevkeys )
BUG();
else
for(i=0;i<pk->numrevkeys;i++)
{
u32 keyid[2];
keyid_from_fingerprint(pk->revkey[i].fpr,MAX_FINGERPRINT_LEN,keyid);
if(keyid[0]==sig->keyid[0] && keyid[1]==sig->keyid[1])
{
MD_HANDLE md;
md=md_open(sig->digest_algo,0);
hash_public_key(md,pk);
rc=signature_check(sig,md);
cache_sig_result(sig,rc);
break;
}
}
busy=0;
return rc;
}
/****************
* check the signature pointed to by NODE. This is a key signature.
* If the function detects a self-signature, it uses the PK from
* ROOT and does not read any public key.
*/
int
check_key_signature( KBNODE root, KBNODE node, int *is_selfsig )
{
u32 dummy;
int dum2;
return check_key_signature2(root, node, NULL, is_selfsig, &dummy, &dum2 );
}
/* If check_pk is set, then use it to check the signature in node
rather than getting it from root or the keydb. */
int
check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk,
int *is_selfsig, u32 *r_expiredate, int *r_expired )
{
MD_HANDLE md;
PKT_public_key *pk;
PKT_signature *sig;
int algo;
int rc;
if( is_selfsig )
*is_selfsig = 0;
*r_expiredate = 0;
*r_expired = 0;
assert( node->pkt->pkttype == PKT_SIGNATURE );
assert( root->pkt->pkttype == PKT_PUBLIC_KEY );
pk = root->pkt->pkt.public_key;
sig = node->pkt->pkt.signature;
algo = sig->digest_algo;
/* check whether we have cached the result of a previous signature check.*/
if ( !opt.no_sig_cache ) {
if (sig->flags.checked) { /*cached status available*/
if( is_selfsig ) {
u32 keyid[2];
keyid_from_pk( pk, keyid );
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
*is_selfsig = 1;
}
if((rc=do_check_messages(pk,sig,r_expired)))
return rc;
return sig->flags.valid? 0 : G10ERR_BAD_SIGN;
}
}
if( (rc=check_digest_algo(algo)) )
return rc;
if( sig->sig_class == 0x20 ) { /* key revocation */
u32 keyid[2];
keyid_from_pk( pk, keyid );
/* is it a designated revoker? */
if(keyid[0]!=sig->keyid[0] || keyid[1]!=sig->keyid[1])
rc=check_revocation_keys(pk,sig);
else
{
md = md_open( algo, 0 );
hash_public_key( md, pk );
rc = do_check( pk, sig, md, r_expired );
cache_sig_result ( sig, rc );
md_close(md);
}
}
else if( sig->sig_class == 0x28 ) { /* subkey revocation */
KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
if( snode ) {
md = md_open( algo, 0 );
hash_public_key( md, pk );
hash_public_key( md, snode->pkt->pkt.public_key );
rc = do_check( pk, sig, md, r_expired );
cache_sig_result ( sig, rc );
md_close(md);
}
else {
if (!opt.quiet)
log_info (_("key %08lX: no subkey for subkey "
"revocation signature\n"),
(ulong)keyid_from_pk (pk, NULL));
rc = G10ERR_SIG_CLASS;
}
}
else if( sig->sig_class == 0x18 ) { /* key binding */
KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
if( snode ) {
if( is_selfsig ) { /* does this make sense????? */
u32 keyid[2]; /* it should always be a selfsig */
keyid_from_pk( pk, keyid );
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
*is_selfsig = 1;
}
md = md_open( algo, 0 );
hash_public_key( md, pk );
hash_public_key( md, snode->pkt->pkt.public_key );
rc = do_check( pk, sig, md, r_expired );
cache_sig_result ( sig, rc );
md_close(md);
}
else {
if (opt.verbose)
log_info(_("key %08lX: no subkey for subkey "
"binding signature\n"),
(ulong)keyid_from_pk (pk, NULL));
rc = G10ERR_SIG_CLASS;
}
}
else if( sig->sig_class == 0x1f ) { /* direct key signature */
md = md_open( algo, 0 );
hash_public_key( md, pk );
rc = do_check( pk, sig, md, r_expired );
cache_sig_result ( sig, rc );
md_close(md);
}
else { /* all other classes */
KBNODE unode = find_prev_kbnode( root, node, PKT_USER_ID );
if( unode ) {
u32 keyid[2];
keyid_from_pk( pk, keyid );
md = md_open( algo, 0 );
hash_public_key( md, pk );
hash_uid_node( unode, md, sig );
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
{
if( is_selfsig )
*is_selfsig = 1;
rc = do_check( pk, sig, md, r_expired );
}
else if (check_pk)
rc=do_check(check_pk,sig,md,r_expired);
else
rc = signature_check2( sig, md, r_expiredate, r_expired );
cache_sig_result ( sig, rc );
md_close(md);
}
else {
if (!opt.quiet)
log_info ("key %08lX: no user ID for key signature packet "
"of class %02x\n",
(ulong)keyid_from_pk (pk, NULL), sig->sig_class );
rc = G10ERR_SIG_CLASS;
}
}
return rc;
}

1358
g10/sign.c Normal file

File diff suppressed because it is too large Load diff

217
g10/signal.c Normal file
View file

@ -0,0 +1,217 @@
/* signal.c - signal handling
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "options.h"
#include "errors.h"
#include "memory.h"
#include "util.h"
#include "main.h"
#include "ttyio.h"
static volatile int caught_fatal_sig = 0;
static volatile int caught_sigusr1 = 0;
static void
init_one_signal (int sig, RETSIGTYPE (*handler)(int), int check_ign )
{
#ifndef HAVE_DOSISH_SYSTEM
#ifdef HAVE_SIGACTION
struct sigaction oact, nact;
if (check_ign) {
/* we don't want to change an IGN handler */
sigaction (sig, NULL, &oact );
if (oact.sa_handler == SIG_IGN )
return;
}
nact.sa_handler = handler;
sigemptyset (&nact.sa_mask);
nact.sa_flags = 0;
sigaction ( sig, &nact, NULL);
#else
RETSIGTYPE (*ohandler)(int);
ohandler = signal (sig, handler);
if (check_ign && ohandler == SIG_IGN) {
/* Change it back if it was already set to IGN */
signal (sig, SIG_IGN);
}
#endif
#endif /*!HAVE_DOSISH_SYSTEM*/
}
static const char *
get_signal_name( int signum )
{
#if defined(SYS_SIGLIST_DECLARED) && defined(NSIG)
return (signum >= 0 && signum < NSIG) ? sys_siglist[signum] : "?";
#else
return "some signal";
#endif
}
static RETSIGTYPE
got_fatal_signal( int sig )
{
const char *s;
if( caught_fatal_sig )
raise( sig );
caught_fatal_sig = 1;
secmem_term();
/* better don't transtale these messages */
write(2, "\n", 1 );
s = log_get_name(); if( s ) write(2, s, strlen(s) );
write(2, ": ", 2 );
s = get_signal_name(sig); write(2, s, strlen(s) );
write(2, " caught ... exiting\n", 20 );
/* reset action to default action and raise signal again */
init_one_signal (sig, SIG_DFL, 0);
remove_lockfiles ();
#ifdef __riscos__
riscos_close_fds ();
#endif /* __riscos__ */
raise( sig );
}
static RETSIGTYPE
got_usr_signal( int sig )
{
caught_sigusr1 = 1;
}
void
init_signals()
{
#ifndef HAVE_DOSISH_SYSTEM
init_one_signal (SIGINT, got_fatal_signal, 1 );
init_one_signal (SIGHUP, got_fatal_signal, 1 );
init_one_signal (SIGTERM, got_fatal_signal, 1 );
init_one_signal (SIGQUIT, got_fatal_signal, 1 );
init_one_signal (SIGSEGV, got_fatal_signal, 1 );
init_one_signal (SIGUSR1, got_usr_signal, 0 );
init_one_signal (SIGPIPE, SIG_IGN, 0 );
#endif
}
void
pause_on_sigusr( int which )
{
#ifndef HAVE_DOSISH_SYSTEM
#ifdef HAVE_SIGPROCMASK
sigset_t mask, oldmask;
assert( which == 1 );
sigemptyset( &mask );
sigaddset( &mask, SIGUSR1 );
sigprocmask( SIG_BLOCK, &mask, &oldmask );
while( !caught_sigusr1 )
sigsuspend( &oldmask );
caught_sigusr1 = 0;
sigprocmask( SIG_UNBLOCK, &mask, NULL );
#else
assert (which == 1);
sighold (SIGUSR1);
while (!caught_sigusr1)
sigpause(SIGUSR1);
caught_sigusr1 = 0;
sigrelse(SIGUSR1); ????
#endif /*!HAVE_SIGPROCMASK*/
#endif
}
static void
do_block( int block )
{
#ifndef HAVE_DOSISH_SYSTEM
static int is_blocked;
#ifdef HAVE_SIGPROCMASK
static sigset_t oldmask;
if( block ) {
sigset_t newmask;
if( is_blocked )
log_bug("signals are already blocked\n");
sigfillset( &newmask );
sigprocmask( SIG_BLOCK, &newmask, &oldmask );
is_blocked = 1;
}
else {
if( !is_blocked )
log_bug("signals are not blocked\n");
sigprocmask( SIG_SETMASK, &oldmask, NULL );
is_blocked = 0;
}
#else /*!HAVE_SIGPROCMASK*/
static void (*disposition[MAXSIG])();
int sig;
if( block ) {
if( is_blocked )
log_bug("signals are already blocked\n");
for (sig=1; sig < MAXSIG; sig++) {
disposition[sig] = sigset (sig, SIG_HOLD);
}
is_blocked = 1;
}
else {
if( !is_blocked )
log_bug("signals are not blocked\n");
for (sig=1; sig < MAXSIG; sig++) {
sigset (sig, disposition[sig]);
}
is_blocked = 0;
}
#endif /*!HAVE_SIGPROCMASK*/
#endif /*HAVE_DOSISH_SYSTEM*/
}
void
block_all_signals()
{
do_block(1);
}
void
unblock_all_signals()
{
do_block(0);
}

693
g10/status.c Normal file
View file

@ -0,0 +1,693 @@
/* status.c
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#ifdef USE_SHM_COPROCESSING
#ifdef USE_CAPABILITIES
#include <sys/capability.h>
#endif
#ifdef HAVE_SYS_IPC_H
#include <sys/types.h>
#include <sys/ipc.h>
#endif
#ifdef HAVE_SYS_SHM_H
#include <sys/shm.h>
#endif
#if defined(HAVE_MLOCK)
#include <sys/mman.h>
#endif
#endif
#include "util.h"
#include "status.h"
#include "ttyio.h"
#include "options.h"
#include "main.h"
#include "i18n.h"
#include "cipher.h" /* for progress functions */
#define CONTROL_D ('D' - 'A' + 1)
static FILE *statusfp;
#ifdef USE_SHM_COPROCESSING
static int shm_id = -1;
static volatile char *shm_area;
static size_t shm_size;
static int shm_is_locked;
#endif /*USE_SHM_COPROCESSING*/
static void
progress_cb ( void *ctx, int c )
{
char buf[50];
if ( c == '\n' )
sprintf ( buf, "%.20s X 100 100", (char*)ctx );
else
sprintf ( buf, "%.20s %c 0 0", (char*)ctx, c );
write_status_text ( STATUS_PROGRESS, buf );
}
static const char *
get_status_string ( int no )
{
const char *s;
switch( no ) {
case STATUS_ENTER : s = "ENTER"; break;
case STATUS_LEAVE : s = "LEAVE"; break;
case STATUS_ABORT : s = "ABORT"; break;
case STATUS_GOODSIG: s = "GOODSIG"; break;
case STATUS_KEYEXPIRED: s = "KEYEXPIRED"; break;
case STATUS_KEYREVOKED: s = "KEYREVOKED"; break;
case STATUS_BADSIG : s = "BADSIG"; break;
case STATUS_ERRSIG : s = "ERRSIG"; break;
case STATUS_BADARMOR : s = "BADARMOR"; break;
case STATUS_RSA_OR_IDEA : s= "RSA_OR_IDEA"; break;
case STATUS_TRUST_UNDEFINED: s = "TRUST_UNDEFINED"; break;
case STATUS_TRUST_NEVER : s = "TRUST_NEVER"; break;
case STATUS_TRUST_MARGINAL : s = "TRUST_MARGINAL"; break;
case STATUS_TRUST_FULLY : s = "TRUST_FULLY"; break;
case STATUS_TRUST_ULTIMATE : s = "TRUST_ULTIMATE"; break;
case STATUS_GET_BOOL : s = "GET_BOOL"; break;
case STATUS_GET_LINE : s = "GET_LINE"; break;
case STATUS_GET_HIDDEN : s = "GET_HIDDEN"; break;
case STATUS_GOT_IT : s = "GOT_IT"; break;
case STATUS_SHM_INFO : s = "SHM_INFO"; break;
case STATUS_SHM_GET : s = "SHM_GET"; break;
case STATUS_SHM_GET_BOOL : s = "SHM_GET_BOOL"; break;
case STATUS_SHM_GET_HIDDEN : s = "SHM_GET_HIDDEN"; break;
case STATUS_NEED_PASSPHRASE: s = "NEED_PASSPHRASE"; break;
case STATUS_VALIDSIG : s = "VALIDSIG"; break;
case STATUS_SIG_ID : s = "SIG_ID"; break;
case STATUS_ENC_TO : s = "ENC_TO"; break;
case STATUS_NODATA : s = "NODATA"; break;
case STATUS_BAD_PASSPHRASE : s = "BAD_PASSPHRASE"; break;
case STATUS_NO_PUBKEY : s = "NO_PUBKEY"; break;
case STATUS_NO_SECKEY : s = "NO_SECKEY"; break;
case STATUS_NEED_PASSPHRASE_SYM: s = "NEED_PASSPHRASE_SYM"; break;
case STATUS_DECRYPTION_FAILED: s = "DECRYPTION_FAILED"; break;
case STATUS_DECRYPTION_OKAY: s = "DECRYPTION_OKAY"; break;
case STATUS_MISSING_PASSPHRASE: s = "MISSING_PASSPHRASE"; break;
case STATUS_GOOD_PASSPHRASE : s = "GOOD_PASSPHRASE"; break;
case STATUS_GOODMDC : s = "GOODMDC"; break;
case STATUS_BADMDC : s = "BADMDC"; break;
case STATUS_ERRMDC : s = "ERRMDC"; break;
case STATUS_IMPORTED : s = "IMPORTED"; break;
case STATUS_IMPORT_OK : s = "IMPORT_OK"; break;
case STATUS_IMPORT_CHECK : s = "IMPORT_CHECK"; break;
case STATUS_IMPORT_RES : s = "IMPORT_RES"; break;
case STATUS_FILE_START : s = "FILE_START"; break;
case STATUS_FILE_DONE : s = "FILE_DONE"; break;
case STATUS_FILE_ERROR : s = "FILE_ERROR"; break;
case STATUS_BEGIN_DECRYPTION:s = "BEGIN_DECRYPTION"; break;
case STATUS_END_DECRYPTION : s = "END_DECRYPTION"; break;
case STATUS_BEGIN_ENCRYPTION:s = "BEGIN_ENCRYPTION"; break;
case STATUS_END_ENCRYPTION : s = "END_ENCRYPTION"; break;
case STATUS_DELETE_PROBLEM : s = "DELETE_PROBLEM"; break;
case STATUS_PROGRESS : s = "PROGRESS"; break;
case STATUS_SIG_CREATED : s = "SIG_CREATED"; break;
case STATUS_SESSION_KEY : s = "SESSION_KEY"; break;
case STATUS_NOTATION_NAME : s = "NOTATION_NAME" ; break;
case STATUS_NOTATION_DATA : s = "NOTATION_DATA" ; break;
case STATUS_POLICY_URL : s = "POLICY_URL" ; break;
case STATUS_BEGIN_STREAM : s = "BEGIN_STREAM"; break;
case STATUS_END_STREAM : s = "END_STREAM"; break;
case STATUS_KEY_CREATED : s = "KEY_CREATED"; break;
case STATUS_USERID_HINT : s = "USERID_HINT"; break;
case STATUS_UNEXPECTED : s = "UNEXPECTED"; break;
case STATUS_INV_RECP : s = "INV_RECP"; break;
case STATUS_NO_RECP : s = "NO_RECP"; break;
case STATUS_ALREADY_SIGNED : s = "ALREADY_SIGNED"; break;
case STATUS_SIGEXPIRED : s = "SIGEXPIRED deprecated-use-keyexpired-instead"; break;
case STATUS_EXPSIG : s = "EXPSIG"; break;
case STATUS_EXPKEYSIG : s = "EXPKEYSIG"; break;
case STATUS_ATTRIBUTE : s = "ATTRIBUTE"; break;
default: s = "?"; break;
}
return s;
}
void
set_status_fd ( int fd )
{
static int last_fd = -1;
if ( fd != -1 && last_fd == fd )
return;
if ( statusfp && statusfp != stdout && statusfp != stderr )
fclose (statusfp);
statusfp = NULL;
if ( fd == -1 )
return;
if( fd == 1 )
statusfp = stdout;
else if( fd == 2 )
statusfp = stderr;
else
statusfp = fdopen( fd, "w" );
if( !statusfp ) {
log_fatal("can't open fd %d for status output: %s\n",
fd, strerror(errno));
}
last_fd = fd;
register_primegen_progress ( progress_cb, "primegen" );
register_pk_dsa_progress ( progress_cb, "pk_dsa" );
register_pk_elg_progress ( progress_cb, "pk_elg" );
}
int
is_status_enabled()
{
return !!statusfp;
}
void
write_status ( int no )
{
write_status_text( no, NULL );
}
void
write_status_text ( int no, const char *text)
{
if( !statusfp )
return; /* not enabled */
fputs ( "[GNUPG:] ", statusfp );
fputs ( get_status_string (no), statusfp );
if( text ) {
putc ( ' ', statusfp );
for (; *text; text++) {
if (*text == '\n')
fputs ( "\\n", statusfp );
else if (*text == '\r')
fputs ( "\\r", statusfp );
else
putc ( *(const byte *)text, statusfp );
}
}
putc ('\n',statusfp);
fflush (statusfp);
}
/*
* Write a status line with a buffer using %XX escapes. If WRAP is >
* 0 wrap the line after this length. If STRING is not NULL it will
* be prepended to the buffer, no escaping is done for string.
* A wrap of -1 forces spaces not to be encoded as %20.
*/
void
write_status_text_and_buffer ( int no, const char *string,
const char *buffer, size_t len, int wrap )
{
const char *s, *text;
int esc, first;
int lower_limit = ' ';
size_t n, count, dowrap;
if( !statusfp )
return; /* not enabled */
if (wrap == -1) {
lower_limit--;
wrap = 0;
}
text = get_status_string (no);
count = dowrap = first = 1;
do {
if (dowrap) {
fprintf (statusfp, "[GNUPG:] %s ", text );
count = dowrap = 0;
if (first && string) {
fputs (string, statusfp);
count += strlen (string);
}
first = 0;
}
for (esc=0, s=buffer, n=len; n && !esc; s++, n-- ) {
if ( *s == '%' || *(const byte*)s <= lower_limit
|| *(const byte*)s == 127 )
esc = 1;
if ( wrap && ++count > wrap ) {
dowrap=1;
break;
}
}
if (esc) {
s--; n++;
}
if (s != buffer)
fwrite (buffer, s-buffer, 1, statusfp );
if ( esc ) {
fprintf (statusfp, "%%%02X", *(const byte*)s );
s++; n--;
}
buffer = s;
len = n;
if ( dowrap && len )
putc ( '\n', statusfp );
} while ( len );
putc ('\n',statusfp);
fflush (statusfp);
}
void
write_status_buffer ( int no, const char *buffer, size_t len, int wrap )
{
write_status_text_and_buffer (no, NULL, buffer, len, wrap);
}
#ifdef USE_SHM_COPROCESSING
#ifndef IPC_RMID_DEFERRED_RELEASE
static void
remove_shmid( void )
{
if( shm_id != -1 ) {
shmctl ( shm_id, IPC_RMID, 0);
shm_id = -1;
}
}
#endif
void
init_shm_coprocessing ( ulong requested_shm_size, int lock_mem )
{
char buf[100];
struct shmid_ds shmds;
#ifndef IPC_RMID_DEFERRED_RELEASE
atexit( remove_shmid );
#endif
requested_shm_size = (requested_shm_size + 4095) & ~4095;
if ( requested_shm_size > 2 * 4096 )
log_fatal("too much shared memory requested; only 8k are allowed\n");
shm_size = 4096 /* one page for us */ + requested_shm_size;
shm_id = shmget( IPC_PRIVATE, shm_size, IPC_CREAT | 0700 );
if ( shm_id == -1 )
log_fatal("can't get %uk of shared memory: %s\n",
(unsigned)shm_size/1024, strerror(errno));
#if !defined(IPC_HAVE_SHM_LOCK) \
&& defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
/* part of the old code which uses mlock */
shm_area = shmat( shm_id, 0, 0 );
if ( shm_area == (char*)-1 )
log_fatal("can't attach %uk shared memory: %s\n",
(unsigned)shm_size/1024, strerror(errno));
log_debug("mapped %uk shared memory at %p, id=%d\n",
(unsigned)shm_size/1024, shm_area, shm_id );
if( lock_mem ) {
#ifdef USE_CAPABILITIES
cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
#endif
/* (need the cast for Solaris with Sun's workshop compilers) */
if ( mlock ( (char*)shm_area, shm_size) )
log_info("locking shared memory %d failed: %s\n",
shm_id, strerror(errno));
else
shm_is_locked = 1;
#ifdef USE_CAPABILITIES
cap_set_proc( cap_from_text("cap_ipc_lock+p") );
#endif
}
#ifdef IPC_RMID_DEFERRED_RELEASE
if( shmctl( shm_id, IPC_RMID, 0) )
log_fatal("shmctl IPC_RMDID of %d failed: %s\n",
shm_id, strerror(errno));
#endif
if( shmctl( shm_id, IPC_STAT, &shmds ) )
log_fatal("shmctl IPC_STAT of %d failed: %s\n",
shm_id, strerror(errno));
if( shmds.shm_perm.uid != getuid() ) {
shmds.shm_perm.uid = getuid();
if( shmctl( shm_id, IPC_SET, &shmds ) )
log_fatal("shmctl IPC_SET of %d failed: %s\n",
shm_id, strerror(errno));
}
#else /* this is the new code which handles the changes in the SHM
* semantics introduced with Linux 2.4. The changes is that we
* now change the permissions and then attach to the memory.
*/
if( lock_mem ) {
#ifdef USE_CAPABILITIES
cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
#endif
#ifdef IPC_HAVE_SHM_LOCK
if ( shmctl (shm_id, SHM_LOCK, 0) )
log_info("locking shared memory %d failed: %s\n",
shm_id, strerror(errno));
else
shm_is_locked = 1;
#else
log_info("Locking shared memory %d failed: No way to do it\n", shm_id );
#endif
#ifdef USE_CAPABILITIES
cap_set_proc( cap_from_text("cap_ipc_lock+p") );
#endif
}
if( shmctl( shm_id, IPC_STAT, &shmds ) )
log_fatal("shmctl IPC_STAT of %d failed: %s\n",
shm_id, strerror(errno));
if( shmds.shm_perm.uid != getuid() ) {
shmds.shm_perm.uid = getuid();
if( shmctl( shm_id, IPC_SET, &shmds ) )
log_fatal("shmctl IPC_SET of %d failed: %s\n",
shm_id, strerror(errno));
}
shm_area = shmat( shm_id, 0, 0 );
if ( shm_area == (char*)-1 )
log_fatal("can't attach %uk shared memory: %s\n",
(unsigned)shm_size/1024, strerror(errno));
log_debug("mapped %uk shared memory at %p, id=%d\n",
(unsigned)shm_size/1024, shm_area, shm_id );
#ifdef IPC_RMID_DEFERRED_RELEASE
if( shmctl( shm_id, IPC_RMID, 0) )
log_fatal("shmctl IPC_RMDID of %d failed: %s\n",
shm_id, strerror(errno));
#endif
#endif
/* write info; Protocol version, id, size, locked size */
sprintf( buf, "pv=1 pid=%d shmid=%d sz=%u lz=%u", (int)getpid(),
shm_id, (unsigned)shm_size, shm_is_locked? (unsigned)shm_size:0 );
write_status_text( STATUS_SHM_INFO, buf );
}
/****************
* Request a string from client
* If bool, returns static string on true (do not free) or NULL for false
*/
static char *
do_shm_get( const char *keyword, int hidden, int bool )
{
size_t n;
byte *p;
char *string;
if( !shm_area )
BUG();
shm_area[0] = 0; /* msb of length of control block */
shm_area[1] = 32; /* and lsb */
shm_area[2] = 1; /* indicate that we are waiting on a reply */
shm_area[3] = 0; /* clear data available flag */
write_status_text( bool? STATUS_SHM_GET_BOOL :
hidden? STATUS_SHM_GET_HIDDEN : STATUS_SHM_GET, keyword );
do {
pause_on_sigusr(1);
if( shm_area[0] || shm_area[1] != 32 || shm_area[2] != 1 )
log_fatal("client modified shm control block - abort\n");
} while( !shm_area[3] );
shm_area[2] = 0; /* reset request flag */
p = (byte*)shm_area+32;
n = p[0] << 8 | p[1];
p += 2;
if( n+32+2+1 > 4095 )
log_fatal("client returns too large data (%u bytes)\n", (unsigned)n );
if( bool )
return p[0]? "" : NULL;
string = hidden? m_alloc_secure( n+1 ) : m_alloc( n+1 );
memcpy(string, p, n );
string[n] = 0; /* make sure it is a string */
if( hidden ) /* invalidate the memory */
memset( p, 0, n );
return string;
}
#endif /* USE_SHM_COPROCESSING */
static int
myread(int fd, void *buf, size_t count)
{
int rc;
do {
rc = read( fd, buf, count );
} while ( rc == -1 && errno == EINTR );
if ( !rc && count ) {
static int eof_emmited=0;
if ( eof_emmited < 3 ) {
*(char*)buf = CONTROL_D;
rc = 1;
eof_emmited++;
}
else { /* Ctrl-D not caught - do something reasonable */
#ifdef HAVE_DOSISH_SYSTEM
raise (SIGINT); /* nothing to hangup under DOS */
#else
raise (SIGHUP); /* no more input data */
#endif
}
}
return rc;
}
/****************
* Request a string from the client over the command-fd
* If bool, returns static string on true (do not free) or NULL for false
*/
static char *
do_get_from_fd( const char *keyword, int hidden, int bool )
{
int i, len;
char *string;
write_status_text( bool? STATUS_GET_BOOL :
hidden? STATUS_GET_HIDDEN : STATUS_GET_LINE, keyword );
for( string = NULL, i = len = 200; ; i++ ) {
if( i >= len-1 ) {
char *save = string;
len += 100;
string = hidden? m_alloc_secure ( len ) : m_alloc ( len );
if( save )
memcpy(string, save, i );
else
i=0;
}
/* Hmmm: why not use our read_line function here */
if( myread( opt.command_fd, string+i, 1) != 1 || string[i] == '\n' )
break;
else if ( string[i] == CONTROL_D ) {
/* found ETX - cancel the line and return a sole ETX */
string[0] = CONTROL_D;
i=1;
break;
}
}
string[i] = 0;
write_status( STATUS_GOT_IT );
if( bool ) /* Fixme: is this correct??? */
return (string[0] == 'Y' || string[0] == 'y') ? "" : NULL;
return string;
}
int
cpr_enabled()
{
if( opt.command_fd != -1 )
return 1;
#ifdef USE_SHM_COPROCESSING
if( opt.shm_coprocess )
return 1;
#endif
return 0;
}
char *
cpr_get_no_help( const char *keyword, const char *prompt )
{
char *p;
if( opt.command_fd != -1 )
return do_get_from_fd ( keyword, 0, 0 );
#ifdef USE_SHM_COPROCESSING
if( opt.shm_coprocess )
return do_shm_get( keyword, 0, 0 );
#endif
for(;;) {
p = tty_get( prompt );
return p;
}
}
char *
cpr_get( const char *keyword, const char *prompt )
{
char *p;
if( opt.command_fd != -1 )
return do_get_from_fd ( keyword, 0, 0 );
#ifdef USE_SHM_COPROCESSING
if( opt.shm_coprocess )
return do_shm_get( keyword, 0, 0 );
#endif
for(;;) {
p = tty_get( prompt );
if( *p=='?' && !p[1] && !(keyword && !*keyword)) {
m_free(p);
display_online_help( keyword );
}
else
return p;
}
}
char *
cpr_get_utf8( const char *keyword, const char *prompt )
{
char *p;
p = cpr_get( keyword, prompt );
if( p ) {
char *utf8 = native_to_utf8( p );
m_free( p );
p = utf8;
}
return p;
}
char *
cpr_get_hidden( const char *keyword, const char *prompt )
{
char *p;
if( opt.command_fd != -1 )
return do_get_from_fd ( keyword, 1, 0 );
#ifdef USE_SHM_COPROCESSING
if( opt.shm_coprocess )
return do_shm_get( keyword, 1, 0 );
#endif
for(;;) {
p = tty_get_hidden( prompt );
if( *p == '?' && !p[1] ) {
m_free(p);
display_online_help( keyword );
}
else
return p;
}
}
void
cpr_kill_prompt(void)
{
if( opt.command_fd != -1 )
return;
#ifdef USE_SHM_COPROCESSING
if( opt.shm_coprocess )
return;
#endif
tty_kill_prompt();
return;
}
int
cpr_get_answer_is_yes( const char *keyword, const char *prompt )
{
int yes;
char *p;
if( opt.command_fd != -1 )
return !!do_get_from_fd ( keyword, 0, 1 );
#ifdef USE_SHM_COPROCESSING
if( opt.shm_coprocess )
return !!do_shm_get( keyword, 0, 1 );
#endif
for(;;) {
p = tty_get( prompt );
trim_spaces(p); /* it is okay to do this here */
if( *p == '?' && !p[1] ) {
m_free(p);
display_online_help( keyword );
}
else {
tty_kill_prompt();
yes = answer_is_yes(p);
m_free(p);
return yes;
}
}
}
int
cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt )
{
int yes;
char *p;
if( opt.command_fd != -1 )
return !!do_get_from_fd ( keyword, 0, 1 );
#ifdef USE_SHM_COPROCESSING
if( opt.shm_coprocess )
return !!do_shm_get( keyword, 0, 1 );
#endif
for(;;) {
p = tty_get( prompt );
trim_spaces(p); /* it is okay to do this here */
if( *p == '?' && !p[1] ) {
m_free(p);
display_online_help( keyword );
}
else {
tty_kill_prompt();
yes = answer_is_yes_no_quit(p);
m_free(p);
return yes;
}
}
}

1624
g10/tdbio.c Normal file

File diff suppressed because it is too large Load diff

117
g10/tdbio.h Normal file
View file

@ -0,0 +1,117 @@
/* tdbio.h - Trust database I/O functions
* Copyright (C) 1998, 1999, 2000, 2001, 2002 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_TDBIO_H
#define G10_TDBIO_H
#include "host2net.h"
#define TRUST_RECORD_LEN 40
#define SIGS_PER_RECORD ((TRUST_RECORD_LEN-10)/5)
#define ITEMS_PER_HTBL_RECORD ((TRUST_RECORD_LEN-2)/4)
#define ITEMS_PER_HLST_RECORD ((TRUST_RECORD_LEN-6)/5)
#define ITEMS_PER_PREF_RECORD (TRUST_RECORD_LEN-10)
#if ITEMS_PER_PREF_RECORD % 2
#error ITEMS_PER_PREF_RECORD must be even
#endif
#define MAX_LIST_SIGS_DEPTH 20
#define RECTYPE_VER 1
#define RECTYPE_HTBL 10
#define RECTYPE_HLST 11
#define RECTYPE_TRUST 12
#define RECTYPE_VALID 13
#define RECTYPE_FREE 254
struct trust_record {
int rectype;
int mark;
int dirty; /* for now only used internal by functions */
struct trust_record *next; /* help pointer to build lists in memory */
ulong recnum;
union {
struct { /* version record: */
byte version; /* should be 3 */
byte marginals;
byte completes;
byte cert_depth;
byte trust_model;
ulong created; /* timestamp of trustdb creation */
ulong nextcheck; /* timestamp of next scheduled check */
ulong reserved;
ulong reserved2;
ulong firstfree;
ulong reserved3;
ulong trusthashtbl;
} ver;
struct { /* free record */
ulong next;
} free;
struct {
ulong item[ITEMS_PER_HTBL_RECORD];
} htbl;
struct {
ulong next;
ulong rnum[ITEMS_PER_HLST_RECORD]; /* of another record */
} hlst;
struct {
byte fingerprint[20];
byte ownertrust;
byte depth;
ulong validlist;
byte min_ownertrust;
} trust;
struct {
byte namehash[20];
ulong next;
byte validity;
byte full_count;
byte marginal_count;
} valid;
} r;
};
typedef struct trust_record TRUSTREC;
/*-- tdbio.c --*/
int tdbio_update_version_record(void);
int tdbio_set_dbname( const char *new_dbname, int create );
const char *tdbio_get_dbname(void);
void tdbio_dump_record( TRUSTREC *rec, FILE *fp );
int tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected );
int tdbio_write_record( TRUSTREC *rec );
int tdbio_db_matches_options(void);
byte tdbio_read_model(void);
ulong tdbio_read_nextcheck (void);
int tdbio_write_nextcheck (ulong stamp);
int tdbio_is_dirty(void);
int tdbio_sync(void);
int tdbio_begin_transaction(void);
int tdbio_end_transaction(void);
int tdbio_cancel_transaction(void);
int tdbio_delete_record( ulong recnum );
ulong tdbio_new_recnum(void);
int tdbio_search_trust_byfpr(const byte *fingerprint, TRUSTREC *rec );
int tdbio_search_trust_bypk(PKT_public_key *pk, TRUSTREC *rec );
void tdbio_invalid(void);
#endif /*G10_TDBIO_H*/

234
g10/textfilter.c Normal file
View file

@ -0,0 +1,234 @@
/* textfilter.c
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "errors.h"
#include "iobuf.h"
#include "memory.h"
#include "util.h"
#include "filter.h"
#include "i18n.h"
#include "options.h"
#ifdef HAVE_DOSISH_SYSTEM
#define LF "\r\n"
#else
#define LF "\n"
#endif
#define MAX_LINELEN 19995 /* a little bit smaller than in armor.c */
/* to make sure that a warning is displayed while */
/* creating a message */
static unsigned
len_without_trailing_chars( byte *line, unsigned len, const char *trimchars )
{
byte *p, *mark;
unsigned n;
for(mark=NULL, p=line, n=0; n < len; n++, p++ ) {
if( strchr( trimchars, *p ) ) {
if( !mark )
mark = p;
}
else
mark = NULL;
}
return mark? (mark - line) : len;
}
unsigned
len_without_trailing_ws( byte *line, unsigned len )
{
return len_without_trailing_chars( line, len, " \t\r\n" );
}
static int
standard( text_filter_context_t *tfx, IOBUF a,
byte *buf, size_t size, size_t *ret_len)
{
int rc=0;
size_t len = 0;
unsigned maxlen;
assert( size > 10 );
size -= 2; /* reserve 2 bytes to append CR,LF */
while( !rc && len < size ) {
int lf_seen;
while( len < size && tfx->buffer_pos < tfx->buffer_len )
buf[len++] = tfx->buffer[tfx->buffer_pos++];
if( len >= size )
continue;
/* read the next line */
maxlen = MAX_LINELEN;
tfx->buffer_pos = 0;
tfx->buffer_len = iobuf_read_line( a, &tfx->buffer,
&tfx->buffer_size, &maxlen );
if( !maxlen )
tfx->truncated++;
if( !tfx->buffer_len ) {
if( !len )
rc = -1; /* eof */
break;
}
lf_seen = tfx->buffer[tfx->buffer_len-1] == '\n';
tfx->buffer_len = trim_trailing_ws( tfx->buffer, tfx->buffer_len );
if( lf_seen ) {
tfx->buffer[tfx->buffer_len++] = '\r';
tfx->buffer[tfx->buffer_len++] = '\n';
}
}
*ret_len = len;
return rc;
}
/****************
* The filter is used to make canonical text: Lines are terminated by
* CR, LF, trailing white spaces are removed.
*/
int
text_filter( void *opaque, int control,
IOBUF a, byte *buf, size_t *ret_len)
{
size_t size = *ret_len;
text_filter_context_t *tfx = opaque;
int rc=0;
if( control == IOBUFCTRL_UNDERFLOW ) {
rc = standard( tfx, a, buf, size, ret_len );
}
else if( control == IOBUFCTRL_FREE ) {
if( tfx->truncated )
log_error(_("can't handle text lines longer than %d characters\n"),
MAX_LINELEN );
m_free( tfx->buffer );
tfx->buffer = NULL;
}
else if( control == IOBUFCTRL_DESC )
*(char**)buf = "text_filter";
return rc;
}
/****************
* Copy data from INP to OUT and do some escaping if requested.
* md is updated as required by rfc2440
*/
int
copy_clearsig_text( IOBUF out, IOBUF inp, MD_HANDLE md,
int escape_dash, int escape_from, int pgp2mode )
{
unsigned maxlen;
byte *buffer = NULL; /* malloced buffer */
unsigned bufsize; /* and size of this buffer */
unsigned n;
int truncated = 0;
int pending_lf = 0;
if( !opt.pgp2_workarounds )
pgp2mode = 0;
if( !escape_dash )
escape_from = 0;
for(;;) {
maxlen = MAX_LINELEN;
n = iobuf_read_line( inp, &buffer, &bufsize, &maxlen );
if( !maxlen )
truncated++;
if( !n )
break; /* read_line has returned eof */
/* update the message digest */
if( escape_dash ) {
if( pending_lf ) {
md_putc( md, '\r' );
md_putc( md, '\n' );
}
md_write( md, buffer,
len_without_trailing_chars( buffer, n,
pgp2mode? " \r\n":" \t\r\n"));
}
else
md_write( md, buffer, n );
pending_lf = buffer[n-1] == '\n';
/* write the output */
if( ( escape_dash && *buffer == '-')
|| ( escape_from && n > 4 && !memcmp(buffer, "From ", 5 ) ) ) {
iobuf_put( out, '-' );
iobuf_put( out, ' ' );
}
#if 0 /*defined(HAVE_DOSISH_SYSTEM)*/
/* We don't use this anymore because my interpretation of rfc2440 7.1
* is that there is no conversion needed. If one decides to
* clearsign a unix file on a DOS box he will get a mixed line endings.
* If at some point it turns out, that a conversion is a nice feature
* we can make an option out of it.
*/
/* make sure the lines do end in CR,LF */
if( n > 1 && ( (buffer[n-2] == '\r' && buffer[n-1] == '\n' )
|| (buffer[n-2] == '\n' && buffer[n-1] == '\r'))) {
iobuf_write( out, buffer, n-2 );
iobuf_put( out, '\r');
iobuf_put( out, '\n');
}
else if( n && buffer[n-1] == '\n' ) {
iobuf_write( out, buffer, n-1 );
iobuf_put( out, '\r');
iobuf_put( out, '\n');
}
else
iobuf_write( out, buffer, n );
#else
iobuf_write( out, buffer, n );
#endif
}
/* at eof */
if( !pending_lf ) { /* make sure that the file ends with a LF */
iobuf_writestr( out, LF );
if( !escape_dash )
md_putc( md, '\n' );
}
if( truncated )
log_info(_("input line longer than %d characters\n"), MAX_LINELEN );
return 0; /* okay */
}

2129
g10/trustdb.c Normal file

File diff suppressed because it is too large Load diff

83
g10/trustdb.h Normal file
View file

@ -0,0 +1,83 @@
/* trustdb.h - Trust database
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifndef G10_TRUSTDB_H
#define G10_TRUSTDB_H
/* Trust values must be sorted in ascending order */
#define TRUST_MASK 15
#define TRUST_UNKNOWN 0 /* o: not yet calculated/assigned */
#define TRUST_EXPIRED 1 /* e: calculation may be invalid */
#define TRUST_UNDEFINED 2 /* q: not enough information for calculation */
#define TRUST_NEVER 3 /* n: never trust this pubkey */
#define TRUST_MARGINAL 4 /* m: marginally trusted */
#define TRUST_FULLY 5 /* f: fully trusted */
#define TRUST_ULTIMATE 6 /* u: ultimately trusted */
/* trust values not covered by the mask */
#define TRUST_FLAG_REVOKED 32 /* r: revoked */
#define TRUST_FLAG_SUB_REVOKED 64 /* r: revoked but for subkeys */
#define TRUST_FLAG_DISABLED 128 /* d: key/uid disabled */
#define TRUST_FLAG_PENDING_CHECK 256 /* a check-trustdb is pending */
/*-- trustdb.c --*/
void register_trusted_key( const char *string );
void check_trustdb (void);
void update_trustdb (void);
int setup_trustdb( int level, const char *dbname );
void init_trustdb( void );
void sync_trustdb( void );
const char *trust_value_to_string (unsigned int value);
int string_to_trust_value (const char *str);
void revalidation_mark (void);
int trustdb_pending_check(void);
int cache_disabled_value(PKT_public_key *pk);
unsigned int get_validity (PKT_public_key *pk, PKT_user_id *uid);
int get_validity_info (PKT_public_key *pk, PKT_user_id *uid);
const char *get_validity_string (PKT_public_key *pk, PKT_user_id *uid);
void list_trust_path( const char *username );
int enum_cert_paths( void **context, ulong *lid,
unsigned *ownertrust, unsigned *validity );
void enum_cert_paths_print( void **context, FILE *fp,
int refresh, ulong selected_lid );
unsigned int get_ownertrust (PKT_public_key *pk);
unsigned int get_min_ownertrust (PKT_public_key *pk);
int get_ownertrust_info (PKT_public_key *pk);
const char *get_ownertrust_string (PKT_public_key *pk);
void update_ownertrust (PKT_public_key *pk, unsigned int new_trust );
int clear_ownertrusts (PKT_public_key *pk);
/*-- tdbdump.c --*/
void list_trustdb(const char *username);
void export_ownertrust(void);
void import_ownertrust(const char *fname);
/*-- pkclist.c --*/
int edit_ownertrust (PKT_public_key *pk, int mode );
#endif /*G10_TRUSTDB_H*/

193
g10/verify.c Normal file
View file

@ -0,0 +1,193 @@
/* verify.c - verify signed data
* Copyright (C) 1998, 1999, 2000, 2001 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h> /* for isatty() */
#include "options.h"
#include "packet.h"
#include "errors.h"
#include "iobuf.h"
#include "keydb.h"
#include "memory.h"
#include "util.h"
#include "main.h"
#include "status.h"
#include "filter.h"
#include "ttyio.h"
#include "i18n.h"
/****************
* Assume that the input is a signature and verify it without
* generating any output. With no arguments, the signature packet
* is read from stdin (it may be a detached signature when not
* used in batch mode). If only a sigfile is given, it may be a complete
* signature or a detached signature in which case the signed stuff
* is expected from stdin. With more than 1 argument, the first should
* be a detached signature and the remaining files are the signed stuff.
*/
int
verify_signatures( int nfiles, char **files )
{
IOBUF fp;
armor_filter_context_t afx;
progress_filter_context_t pfx;
const char *sigfile;
int i, rc;
STRLIST sl;
memset( &afx, 0, sizeof afx);
/* decide whether we should handle a detached or a normal signature,
* which is needed so that the code later can hash the correct data and
* not have a normal signature act as detached signature and ignoring the
* indended signed material from the 2nd file or stdin.
* 1. gpg <file - normal
* 2. gpg file - normal (or detached)
* 3. gpg file <file2 - detached
* 4. gpg file file2 - detached
* The question is how decide between case 2 and 3? The only way
* we can do it is by reading one byte from stdin and the unget
* it; the problem here is that we may be reading from the
* terminal (which could be detected using isatty() but won't work
* when under contol of a pty using program (e.g. expect)) and
* might get us in trouble when stdin is used for another purpose
* (--passphrase-fd 0). So we have to break with the behaviour
* prior to gpg 1.0.4 by assuming that case 3 is a normal
* signature (where file2 is ignored and require for a detached
* signature to indicate signed material comes from stdin by using
* case 4 with a file2 of "-".
*
* Actually we don't have to change anything here but can handle
* that all quite easily in mainproc.c
*/
sigfile = nfiles? *files : NULL;
/* open the signature file */
fp = iobuf_open(sigfile);
if( !fp ) {
log_error(_("can't open `%s'\n"), print_fname_stdin(sigfile));
return G10ERR_OPEN_FILE;
}
handle_progress (&pfx, fp, sigfile);
if( !opt.no_armor && use_armor_filter( fp ) )
iobuf_push_filter( fp, armor_filter, &afx );
sl = NULL;
for(i=1 ; i < nfiles; i++ )
add_to_strlist( &sl, files[i] );
rc = proc_signature_packets( NULL, fp, sl, sigfile );
free_strlist(sl);
iobuf_close(fp);
if( afx.no_openpgp_data && rc == -1 ) {
log_error(_("the signature could not be verified.\n"
"Please remember that the signature file (.sig or .asc)\n"
"should be the first file given on the command line.\n") );
rc = 0;
}
return rc;
}
void
print_file_status( int status, const char *name, int what )
{
char *p = m_alloc(strlen(name)+10);
sprintf(p, "%d %s", what, name );
write_status_text( status, p );
m_free(p);
}
static int
verify_one_file( const char *name )
{
IOBUF fp;
armor_filter_context_t afx;
progress_filter_context_t pfx;
int rc;
print_file_status( STATUS_FILE_START, name, 1 );
fp = iobuf_open(name);
if( !fp ) {
print_file_status( STATUS_FILE_ERROR, name, 1 );
log_error(_("can't open `%s'\n"), print_fname_stdin(name));
return G10ERR_OPEN_FILE;
}
handle_progress (&pfx, fp, name);
if( !opt.no_armor ) {
if( use_armor_filter( fp ) ) {
memset( &afx, 0, sizeof afx);
iobuf_push_filter( fp, armor_filter, &afx );
}
}
rc = proc_signature_packets( NULL, fp, NULL, name );
iobuf_close(fp);
write_status( STATUS_FILE_DONE );
return rc;
}
/****************
* Verify each file given in the files array or read the names of the
* files from stdin.
* Note: This function can not handle detached signatures.
*/
int
verify_files( int nfiles, char **files )
{
int i;
if( !nfiles ) { /* read the filenames from stdin */
char line[2048];
unsigned int lno = 0;
while( fgets(line, DIM(line), stdin) ) {
lno++;
if( !*line || line[strlen(line)-1] != '\n' ) {
log_error(_("input line %u too long or missing LF\n"), lno );
return G10ERR_GENERAL;
}
/* This code does not work on MSDOS but how cares there are
* also no script languages available. We don't strip any
* spaces, so that we can process nearly all filenames */
line[strlen(line)-1] = 0;
verify_one_file( line );
}
}
else { /* take filenames from the array */
for(i=0; i < nfiles; i++ )
verify_one_file( files[i] );
}
return 0;
}