mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-17 15:44:34 +02:00
322 lines
9.4 KiB
C
322 lines
9.4 KiB
C
/* mainproc.c - handle packets
|
|
* Copyright (c) 1997 by Werner Koch (dd9jn)
|
|
*
|
|
* This file is part of G10.
|
|
*
|
|
* G10 is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* G10 is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "packet.h"
|
|
#include "iobuf.h"
|
|
#include "memory.h"
|
|
#include "options.h"
|
|
#include "util.h"
|
|
#include "cipher.h"
|
|
#include "keydb.h"
|
|
#include "filter.h"
|
|
#include "main.h"
|
|
|
|
static int opt_list=1; /* and list the data packets to stdout */
|
|
|
|
int
|
|
proc_packets( IOBUF a )
|
|
{
|
|
PACKET *pkt;
|
|
PKT_pubkey_cert *last_pubkey = NULL;
|
|
PKT_seckey_cert *last_seckey = NULL;
|
|
PKT_user_id *last_user_id = NULL;
|
|
DEK *dek = NULL;
|
|
PKT_signature *sig; /* CHECK: "might be used uninitialied" */
|
|
int rc, result;
|
|
MD_HANDLE md_handle; /* union to pass handles */
|
|
char *ustr;
|
|
int lvl0, lvl1;
|
|
int last_was_pubkey_enc = 0;
|
|
u32 keyid[2];
|
|
md_filter_context_t mfx;
|
|
|
|
memset( &mfx, 0, sizeof mfx );
|
|
lvl0 = opt.check_sigs? 1:0; /* stdout or /dev/null */
|
|
lvl1 = opt.check_sigs? 1:3; /* stdout or error */
|
|
pkt = m_alloc( sizeof *pkt );
|
|
init_packet(pkt);
|
|
while( (rc=parse_packet(a, pkt)) != -1 ) {
|
|
if( dek && pkt->pkttype != PKT_ENCR_DATA ) {
|
|
log_error("oops: valid pubkey enc packet not followed by data\n");
|
|
m_free(dek); dek = NULL; /* burn it */
|
|
}
|
|
|
|
if( rc )
|
|
free_packet(pkt);
|
|
else if( pkt->pkttype == PKT_PUBKEY_CERT ) {
|
|
if( last_user_id ) {
|
|
free_user_id( last_user_id );
|
|
last_user_id = NULL;
|
|
}
|
|
if( last_pubkey ) {
|
|
free_pubkey_cert( last_pubkey );
|
|
last_pubkey = NULL;
|
|
}
|
|
if( opt.check_sigs ) {
|
|
ustr = get_user_id_string(sig->keyid);
|
|
printstr(lvl0, "pub: %s\n", ustr );
|
|
m_free(ustr);
|
|
}
|
|
else
|
|
fputs( "pub: [Public Key Cerificate]\n", stdout );
|
|
last_pubkey = pkt->pkt.pubkey_cert;
|
|
pkt->pkt.pubkey_cert = NULL;
|
|
free_packet(pkt);
|
|
pkt->pkc_parent = last_pubkey; /* set this as parent */
|
|
}
|
|
else if( pkt->pkttype == PKT_SECKEY_CERT ) {
|
|
if( last_user_id ) {
|
|
free_user_id( last_user_id );
|
|
last_user_id = NULL;
|
|
}
|
|
if( last_seckey ) {
|
|
free_seckey_cert( last_seckey );
|
|
last_seckey = NULL;
|
|
}
|
|
if( opt_list )
|
|
fputs( "sec: (secret key certificate)\n", stdout );
|
|
rc = check_secret_key( pkt->pkt.seckey_cert );
|
|
if( opt_list ) {
|
|
if( !rc )
|
|
fputs( " Secret key is good", stdout );
|
|
else
|
|
fputs( g10_errstr(rc), stdout);
|
|
putchar('\n');
|
|
}
|
|
else if( rc )
|
|
log_error("secret key certificate error: %s\n", g10_errstr(rc));
|
|
last_seckey = pkt->pkt.seckey_cert;
|
|
pkt->pkt.seckey_cert = NULL;
|
|
free_packet(pkt);
|
|
pkt->skc_parent = last_seckey; /* set this as parent */
|
|
}
|
|
else if( pkt->pkttype == PKT_USER_ID ) {
|
|
if( last_user_id ) {
|
|
free_user_id( last_user_id );
|
|
last_user_id = NULL;
|
|
}
|
|
if( opt_list ) {
|
|
printf("uid: '%.*s'\n", pkt->pkt.user_id->len,
|
|
pkt->pkt.user_id->name );
|
|
if( !pkt->pkc_parent && !pkt->skc_parent )
|
|
puts(" (orphaned)");
|
|
}
|
|
if( pkt->pkc_parent ) {
|
|
if( pkt->pkc_parent->pubkey_algo == PUBKEY_ALGO_ELGAMAL
|
|
|| pkt->pkc_parent->pubkey_algo == PUBKEY_ALGO_RSA ) {
|
|
keyid_from_pkc( pkt->pkc_parent, keyid );
|
|
cache_user_id( pkt->pkt.user_id, keyid );
|
|
}
|
|
}
|
|
|
|
last_user_id = pkt->pkt.user_id; /* save */
|
|
pkt->pkt.user_id = NULL;
|
|
free_packet(pkt); /* fixme: free_packet is not a good name */
|
|
pkt->user_parent = last_user_id; /* and set this as user */
|
|
}
|
|
else if( pkt->pkttype == PKT_SIGNATURE ) {
|
|
sig = pkt->pkt.signature;
|
|
ustr = get_user_id_string(sig->keyid);
|
|
result = -1;
|
|
if( sig->sig_class == 0x00 ) {
|
|
if( mfx.rmd160 )
|
|
result = 0;
|
|
else
|
|
printstr(lvl1,"sig?: %s: no plaintext for signature\n",
|
|
ustr);
|
|
}
|
|
else if( sig->sig_class != 0x10 )
|
|
printstr(lvl1,"sig?: %s: unknown signature class %02x\n",
|
|
ustr, sig->sig_class);
|
|
else if( !pkt->pkc_parent || !pkt->user_parent )
|
|
printstr(lvl1,"sig?: %s: orphaned encoded packet\n", ustr);
|
|
else
|
|
result = 0;
|
|
|
|
if( result )
|
|
;
|
|
else if( !opt.check_sigs && sig->sig_class != 0x00 ) {
|
|
result = -1;
|
|
printstr(lvl0, "sig: from %s\n", ustr );
|
|
}
|
|
else if(sig->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
|
|
md_handle.algo = sig->d.elg.digest_algo;
|
|
if( sig->d.elg.digest_algo == DIGEST_ALGO_RMD160 ) {
|
|
if( sig->sig_class == 0x00 )
|
|
md_handle.u.rmd = rmd160_copy( mfx.rmd160 );
|
|
else {
|
|
md_handle.u.rmd = rmd160_copy(pkt->pkc_parent->mfx.rmd160);
|
|
rmd160_write(md_handle.u.rmd, pkt->user_parent->name,
|
|
pkt->user_parent->len);
|
|
}
|
|
result = signature_check( sig, md_handle );
|
|
rmd160_close(md_handle.u.rmd);
|
|
}
|
|
else if( sig->d.elg.digest_algo == DIGEST_ALGO_MD5
|
|
&& sig->sig_class != 0x00 ) {
|
|
md_handle.u.md5 = md5_copy(pkt->pkc_parent->mfx.md5);
|
|
md5_write(md_handle.u.md5, pkt->user_parent->name,
|
|
pkt->user_parent->len);
|
|
result = signature_check( sig, md_handle );
|
|
md5_close(md_handle.u.md5);
|
|
}
|
|
else
|
|
result = G10ERR_DIGEST_ALGO;
|
|
}
|
|
else if(sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
|
|
md_handle.algo = sig->d.rsa.digest_algo;
|
|
if( sig->d.rsa.digest_algo == DIGEST_ALGO_RMD160 ) {
|
|
if( sig->sig_class == 0x00 )
|
|
md_handle.u.rmd = rmd160_copy( mfx.rmd160 );
|
|
else {
|
|
md_handle.u.rmd = rmd160_copy(pkt->pkc_parent->mfx.rmd160);
|
|
rmd160_write(md_handle.u.rmd, pkt->user_parent->name,
|
|
pkt->user_parent->len);
|
|
}
|
|
result = signature_check( sig, md_handle );
|
|
rmd160_close(md_handle.u.rmd);
|
|
}
|
|
else if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5
|
|
&& sig->sig_class != 0x00 ) {
|
|
md_handle.u.md5 = md5_copy(pkt->pkc_parent->mfx.md5);
|
|
md5_write(md_handle.u.md5, pkt->user_parent->name,
|
|
pkt->user_parent->len);
|
|
result = signature_check( sig, md_handle );
|
|
md5_close(md_handle.u.md5);
|
|
}
|
|
else
|
|
result = G10ERR_DIGEST_ALGO;
|
|
}
|
|
else
|
|
result = G10ERR_PUBKEY_ALGO;
|
|
|
|
if( result == -1 )
|
|
;
|
|
else if( !result && sig->sig_class == 0x00 )
|
|
printstr(1, "sig: good signature from %s\n", ustr );
|
|
else if( !result )
|
|
printstr(lvl0, "sig: good signature from %s\n", ustr );
|
|
else
|
|
printstr(lvl1, "sig? %s: %s\n", ustr, g10_errstr(result));
|
|
free_packet(pkt);
|
|
m_free(ustr);
|
|
}
|
|
else if( pkt->pkttype == PKT_PUBKEY_ENC ) {
|
|
PKT_pubkey_enc *enc;
|
|
|
|
last_was_pubkey_enc = 1;
|
|
result = 0;
|
|
enc = pkt->pkt.pubkey_enc;
|
|
printf("enc: encrypted by a pubkey with keyid %08lX\n",
|
|
enc->keyid[1] );
|
|
if( enc->pubkey_algo == PUBKEY_ALGO_ELGAMAL
|
|
|| enc->pubkey_algo == PUBKEY_ALGO_RSA ) {
|
|
m_free(dek ); /* paranoid: delete a pending DEK */
|
|
dek = m_alloc_secure( sizeof *dek );
|
|
if( (result = get_session_key( enc, dek )) ) {
|
|
/* error: delete the DEK */
|
|
m_free(dek); dek = NULL;
|
|
}
|
|
}
|
|
else
|
|
result = G10ERR_PUBKEY_ALGO;
|
|
|
|
if( result == -1 )
|
|
;
|
|
else if( !result )
|
|
fputs( " DEK is good", stdout );
|
|
else
|
|
printf( " %s", g10_errstr(result));
|
|
putchar('\n');
|
|
free_packet(pkt);
|
|
}
|
|
else if( pkt->pkttype == PKT_ENCR_DATA ) {
|
|
result = 0;
|
|
printf("dat: %sencrypted data\n", dek?"":"conventional ");
|
|
if( !dek && !last_was_pubkey_enc ) {
|
|
/* assume this is conventional encrypted data */
|
|
dek = m_alloc_secure( sizeof *dek );
|
|
dek->algo = DEFAULT_CIPHER_ALGO;
|
|
result = make_dek_from_passphrase( dek, 0 );
|
|
}
|
|
else if( !dek )
|
|
result = G10ERR_NO_SECKEY;
|
|
if( !result )
|
|
result = decrypt_data( pkt->pkt.encr_data, dek );
|
|
m_free(dek); dek = NULL;
|
|
if( result == -1 )
|
|
;
|
|
else if( !result )
|
|
fputs( " encryption okay",stdout);
|
|
else
|
|
printf( " %s", g10_errstr(result));
|
|
putchar('\n');
|
|
free_packet(pkt);
|
|
last_was_pubkey_enc = 0;
|
|
}
|
|
else if( pkt->pkttype == PKT_PLAINTEXT ) {
|
|
PKT_plaintext *pt = pkt->pkt.plaintext;
|
|
printf("txt: plain text data name='%.*s'\n", pt->namelen, pt->name);
|
|
free_md_filter_context( &mfx );
|
|
mfx.rmd160 = rmd160_open(0);
|
|
result = handle_plaintext( pt, &mfx );
|
|
if( !result )
|
|
fputs( " okay",stdout);
|
|
else
|
|
printf( " %s", g10_errstr(result));
|
|
putchar('\n');
|
|
free_packet(pkt);
|
|
last_was_pubkey_enc = 0;
|
|
}
|
|
else if( pkt->pkttype == PKT_COMPR_DATA ) {
|
|
PKT_compressed *zd = pkt->pkt.compressed;
|
|
printf("zip: compressed data packet\n");
|
|
result = handle_compressed( zd );
|
|
if( !result )
|
|
fputs( " okay",stdout);
|
|
else
|
|
printf( " %s", g10_errstr(result));
|
|
putchar('\n');
|
|
free_packet(pkt);
|
|
last_was_pubkey_enc = 0;
|
|
}
|
|
else
|
|
free_packet(pkt);
|
|
}
|
|
|
|
if( last_user_id )
|
|
free_user_id( last_user_id );
|
|
if( last_seckey )
|
|
free_seckey_cert( last_seckey );
|
|
if( last_pubkey )
|
|
free_pubkey_cert( last_pubkey );
|
|
m_free(dek);
|
|
free_packet( pkt );
|
|
m_free( pkt );
|
|
free_md_filter_context( &mfx );
|
|
return 0;
|
|
}
|
|
|
|
|