1999-11-13 16:43:23 +00:00
|
|
|
/* mainproc.c - handle packets
|
2004-02-10 22:42:34 +00:00
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
|
|
|
|
* 2004 Free Software Foundation, Inc.
|
1997-11-18 14:06:00 +00:00
|
|
|
*
|
1998-12-23 12:41:40 +00:00
|
|
|
* This file is part of GnuPG.
|
1997-11-18 14:06:00 +00:00
|
|
|
*
|
1998-12-23 12:41:40 +00:00
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
1997-11-18 14:06:00 +00:00
|
|
|
* 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.
|
|
|
|
*
|
1998-12-23 12:41:40 +00:00
|
|
|
* GnuPG is distributed in the hope that it will be useful,
|
1997-11-18 14:06:00 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* 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>
|
1998-03-09 21:44:06 +00:00
|
|
|
#include <string.h>
|
1997-12-01 10:33:23 +00:00
|
|
|
#include <assert.h>
|
1998-05-29 11:53:54 +00:00
|
|
|
#include <time.h>
|
1997-11-18 14:06:00 +00:00
|
|
|
|
|
|
|
#include "packet.h"
|
|
|
|
#include "iobuf.h"
|
2002-06-29 13:46:34 +00:00
|
|
|
#include "memory.h"
|
1997-11-18 14:06:00 +00:00
|
|
|
#include "options.h"
|
|
|
|
#include "util.h"
|
2002-06-29 13:46:34 +00:00
|
|
|
#include "cipher.h"
|
1997-11-18 14:06:00 +00:00
|
|
|
#include "keydb.h"
|
1997-11-24 11:04:11 +00:00
|
|
|
#include "filter.h"
|
1997-11-24 22:24:04 +00:00
|
|
|
#include "main.h"
|
1998-01-30 16:23:16 +00:00
|
|
|
#include "status.h"
|
1998-05-29 11:53:54 +00:00
|
|
|
#include "i18n.h"
|
|
|
|
#include "trustdb.h"
|
2002-06-29 13:46:34 +00:00
|
|
|
#include "keyserver-internal.h"
|
2002-07-04 16:06:38 +00:00
|
|
|
#include "photoid.h"
|
1997-11-27 11:44:13 +00:00
|
|
|
|
1999-07-12 12:57:54 +00:00
|
|
|
|
|
|
|
struct kidlist_item {
|
|
|
|
struct kidlist_item *next;
|
|
|
|
u32 kid[2];
|
|
|
|
int pubkey_algo;
|
|
|
|
int reason;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
1997-12-01 10:33:23 +00:00
|
|
|
/****************
|
|
|
|
* Structure to hold the context
|
|
|
|
*/
|
1999-04-26 15:53:01 +00:00
|
|
|
typedef struct mainproc_context *CTX;
|
|
|
|
struct mainproc_context {
|
1999-05-17 20:03:24 +00:00
|
|
|
struct mainproc_context *anchor; /* may be useful in the future */
|
1998-06-29 12:30:57 +00:00
|
|
|
PKT_public_key *last_pubkey;
|
|
|
|
PKT_secret_key *last_seckey;
|
1997-11-27 11:44:13 +00:00
|
|
|
PKT_user_id *last_user_id;
|
|
|
|
md_filter_context_t mfx;
|
1998-03-09 21:44:06 +00:00
|
|
|
int sigs_only; /* process only signatures and reject all other stuff */
|
1998-04-14 17:51:16 +00:00
|
|
|
int encrypt_only; /* process only encrytion messages */
|
1998-03-09 21:44:06 +00:00
|
|
|
STRLIST signed_data;
|
1998-07-14 17:10:28 +00:00
|
|
|
const char *sigfilename;
|
1997-11-27 11:44:13 +00:00
|
|
|
DEK *dek;
|
1998-05-03 15:42:08 +00:00
|
|
|
int last_was_session_key;
|
1998-02-17 20:48:52 +00:00
|
|
|
KBNODE list; /* the current list of packets */
|
1997-12-03 10:20:03 +00:00
|
|
|
int have_data;
|
1997-12-23 17:30:18 +00:00
|
|
|
IOBUF iobuf; /* used to get the filename etc. */
|
1998-05-29 11:53:54 +00:00
|
|
|
int trustletter; /* temp usage in list_node */
|
2003-11-01 01:13:16 +00:00
|
|
|
ulong symkeys;
|
2002-06-29 13:46:34 +00:00
|
|
|
struct kidlist_item *pkenc_list; /* list of encryption packets */
|
|
|
|
struct {
|
|
|
|
int op;
|
|
|
|
int stop_now;
|
|
|
|
} pipemode;
|
1999-04-26 15:53:01 +00:00
|
|
|
};
|
1997-11-27 11:44:13 +00:00
|
|
|
|
|
|
|
|
1998-03-09 21:44:06 +00:00
|
|
|
static int do_proc_packets( CTX c, IOBUF a );
|
1997-11-27 11:44:13 +00:00
|
|
|
|
1997-12-12 12:03:58 +00:00
|
|
|
static void list_node( CTX c, KBNODE node );
|
|
|
|
static void proc_tree( CTX c, KBNODE node );
|
1997-12-01 10:33:23 +00:00
|
|
|
|
|
|
|
|
1997-11-26 22:02:28 +00:00
|
|
|
static void
|
1998-02-17 20:48:52 +00:00
|
|
|
release_list( CTX c )
|
1997-11-26 22:02:28 +00:00
|
|
|
{
|
1998-02-17 20:48:52 +00:00
|
|
|
if( !c->list )
|
1997-12-01 10:33:23 +00:00
|
|
|
return;
|
1998-02-17 20:48:52 +00:00
|
|
|
proc_tree(c, c->list );
|
|
|
|
release_kbnode( c->list );
|
2002-06-29 13:46:34 +00:00
|
|
|
while( c->pkenc_list ) {
|
|
|
|
struct kidlist_item *tmp = c->pkenc_list->next;
|
|
|
|
m_free( c->pkenc_list );
|
|
|
|
c->pkenc_list = tmp;
|
1999-07-12 12:57:54 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
c->pkenc_list = NULL;
|
1998-02-17 20:48:52 +00:00
|
|
|
c->list = NULL;
|
2002-06-29 13:46:34 +00:00
|
|
|
c->have_data = 0;
|
|
|
|
c->last_was_session_key = 0;
|
|
|
|
c->pipemode.op = 0;
|
|
|
|
c->pipemode.stop_now = 0;
|
|
|
|
m_free(c->dek); c->dek = NULL;
|
1997-11-26 22:02:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-12-02 19:36:53 +00:00
|
|
|
static int
|
|
|
|
add_onepass_sig( CTX c, PACKET *pkt )
|
|
|
|
{
|
1997-12-12 12:03:58 +00:00
|
|
|
KBNODE node;
|
1997-12-03 10:20:03 +00:00
|
|
|
|
1998-02-17 20:48:52 +00:00
|
|
|
if( c->list ) { /* add another packet */
|
2002-06-29 13:46:34 +00:00
|
|
|
/* We can only append another onepass packet if the list
|
|
|
|
* does contain only onepass packets */
|
|
|
|
for( node=c->list; node && node->pkt->pkttype == PKT_ONEPASS_SIG;
|
|
|
|
node = node->next )
|
|
|
|
;
|
|
|
|
if( node ) {
|
|
|
|
/* this is not the case, so we flush the current thing and
|
|
|
|
* allow this packet to start a new verification thing */
|
1998-02-17 20:48:52 +00:00
|
|
|
release_list( c );
|
1998-09-28 19:25:31 +00:00
|
|
|
c->list = new_kbnode( pkt );
|
1997-12-02 19:36:53 +00:00
|
|
|
}
|
1998-09-28 19:25:31 +00:00
|
|
|
else
|
|
|
|
add_kbnode( c->list, new_kbnode( pkt ));
|
1997-12-02 19:36:53 +00:00
|
|
|
}
|
|
|
|
else /* insert the first one */
|
1998-02-17 20:48:52 +00:00
|
|
|
c->list = node = new_kbnode( pkt );
|
1997-12-03 10:20:03 +00:00
|
|
|
|
1997-12-02 19:36:53 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
1997-12-01 10:33:23 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
static int
|
|
|
|
add_gpg_control( CTX c, PACKET *pkt )
|
|
|
|
{
|
|
|
|
if ( pkt->pkt.gpg_control->control == CTRLPKT_CLEARSIGN_START ) {
|
|
|
|
/* New clear text signature.
|
|
|
|
* Process the last one and reset everything */
|
|
|
|
release_list(c);
|
|
|
|
}
|
|
|
|
else if ( pkt->pkt.gpg_control->control == CTRLPKT_PIPEMODE ) {
|
|
|
|
/* Pipemode control packet */
|
|
|
|
if ( pkt->pkt.gpg_control->datalen < 2 )
|
|
|
|
log_fatal ("invalid pipemode control packet length\n");
|
|
|
|
if (pkt->pkt.gpg_control->data[0] == 1) {
|
|
|
|
/* start the whole thing */
|
|
|
|
assert ( !c->list ); /* we should be in a pretty virgin state */
|
|
|
|
assert ( !c->pipemode.op );
|
|
|
|
c->pipemode.op = pkt->pkt.gpg_control->data[1];
|
|
|
|
}
|
|
|
|
else if (pkt->pkt.gpg_control->data[0] == 2) {
|
|
|
|
/* the signed material follows in a plaintext packet */
|
|
|
|
assert ( c->pipemode.op == 'B' );
|
|
|
|
}
|
|
|
|
else if (pkt->pkt.gpg_control->data[0] == 3) {
|
|
|
|
assert ( c->pipemode.op == 'B' );
|
|
|
|
release_list (c);
|
|
|
|
/* and tell the outer loop to terminate */
|
|
|
|
c->pipemode.stop_now = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
log_fatal ("invalid pipemode control packet code\n");
|
|
|
|
return 0; /* no need to store the packet */
|
|
|
|
}
|
|
|
|
|
|
|
|
if( c->list ) /* add another packet */
|
|
|
|
add_kbnode( c->list, new_kbnode( pkt ));
|
|
|
|
else /* insert the first one */
|
|
|
|
c->list = new_kbnode( pkt );
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-12-01 10:33:23 +00:00
|
|
|
|
|
|
|
static int
|
1998-04-02 10:30:03 +00:00
|
|
|
add_user_id( CTX c, PACKET *pkt )
|
1997-12-01 10:33:23 +00:00
|
|
|
{
|
1998-04-02 10:30:03 +00:00
|
|
|
if( !c->list ) {
|
1999-09-01 13:40:07 +00:00
|
|
|
log_error("orphaned user ID\n" );
|
1998-04-02 10:30:03 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
add_kbnode( c->list, new_kbnode( pkt ) );
|
1997-12-01 10:33:23 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
1998-04-02 10:30:03 +00:00
|
|
|
add_subkey( CTX c, PACKET *pkt )
|
1997-11-27 11:44:13 +00:00
|
|
|
{
|
1998-02-17 20:48:52 +00:00
|
|
|
if( !c->list ) {
|
1998-04-02 10:30:03 +00:00
|
|
|
log_error("subkey w/o mainkey\n" );
|
1997-12-01 10:33:23 +00:00
|
|
|
return 0;
|
1997-11-27 11:44:13 +00:00
|
|
|
}
|
1998-02-17 20:48:52 +00:00
|
|
|
add_kbnode( c->list, new_kbnode( pkt ) );
|
1997-12-01 10:33:23 +00:00
|
|
|
return 1;
|
1997-11-27 11:44:13 +00:00
|
|
|
}
|
|
|
|
|
1999-07-08 14:24:35 +00:00
|
|
|
static int
|
|
|
|
add_ring_trust( CTX c, PACKET *pkt )
|
|
|
|
{
|
|
|
|
if( !c->list ) {
|
|
|
|
log_error("ring trust w/o key\n" );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
add_kbnode( c->list, new_kbnode( pkt ) );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
1997-11-27 11:44:13 +00:00
|
|
|
|
1997-12-01 10:33:23 +00:00
|
|
|
static int
|
|
|
|
add_signature( CTX c, PACKET *pkt )
|
1997-11-27 11:44:13 +00:00
|
|
|
{
|
1998-02-11 23:22:09 +00:00
|
|
|
KBNODE node;
|
1997-11-27 11:44:13 +00:00
|
|
|
|
1998-02-17 20:48:52 +00:00
|
|
|
if( pkt->pkttype == PKT_SIGNATURE && !c->list ) {
|
1998-04-14 17:51:16 +00:00
|
|
|
/* This is the first signature for the following datafile.
|
2000-07-14 17:34:53 +00:00
|
|
|
* GPG does not write such packets; instead it always uses
|
1998-01-30 16:23:16 +00:00
|
|
|
* onepass-sig packets. The drawback of PGP's method
|
1998-04-14 17:51:16 +00:00
|
|
|
* of prepending the signature to the data is
|
1998-02-11 03:25:44 +00:00
|
|
|
* that it is not possible to make a signature from data read
|
2000-07-14 17:34:53 +00:00
|
|
|
* from stdin. (GPG is able to read PGP stuff anyway.) */
|
1998-01-30 16:23:16 +00:00
|
|
|
node = new_kbnode( pkt );
|
1998-02-17 20:48:52 +00:00
|
|
|
c->list = node;
|
1998-01-30 16:23:16 +00:00
|
|
|
return 1;
|
1997-11-27 11:44:13 +00:00
|
|
|
}
|
1998-02-17 20:48:52 +00:00
|
|
|
else if( !c->list )
|
1998-02-11 23:22:09 +00:00
|
|
|
return 0; /* oops (invalid packet sequence)*/
|
1998-02-17 20:48:52 +00:00
|
|
|
else if( !c->list->pkt )
|
1998-02-11 23:22:09 +00:00
|
|
|
BUG(); /* so nicht */
|
1998-01-30 16:23:16 +00:00
|
|
|
|
1998-02-11 23:22:09 +00:00
|
|
|
/* add a new signature node id at the end */
|
1997-12-12 12:03:58 +00:00
|
|
|
node = new_kbnode( pkt );
|
1998-02-17 20:48:52 +00:00
|
|
|
add_kbnode( c->list, node );
|
1997-12-01 10:33:23 +00:00
|
|
|
return 1;
|
1997-11-27 11:44:13 +00:00
|
|
|
}
|
|
|
|
|
2003-10-26 03:26:14 +00:00
|
|
|
static int
|
|
|
|
symkey_decrypt_seskey( DEK *dek, byte *seskey, size_t slen )
|
2002-06-29 13:46:34 +00:00
|
|
|
{
|
|
|
|
CIPHER_HANDLE hd;
|
2002-09-10 08:40:12 +00:00
|
|
|
int n;
|
2002-06-29 13:46:34 +00:00
|
|
|
|
|
|
|
if ( slen < 17 || slen > 33 ) {
|
2002-10-07 22:19:11 +00:00
|
|
|
log_error ( _("weird size for an encrypted session key (%d)\n"),
|
|
|
|
(int)slen);
|
2003-10-26 03:26:14 +00:00
|
|
|
return G10ERR_BAD_KEY;
|
2002-06-29 13:46:34 +00:00
|
|
|
}
|
|
|
|
hd = cipher_open( dek->algo, CIPHER_MODE_CFB, 1 );
|
|
|
|
cipher_setkey( hd, dek->key, dek->keylen );
|
|
|
|
cipher_setiv( hd, NULL, 0 );
|
2003-10-26 03:26:14 +00:00
|
|
|
cipher_decrypt( hd, seskey, seskey, slen );
|
2002-06-29 13:46:34 +00:00
|
|
|
cipher_close( hd );
|
|
|
|
/* check first byte (the cipher algo) */
|
2003-10-26 03:26:14 +00:00
|
|
|
if(check_cipher_algo(seskey[0]))
|
|
|
|
{
|
|
|
|
/* There is no way to tell the difference here between a bad
|
|
|
|
passphrase and a cipher algorithm that we don't have. */
|
|
|
|
log_error(_("bad passphrase or unknown cipher algorithm (%d)\n"),
|
|
|
|
seskey[0]);
|
|
|
|
if(seskey[0]==CIPHER_ALGO_IDEA)
|
|
|
|
idea_cipher_warn(0);
|
|
|
|
return G10ERR_PASSPHRASE;
|
|
|
|
}
|
|
|
|
n = cipher_get_keylen (seskey[0]) / 8;
|
2002-09-10 08:40:12 +00:00
|
|
|
if (n > DIM(dek->key))
|
|
|
|
BUG ();
|
2002-06-29 13:46:34 +00:00
|
|
|
/* now we replace the dek components with the real session key
|
|
|
|
to decrypt the contents of the sequencing packet. */
|
2003-10-26 03:26:14 +00:00
|
|
|
dek->keylen = cipher_get_keylen( seskey[0] ) / 8;
|
|
|
|
dek->algo = seskey[0];
|
|
|
|
memcpy( dek->key, seskey + 1, dek->keylen );
|
2002-06-29 13:46:34 +00:00
|
|
|
/*log_hexdump( "thekey", dek->key, dek->keylen );*/
|
2003-10-26 03:26:14 +00:00
|
|
|
|
|
|
|
return 0;
|
2002-06-29 13:46:34 +00:00
|
|
|
}
|
1997-11-27 11:44:13 +00:00
|
|
|
|
1998-05-03 15:42:08 +00:00
|
|
|
static void
|
|
|
|
proc_symkey_enc( CTX c, PACKET *pkt )
|
|
|
|
{
|
|
|
|
PKT_symkey_enc *enc;
|
|
|
|
|
|
|
|
enc = pkt->pkt.symkey_enc;
|
2002-06-29 13:46:34 +00:00
|
|
|
if (!enc)
|
|
|
|
log_error ("invalid symkey encrypted packet\n");
|
2003-10-26 03:26:14 +00:00
|
|
|
else if(!c->dek)
|
|
|
|
{
|
2002-06-29 13:46:34 +00:00
|
|
|
int algo = enc->cipher_algo;
|
2003-10-26 03:26:14 +00:00
|
|
|
const char *s = cipher_algo_to_string (algo);
|
2002-06-29 13:46:34 +00:00
|
|
|
|
2003-11-10 04:33:13 +00:00
|
|
|
if(s)
|
2003-10-26 03:26:14 +00:00
|
|
|
{
|
2003-11-10 04:33:13 +00:00
|
|
|
if(!opt.quiet)
|
|
|
|
{
|
|
|
|
if(enc->seskeylen)
|
|
|
|
log_info(_("%s encrypted session key\n"), s );
|
|
|
|
else
|
|
|
|
log_info(_("%s encrypted data\n"), s );
|
|
|
|
}
|
2003-10-26 03:26:14 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
else
|
2003-11-10 04:33:13 +00:00
|
|
|
log_error(_("encrypted with unknown algorithm %d\n"), algo );
|
2002-06-29 13:46:34 +00:00
|
|
|
|
1998-05-04 18:49:26 +00:00
|
|
|
c->last_was_session_key = 2;
|
2003-11-10 04:33:13 +00:00
|
|
|
if(!s || opt.list_only)
|
|
|
|
goto leave;
|
2003-11-30 15:33:04 +00:00
|
|
|
|
|
|
|
if(opt.override_session_key)
|
|
|
|
{
|
|
|
|
c->dek = m_alloc_clear( sizeof *c->dek );
|
|
|
|
if(get_override_session_key(c->dek, opt.override_session_key))
|
|
|
|
{
|
|
|
|
m_free(c->dek);
|
|
|
|
c->dek = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2003-10-26 03:26:14 +00:00
|
|
|
{
|
2003-11-30 15:33:04 +00:00
|
|
|
c->dek=passphrase_to_dek(NULL, 0, algo, &enc->s2k, 0, NULL, NULL);
|
|
|
|
|
|
|
|
if(c->dek)
|
2003-10-26 03:26:14 +00:00
|
|
|
{
|
2003-11-30 15:33:04 +00:00
|
|
|
/* FIXME: This doesn't work perfectly if a symmetric
|
|
|
|
key comes before a public key in the message - if
|
|
|
|
the user doesn't know the passphrase, then there is
|
|
|
|
a chance that the "decrypted" algorithm will happen
|
|
|
|
to be a valid one, which will make the returned dek
|
|
|
|
appear valid, so we won't try any public keys that
|
|
|
|
come later. */
|
|
|
|
if(enc->seskeylen)
|
2003-10-26 03:26:14 +00:00
|
|
|
{
|
2003-11-30 15:33:04 +00:00
|
|
|
if(symkey_decrypt_seskey(c->dek, enc->seskey,
|
|
|
|
enc->seskeylen))
|
|
|
|
{
|
|
|
|
m_free(c->dek);
|
|
|
|
c->dek=NULL;
|
|
|
|
}
|
2003-10-26 03:26:14 +00:00
|
|
|
}
|
2003-11-30 15:33:04 +00:00
|
|
|
else
|
|
|
|
c->dek->algo_info_printed = 1;
|
2003-10-26 03:26:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-11-01 01:13:16 +00:00
|
|
|
|
2003-10-26 03:26:14 +00:00
|
|
|
leave:
|
2003-11-01 01:13:16 +00:00
|
|
|
c->symkeys++;
|
1998-05-03 15:42:08 +00:00
|
|
|
free_packet(pkt);
|
|
|
|
}
|
|
|
|
|
1997-11-27 11:44:13 +00:00
|
|
|
static void
|
|
|
|
proc_pubkey_enc( CTX c, PACKET *pkt )
|
|
|
|
{
|
|
|
|
PKT_pubkey_enc *enc;
|
|
|
|
int result = 0;
|
|
|
|
|
1998-08-05 16:51:59 +00:00
|
|
|
/* check whether the secret key is available and store in this case */
|
1998-05-03 15:42:08 +00:00
|
|
|
c->last_was_session_key = 1;
|
1997-11-27 11:44:13 +00:00
|
|
|
enc = pkt->pkt.pubkey_enc;
|
1998-01-02 20:40:10 +00:00
|
|
|
/*printf("enc: encrypted by a pubkey with keyid %08lX\n", enc->keyid[1] );*/
|
1999-02-26 16:59:48 +00:00
|
|
|
/* Hmmm: why do I have this algo check here - anyway there is
|
|
|
|
* function to check it. */
|
1999-03-14 18:35:18 +00:00
|
|
|
if( opt.verbose )
|
2004-03-18 02:56:41 +00:00
|
|
|
log_info(_("public key is %s\n"), keystr(enc->keyid) );
|
1999-03-17 12:13:04 +00:00
|
|
|
|
|
|
|
if( is_status_enabled() ) {
|
|
|
|
char buf[50];
|
1999-07-01 10:53:35 +00:00
|
|
|
sprintf(buf, "%08lX%08lX %d 0",
|
|
|
|
(ulong)enc->keyid[0], (ulong)enc->keyid[1], enc->pubkey_algo );
|
1999-03-17 12:13:04 +00:00
|
|
|
write_status_text( STATUS_ENC_TO, buf );
|
|
|
|
}
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
if( !opt.list_only && opt.override_session_key ) {
|
|
|
|
/* It does not make much sense to store the session key in
|
|
|
|
* secure memory because it has already been passed on the
|
|
|
|
* command line and the GCHQ knows about it */
|
|
|
|
c->dek = m_alloc_clear( sizeof *c->dek );
|
|
|
|
result = get_override_session_key ( c->dek, opt.override_session_key );
|
|
|
|
if ( result ) {
|
|
|
|
m_free(c->dek); c->dek = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( is_ELGAMAL(enc->pubkey_algo)
|
|
|
|
|| enc->pubkey_algo == PUBKEY_ALGO_DSA
|
1998-05-04 18:49:26 +00:00
|
|
|
|| is_RSA(enc->pubkey_algo) ) {
|
1999-02-26 16:59:48 +00:00
|
|
|
if ( !c->dek && ((!enc->keyid[0] && !enc->keyid[1])
|
2002-06-29 13:46:34 +00:00
|
|
|
|| opt.try_all_secrets
|
1999-02-26 16:59:48 +00:00
|
|
|
|| !seckey_available( enc->keyid )) ) {
|
2000-07-14 17:34:53 +00:00
|
|
|
if( opt.list_only )
|
|
|
|
result = -1;
|
|
|
|
else {
|
2002-06-29 13:46:34 +00:00
|
|
|
c->dek = m_alloc_secure_clear( sizeof *c->dek );
|
2000-07-14 17:34:53 +00:00
|
|
|
if( (result = get_session_key( enc, c->dek )) ) {
|
|
|
|
/* error: delete the DEK */
|
2002-06-29 13:46:34 +00:00
|
|
|
m_free(c->dek); c->dek = NULL;
|
2000-07-14 17:34:53 +00:00
|
|
|
}
|
1998-10-25 19:00:01 +00:00
|
|
|
}
|
1997-11-27 11:44:13 +00:00
|
|
|
}
|
1999-07-12 12:57:54 +00:00
|
|
|
else
|
2002-06-29 13:46:34 +00:00
|
|
|
result = G10ERR_NO_SECKEY;
|
1997-11-27 11:44:13 +00:00
|
|
|
}
|
|
|
|
else
|
2002-06-29 13:46:34 +00:00
|
|
|
result = G10ERR_PUBKEY_ALGO;
|
1997-11-27 11:44:13 +00:00
|
|
|
|
|
|
|
if( result == -1 )
|
|
|
|
;
|
2003-11-30 15:33:04 +00:00
|
|
|
else
|
|
|
|
{
|
2002-06-29 13:46:34 +00:00
|
|
|
/* store it for later display */
|
2003-11-30 15:33:04 +00:00
|
|
|
struct kidlist_item *x = m_alloc( sizeof *x );
|
|
|
|
x->kid[0] = enc->keyid[0];
|
|
|
|
x->kid[1] = enc->keyid[1];
|
|
|
|
x->pubkey_algo = enc->pubkey_algo;
|
|
|
|
x->reason = result;
|
|
|
|
x->next = c->pkenc_list;
|
|
|
|
c->pkenc_list = x;
|
|
|
|
|
|
|
|
if( !result && opt.verbose > 1 )
|
|
|
|
log_info( _("public key encrypted data: good DEK\n") );
|
|
|
|
}
|
|
|
|
|
1997-11-27 11:44:13 +00:00
|
|
|
free_packet(pkt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-07-12 12:57:54 +00:00
|
|
|
|
|
|
|
/****************
|
|
|
|
* Print the list of public key encrypted packets which we could
|
|
|
|
* not decrypt.
|
|
|
|
*/
|
|
|
|
static void
|
2002-06-29 13:46:34 +00:00
|
|
|
print_pkenc_list( struct kidlist_item *list, int failed )
|
1999-07-12 12:57:54 +00:00
|
|
|
{
|
|
|
|
for( ; list; list = list->next ) {
|
2002-06-29 13:46:34 +00:00
|
|
|
PKT_public_key *pk;
|
|
|
|
const char *algstr;
|
|
|
|
|
|
|
|
if ( failed && !list->reason )
|
|
|
|
continue;
|
|
|
|
if ( !failed && list->reason )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
algstr = pubkey_algo_to_string( list->pubkey_algo );
|
|
|
|
pk = m_alloc_clear( sizeof *pk );
|
1999-07-12 12:57:54 +00:00
|
|
|
|
2000-07-14 17:34:53 +00:00
|
|
|
if( !algstr )
|
|
|
|
algstr = "[?]";
|
1999-07-12 12:57:54 +00:00
|
|
|
pk->pubkey_algo = list->pubkey_algo;
|
2004-03-18 02:56:41 +00:00
|
|
|
if( !get_pubkey( pk, list->kid ) )
|
|
|
|
{
|
1999-07-12 12:57:54 +00:00
|
|
|
size_t n;
|
|
|
|
char *p;
|
2004-03-18 02:56:41 +00:00
|
|
|
log_info( _("encrypted with %u-bit %s key, ID %s, created %s\n"),
|
|
|
|
nbits_from_pk( pk ), algstr, keystr_from_pk(pk),
|
|
|
|
strtimestamp(pk->timestamp) );
|
1999-07-12 12:57:54 +00:00
|
|
|
fputs(" \"", log_stream() );
|
|
|
|
p = get_user_id( list->kid, &n );
|
2002-06-29 13:46:34 +00:00
|
|
|
print_utf8_string2 ( log_stream(), p, n, '"' );
|
|
|
|
m_free(p);
|
1999-07-12 12:57:54 +00:00
|
|
|
fputs("\"\n", log_stream() );
|
2004-03-18 02:56:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
log_info(_("encrypted with %s key, ID %s\n"),
|
|
|
|
algstr,keystr(list->kid));
|
|
|
|
|
1999-07-12 12:57:54 +00:00
|
|
|
free_public_key( pk );
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
if( list->reason == G10ERR_NO_SECKEY ) {
|
1999-07-22 18:11:55 +00:00
|
|
|
if( is_status_enabled() ) {
|
|
|
|
char buf[20];
|
|
|
|
sprintf(buf,"%08lX%08lX", (ulong)list->kid[0],
|
|
|
|
(ulong)list->kid[1] );
|
|
|
|
write_status_text( STATUS_NO_SECKEY, buf );
|
|
|
|
}
|
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
else if (list->reason)
|
2002-09-04 02:48:47 +00:00
|
|
|
log_info(_("public key decryption failed: %s\n"),
|
2002-06-29 13:46:34 +00:00
|
|
|
g10_errstr(list->reason));
|
1999-07-12 12:57:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-11-27 11:44:13 +00:00
|
|
|
static void
|
1997-12-01 10:33:23 +00:00
|
|
|
proc_encrypted( CTX c, PACKET *pkt )
|
1997-11-27 11:44:13 +00:00
|
|
|
{
|
|
|
|
int result = 0;
|
|
|
|
|
2003-11-01 01:13:16 +00:00
|
|
|
if (!opt.quiet)
|
|
|
|
{
|
|
|
|
if(c->symkeys>1)
|
|
|
|
log_info(_("encrypted with %lu passphrases\n"),c->symkeys);
|
|
|
|
else if(c->symkeys==1)
|
|
|
|
log_info(_("encrypted with 1 passphrase\n"));
|
2002-06-29 13:46:34 +00:00
|
|
|
print_pkenc_list ( c->pkenc_list, 1 );
|
|
|
|
print_pkenc_list ( c->pkenc_list, 0 );
|
2003-11-01 01:13:16 +00:00
|
|
|
}
|
1999-07-12 12:57:54 +00:00
|
|
|
|
2000-07-14 17:34:53 +00:00
|
|
|
write_status( STATUS_BEGIN_DECRYPTION );
|
|
|
|
|
1999-04-26 15:53:01 +00:00
|
|
|
/*log_debug("dat: %sencrypted data\n", c->dek?"":"conventional ");*/
|
2000-07-14 17:34:53 +00:00
|
|
|
if( opt.list_only )
|
|
|
|
result = -1;
|
|
|
|
else if( !c->dek && !c->last_was_session_key ) {
|
2002-06-29 13:46:34 +00:00
|
|
|
int algo;
|
|
|
|
STRING2KEY s2kbuf, *s2k = NULL;
|
|
|
|
|
2003-11-30 15:33:04 +00:00
|
|
|
if(opt.override_session_key)
|
|
|
|
{
|
|
|
|
c->dek = m_alloc_clear( sizeof *c->dek );
|
|
|
|
result=get_override_session_key(c->dek, opt.override_session_key);
|
|
|
|
if(result)
|
|
|
|
{
|
|
|
|
m_free(c->dek);
|
|
|
|
c->dek = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* assume this is old style conventional encrypted data */
|
|
|
|
if ( (algo = opt.def_cipher_algo))
|
|
|
|
log_info (_("assuming %s encrypted data\n"),
|
2002-06-29 13:46:34 +00:00
|
|
|
cipher_algo_to_string(algo));
|
2003-11-30 15:33:04 +00:00
|
|
|
else if ( check_cipher_algo(CIPHER_ALGO_IDEA) )
|
|
|
|
{
|
|
|
|
algo = opt.def_cipher_algo;
|
|
|
|
if (!algo)
|
|
|
|
algo = opt.s2k_cipher_algo;
|
|
|
|
idea_cipher_warn(1);
|
|
|
|
log_info (_("IDEA cipher unavailable, "
|
|
|
|
"optimistically attempting to use %s instead\n"),
|
|
|
|
cipher_algo_to_string(algo));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
algo = CIPHER_ALGO_IDEA;
|
|
|
|
if (!opt.s2k_digest_algo)
|
|
|
|
{
|
|
|
|
/* If no digest is given we assume MD5 */
|
|
|
|
s2kbuf.mode = 0;
|
|
|
|
s2kbuf.hash_algo = DIGEST_ALGO_MD5;
|
|
|
|
s2k = &s2kbuf;
|
|
|
|
}
|
|
|
|
log_info (_("assuming %s encrypted data\n"), "IDEA");
|
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
|
2003-11-30 15:33:04 +00:00
|
|
|
c->dek = passphrase_to_dek ( NULL, 0, algo, s2k, 0, NULL, NULL );
|
|
|
|
if (c->dek)
|
|
|
|
c->dek->algo_info_printed = 1;
|
|
|
|
}
|
1997-11-27 11:44:13 +00:00
|
|
|
}
|
|
|
|
else if( !c->dek )
|
2002-06-29 13:46:34 +00:00
|
|
|
result = G10ERR_NO_SECKEY;
|
1997-11-27 11:44:13 +00:00
|
|
|
if( !result )
|
1999-04-26 15:53:01 +00:00
|
|
|
result = decrypt_data( c, pkt->pkt.encrypted, c->dek );
|
2000-07-14 17:34:53 +00:00
|
|
|
|
1997-11-27 11:44:13 +00:00
|
|
|
if( result == -1 )
|
|
|
|
;
|
2002-08-06 17:57:53 +00:00
|
|
|
else if( !result || (result==G10ERR_BAD_SIGN && opt.ignore_mdc_error)) {
|
1999-04-09 10:34:44 +00:00
|
|
|
write_status( STATUS_DECRYPTION_OKAY );
|
1998-01-02 20:40:10 +00:00
|
|
|
if( opt.verbose > 1 )
|
1998-11-10 12:59:59 +00:00
|
|
|
log_info(_("decryption okay\n"));
|
2002-08-06 17:57:53 +00:00
|
|
|
if( pkt->pkt.encrypted->mdc_method && !result )
|
1999-05-17 20:03:24 +00:00
|
|
|
write_status( STATUS_GOODMDC );
|
2002-07-30 16:48:21 +00:00
|
|
|
else if(!opt.no_mdc_warn)
|
2003-03-04 15:24:12 +00:00
|
|
|
log_info (_("WARNING: message was not integrity protected\n"));
|
2003-11-30 15:33:04 +00:00
|
|
|
if(opt.show_session_key)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *buf = m_alloc ( c->dek->keylen*2 + 20 );
|
|
|
|
sprintf ( buf, "%d:", c->dek->algo );
|
|
|
|
for(i=0; i < c->dek->keylen; i++ )
|
|
|
|
sprintf(buf+strlen(buf), "%02X", c->dek->key[i] );
|
|
|
|
log_info( "session key: \"%s\"\n", buf );
|
|
|
|
write_status_text ( STATUS_SESSION_KEY, buf );
|
|
|
|
}
|
1999-05-17 20:03:24 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
else if( result == G10ERR_BAD_SIGN ) {
|
1999-05-17 20:03:24 +00:00
|
|
|
log_error(_("WARNING: encrypted message has been manipulated!\n"));
|
|
|
|
write_status( STATUS_BADMDC );
|
2002-07-30 16:48:21 +00:00
|
|
|
write_status( STATUS_DECRYPTION_FAILED );
|
1998-01-02 20:40:10 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-04-08 07:41:35 +00:00
|
|
|
write_status( STATUS_DECRYPTION_FAILED );
|
2002-06-29 13:46:34 +00:00
|
|
|
log_error(_("decryption failed: %s\n"), g10_errstr(result));
|
2000-07-14 17:34:53 +00:00
|
|
|
/* Hmmm: does this work when we have encrypted using multiple
|
1999-07-12 12:57:54 +00:00
|
|
|
* ways to specify the session key (symmmetric and PK)*/
|
1998-01-02 20:40:10 +00:00
|
|
|
}
|
2003-11-30 15:33:04 +00:00
|
|
|
m_free(c->dek); c->dek = NULL;
|
1997-11-27 11:44:13 +00:00
|
|
|
free_packet(pkt);
|
1998-05-03 15:42:08 +00:00
|
|
|
c->last_was_session_key = 0;
|
2000-07-14 17:34:53 +00:00
|
|
|
write_status( STATUS_END_DECRYPTION );
|
1997-11-27 11:44:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-17 20:03:24 +00:00
|
|
|
|
1997-11-27 11:44:13 +00:00
|
|
|
static void
|
|
|
|
proc_plaintext( CTX c, PACKET *pkt )
|
|
|
|
{
|
|
|
|
PKT_plaintext *pt = pkt->pkt.plaintext;
|
1999-05-19 14:12:26 +00:00
|
|
|
int any, clearsig, only_md5, rc;
|
1998-06-25 10:19:08 +00:00
|
|
|
KBNODE n;
|
1997-11-27 11:44:13 +00:00
|
|
|
|
1998-09-29 16:15:15 +00:00
|
|
|
if( pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8 ) )
|
1998-11-10 12:59:59 +00:00
|
|
|
log_info(_("NOTE: sender requested \"for-your-eyes-only\"\n"));
|
1998-09-29 16:15:15 +00:00
|
|
|
else if( opt.verbose )
|
1998-11-10 12:59:59 +00:00
|
|
|
log_info(_("original file name='%.*s'\n"), pt->namelen, pt->name);
|
1997-11-27 11:44:13 +00:00
|
|
|
free_md_filter_context( &c->mfx );
|
2002-06-29 13:46:34 +00:00
|
|
|
c->mfx.md = md_open( 0, 0);
|
1998-07-08 09:29:43 +00:00
|
|
|
/* fixme: we may need to push the textfilter if we have sigclass 1
|
1999-02-10 16:22:40 +00:00
|
|
|
* and no armoring - Not yet tested
|
|
|
|
* Hmmm, why don't we need it at all if we have sigclass 1
|
|
|
|
* Should we assume that plaintext in mode 't' has always sigclass 1??
|
|
|
|
* See: Russ Allbery's mail 1999-02-09
|
|
|
|
*/
|
1999-05-19 14:12:26 +00:00
|
|
|
any = clearsig = only_md5 = 0;
|
1998-06-25 10:19:08 +00:00
|
|
|
for(n=c->list; n; n = n->next ) {
|
1998-07-08 09:29:43 +00:00
|
|
|
if( n->pkt->pkttype == PKT_ONEPASS_SIG ) {
|
|
|
|
if( n->pkt->pkt.onepass_sig->digest_algo ) {
|
2002-06-29 13:46:34 +00:00
|
|
|
md_enable( c->mfx.md, n->pkt->pkt.onepass_sig->digest_algo );
|
1999-05-19 14:12:26 +00:00
|
|
|
if( !any && n->pkt->pkt.onepass_sig->digest_algo
|
2002-06-29 13:46:34 +00:00
|
|
|
== DIGEST_ALGO_MD5 )
|
1999-05-19 14:12:26 +00:00
|
|
|
only_md5 = 1;
|
|
|
|
else
|
|
|
|
only_md5 = 0;
|
1998-07-08 09:29:43 +00:00
|
|
|
any = 1;
|
|
|
|
}
|
1999-05-19 14:12:26 +00:00
|
|
|
if( n->pkt->pkt.onepass_sig->sig_class != 0x01 )
|
|
|
|
only_md5 = 0;
|
1998-06-25 10:19:08 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
else if( n->pkt->pkttype == PKT_GPG_CONTROL
|
|
|
|
&& n->pkt->pkt.gpg_control->control
|
|
|
|
== CTRLPKT_CLEARSIGN_START ) {
|
|
|
|
size_t datalen = n->pkt->pkt.gpg_control->datalen;
|
|
|
|
const byte *data = n->pkt->pkt.gpg_control->data;
|
|
|
|
|
|
|
|
/* check that we have at least the sigclass and one hash */
|
|
|
|
if ( datalen < 2 )
|
|
|
|
log_fatal("invalid control packet CTRLPKT_CLEARSIGN_START\n");
|
|
|
|
/* Note that we don't set the clearsig flag for not-dash-escaped
|
|
|
|
* documents */
|
|
|
|
clearsig = (*data == 0x01);
|
|
|
|
for( data++, datalen--; datalen; datalen--, data++ )
|
|
|
|
md_enable( c->mfx.md, *data );
|
|
|
|
any = 1;
|
|
|
|
break; /* no pass signature pakets are expected */
|
|
|
|
}
|
1998-06-25 10:19:08 +00:00
|
|
|
}
|
2000-07-14 17:34:53 +00:00
|
|
|
|
|
|
|
if( !any && !opt.skip_verify ) {
|
|
|
|
/* no onepass sig packet: enable all standard algos */
|
2002-06-29 13:46:34 +00:00
|
|
|
md_enable( c->mfx.md, DIGEST_ALGO_RMD160 );
|
|
|
|
md_enable( c->mfx.md, DIGEST_ALGO_SHA1 );
|
|
|
|
md_enable( c->mfx.md, DIGEST_ALGO_MD5 );
|
1998-06-25 10:19:08 +00:00
|
|
|
}
|
2000-07-14 17:34:53 +00:00
|
|
|
if( opt.pgp2_workarounds && only_md5 && !opt.skip_verify ) {
|
1999-05-19 14:12:26 +00:00
|
|
|
/* This is a kludge to work around a bug in pgp2. It does only
|
|
|
|
* catch those mails which are armored. To catch the non-armored
|
|
|
|
* pgp mails we could see whether there is the signature packet
|
|
|
|
* in front of the plaintext. If someone needs this, send me a patch.
|
|
|
|
*/
|
2002-06-29 13:46:34 +00:00
|
|
|
c->mfx.md2 = md_open( DIGEST_ALGO_MD5, 0);
|
1999-05-19 14:12:26 +00:00
|
|
|
}
|
2000-07-14 17:34:53 +00:00
|
|
|
if ( DBG_HASHING ) {
|
2002-06-29 13:46:34 +00:00
|
|
|
md_start_debug( c->mfx.md, "verify" );
|
2000-07-14 17:34:53 +00:00
|
|
|
if ( c->mfx.md2 )
|
2002-06-29 13:46:34 +00:00
|
|
|
md_start_debug( c->mfx.md2, "verify2" );
|
2000-07-14 17:34:53 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
if ( c->pipemode.op == 'B' )
|
|
|
|
rc = handle_plaintext( pt, &c->mfx, 1, 0 );
|
|
|
|
else {
|
|
|
|
rc = handle_plaintext( pt, &c->mfx, c->sigs_only, clearsig );
|
|
|
|
if( rc == G10ERR_CREATE_FILE && !c->sigs_only) {
|
|
|
|
/* can't write output but we hash it anyway to
|
|
|
|
* check the signature */
|
|
|
|
rc = handle_plaintext( pt, &c->mfx, 1, clearsig );
|
|
|
|
}
|
1998-07-14 17:10:28 +00:00
|
|
|
}
|
1998-01-02 20:40:10 +00:00
|
|
|
if( rc )
|
2002-06-29 13:46:34 +00:00
|
|
|
log_error( "handle plaintext failed: %s\n", g10_errstr(rc));
|
1997-11-27 11:44:13 +00:00
|
|
|
free_packet(pkt);
|
1998-05-03 15:42:08 +00:00
|
|
|
c->last_was_session_key = 0;
|
2002-06-29 13:46:34 +00:00
|
|
|
|
|
|
|
/* We add a marker control packet instead of the plaintext packet.
|
|
|
|
* This is so that we can later detect invalid packet sequences.
|
|
|
|
*/
|
|
|
|
n = new_kbnode (create_gpg_control (CTRLPKT_PLAINTEXT_MARK, NULL, 0));
|
|
|
|
if (c->list)
|
|
|
|
add_kbnode (c->list, n);
|
|
|
|
else
|
|
|
|
c->list = n;
|
1997-11-27 11:44:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-03-09 21:44:06 +00:00
|
|
|
static int
|
|
|
|
proc_compressed_cb( IOBUF a, void *info )
|
|
|
|
{
|
1999-04-26 15:53:01 +00:00
|
|
|
return proc_signature_packets( info, a, ((CTX)info)->signed_data,
|
|
|
|
((CTX)info)->sigfilename );
|
1998-03-09 21:44:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
proc_encrypt_cb( IOBUF a, void *info )
|
|
|
|
{
|
1999-04-26 15:53:01 +00:00
|
|
|
return proc_encryption_packets( info, a );
|
1998-03-09 21:44:06 +00:00
|
|
|
}
|
|
|
|
|
1997-11-27 11:44:13 +00:00
|
|
|
static void
|
1997-12-01 10:33:23 +00:00
|
|
|
proc_compressed( CTX c, PACKET *pkt )
|
1997-11-27 11:44:13 +00:00
|
|
|
{
|
|
|
|
PKT_compressed *zd = pkt->pkt.compressed;
|
1998-01-02 20:40:10 +00:00
|
|
|
int rc;
|
1997-11-27 11:44:13 +00:00
|
|
|
|
1998-01-02 20:40:10 +00:00
|
|
|
/*printf("zip: compressed data packet\n");*/
|
1998-03-09 21:44:06 +00:00
|
|
|
if( c->sigs_only )
|
1999-04-26 15:53:01 +00:00
|
|
|
rc = handle_compressed( c, zd, proc_compressed_cb, c );
|
1998-03-09 21:44:06 +00:00
|
|
|
else if( c->encrypt_only )
|
1999-04-26 15:53:01 +00:00
|
|
|
rc = handle_compressed( c, zd, proc_encrypt_cb, c );
|
1998-03-09 21:44:06 +00:00
|
|
|
else
|
1999-04-26 15:53:01 +00:00
|
|
|
rc = handle_compressed( c, zd, NULL, NULL );
|
1998-01-02 20:40:10 +00:00
|
|
|
if( rc )
|
2002-06-29 13:46:34 +00:00
|
|
|
log_error("uncompressing failed: %s\n", g10_errstr(rc));
|
1997-11-27 11:44:13 +00:00
|
|
|
free_packet(pkt);
|
1998-05-03 15:42:08 +00:00
|
|
|
c->last_was_session_key = 0;
|
1997-11-27 11:44:13 +00:00
|
|
|
}
|
1997-11-26 22:02:28 +00:00
|
|
|
|
1997-12-01 10:33:23 +00:00
|
|
|
/****************
|
|
|
|
* check the signature
|
|
|
|
* Returns: 0 = valid signature or an error code
|
|
|
|
*/
|
|
|
|
static int
|
2003-08-13 03:31:36 +00:00
|
|
|
do_check_sig( CTX c, KBNODE node, int *is_selfsig,
|
|
|
|
int *is_expkey, int *is_revkey )
|
1997-12-01 10:33:23 +00:00
|
|
|
{
|
|
|
|
PKT_signature *sig;
|
2002-06-29 13:46:34 +00:00
|
|
|
MD_HANDLE md = NULL, md2 = NULL;
|
2003-08-13 03:31:36 +00:00
|
|
|
int algo, rc;
|
1997-12-01 10:33:23 +00:00
|
|
|
|
|
|
|
assert( node->pkt->pkttype == PKT_SIGNATURE );
|
1998-05-29 11:53:54 +00:00
|
|
|
if( is_selfsig )
|
|
|
|
*is_selfsig = 0;
|
1997-12-01 10:33:23 +00:00
|
|
|
sig = node->pkt->pkt.signature;
|
|
|
|
|
1998-05-04 18:49:26 +00:00
|
|
|
algo = sig->digest_algo;
|
2002-06-29 13:46:34 +00:00
|
|
|
if( (rc=check_digest_algo(algo)) )
|
1997-12-01 10:33:23 +00:00
|
|
|
return rc;
|
|
|
|
|
1997-12-03 10:20:03 +00:00
|
|
|
if( sig->sig_class == 0x00 ) {
|
1998-02-27 17:51:28 +00:00
|
|
|
if( c->mfx.md )
|
2002-06-29 13:46:34 +00:00
|
|
|
md = md_copy( c->mfx.md );
|
1998-02-27 17:51:28 +00:00
|
|
|
else /* detached signature */
|
2002-06-29 13:46:34 +00:00
|
|
|
md = md_open( 0, 0 ); /* signature_check() will enable the md*/
|
1997-12-03 10:20:03 +00:00
|
|
|
}
|
1998-02-04 18:54:31 +00:00
|
|
|
else if( sig->sig_class == 0x01 ) {
|
|
|
|
/* how do we know that we have to hash the (already hashed) text
|
|
|
|
* in canonical mode ??? (calculating both modes???) */
|
1999-05-19 14:12:26 +00:00
|
|
|
if( c->mfx.md ) {
|
2002-06-29 13:46:34 +00:00
|
|
|
md = md_copy( c->mfx.md );
|
|
|
|
if( c->mfx.md2 )
|
|
|
|
md2 = md_copy( c->mfx.md2 );
|
1999-05-19 14:12:26 +00:00
|
|
|
}
|
|
|
|
else { /* detached signature */
|
2002-06-29 13:46:34 +00:00
|
|
|
log_debug("Do we really need this here?");
|
|
|
|
md = md_open( 0, 0 ); /* signature_check() will enable the md*/
|
|
|
|
md2 = md_open( 0, 0 );
|
1999-05-19 14:12:26 +00:00
|
|
|
}
|
1998-02-04 18:54:31 +00:00
|
|
|
}
|
1998-02-18 13:58:46 +00:00
|
|
|
else if( (sig->sig_class&~3) == 0x10
|
1998-04-02 10:30:03 +00:00
|
|
|
|| sig->sig_class == 0x18
|
2002-06-29 13:46:34 +00:00
|
|
|
|| sig->sig_class == 0x1f
|
1998-02-18 13:58:46 +00:00
|
|
|
|| sig->sig_class == 0x20
|
2002-06-29 13:46:34 +00:00
|
|
|
|| sig->sig_class == 0x28
|
|
|
|
|| sig->sig_class == 0x30 ) {
|
1998-06-29 12:30:57 +00:00
|
|
|
if( c->list->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|| c->list->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
|
1998-05-29 11:53:54 +00:00
|
|
|
return check_key_signature( c->list, node, is_selfsig );
|
1997-12-01 10:33:23 +00:00
|
|
|
}
|
2000-07-14 17:34:53 +00:00
|
|
|
else if( sig->sig_class == 0x20 ) {
|
|
|
|
log_info(_("standalone revocation - "
|
|
|
|
"use \"gpg --import\" to apply\n"));
|
2002-06-29 13:46:34 +00:00
|
|
|
return G10ERR_NOT_PROCESSED;
|
2000-07-14 17:34:53 +00:00
|
|
|
}
|
1997-12-01 10:33:23 +00:00
|
|
|
else {
|
1998-02-18 13:58:46 +00:00
|
|
|
log_error("invalid root packet for sigclass %02x\n",
|
|
|
|
sig->sig_class);
|
2002-06-29 13:46:34 +00:00
|
|
|
return G10ERR_SIG_CLASS;
|
1997-12-01 10:33:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2002-06-29 13:46:34 +00:00
|
|
|
return G10ERR_SIG_CLASS;
|
2003-08-13 03:31:36 +00:00
|
|
|
rc = signature_check2( sig, md, NULL, is_expkey, is_revkey, NULL );
|
2002-06-29 13:46:34 +00:00
|
|
|
if( rc == G10ERR_BAD_SIGN && md2 )
|
2003-08-13 03:31:36 +00:00
|
|
|
rc = signature_check2( sig, md2, NULL, is_expkey, is_revkey, NULL );
|
2002-06-29 13:46:34 +00:00
|
|
|
md_close(md);
|
|
|
|
md_close(md2);
|
1997-12-01 10:33:23 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
print_userid( PACKET *pkt )
|
|
|
|
{
|
|
|
|
if( !pkt )
|
1998-01-16 21:15:24 +00:00
|
|
|
BUG();
|
1997-12-01 10:33:23 +00:00
|
|
|
if( pkt->pkttype != PKT_USER_ID ) {
|
|
|
|
printf("ERROR: unexpected packet type %d", pkt->pkttype );
|
|
|
|
return;
|
|
|
|
}
|
2000-07-14 17:34:53 +00:00
|
|
|
if( opt.with_colons )
|
2002-06-29 13:46:34 +00:00
|
|
|
{
|
|
|
|
if(pkt->pkt.user_id->attrib_data)
|
|
|
|
printf("%u %lu",
|
|
|
|
pkt->pkt.user_id->numattribs,
|
|
|
|
pkt->pkt.user_id->attrib_len);
|
|
|
|
else
|
|
|
|
print_string( stdout, pkt->pkt.user_id->name,
|
|
|
|
pkt->pkt.user_id->len, ':');
|
|
|
|
}
|
2000-07-14 17:34:53 +00:00
|
|
|
else
|
|
|
|
print_utf8_string( stdout, pkt->pkt.user_id->name,
|
|
|
|
pkt->pkt.user_id->len );
|
1997-12-01 10:33:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* List the certificate in a user friendly way
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
1997-12-12 12:03:58 +00:00
|
|
|
list_node( CTX c, KBNODE node )
|
1997-12-01 10:33:23 +00:00
|
|
|
{
|
1998-02-11 03:25:44 +00:00
|
|
|
int any=0;
|
1998-04-02 10:30:03 +00:00
|
|
|
int mainkey;
|
1997-12-01 10:33:23 +00:00
|
|
|
|
|
|
|
if( !node )
|
|
|
|
;
|
1998-06-29 12:30:57 +00:00
|
|
|
else if( (mainkey = (node->pkt->pkttype == PKT_PUBLIC_KEY) )
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
|
|
|
|
PKT_public_key *pk = node->pkt->pkt.public_key;
|
1997-12-01 10:33:23 +00:00
|
|
|
|
2004-03-18 02:56:41 +00:00
|
|
|
if( opt.with_colons )
|
|
|
|
{
|
1998-03-09 21:44:06 +00:00
|
|
|
u32 keyid[2];
|
1998-06-29 12:30:57 +00:00
|
|
|
keyid_from_pk( pk, keyid );
|
2004-01-30 16:49:28 +00:00
|
|
|
if( mainkey )
|
|
|
|
c->trustletter = opt.fast_list_mode?
|
2004-03-18 02:56:41 +00:00
|
|
|
0 : get_validity_info( pk, NULL );
|
2000-07-14 17:34:53 +00:00
|
|
|
printf("%s:", mainkey? "pub":"sub" );
|
|
|
|
if( c->trustletter )
|
2004-03-18 02:56:41 +00:00
|
|
|
putchar( c->trustletter );
|
2004-01-30 16:49:28 +00:00
|
|
|
printf(":%u:%d:%08lX%08lX:%s:%s::",
|
2004-03-18 02:56:41 +00:00
|
|
|
nbits_from_pk( pk ),
|
|
|
|
pk->pubkey_algo,
|
|
|
|
(ulong)keyid[0],(ulong)keyid[1],
|
|
|
|
colon_datestr_from_pk( pk ),
|
|
|
|
colon_strtime (pk->expiredate) );
|
2002-06-29 13:46:34 +00:00
|
|
|
if( mainkey && !opt.fast_list_mode )
|
2004-03-18 02:56:41 +00:00
|
|
|
putchar( get_ownertrust_info (pk) );
|
1998-05-29 11:53:54 +00:00
|
|
|
putchar(':');
|
1999-07-08 14:24:35 +00:00
|
|
|
if( node->next && node->next->pkt->pkttype == PKT_RING_TRUST) {
|
2004-03-18 02:56:41 +00:00
|
|
|
putchar('\n'); any=1;
|
|
|
|
if( opt.fingerprint )
|
|
|
|
print_fingerprint( pk, NULL, 0 );
|
|
|
|
printf("rtv:1:%u:\n",
|
|
|
|
node->next->pkt->pkt.ring_trust->trustval );
|
1999-07-08 14:24:35 +00:00
|
|
|
}
|
2004-03-18 02:56:41 +00:00
|
|
|
}
|
1998-03-09 21:44:06 +00:00
|
|
|
else
|
2004-03-18 02:56:41 +00:00
|
|
|
printf("%s %4u%c/%s %s%s",
|
|
|
|
mainkey? "pub":"sub", nbits_from_pk( pk ),
|
|
|
|
pubkey_letter( pk->pubkey_algo ), keystr_from_pk( pk ),
|
|
|
|
datestr_from_pk( pk ), mainkey?" ":"");
|
2000-07-14 17:34:53 +00:00
|
|
|
|
1998-05-29 11:53:54 +00:00
|
|
|
if( mainkey ) {
|
|
|
|
/* and now list all userids with their signatures */
|
|
|
|
for( node = node->next; node; node = node->next ) {
|
|
|
|
if( node->pkt->pkttype == PKT_SIGNATURE ) {
|
|
|
|
if( !any ) {
|
|
|
|
if( node->pkt->pkt.signature->sig_class == 0x20 )
|
|
|
|
puts("[revoked]");
|
|
|
|
else
|
|
|
|
putchar('\n');
|
|
|
|
any = 1;
|
|
|
|
}
|
|
|
|
list_node(c, node );
|
1998-03-09 21:44:06 +00:00
|
|
|
}
|
1998-05-29 11:53:54 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_USER_ID ) {
|
|
|
|
if( any ) {
|
|
|
|
if( opt.with_colons )
|
2002-06-29 13:46:34 +00:00
|
|
|
printf("%s:::::::::",
|
|
|
|
node->pkt->pkt.user_id->attrib_data?"uat":"uid");
|
1998-05-29 11:53:54 +00:00
|
|
|
else
|
|
|
|
printf( "uid%*s", 28, "" );
|
|
|
|
}
|
|
|
|
print_userid( node->pkt );
|
1998-03-09 21:44:06 +00:00
|
|
|
if( opt.with_colons )
|
1998-05-29 11:53:54 +00:00
|
|
|
putchar(':');
|
1998-04-02 10:30:03 +00:00
|
|
|
putchar('\n');
|
1998-05-29 11:53:54 +00:00
|
|
|
if( opt.fingerprint && !any )
|
2002-06-29 13:46:34 +00:00
|
|
|
print_fingerprint( pk, NULL, 0 );
|
1999-07-08 14:24:35 +00:00
|
|
|
if( node->next
|
|
|
|
&& node->next->pkt->pkttype == PKT_RING_TRUST ) {
|
|
|
|
printf("rtv:2:%u:\n",
|
|
|
|
node->next->pkt->pkt.ring_trust->trustval );
|
|
|
|
}
|
1998-05-29 11:53:54 +00:00
|
|
|
any=1;
|
|
|
|
}
|
1998-06-29 12:30:57 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
|
1998-05-29 11:53:54 +00:00
|
|
|
if( !any ) {
|
|
|
|
putchar('\n');
|
|
|
|
any = 1;
|
|
|
|
}
|
|
|
|
list_node(c, node );
|
1998-04-02 10:30:03 +00:00
|
|
|
}
|
|
|
|
}
|
1997-12-01 10:33:23 +00:00
|
|
|
}
|
2004-02-10 22:42:34 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* of subkey */
|
|
|
|
if( pk->is_revoked )
|
|
|
|
printf(" %s",_("[revoked] "));
|
|
|
|
else if( pk->expiredate )
|
|
|
|
printf(_(" [expires: %s]"), expirestr_from_pk( pk ) );
|
|
|
|
}
|
2000-07-14 17:34:53 +00:00
|
|
|
|
1998-05-29 11:53:54 +00:00
|
|
|
if( !any )
|
1998-04-02 10:30:03 +00:00
|
|
|
putchar('\n');
|
1998-07-29 19:35:05 +00:00
|
|
|
if( !mainkey && opt.fingerprint > 1 )
|
2002-06-29 13:46:34 +00:00
|
|
|
print_fingerprint( pk, NULL, 0 );
|
1997-12-01 10:33:23 +00:00
|
|
|
}
|
1998-06-29 12:30:57 +00:00
|
|
|
else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) )
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
|
|
|
|
PKT_secret_key *sk = node->pkt->pkt.secret_key;
|
1997-12-01 10:33:23 +00:00
|
|
|
|
2004-03-18 02:56:41 +00:00
|
|
|
if( opt.with_colons )
|
|
|
|
{
|
1998-05-29 11:53:54 +00:00
|
|
|
u32 keyid[2];
|
1998-06-29 12:30:57 +00:00
|
|
|
keyid_from_sk( sk, keyid );
|
1998-10-16 16:00:17 +00:00
|
|
|
printf("%s::%u:%d:%08lX%08lX:%s:%s:::",
|
2004-03-18 02:56:41 +00:00
|
|
|
mainkey? "sec":"ssb",
|
|
|
|
nbits_from_sk( sk ),
|
|
|
|
sk->pubkey_algo,
|
|
|
|
(ulong)keyid[0],(ulong)keyid[1],
|
|
|
|
colon_datestr_from_sk( sk ),
|
|
|
|
colon_strtime (sk->expiredate)
|
|
|
|
/* fixme: add LID */ );
|
|
|
|
}
|
1998-05-29 11:53:54 +00:00
|
|
|
else
|
2004-03-18 02:56:41 +00:00
|
|
|
printf("%s %4u%c/%s %s ", mainkey? "sec":"ssb",
|
|
|
|
nbits_from_sk( sk ), pubkey_letter( sk->pubkey_algo ),
|
|
|
|
keystr_from_sk( sk ), datestr_from_sk( sk ));
|
1998-05-29 11:53:54 +00:00
|
|
|
if( mainkey ) {
|
|
|
|
/* and now list all userids with their signatures */
|
|
|
|
for( node = node->next; node; node = node->next ) {
|
|
|
|
if( node->pkt->pkttype == PKT_SIGNATURE ) {
|
|
|
|
if( !any ) {
|
|
|
|
if( node->pkt->pkt.signature->sig_class == 0x20 )
|
|
|
|
puts("[revoked]");
|
|
|
|
else
|
|
|
|
putchar('\n');
|
|
|
|
any = 1;
|
|
|
|
}
|
|
|
|
list_node(c, node );
|
|
|
|
}
|
|
|
|
else if( node->pkt->pkttype == PKT_USER_ID ) {
|
|
|
|
if( any ) {
|
|
|
|
if( opt.with_colons )
|
2002-06-29 13:46:34 +00:00
|
|
|
printf("%s:::::::::",
|
|
|
|
node->pkt->pkt.user_id->attrib_data?"uat":"uid");
|
1998-05-29 11:53:54 +00:00
|
|
|
else
|
|
|
|
printf( "uid%*s", 28, "" );
|
|
|
|
}
|
|
|
|
print_userid( node->pkt );
|
|
|
|
if( opt.with_colons )
|
|
|
|
putchar(':');
|
|
|
|
putchar('\n');
|
|
|
|
if( opt.fingerprint && !any )
|
2002-06-29 13:46:34 +00:00
|
|
|
print_fingerprint( NULL, sk, 0 );
|
1998-05-29 11:53:54 +00:00
|
|
|
any=1;
|
|
|
|
}
|
1998-06-29 12:30:57 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
|
1998-05-29 11:53:54 +00:00
|
|
|
if( !any ) {
|
|
|
|
putchar('\n');
|
|
|
|
any = 1;
|
|
|
|
}
|
|
|
|
list_node(c, node );
|
|
|
|
}
|
|
|
|
}
|
1997-12-01 10:33:23 +00:00
|
|
|
}
|
1998-05-29 11:53:54 +00:00
|
|
|
if( !any )
|
1998-04-02 10:30:03 +00:00
|
|
|
putchar('\n');
|
1998-07-29 19:35:05 +00:00
|
|
|
if( !mainkey && opt.fingerprint > 1 )
|
2002-06-29 13:46:34 +00:00
|
|
|
print_fingerprint( NULL, sk, 0 );
|
1997-12-01 10:33:23 +00:00
|
|
|
}
|
1997-12-09 12:46:23 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
|
1997-12-01 10:33:23 +00:00
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
1998-05-29 11:53:54 +00:00
|
|
|
int is_selfsig = 0;
|
1998-02-17 20:48:52 +00:00
|
|
|
int rc2=0;
|
1997-12-01 10:33:23 +00:00
|
|
|
size_t n;
|
|
|
|
char *p;
|
|
|
|
int sigrc = ' ';
|
|
|
|
|
2004-01-24 00:47:45 +00:00
|
|
|
if( !opt.verbose )
|
1997-12-09 12:46:23 +00:00
|
|
|
return;
|
|
|
|
|
1998-02-18 13:58:46 +00:00
|
|
|
if( sig->sig_class == 0x20 || sig->sig_class == 0x30 )
|
|
|
|
fputs("rev", stdout);
|
|
|
|
else
|
|
|
|
fputs("sig", stdout);
|
1997-12-01 10:33:23 +00:00
|
|
|
if( opt.check_sigs ) {
|
1997-12-23 17:30:18 +00:00
|
|
|
fflush(stdout);
|
2003-08-13 03:31:36 +00:00
|
|
|
switch( (rc2=do_check_sig( c, node, &is_selfsig, NULL, NULL )) ) {
|
1997-12-01 10:33:23 +00:00
|
|
|
case 0: sigrc = '!'; break;
|
2002-06-29 13:46:34 +00:00
|
|
|
case G10ERR_BAD_SIGN: sigrc = '-'; break;
|
|
|
|
case G10ERR_NO_PUBKEY:
|
|
|
|
case G10ERR_UNU_PUBKEY: sigrc = '?'; break;
|
1997-12-01 10:33:23 +00:00
|
|
|
default: sigrc = '%'; break;
|
|
|
|
}
|
|
|
|
}
|
1998-05-29 11:53:54 +00:00
|
|
|
else { /* check whether this is a self signature */
|
|
|
|
u32 keyid[2];
|
|
|
|
|
1998-06-29 12:30:57 +00:00
|
|
|
if( c->list->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|| c->list->pkt->pkttype == PKT_SECRET_KEY ) {
|
|
|
|
if( c->list->pkt->pkttype == PKT_PUBLIC_KEY )
|
|
|
|
keyid_from_pk( c->list->pkt->pkt.public_key, keyid );
|
1998-05-29 11:53:54 +00:00
|
|
|
else
|
1998-06-29 12:30:57 +00:00
|
|
|
keyid_from_sk( c->list->pkt->pkt.secret_key, keyid );
|
1998-05-29 11:53:54 +00:00
|
|
|
|
|
|
|
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
|
|
|
|
is_selfsig = 1;
|
|
|
|
}
|
|
|
|
}
|
1998-03-09 21:44:06 +00:00
|
|
|
if( opt.with_colons ) {
|
|
|
|
putchar(':');
|
|
|
|
if( sigrc != ' ' )
|
|
|
|
putchar(sigrc);
|
2003-01-27 21:49:37 +00:00
|
|
|
printf("::%d:%08lX%08lX:%s:%s:", sig->pubkey_algo,
|
|
|
|
(ulong)sig->keyid[0], (ulong)sig->keyid[1],
|
|
|
|
colon_datestr_from_sig(sig),
|
|
|
|
colon_expirestr_from_sig(sig));
|
|
|
|
|
|
|
|
if(sig->trust_depth || sig->trust_value)
|
|
|
|
printf("%d %d",sig->trust_depth,sig->trust_value);
|
|
|
|
printf(":");
|
|
|
|
|
|
|
|
if(sig->trust_regexp)
|
|
|
|
print_string(stdout,sig->trust_regexp,
|
|
|
|
strlen(sig->trust_regexp),':');
|
|
|
|
printf(":");
|
1998-03-09 21:44:06 +00:00
|
|
|
}
|
|
|
|
else
|
2004-03-18 02:56:41 +00:00
|
|
|
printf("%c %s %s ",
|
|
|
|
sigrc, keystr(sig->keyid), datestr_from_sig(sig));
|
1997-12-01 10:33:23 +00:00
|
|
|
if( sigrc == '%' )
|
2002-06-29 13:46:34 +00:00
|
|
|
printf("[%s] ", g10_errstr(rc2) );
|
1997-12-01 10:33:23 +00:00
|
|
|
else if( sigrc == '?' )
|
|
|
|
;
|
1998-05-29 11:53:54 +00:00
|
|
|
else if( is_selfsig ) {
|
|
|
|
if( opt.with_colons )
|
|
|
|
putchar(':');
|
|
|
|
fputs( sig->sig_class == 0x18? "[keybind]":"[selfsig]", stdout);
|
|
|
|
if( opt.with_colons )
|
|
|
|
putchar(':');
|
|
|
|
}
|
2000-07-14 17:34:53 +00:00
|
|
|
else if( !opt.fast_list_mode ) {
|
1997-12-01 10:33:23 +00:00
|
|
|
p = get_user_id( sig->keyid, &n );
|
1998-03-09 21:44:06 +00:00
|
|
|
print_string( stdout, p, n, opt.with_colons );
|
2002-06-29 13:46:34 +00:00
|
|
|
m_free(p);
|
1997-12-01 10:33:23 +00:00
|
|
|
}
|
1998-03-09 21:44:06 +00:00
|
|
|
if( opt.with_colons )
|
2002-06-29 13:46:34 +00:00
|
|
|
printf(":%02x%c:", sig->sig_class, sig->flags.exportable?'x':'l');
|
1997-12-01 10:33:23 +00:00
|
|
|
putchar('\n');
|
|
|
|
}
|
|
|
|
else
|
|
|
|
log_error("invalid node with packet of type %d\n", node->pkt->pkttype);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-14 17:34:53 +00:00
|
|
|
|
1997-11-26 22:02:28 +00:00
|
|
|
int
|
1999-04-26 15:53:01 +00:00
|
|
|
proc_packets( void *anchor, IOBUF a )
|
1997-11-26 22:02:28 +00:00
|
|
|
{
|
1999-04-26 15:53:01 +00:00
|
|
|
int rc;
|
2002-06-29 13:46:34 +00:00
|
|
|
CTX c = m_alloc_clear( sizeof *c );
|
1999-04-26 15:53:01 +00:00
|
|
|
|
|
|
|
c->anchor = anchor;
|
|
|
|
rc = do_proc_packets( c, a );
|
2002-06-29 13:46:34 +00:00
|
|
|
m_free( c );
|
1998-03-09 21:44:06 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2000-07-14 17:34:53 +00:00
|
|
|
|
|
|
|
|
1998-03-09 21:44:06 +00:00
|
|
|
int
|
1999-04-26 15:53:01 +00:00
|
|
|
proc_signature_packets( void *anchor, IOBUF a,
|
|
|
|
STRLIST signedfiles, const char *sigfilename )
|
1998-03-09 21:44:06 +00:00
|
|
|
{
|
2002-06-29 13:46:34 +00:00
|
|
|
CTX c = m_alloc_clear( sizeof *c );
|
1998-01-16 21:15:24 +00:00
|
|
|
int rc;
|
1999-04-26 15:53:01 +00:00
|
|
|
|
|
|
|
c->anchor = anchor;
|
1998-03-09 21:44:06 +00:00
|
|
|
c->sigs_only = 1;
|
|
|
|
c->signed_data = signedfiles;
|
1998-07-14 17:10:28 +00:00
|
|
|
c->sigfilename = sigfilename;
|
1998-03-09 21:44:06 +00:00
|
|
|
rc = do_proc_packets( c, a );
|
2002-06-29 13:46:34 +00:00
|
|
|
m_free( c );
|
1998-03-09 21:44:06 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
1999-04-26 15:53:01 +00:00
|
|
|
proc_encryption_packets( void *anchor, IOBUF a )
|
1998-03-09 21:44:06 +00:00
|
|
|
{
|
2002-06-29 13:46:34 +00:00
|
|
|
CTX c = m_alloc_clear( sizeof *c );
|
1998-03-09 21:44:06 +00:00
|
|
|
int rc;
|
1999-04-26 15:53:01 +00:00
|
|
|
|
|
|
|
c->anchor = anchor;
|
1998-03-09 21:44:06 +00:00
|
|
|
c->encrypt_only = 1;
|
|
|
|
rc = do_proc_packets( c, a );
|
2002-06-29 13:46:34 +00:00
|
|
|
m_free( c );
|
1998-03-09 21:44:06 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
do_proc_packets( CTX c, IOBUF a )
|
|
|
|
{
|
2002-06-29 13:46:34 +00:00
|
|
|
PACKET *pkt = m_alloc( sizeof *pkt );
|
1998-03-09 21:44:06 +00:00
|
|
|
int rc=0;
|
1999-05-06 12:26:10 +00:00
|
|
|
int any_data=0;
|
1997-12-01 10:33:23 +00:00
|
|
|
int newpkt;
|
1997-11-26 22:02:28 +00:00
|
|
|
|
1997-12-23 17:30:18 +00:00
|
|
|
c->iobuf = a;
|
1997-11-26 22:02:28 +00:00
|
|
|
init_packet(pkt);
|
2002-06-29 13:46:34 +00:00
|
|
|
while( (rc=parse_packet(a, pkt)) != -1 ) {
|
1999-05-06 12:26:10 +00:00
|
|
|
any_data = 1;
|
1997-11-26 22:02:28 +00:00
|
|
|
if( rc ) {
|
|
|
|
free_packet(pkt);
|
2002-10-28 13:26:44 +00:00
|
|
|
/* stop processing when an invalid packet has been encountered
|
2002-06-29 13:46:34 +00:00
|
|
|
* but don't do so when we are doing a --list-packet. */
|
|
|
|
if( rc == G10ERR_INVALID_PACKET && opt.list_packets != 2 )
|
1997-12-23 17:30:18 +00:00
|
|
|
break;
|
1997-11-26 22:02:28 +00:00
|
|
|
continue;
|
|
|
|
}
|
1997-12-01 10:33:23 +00:00
|
|
|
newpkt = -1;
|
1998-01-02 20:40:10 +00:00
|
|
|
if( opt.list_packets ) {
|
|
|
|
switch( pkt->pkttype ) {
|
|
|
|
case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break;
|
1999-02-28 18:14:18 +00:00
|
|
|
case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break;
|
1999-05-17 20:03:24 +00:00
|
|
|
case PKT_ENCRYPTED:
|
|
|
|
case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break;
|
1998-01-02 20:40:10 +00:00
|
|
|
case PKT_COMPRESSED: proc_compressed( c, pkt ); break;
|
|
|
|
default: newpkt = 0; break;
|
|
|
|
}
|
|
|
|
}
|
1998-03-09 21:44:06 +00:00
|
|
|
else if( c->sigs_only ) {
|
|
|
|
switch( pkt->pkttype ) {
|
1998-06-29 12:30:57 +00:00
|
|
|
case PKT_PUBLIC_KEY:
|
|
|
|
case PKT_SECRET_KEY:
|
1998-03-09 21:44:06 +00:00
|
|
|
case PKT_USER_ID:
|
1998-05-03 15:42:08 +00:00
|
|
|
case PKT_SYMKEY_ENC:
|
1998-03-09 21:44:06 +00:00
|
|
|
case PKT_PUBKEY_ENC:
|
|
|
|
case PKT_ENCRYPTED:
|
1999-05-17 20:03:24 +00:00
|
|
|
case PKT_ENCRYPTED_MDC:
|
2002-06-29 13:46:34 +00:00
|
|
|
write_status_text( STATUS_UNEXPECTED, "0" );
|
|
|
|
rc = G10ERR_UNEXPECTED;
|
1998-03-09 21:44:06 +00:00
|
|
|
goto leave;
|
|
|
|
case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break;
|
|
|
|
case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break;
|
|
|
|
case PKT_COMPRESSED: proc_compressed( c, pkt ); break;
|
|
|
|
case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break;
|
2002-06-29 13:46:34 +00:00
|
|
|
case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break;
|
1998-03-09 21:44:06 +00:00
|
|
|
default: newpkt = 0; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( c->encrypt_only ) {
|
|
|
|
switch( pkt->pkttype ) {
|
1998-06-29 12:30:57 +00:00
|
|
|
case PKT_PUBLIC_KEY:
|
|
|
|
case PKT_SECRET_KEY:
|
1998-03-09 21:44:06 +00:00
|
|
|
case PKT_USER_ID:
|
2002-06-29 13:46:34 +00:00
|
|
|
write_status_text( STATUS_UNEXPECTED, "0" );
|
|
|
|
rc = G10ERR_UNEXPECTED;
|
1998-03-09 21:44:06 +00:00
|
|
|
goto leave;
|
|
|
|
case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break;
|
1998-05-03 15:42:08 +00:00
|
|
|
case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break;
|
1998-03-09 21:44:06 +00:00
|
|
|
case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break;
|
1999-05-17 20:03:24 +00:00
|
|
|
case PKT_ENCRYPTED:
|
|
|
|
case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break;
|
1998-03-09 21:44:06 +00:00
|
|
|
case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break;
|
|
|
|
case PKT_COMPRESSED: proc_compressed( c, pkt ); break;
|
|
|
|
case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break;
|
2002-06-29 13:46:34 +00:00
|
|
|
case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break;
|
1998-03-09 21:44:06 +00:00
|
|
|
default: newpkt = 0; break;
|
|
|
|
}
|
|
|
|
}
|
1998-01-02 20:40:10 +00:00
|
|
|
else {
|
|
|
|
switch( pkt->pkttype ) {
|
1998-06-29 12:30:57 +00:00
|
|
|
case PKT_PUBLIC_KEY:
|
|
|
|
case PKT_SECRET_KEY:
|
1998-04-02 10:30:03 +00:00
|
|
|
release_list( c );
|
|
|
|
c->list = new_kbnode( pkt );
|
|
|
|
newpkt = 1;
|
|
|
|
break;
|
1998-06-29 12:30:57 +00:00
|
|
|
case PKT_PUBLIC_SUBKEY:
|
|
|
|
case PKT_SECRET_SUBKEY:
|
1998-04-02 10:30:03 +00:00
|
|
|
newpkt = add_subkey( c, pkt );
|
|
|
|
break;
|
1998-01-02 20:40:10 +00:00
|
|
|
case PKT_USER_ID: newpkt = add_user_id( c, pkt ); break;
|
|
|
|
case PKT_SIGNATURE: newpkt = add_signature( c, pkt ); break;
|
|
|
|
case PKT_PUBKEY_ENC: proc_pubkey_enc( c, pkt ); break;
|
1998-05-03 15:42:08 +00:00
|
|
|
case PKT_SYMKEY_ENC: proc_symkey_enc( c, pkt ); break;
|
1999-05-17 20:03:24 +00:00
|
|
|
case PKT_ENCRYPTED:
|
|
|
|
case PKT_ENCRYPTED_MDC: proc_encrypted( c, pkt ); break;
|
1998-01-02 20:40:10 +00:00
|
|
|
case PKT_PLAINTEXT: proc_plaintext( c, pkt ); break;
|
|
|
|
case PKT_COMPRESSED: proc_compressed( c, pkt ); break;
|
|
|
|
case PKT_ONEPASS_SIG: newpkt = add_onepass_sig( c, pkt ); break;
|
2002-06-29 13:46:34 +00:00
|
|
|
case PKT_GPG_CONTROL: newpkt = add_gpg_control(c, pkt); break;
|
1999-07-08 14:24:35 +00:00
|
|
|
case PKT_RING_TRUST: newpkt = add_ring_trust( c, pkt ); break;
|
1998-01-02 20:40:10 +00:00
|
|
|
default: newpkt = 0; break;
|
|
|
|
}
|
1997-12-01 10:33:23 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
/* This is a very ugly construct and frankly, I don't remember why
|
|
|
|
* I used it. Adding the MDC check here is a hack.
|
|
|
|
* The right solution is to initiate another context for encrypted
|
|
|
|
* packet and not to reuse the current one ... It works right
|
|
|
|
* when there is a compression packet inbetween which adds just
|
|
|
|
* an extra layer.
|
|
|
|
* Hmmm: Rewrite this whole module here??
|
|
|
|
*/
|
|
|
|
if( pkt->pkttype != PKT_SIGNATURE && pkt->pkttype != PKT_MDC )
|
1997-12-03 10:20:03 +00:00
|
|
|
c->have_data = pkt->pkttype == PKT_PLAINTEXT;
|
|
|
|
|
1997-12-01 10:33:23 +00:00
|
|
|
if( newpkt == -1 )
|
|
|
|
;
|
|
|
|
else if( newpkt ) {
|
2002-06-29 13:46:34 +00:00
|
|
|
pkt = m_alloc( sizeof *pkt );
|
1997-12-01 10:33:23 +00:00
|
|
|
init_packet(pkt);
|
1997-11-26 22:02:28 +00:00
|
|
|
}
|
1997-12-01 10:33:23 +00:00
|
|
|
else
|
|
|
|
free_packet(pkt);
|
2002-06-29 13:46:34 +00:00
|
|
|
if ( c->pipemode.stop_now ) {
|
|
|
|
/* we won't get an EOF in pipemode, so we have to
|
|
|
|
* break the loop here */
|
|
|
|
rc = -1;
|
|
|
|
break;
|
|
|
|
}
|
1997-11-26 22:02:28 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
if( rc == G10ERR_INVALID_PACKET )
|
1999-05-06 12:26:10 +00:00
|
|
|
write_status_text( STATUS_NODATA, "3" );
|
|
|
|
if( any_data )
|
|
|
|
rc = 0;
|
|
|
|
else if( rc == -1 )
|
|
|
|
write_status_text( STATUS_NODATA, "2" );
|
|
|
|
|
1997-11-26 22:02:28 +00:00
|
|
|
|
1998-03-09 21:44:06 +00:00
|
|
|
leave:
|
1998-02-17 20:48:52 +00:00
|
|
|
release_list( c );
|
2002-06-29 13:46:34 +00:00
|
|
|
m_free(c->dek);
|
1997-11-26 22:02:28 +00:00
|
|
|
free_packet( pkt );
|
2002-06-29 13:46:34 +00:00
|
|
|
m_free( pkt );
|
1997-11-27 11:44:13 +00:00
|
|
|
free_md_filter_context( &c->mfx );
|
1998-03-09 21:44:06 +00:00
|
|
|
return rc;
|
1997-11-26 22:02:28 +00:00
|
|
|
}
|
1997-11-18 14:06:00 +00:00
|
|
|
|
|
|
|
|
1998-01-30 16:23:16 +00:00
|
|
|
static int
|
|
|
|
check_sig_and_print( CTX c, KBNODE node )
|
|
|
|
{
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
2004-03-03 20:54:03 +00:00
|
|
|
const char *astr;
|
2003-08-13 03:31:36 +00:00
|
|
|
int rc, is_expkey=0, is_revkey=0;
|
1998-01-30 16:23:16 +00:00
|
|
|
|
1999-05-08 17:35:16 +00:00
|
|
|
if( opt.skip_verify ) {
|
1998-11-10 12:59:59 +00:00
|
|
|
log_info(_("signature verification suppressed\n"));
|
1998-04-30 14:06:01 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
/* It is not in all cases possible to check multiple signatures:
|
|
|
|
* PGP 2 (which is also allowed by OpenPGP), does use the packet
|
|
|
|
* sequence: sig+data, OpenPGP does use onepas+data=sig and GnuPG
|
|
|
|
* sometimes uses (because I did'nt read the specs right) data+sig.
|
|
|
|
* Because it is possible to create multiple signatures with
|
|
|
|
* different packet sequence (e.g. data+sig and sig+data) it might
|
|
|
|
* not be possible to get it right: let's say we have:
|
|
|
|
* data+sig, sig+data,sig+data and we have not yet encountered the last
|
|
|
|
* data, we could also see this a one data with 2 signatures and then
|
|
|
|
* data+sig.
|
|
|
|
* To protect against this we check that all signatures follow
|
|
|
|
* without any intermediate packets. Note, that we won't get this
|
|
|
|
* error when we use onepass packets or cleartext signatures because
|
|
|
|
* we reset the list every time
|
|
|
|
*
|
|
|
|
* FIXME: Now that we have these marker packets, we should create a
|
|
|
|
* real grammar and check against this.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
KBNODE n;
|
|
|
|
int n_sig=0;
|
|
|
|
|
|
|
|
for (n=c->list; n; n=n->next ) {
|
|
|
|
if ( n->pkt->pkttype == PKT_SIGNATURE )
|
|
|
|
n_sig++;
|
|
|
|
}
|
|
|
|
if (n_sig > 1) { /* more than one signature - check sequence */
|
|
|
|
int tmp, onepass;
|
|
|
|
|
|
|
|
for (tmp=onepass=0,n=c->list; n; n=n->next ) {
|
|
|
|
if (n->pkt->pkttype == PKT_ONEPASS_SIG)
|
|
|
|
onepass++;
|
|
|
|
else if (n->pkt->pkttype == PKT_GPG_CONTROL
|
|
|
|
&& n->pkt->pkt.gpg_control->control
|
|
|
|
== CTRLPKT_CLEARSIGN_START ) {
|
|
|
|
onepass++; /* handle the same way as a onepass */
|
|
|
|
}
|
|
|
|
else if ( (tmp && n->pkt->pkttype != PKT_SIGNATURE) ) {
|
|
|
|
log_error(_("can't handle these multiple signatures\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if ( n->pkt->pkttype == PKT_SIGNATURE )
|
|
|
|
tmp = 1;
|
|
|
|
else if (!tmp && !onepass
|
|
|
|
&& n->pkt->pkttype == PKT_GPG_CONTROL
|
|
|
|
&& n->pkt->pkt.gpg_control->control
|
|
|
|
== CTRLPKT_PLAINTEXT_MARK ) {
|
|
|
|
/* plaintext before signatures but no one-pass packets*/
|
|
|
|
log_error(_("can't handle these multiple signatures\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
astr = pubkey_algo_to_string( sig->pubkey_algo );
|
2004-03-03 20:54:03 +00:00
|
|
|
if(keystrlen()>8)
|
2003-07-20 02:09:06 +00:00
|
|
|
{
|
2004-03-03 20:54:03 +00:00
|
|
|
log_info(_("Signature made %s\n"),asctimestamp(sig->timestamp));
|
|
|
|
log_info(_(" using %s key %s\n"),
|
|
|
|
astr? astr: "?",keystr(sig->keyid));
|
2003-07-20 02:09:06 +00:00
|
|
|
}
|
|
|
|
else
|
2004-03-03 20:54:03 +00:00
|
|
|
log_info(_("Signature made %s using %s key ID %s\n"),
|
|
|
|
asctimestamp(sig->timestamp), astr? astr: "?",
|
|
|
|
keystr(sig->keyid));
|
1998-05-29 11:53:54 +00:00
|
|
|
|
2003-08-13 03:31:36 +00:00
|
|
|
rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey );
|
2004-04-14 21:33:45 +00:00
|
|
|
if( rc == G10ERR_NO_PUBKEY && opt.keyserver
|
2004-04-15 18:16:17 +00:00
|
|
|
&& (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE))
|
2004-04-14 17:56:23 +00:00
|
|
|
{
|
2002-06-29 13:46:34 +00:00
|
|
|
if( keyserver_import_keyid ( sig->keyid )==0 )
|
2004-04-14 17:56:23 +00:00
|
|
|
rc = do_check_sig(c, node, NULL, &is_expkey, &is_revkey );
|
|
|
|
}
|
* parse-packet.c (parse_signature): No need to reserve 8 bytes for the
unhashed signature cache any longer.
* misc.c (pct_expando): Add two new expandos - signer's fingerprint (%g),
and signer's primary fingerprint (%p).
* Makefile.am: Include W32LIBS where appropriate.
* g10.c (main): Add --rfc2440 alias for --openpgp since in a few months,
they won't be the same thing.
* keyserver.c (parse_keyserver_uri): Accept "http" as an alias for "hkp",
since it is occasionally written that way. (keyserver_spawn): Use
ascii_isspace to avoid locale issues.
* keygen.c (ask_user_id): Make --allow-freeform-uid apply to the email
field as well as the name field, and allow mixing fields when it is set.
* options.skel: Use subkeys.pgp.net as the default keyserver.
* trustdb.c (validate_one_keyblock): Certifications on revoked or expired
uids do not count in the web of trust.
* signal.c (init_one_signal, pause_on_sigusr, do_block): Only use
sigprocmask() if we have sigset_t, and only use sigaction() if we have
struct sigaction. This is for Forte c89 on Solaris which seems to define
only the function call half of the two pairs by default.
(pause_on_sigusr): Typo. (do_block): If we can't use sigprocmask() and
sigset_t, try to get the number of signals from NSIG as well as MAXSIG,
and if we can't, fail with an explanation.
* signal.c, tdbio.c: Comment out the transaction code. It was not used in
this version, and was causing some build problems on quasi-posix platforms
(Solaris and Forte c89).
* keylist.c (list_keyblock_colon): Don't include validity values when
listing secret keys since they can be incorrect and/or misleading. This
is a temporary kludge, and will be handled properly in 1.9/2.0.
* mainproc.c (check_sig_and_print): Only show the "key available from"
preferred keyserver line if the key is not currently present.
* keyedit.c (sign_uids): Do not sign expired uids without --expert (same
behavior as revoked uids). Do not allow signing a user ID without a
self-signature. --expert overrides. Add additional prompt to the
signature level question. (menu_expire): When changing expiration dates,
don't replace selfsigs on revoked uids since this would effectively
unrevoke them. There is also no point in replacing expired selfsigs.
This is bug #181
* g10.c (add_notation_data): Make sure that only ascii is passed to
iscntrl. Noted by Christian Biere.
* getkey.c (classify_user_id2): Replaced isspace by spacep
* keygen.c (ask_user_id): Ditto. (get_parameter_algo): Ditto.
* keyedit.c (keyedit_menu): Ditto.
* tdbdump.c (import_ownertrust): Ditto. s/isxdigit/hexdigitp/.
* revoke.c (ask_revocation_reason):
* keyserver.c (keyserver_spawn): Dito.
2003-07-10 14:30:07 +00:00
|
|
|
|
|
|
|
/* If the key still isn't found, try to inform the user where it
|
|
|
|
can be found. */
|
|
|
|
|
2003-08-26 03:56:47 +00:00
|
|
|
if(rc==G10ERR_NO_PUBKEY && sig->flags.pref_ks)
|
* parse-packet.c (parse_signature): No need to reserve 8 bytes for the
unhashed signature cache any longer.
* misc.c (pct_expando): Add two new expandos - signer's fingerprint (%g),
and signer's primary fingerprint (%p).
* Makefile.am: Include W32LIBS where appropriate.
* g10.c (main): Add --rfc2440 alias for --openpgp since in a few months,
they won't be the same thing.
* keyserver.c (parse_keyserver_uri): Accept "http" as an alias for "hkp",
since it is occasionally written that way. (keyserver_spawn): Use
ascii_isspace to avoid locale issues.
* keygen.c (ask_user_id): Make --allow-freeform-uid apply to the email
field as well as the name field, and allow mixing fields when it is set.
* options.skel: Use subkeys.pgp.net as the default keyserver.
* trustdb.c (validate_one_keyblock): Certifications on revoked or expired
uids do not count in the web of trust.
* signal.c (init_one_signal, pause_on_sigusr, do_block): Only use
sigprocmask() if we have sigset_t, and only use sigaction() if we have
struct sigaction. This is for Forte c89 on Solaris which seems to define
only the function call half of the two pairs by default.
(pause_on_sigusr): Typo. (do_block): If we can't use sigprocmask() and
sigset_t, try to get the number of signals from NSIG as well as MAXSIG,
and if we can't, fail with an explanation.
* signal.c, tdbio.c: Comment out the transaction code. It was not used in
this version, and was causing some build problems on quasi-posix platforms
(Solaris and Forte c89).
* keylist.c (list_keyblock_colon): Don't include validity values when
listing secret keys since they can be incorrect and/or misleading. This
is a temporary kludge, and will be handled properly in 1.9/2.0.
* mainproc.c (check_sig_and_print): Only show the "key available from"
preferred keyserver line if the key is not currently present.
* keyedit.c (sign_uids): Do not sign expired uids without --expert (same
behavior as revoked uids). Do not allow signing a user ID without a
self-signature. --expert overrides. Add additional prompt to the
signature level question. (menu_expire): When changing expiration dates,
don't replace selfsigs on revoked uids since this would effectively
unrevoke them. There is also no point in replacing expired selfsigs.
This is bug #181
* g10.c (add_notation_data): Make sure that only ascii is passed to
iscntrl. Noted by Christian Biere.
* getkey.c (classify_user_id2): Replaced isspace by spacep
* keygen.c (ask_user_id): Ditto. (get_parameter_algo): Ditto.
* keyedit.c (keyedit_menu): Ditto.
* tdbdump.c (import_ownertrust): Ditto. s/isxdigit/hexdigitp/.
* revoke.c (ask_revocation_reason):
* keyserver.c (keyserver_spawn): Dito.
2003-07-10 14:30:07 +00:00
|
|
|
{
|
|
|
|
const byte *p;
|
|
|
|
int seq=0;
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
while((p=enum_sig_subpkt(sig->hashed,SIGSUBPKT_PREF_KS,&n,&seq,NULL)))
|
|
|
|
{
|
|
|
|
/* According to my favorite copy editor, in English
|
|
|
|
grammar, you say "at" if the key is located on a web
|
|
|
|
page, but "from" if it is located on a keyserver. I'm
|
|
|
|
not going to even try to make two strings here :) */
|
|
|
|
log_info(_("Key available at: ") );
|
|
|
|
print_string( log_stream(), p, n, 0 );
|
|
|
|
putc( '\n', log_stream() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
if( !rc || rc == G10ERR_BAD_SIGN ) {
|
1999-02-19 14:54:00 +00:00
|
|
|
KBNODE un, keyblock;
|
2002-06-29 13:46:34 +00:00
|
|
|
int count=0, statno;
|
|
|
|
char keyid_str[50];
|
2003-07-20 02:09:06 +00:00
|
|
|
PKT_public_key *pk=NULL;
|
2002-06-29 13:46:34 +00:00
|
|
|
|
|
|
|
if(rc)
|
|
|
|
statno=STATUS_BADSIG;
|
|
|
|
else if(sig->flags.expired)
|
|
|
|
statno=STATUS_EXPSIG;
|
|
|
|
else if(is_expkey)
|
|
|
|
statno=STATUS_EXPKEYSIG;
|
2003-08-13 03:31:36 +00:00
|
|
|
else if(is_revkey)
|
|
|
|
statno=STATUS_REVKEYSIG;
|
2002-06-29 13:46:34 +00:00
|
|
|
else
|
|
|
|
statno=STATUS_GOODSIG;
|
1999-02-19 14:54:00 +00:00
|
|
|
|
|
|
|
keyblock = get_pubkeyblock( sig->keyid );
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
sprintf (keyid_str, "%08lX%08lX [uncertain] ",
|
|
|
|
(ulong)sig->keyid[0], (ulong)sig->keyid[1]);
|
1999-02-19 14:54:00 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
/* find and print the primary user ID */
|
1999-02-19 14:54:00 +00:00
|
|
|
for( un=keyblock; un; un = un->next ) {
|
2003-08-24 23:01:26 +00:00
|
|
|
int valid;
|
2003-07-20 02:09:06 +00:00
|
|
|
if(un->pkt->pkttype==PKT_PUBLIC_KEY)
|
|
|
|
{
|
|
|
|
pk=un->pkt->pkt.public_key;
|
|
|
|
continue;
|
|
|
|
}
|
1999-02-19 14:54:00 +00:00
|
|
|
if( un->pkt->pkttype != PKT_USER_ID )
|
|
|
|
continue;
|
2002-06-29 13:46:34 +00:00
|
|
|
if ( !un->pkt->pkt.user_id->created )
|
|
|
|
continue;
|
|
|
|
if ( un->pkt->pkt.user_id->is_revoked )
|
|
|
|
continue;
|
2002-07-02 22:13:00 +00:00
|
|
|
if ( un->pkt->pkt.user_id->is_expired )
|
2002-06-29 13:46:34 +00:00
|
|
|
continue;
|
2002-07-02 22:13:00 +00:00
|
|
|
if ( !un->pkt->pkt.user_id->is_primary )
|
|
|
|
continue;
|
2003-09-30 21:16:36 +00:00
|
|
|
/* We want the textual primary user ID here */
|
2002-07-02 22:13:00 +00:00
|
|
|
if ( un->pkt->pkt.user_id->attrib_data )
|
|
|
|
continue;
|
2003-07-20 02:09:06 +00:00
|
|
|
|
|
|
|
assert(pk);
|
|
|
|
|
2003-08-24 23:01:26 +00:00
|
|
|
/* Get it before we print anything to avoid interrupting
|
|
|
|
the output with the "please do a --check-trustdb"
|
|
|
|
line. */
|
|
|
|
valid=get_validity(pk,un->pkt->pkt.user_id);
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
keyid_str[17] = 0; /* cut off the "[uncertain]" part */
|
|
|
|
write_status_text_and_buffer (statno, keyid_str,
|
|
|
|
un->pkt->pkt.user_id->name,
|
|
|
|
un->pkt->pkt.user_id->len,
|
|
|
|
-1 );
|
|
|
|
|
|
|
|
log_info(rc? _("BAD signature from \"")
|
|
|
|
: sig->flags.expired ? _("Expired signature from \"")
|
|
|
|
: _("Good signature from \""));
|
1999-09-03 08:15:32 +00:00
|
|
|
print_utf8_string( log_stream(), un->pkt->pkt.user_id->name,
|
|
|
|
un->pkt->pkt.user_id->len );
|
2003-07-20 02:09:06 +00:00
|
|
|
if(opt.verify_options&VERIFY_SHOW_VALIDITY)
|
2003-08-24 23:01:26 +00:00
|
|
|
fprintf(log_stream(),"\" [%s]\n",trust_value_to_string(valid));
|
2003-07-20 02:09:06 +00:00
|
|
|
else
|
|
|
|
fputs("\"\n", log_stream() );
|
2002-06-29 13:46:34 +00:00
|
|
|
count++;
|
1999-02-19 14:54:00 +00:00
|
|
|
}
|
2002-07-02 22:13:00 +00:00
|
|
|
if( !count ) { /* just in case that we have no valid textual
|
|
|
|
userid */
|
|
|
|
/* Try for an invalid textual userid */
|
2002-06-29 13:46:34 +00:00
|
|
|
for( un=keyblock; un; un = un->next ) {
|
2002-07-02 22:13:00 +00:00
|
|
|
if( un->pkt->pkttype == PKT_USER_ID &&
|
|
|
|
!un->pkt->pkt.user_id->attrib_data )
|
2002-06-29 13:46:34 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2002-07-02 22:13:00 +00:00
|
|
|
/* Try for any userid at all */
|
|
|
|
if(!un) {
|
|
|
|
for( un=keyblock; un; un = un->next ) {
|
|
|
|
if( un->pkt->pkttype == PKT_USER_ID )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-03 20:18:56 +00:00
|
|
|
if (opt.trust_model==TM_ALWAYS || !un)
|
2002-06-29 13:46:34 +00:00
|
|
|
keyid_str[17] = 0; /* cut off the "[uncertain]" part */
|
|
|
|
|
|
|
|
write_status_text_and_buffer (statno, keyid_str,
|
|
|
|
un? un->pkt->pkt.user_id->name:"[?]",
|
|
|
|
un? un->pkt->pkt.user_id->len:3,
|
|
|
|
-1 );
|
|
|
|
|
|
|
|
log_info(rc? _("BAD signature from \"")
|
|
|
|
: sig->flags.expired ? _("Expired signature from \"")
|
1999-02-19 14:54:00 +00:00
|
|
|
: _("Good signature from \""));
|
2002-11-03 20:18:56 +00:00
|
|
|
if (opt.trust_model!=TM_ALWAYS && un) {
|
2002-06-29 13:46:34 +00:00
|
|
|
fputs(_("[uncertain]"), log_stream() );
|
|
|
|
putc(' ', log_stream() );
|
|
|
|
}
|
|
|
|
print_utf8_string( log_stream(),
|
|
|
|
un? un->pkt->pkt.user_id->name:"[?]",
|
|
|
|
un? un->pkt->pkt.user_id->len:3 );
|
|
|
|
fputs("\"\n", log_stream() );
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we have a good signature and already printed
|
|
|
|
* the primary user ID, print all the other user IDs */
|
|
|
|
if ( count && !rc ) {
|
|
|
|
for( un=keyblock; un; un = un->next ) {
|
|
|
|
if( un->pkt->pkttype != PKT_USER_ID )
|
|
|
|
continue;
|
2003-09-30 21:16:36 +00:00
|
|
|
if((un->pkt->pkt.user_id->is_revoked
|
|
|
|
|| un->pkt->pkt.user_id->is_expired)
|
|
|
|
&& !(opt.verify_options&VERIFY_SHOW_UNUSABLE_UIDS))
|
|
|
|
continue;
|
2002-07-02 22:13:00 +00:00
|
|
|
/* Only skip textual primaries */
|
|
|
|
if ( un->pkt->pkt.user_id->is_primary &&
|
|
|
|
!un->pkt->pkt.user_id->attrib_data )
|
|
|
|
continue;
|
2002-06-29 13:46:34 +00:00
|
|
|
|
* trustdb.h, trustdb.c (is_disabled), gpgv.c (is_disabled): Rename
is_disabled to cache_disabled_value, which now takes a pk and not just the
keyid. This is for speed since there is no need to re-fetch a key when we
already have that key handy. Cache the result of the check so we don't
need to hit the trustdb more than once.
* getkey.c (skip_disabled): New function to get a pk and call is_disabled
on it. (key_byname): Use it here.
* packet.h, getkey.c (skip_disabled), keylist.c (print_capabilities): New
"pk_is_disabled" macro to retrieve the cached disabled value if available,
and fill it in via cache_disabled_value if not available.
* trustdb.c (get_validity): Cache the disabled value since we have it
handy and it might be useful later.
* parse-packet.c (parse_key): Clear disabled flag when parsing a new key.
Just in case someone forgets to clear the whole key.
* getkey.c (merge_selfsigs_main): Add an "if all else fails" path for
setting a single user ID primary when there are multiple set primaries all
at the same second, or no primaries set and the most recent user IDs are
at the same second, or no signed user IDs at all. This is arbitrary, but
deterministic.
* exec.h, photoid.h: Add copyright message.
* keylist.c (list_keyblock_print): Don't dump attribs for
revoked/expired/etc uids for non-colon key listings. This is for
consistency with --show-photos.
* main.h, keylist.c (dump_attribs), mainproc.c (check_sig_and_print): Dump
attribs if --attrib-fd is set when verifying signatures.
* g10.c (main): New --gnupg option to disable the various --openpgp,
--pgpX, etc. options. This is the same as --no-XXXX for those options.
* revoke.c (ask_revocation_reason): Clear old reason if user elects to
repeat question. This is bug 153.
* keyedit.c (sign_uids): Show keyid of the key making the signature.
2003-05-21 16:42:22 +00:00
|
|
|
if(un->pkt->pkt.user_id->attrib_data)
|
|
|
|
{
|
|
|
|
dump_attribs(un->pkt->pkt.user_id,pk,NULL);
|
|
|
|
|
* mainproc.c (check_sig_and_print), main.h, keylist.c (show_policy,
show_notation): Collapse the old print_notation_data into show_policy()
and show_notation() so there is only one function to print notations and
policy URLs.
* options.h, main.h, g10.c (main), keyedit.c (print_and_check_one_sig),
keylist.c (list_one, list_keyblock_print), pkclist.c (do_edit_ownertrust),
sign.c (mk_notation_and_policy): New "list-options" and "verify-options"
commands. These replace the existing --show-photos/--no-show-photos,
--show-notation/--no-show-notation,
--show-policy-url/--no-show-policy-url, and --show-keyring options. The
new method is more flexible since a user can specify (for example) showing
photos during sig verification, but not in key listings. The old options
are emulated.
2003-05-31 23:23:19 +00:00
|
|
|
if(opt.verify_options&VERIFY_SHOW_PHOTOS)
|
* trustdb.h, trustdb.c (is_disabled), gpgv.c (is_disabled): Rename
is_disabled to cache_disabled_value, which now takes a pk and not just the
keyid. This is for speed since there is no need to re-fetch a key when we
already have that key handy. Cache the result of the check so we don't
need to hit the trustdb more than once.
* getkey.c (skip_disabled): New function to get a pk and call is_disabled
on it. (key_byname): Use it here.
* packet.h, getkey.c (skip_disabled), keylist.c (print_capabilities): New
"pk_is_disabled" macro to retrieve the cached disabled value if available,
and fill it in via cache_disabled_value if not available.
* trustdb.c (get_validity): Cache the disabled value since we have it
handy and it might be useful later.
* parse-packet.c (parse_key): Clear disabled flag when parsing a new key.
Just in case someone forgets to clear the whole key.
* getkey.c (merge_selfsigs_main): Add an "if all else fails" path for
setting a single user ID primary when there are multiple set primaries all
at the same second, or no primaries set and the most recent user IDs are
at the same second, or no signed user IDs at all. This is arbitrary, but
deterministic.
* exec.h, photoid.h: Add copyright message.
* keylist.c (list_keyblock_print): Don't dump attribs for
revoked/expired/etc uids for non-colon key listings. This is for
consistency with --show-photos.
* main.h, keylist.c (dump_attribs), mainproc.c (check_sig_and_print): Dump
attribs if --attrib-fd is set when verifying signatures.
* g10.c (main): New --gnupg option to disable the various --openpgp,
--pgpX, etc. options. This is the same as --no-XXXX for those options.
* revoke.c (ask_revocation_reason): Clear old reason if user elects to
repeat question. This is bug 153.
* keyedit.c (sign_uids): Show keyid of the key making the signature.
2003-05-21 16:42:22 +00:00
|
|
|
show_photos(un->pkt->pkt.user_id->attribs,
|
|
|
|
un->pkt->pkt.user_id->numattribs,pk,NULL);
|
|
|
|
}
|
2002-07-04 16:06:38 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
log_info( _(" aka \""));
|
|
|
|
print_utf8_string( log_stream(), un->pkt->pkt.user_id->name,
|
|
|
|
un->pkt->pkt.user_id->len );
|
2003-07-20 02:09:06 +00:00
|
|
|
|
|
|
|
if(opt.verify_options&VERIFY_SHOW_VALIDITY)
|
2003-09-30 21:16:36 +00:00
|
|
|
{
|
|
|
|
const char *valid;
|
|
|
|
if(un->pkt->pkt.user_id->is_revoked)
|
|
|
|
valid=_("revoked");
|
|
|
|
else if(un->pkt->pkt.user_id->is_expired)
|
|
|
|
valid=_("expired");
|
|
|
|
else
|
|
|
|
valid=trust_value_to_string(get_validity(pk,
|
|
|
|
un->pkt->
|
|
|
|
pkt.user_id));
|
|
|
|
fprintf(log_stream(),"\" [%s]\n",valid);
|
|
|
|
}
|
2003-07-20 02:09:06 +00:00
|
|
|
else
|
|
|
|
fputs("\"\n", log_stream() );
|
2002-06-29 13:46:34 +00:00
|
|
|
}
|
1999-02-19 14:54:00 +00:00
|
|
|
}
|
|
|
|
release_kbnode( keyblock );
|
2002-06-29 13:46:34 +00:00
|
|
|
|
1999-05-25 17:56:15 +00:00
|
|
|
if( !rc )
|
* mainproc.c (check_sig_and_print), main.h, keylist.c (show_policy,
show_notation): Collapse the old print_notation_data into show_policy()
and show_notation() so there is only one function to print notations and
policy URLs.
* options.h, main.h, g10.c (main), keyedit.c (print_and_check_one_sig),
keylist.c (list_one, list_keyblock_print), pkclist.c (do_edit_ownertrust),
sign.c (mk_notation_and_policy): New "list-options" and "verify-options"
commands. These replace the existing --show-photos/--no-show-photos,
--show-notation/--no-show-notation,
--show-policy-url/--no-show-policy-url, and --show-keyring options. The
new method is more flexible since a user can specify (for example) showing
photos during sig verification, but not in key listings. The old options
are emulated.
2003-05-31 23:23:19 +00:00
|
|
|
{
|
2003-11-14 05:06:19 +00:00
|
|
|
if(opt.verify_options&VERIFY_SHOW_POLICY_URLS)
|
2003-06-04 21:21:23 +00:00
|
|
|
show_policy_url(sig,0,1);
|
|
|
|
else
|
|
|
|
show_policy_url(sig,0,2);
|
|
|
|
|
2003-11-14 05:06:19 +00:00
|
|
|
if(opt.verify_options&VERIFY_SHOW_KEYSERVER_URLS)
|
2003-08-26 03:56:47 +00:00
|
|
|
show_keyserver_url(sig,0,1);
|
|
|
|
else
|
|
|
|
show_keyserver_url(sig,0,2);
|
|
|
|
|
2003-11-14 05:06:19 +00:00
|
|
|
if(opt.verify_options&VERIFY_SHOW_NOTATIONS)
|
2003-06-04 21:21:23 +00:00
|
|
|
show_notation(sig,0,1);
|
|
|
|
else
|
|
|
|
show_notation(sig,0,2);
|
* mainproc.c (check_sig_and_print), main.h, keylist.c (show_policy,
show_notation): Collapse the old print_notation_data into show_policy()
and show_notation() so there is only one function to print notations and
policy URLs.
* options.h, main.h, g10.c (main), keyedit.c (print_and_check_one_sig),
keylist.c (list_one, list_keyblock_print), pkclist.c (do_edit_ownertrust),
sign.c (mk_notation_and_policy): New "list-options" and "verify-options"
commands. These replace the existing --show-photos/--no-show-photos,
--show-notation/--no-show-notation,
--show-policy-url/--no-show-policy-url, and --show-keyring options. The
new method is more flexible since a user can specify (for example) showing
photos during sig verification, but not in key listings. The old options
are emulated.
2003-05-31 23:23:19 +00:00
|
|
|
}
|
1999-02-19 14:54:00 +00:00
|
|
|
|
1999-01-09 15:06:59 +00:00
|
|
|
if( !rc && is_status_enabled() ) {
|
|
|
|
/* print a status response with the fingerprint */
|
2003-07-20 02:09:06 +00:00
|
|
|
PKT_public_key *vpk = m_alloc_clear( sizeof *vpk );
|
1999-01-09 15:06:59 +00:00
|
|
|
|
2003-07-20 02:09:06 +00:00
|
|
|
if( !get_pubkey( vpk, sig->keyid ) ) {
|
1999-01-09 15:06:59 +00:00
|
|
|
byte array[MAX_FINGERPRINT_LEN], *p;
|
* g10.c (main): Add --no-textmode.
* export.c (do_export_stream), keyedit.c (show_key_with_all_names,
menu_addrevoker), mainproc.c (check_sig_and_print), photoid.c
(show_photos), sign.c (mk_notation_and_policy), trustdb.c (get_validity,
reset_trust_records, validate_keys): Make some strings translatable.
* mainproc.c (check_sig_and_print): Show digest algorithm and sig class
when verifying a sig with --verbose on, and add version, pk and hash
algorithms and sig class to VALIDSIG.
* parse-packet.c (enum_sig_subpkt): Make a warning message a --verbose
warning message since we don't need to warn every time we see an unknown
critical (we only need to invalidate the signature).
* trustdb.c (init_trustdb): Check the trustdb options even with TM_AUTO
since the auto may become TM_CLASSIC or TM_OPENPGP.
2003-04-27 20:22:09 +00:00
|
|
|
char buf[MAX_FINGERPRINT_LEN*4+90], *bufp;
|
1999-01-09 15:06:59 +00:00
|
|
|
size_t i, n;
|
|
|
|
|
2003-04-08 08:42:47 +00:00
|
|
|
bufp = buf;
|
2003-07-20 02:09:06 +00:00
|
|
|
fingerprint_from_pk( vpk, array, &n );
|
1999-01-09 15:06:59 +00:00
|
|
|
p = array;
|
2003-04-08 08:42:47 +00:00
|
|
|
for(i=0; i < n ; i++, p++, bufp += 2)
|
|
|
|
sprintf(bufp, "%02X", *p );
|
* g10.c (main): Add --no-textmode.
* export.c (do_export_stream), keyedit.c (show_key_with_all_names,
menu_addrevoker), mainproc.c (check_sig_and_print), photoid.c
(show_photos), sign.c (mk_notation_and_policy), trustdb.c (get_validity,
reset_trust_records, validate_keys): Make some strings translatable.
* mainproc.c (check_sig_and_print): Show digest algorithm and sig class
when verifying a sig with --verbose on, and add version, pk and hash
algorithms and sig class to VALIDSIG.
* parse-packet.c (enum_sig_subpkt): Make a warning message a --verbose
warning message since we don't need to warn every time we see an unknown
critical (we only need to invalidate the signature).
* trustdb.c (init_trustdb): Check the trustdb options even with TM_AUTO
since the auto may become TM_CLASSIC or TM_OPENPGP.
2003-04-27 20:22:09 +00:00
|
|
|
/* TODO: Replace the reserved '0' in the field below
|
|
|
|
with bits for status flags (policy url, notation,
|
|
|
|
etc.). Remember to make the buffer larger to
|
|
|
|
match! */
|
|
|
|
sprintf(bufp, " %s %lu %lu %d 0 %d %d %02X ",
|
2003-04-08 08:42:47 +00:00
|
|
|
strtimestamp( sig->timestamp ),
|
* g10.c (main): Add --no-textmode.
* export.c (do_export_stream), keyedit.c (show_key_with_all_names,
menu_addrevoker), mainproc.c (check_sig_and_print), photoid.c
(show_photos), sign.c (mk_notation_and_policy), trustdb.c (get_validity,
reset_trust_records, validate_keys): Make some strings translatable.
* mainproc.c (check_sig_and_print): Show digest algorithm and sig class
when verifying a sig with --verbose on, and add version, pk and hash
algorithms and sig class to VALIDSIG.
* parse-packet.c (enum_sig_subpkt): Make a warning message a --verbose
warning message since we don't need to warn every time we see an unknown
critical (we only need to invalidate the signature).
* trustdb.c (init_trustdb): Check the trustdb options even with TM_AUTO
since the auto may become TM_CLASSIC or TM_OPENPGP.
2003-04-27 20:22:09 +00:00
|
|
|
(ulong)sig->timestamp,(ulong)sig->expiredate,
|
|
|
|
sig->version,sig->pubkey_algo,sig->digest_algo,
|
|
|
|
sig->sig_class);
|
2003-04-08 08:42:47 +00:00
|
|
|
bufp = bufp + strlen (bufp);
|
2003-07-20 02:09:06 +00:00
|
|
|
if (!vpk->is_primary) {
|
2003-04-08 08:42:47 +00:00
|
|
|
u32 akid[2];
|
|
|
|
|
2003-07-20 02:09:06 +00:00
|
|
|
akid[0] = vpk->main_keyid[0];
|
|
|
|
akid[1] = vpk->main_keyid[1];
|
|
|
|
free_public_key (vpk);
|
|
|
|
vpk = m_alloc_clear( sizeof *vpk );
|
|
|
|
if (get_pubkey (vpk, akid)) {
|
2003-04-08 08:42:47 +00:00
|
|
|
/* impossible error, we simply return a zeroed out fpr */
|
|
|
|
n = MAX_FINGERPRINT_LEN < 20? MAX_FINGERPRINT_LEN : 20;
|
|
|
|
memset (array, 0, n);
|
|
|
|
}
|
|
|
|
else
|
2003-07-20 02:09:06 +00:00
|
|
|
fingerprint_from_pk( vpk, array, &n );
|
2003-04-08 08:42:47 +00:00
|
|
|
}
|
|
|
|
p = array;
|
|
|
|
for(i=0; i < n ; i++, p++, bufp += 2)
|
|
|
|
sprintf(bufp, "%02X", *p );
|
1999-01-09 15:06:59 +00:00
|
|
|
write_status_text( STATUS_VALIDSIG, buf );
|
|
|
|
}
|
2003-07-20 02:09:06 +00:00
|
|
|
free_public_key( vpk );
|
1999-01-09 15:06:59 +00:00
|
|
|
}
|
|
|
|
|
1998-07-09 13:37:17 +00:00
|
|
|
if( !rc )
|
|
|
|
rc = check_signatures_trust( sig );
|
2002-06-29 13:46:34 +00:00
|
|
|
|
|
|
|
if(sig->flags.expired)
|
|
|
|
{
|
* g10.c (main): Add --no-textmode.
* export.c (do_export_stream), keyedit.c (show_key_with_all_names,
menu_addrevoker), mainproc.c (check_sig_and_print), photoid.c
(show_photos), sign.c (mk_notation_and_policy), trustdb.c (get_validity,
reset_trust_records, validate_keys): Make some strings translatable.
* mainproc.c (check_sig_and_print): Show digest algorithm and sig class
when verifying a sig with --verbose on, and add version, pk and hash
algorithms and sig class to VALIDSIG.
* parse-packet.c (enum_sig_subpkt): Make a warning message a --verbose
warning message since we don't need to warn every time we see an unknown
critical (we only need to invalidate the signature).
* trustdb.c (init_trustdb): Check the trustdb options even with TM_AUTO
since the auto may become TM_CLASSIC or TM_OPENPGP.
2003-04-27 20:22:09 +00:00
|
|
|
log_info(_("Signature expired %s\n"),
|
|
|
|
asctimestamp(sig->expiredate));
|
2002-06-29 13:46:34 +00:00
|
|
|
rc=G10ERR_GENERAL; /* need a better error here? */
|
|
|
|
}
|
|
|
|
else if(sig->expiredate)
|
* g10.c (main): Add --no-textmode.
* export.c (do_export_stream), keyedit.c (show_key_with_all_names,
menu_addrevoker), mainproc.c (check_sig_and_print), photoid.c
(show_photos), sign.c (mk_notation_and_policy), trustdb.c (get_validity,
reset_trust_records, validate_keys): Make some strings translatable.
* mainproc.c (check_sig_and_print): Show digest algorithm and sig class
when verifying a sig with --verbose on, and add version, pk and hash
algorithms and sig class to VALIDSIG.
* parse-packet.c (enum_sig_subpkt): Make a warning message a --verbose
warning message since we don't need to warn every time we see an unknown
critical (we only need to invalidate the signature).
* trustdb.c (init_trustdb): Check the trustdb options even with TM_AUTO
since the auto may become TM_CLASSIC or TM_OPENPGP.
2003-04-27 20:22:09 +00:00
|
|
|
log_info(_("Signature expires %s\n"),asctimestamp(sig->expiredate));
|
|
|
|
|
|
|
|
if(opt.verbose)
|
|
|
|
log_info(_("%s signature, digest algorithm %s\n"),
|
|
|
|
sig->sig_class==0x00?_("binary"):
|
|
|
|
sig->sig_class==0x01?_("textmode"):_("unknown"),
|
|
|
|
digest_algo_to_string(sig->digest_algo));
|
2002-06-29 13:46:34 +00:00
|
|
|
|
1998-11-10 12:59:59 +00:00
|
|
|
if( rc )
|
2002-06-29 13:46:34 +00:00
|
|
|
g10_errors_seen = 1;
|
1998-03-19 15:27:29 +00:00
|
|
|
if( opt.batch && rc )
|
2002-06-29 13:46:34 +00:00
|
|
|
g10_exit(1);
|
1998-01-30 16:23:16 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-03-17 12:13:04 +00:00
|
|
|
char buf[50];
|
1999-05-22 20:54:54 +00:00
|
|
|
sprintf(buf, "%08lX%08lX %d %d %02x %lu %d",
|
1999-03-17 12:13:04 +00:00
|
|
|
(ulong)sig->keyid[0], (ulong)sig->keyid[1],
|
1999-05-22 20:54:54 +00:00
|
|
|
sig->pubkey_algo, sig->digest_algo,
|
|
|
|
sig->sig_class, (ulong)sig->timestamp, rc );
|
1999-03-17 12:13:04 +00:00
|
|
|
write_status_text( STATUS_ERRSIG, buf );
|
2002-06-29 13:46:34 +00:00
|
|
|
if( rc == G10ERR_NO_PUBKEY ) {
|
1999-07-22 18:11:55 +00:00
|
|
|
buf[16] = 0;
|
|
|
|
write_status_text( STATUS_NO_PUBKEY, buf );
|
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
if( rc != G10ERR_NOT_PROCESSED )
|
|
|
|
log_error(_("Can't check signature: %s\n"), g10_errstr(rc) );
|
1998-01-30 16:23:16 +00:00
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-12-02 19:36:53 +00:00
|
|
|
/****************
|
1997-12-23 17:30:18 +00:00
|
|
|
* Process the tree which starts at node
|
1997-12-02 19:36:53 +00:00
|
|
|
*/
|
|
|
|
static void
|
1997-12-12 12:03:58 +00:00
|
|
|
proc_tree( CTX c, KBNODE node )
|
1997-12-02 19:36:53 +00:00
|
|
|
{
|
1997-12-12 12:03:58 +00:00
|
|
|
KBNODE n1;
|
1997-12-02 19:36:53 +00:00
|
|
|
int rc;
|
|
|
|
|
2000-07-14 17:34:53 +00:00
|
|
|
if( opt.list_packets || opt.list_only )
|
1998-01-02 20:40:10 +00:00
|
|
|
return;
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
/* we must skip our special plaintext marker packets here becuase
|
|
|
|
they may be the root packet. These packets are only used in
|
|
|
|
addionla checks and skipping them here doesn't matter */
|
|
|
|
while ( node
|
|
|
|
&& node->pkt->pkttype == PKT_GPG_CONTROL
|
|
|
|
&& node->pkt->pkt.gpg_control->control
|
|
|
|
== CTRLPKT_PLAINTEXT_MARK ) {
|
|
|
|
node = node->next;
|
|
|
|
}
|
|
|
|
if (!node)
|
|
|
|
return;
|
|
|
|
|
1998-05-29 11:53:54 +00:00
|
|
|
c->trustletter = ' ';
|
1998-06-29 12:30:57 +00:00
|
|
|
if( node->pkt->pkttype == PKT_PUBLIC_KEY
|
1998-10-21 17:34:36 +00:00
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
|
|
|
|
merge_keys_and_selfsig( node );
|
1997-12-02 19:36:53 +00:00
|
|
|
list_node( c, node );
|
1998-10-21 17:34:36 +00:00
|
|
|
}
|
|
|
|
else if( node->pkt->pkttype == PKT_SECRET_KEY ) {
|
|
|
|
merge_keys_and_selfsig( node );
|
1997-12-02 19:36:53 +00:00
|
|
|
list_node( c, node );
|
1998-10-21 17:34:36 +00:00
|
|
|
}
|
1997-12-02 19:36:53 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_ONEPASS_SIG ) {
|
1998-02-11 03:25:44 +00:00
|
|
|
/* check all signatures */
|
|
|
|
if( !c->have_data ) {
|
|
|
|
free_md_filter_context( &c->mfx );
|
|
|
|
/* prepare to create all requested message digests */
|
2002-06-29 13:46:34 +00:00
|
|
|
c->mfx.md = md_open(0, 0);
|
1999-05-19 14:12:26 +00:00
|
|
|
|
1998-03-09 21:44:06 +00:00
|
|
|
/* fixme: why looking for the signature packet and not 1passpacket*/
|
1998-02-11 03:25:44 +00:00
|
|
|
for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); ) {
|
2002-06-29 13:46:34 +00:00
|
|
|
md_enable( c->mfx.md, n1->pkt->pkt.signature->digest_algo);
|
1998-02-11 03:25:44 +00:00
|
|
|
}
|
|
|
|
/* ask for file and hash it */
|
2000-07-14 17:34:53 +00:00
|
|
|
if( c->sigs_only ) {
|
1999-05-19 14:12:26 +00:00
|
|
|
rc = hash_datafiles( c->mfx.md, NULL,
|
|
|
|
c->signed_data, c->sigfilename,
|
1998-08-05 16:51:59 +00:00
|
|
|
n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 );
|
2000-07-14 17:34:53 +00:00
|
|
|
}
|
|
|
|
else {
|
1999-08-31 15:30:12 +00:00
|
|
|
rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2,
|
2002-06-29 13:46:34 +00:00
|
|
|
iobuf_get_real_fname(c->iobuf),
|
2000-07-14 17:34:53 +00:00
|
|
|
n1? (n1->pkt->pkt.onepass_sig->sig_class == 0x01):0 );
|
|
|
|
}
|
1998-02-11 03:25:44 +00:00
|
|
|
if( rc ) {
|
2002-06-29 13:46:34 +00:00
|
|
|
log_error("can't hash datafile: %s\n", g10_errstr(rc));
|
1998-02-11 03:25:44 +00:00
|
|
|
return;
|
1997-12-03 10:20:03 +00:00
|
|
|
}
|
1997-12-02 19:36:53 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
else if ( c->signed_data ) {
|
|
|
|
log_error (_("not a detached signature\n") );
|
|
|
|
return;
|
|
|
|
}
|
1998-02-11 03:25:44 +00:00
|
|
|
|
|
|
|
for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); )
|
|
|
|
check_sig_and_print( c, n1 );
|
1997-12-02 19:36:53 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_GPG_CONTROL
|
|
|
|
&& node->pkt->pkt.gpg_control->control
|
|
|
|
== CTRLPKT_CLEARSIGN_START ) {
|
|
|
|
/* clear text signed message */
|
|
|
|
if( !c->have_data ) {
|
|
|
|
log_error("cleartext signature without data\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if ( c->signed_data ) {
|
|
|
|
log_error (_("not a detached signature\n") );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( n1 = node; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )); )
|
|
|
|
check_sig_and_print( c, n1 );
|
|
|
|
}
|
1997-12-02 19:36:53 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
|
1998-01-30 16:23:16 +00:00
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
2003-05-31 04:06:06 +00:00
|
|
|
int multiple_ok=1;
|
|
|
|
|
|
|
|
n1=find_next_kbnode(node, PKT_SIGNATURE);
|
|
|
|
if(n1)
|
|
|
|
{
|
|
|
|
byte class=sig->sig_class;
|
|
|
|
byte hash=sig->digest_algo;
|
|
|
|
|
|
|
|
for(; n1; (n1 = find_next_kbnode(n1, PKT_SIGNATURE)))
|
|
|
|
{
|
|
|
|
/* We can't currently handle multiple signatures of
|
|
|
|
different classes or digests (we'd pretty much have
|
|
|
|
to run a different hash context for each), but if
|
|
|
|
they are all the same, make an exception. */
|
|
|
|
if(n1->pkt->pkt.signature->sig_class!=class
|
|
|
|
|| n1->pkt->pkt.signature->digest_algo!=hash)
|
|
|
|
{
|
|
|
|
multiple_ok=0;
|
|
|
|
log_info(_("WARNING: multiple signatures detected. "
|
|
|
|
"Only the first will be checked.\n"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-01-30 16:23:16 +00:00
|
|
|
|
2000-07-14 17:34:53 +00:00
|
|
|
if( sig->sig_class != 0x00 && sig->sig_class != 0x01 )
|
|
|
|
log_info(_("standalone signature of class 0x%02x\n"),
|
|
|
|
sig->sig_class);
|
|
|
|
else if( !c->have_data ) {
|
1999-08-31 15:30:12 +00:00
|
|
|
/* detached signature */
|
1998-02-27 17:51:28 +00:00
|
|
|
free_md_filter_context( &c->mfx );
|
2002-06-29 13:46:34 +00:00
|
|
|
c->mfx.md = md_open(sig->digest_algo, 0);
|
2000-07-14 17:34:53 +00:00
|
|
|
if( !opt.pgp2_workarounds )
|
|
|
|
;
|
2002-06-29 13:46:34 +00:00
|
|
|
else if( sig->digest_algo == DIGEST_ALGO_MD5
|
2000-07-14 17:34:53 +00:00
|
|
|
&& is_RSA( sig->pubkey_algo ) ) {
|
1999-05-19 14:12:26 +00:00
|
|
|
/* enable a workaround for a pgp2 bug */
|
2002-06-29 13:46:34 +00:00
|
|
|
c->mfx.md2 = md_open( DIGEST_ALGO_MD5, 0 );
|
1999-05-19 14:12:26 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
else if( sig->digest_algo == DIGEST_ALGO_SHA1
|
|
|
|
&& sig->pubkey_algo == PUBKEY_ALGO_DSA
|
1999-08-31 15:30:12 +00:00
|
|
|
&& sig->sig_class == 0x01 ) {
|
|
|
|
/* enable the workaround also for pgp5 when the detached
|
|
|
|
* signature has been created in textmode */
|
2002-06-29 13:46:34 +00:00
|
|
|
c->mfx.md2 = md_open( sig->digest_algo, 0 );
|
1999-08-31 15:30:12 +00:00
|
|
|
}
|
* armor.c, g10.c, kbnode.c, misc.c, pkclist.c, sign.c, build-packet.c,
getkey.c, keydb.c, openfile.c, plaintext.c, status.c, gpgv.c, keygen.c,
options.h, sig-check.c, tdbio.h, encode.c, mainproc.c, parse-packet.c,
signal.c, textfilter.c: Edit all preprocessor instructions to remove
whitespace before the '#'. This is not required by C89, but there are some
compilers out there that don't like it.
2003-05-24 21:50:33 +00:00
|
|
|
#if 0 /* workaround disabled */
|
1999-06-02 12:25:59 +00:00
|
|
|
/* Here we have another hack to work around a pgp 2 bug
|
|
|
|
* It works by not using the textmode for detached signatures;
|
1999-08-31 15:30:12 +00:00
|
|
|
* this will let the first signature check (on md) fail
|
1999-06-02 12:25:59 +00:00
|
|
|
* but the second one (on md2) which adds an extra CR should
|
|
|
|
* then produce the "correct" hash. This is very, very ugly
|
|
|
|
* hack but it may help in some cases (and break others)
|
|
|
|
*/
|
2000-07-14 17:34:53 +00:00
|
|
|
/* c->mfx.md2? 0 :(sig->sig_class == 0x01) */
|
* armor.c, g10.c, kbnode.c, misc.c, pkclist.c, sign.c, build-packet.c,
getkey.c, keydb.c, openfile.c, plaintext.c, status.c, gpgv.c, keygen.c,
options.h, sig-check.c, tdbio.h, encode.c, mainproc.c, parse-packet.c,
signal.c, textfilter.c: Edit all preprocessor instructions to remove
whitespace before the '#'. This is not required by C89, but there are some
compilers out there that don't like it.
2003-05-24 21:50:33 +00:00
|
|
|
#endif
|
2002-06-29 13:46:34 +00:00
|
|
|
if ( DBG_HASHING ) {
|
|
|
|
md_start_debug( c->mfx.md, "verify" );
|
|
|
|
if ( c->mfx.md2 )
|
|
|
|
md_start_debug( c->mfx.md2, "verify2" );
|
|
|
|
}
|
2000-07-14 17:34:53 +00:00
|
|
|
if( c->sigs_only ) {
|
1999-05-19 14:12:26 +00:00
|
|
|
rc = hash_datafiles( c->mfx.md, c->mfx.md2,
|
|
|
|
c->signed_data, c->sigfilename,
|
2000-07-14 17:34:53 +00:00
|
|
|
(sig->sig_class == 0x01) );
|
|
|
|
}
|
|
|
|
else {
|
1999-08-31 15:30:12 +00:00
|
|
|
rc = ask_for_detached_datafile( c->mfx.md, c->mfx.md2,
|
2002-06-29 13:46:34 +00:00
|
|
|
iobuf_get_real_fname(c->iobuf),
|
2000-07-14 17:34:53 +00:00
|
|
|
(sig->sig_class == 0x01) );
|
|
|
|
}
|
1998-02-27 17:51:28 +00:00
|
|
|
if( rc ) {
|
2002-06-29 13:46:34 +00:00
|
|
|
log_error("can't hash datafile: %s\n", g10_errstr(rc));
|
1998-02-27 17:51:28 +00:00
|
|
|
return;
|
1998-01-30 16:23:16 +00:00
|
|
|
}
|
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
else if ( c->signed_data ) {
|
|
|
|
log_error (_("not a detached signature\n") );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if ( c->pipemode.op == 'B' )
|
|
|
|
; /* this is a detached signature trough the pipemode handler */
|
|
|
|
else if (!opt.quiet)
|
1998-11-10 12:59:59 +00:00
|
|
|
log_info(_("old style (PGP 2.x) signature\n"));
|
1998-01-30 16:23:16 +00:00
|
|
|
|
2003-05-31 04:06:06 +00:00
|
|
|
if(multiple_ok)
|
|
|
|
for( n1 = node; n1; (n1 = find_next_kbnode(n1, PKT_SIGNATURE )) )
|
2002-06-29 13:46:34 +00:00
|
|
|
check_sig_and_print( c, n1 );
|
2003-05-31 04:06:06 +00:00
|
|
|
else
|
|
|
|
check_sig_and_print( c, node );
|
1997-12-02 19:36:53 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
else {
|
|
|
|
dump_kbnode (c->list);
|
1998-11-10 12:59:59 +00:00
|
|
|
log_error(_("invalid root packet detected in proc_tree()\n"));
|
2002-06-29 13:46:34 +00:00
|
|
|
dump_kbnode (node);
|
|
|
|
}
|
1997-12-02 19:36:53 +00:00
|
|
|
}
|