summaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>1997-11-18 15:06:00 +0100
committerWerner Koch <wk@gnupg.org>1997-11-18 15:06:00 +0100
commit5393dd53c5e06f0458949217317601b2eaed8350 (patch)
treec4b8d021851c32a611165c5fc215ad88604b5a94 /g10
parentNew repository initialized by cvs2svn. (diff)
downloadgnupg2-5393dd53c5e06f0458949217317601b2eaed8350.tar.xz
gnupg2-5393dd53c5e06f0458949217317601b2eaed8350.zip
initially checkin
Diffstat (limited to 'g10')
-rw-r--r--g10/Makefile.am33
-rw-r--r--g10/Makefile.in285
-rw-r--r--g10/build-packet.c386
-rw-r--r--g10/checksig.c96
-rw-r--r--g10/compressed.c114
-rw-r--r--g10/encode.c470
-rw-r--r--g10/encr-data.c122
-rw-r--r--g10/filter.h35
-rw-r--r--g10/free-packet.c198
-rw-r--r--g10/g10.c219
-rw-r--r--g10/getkey.c475
-rw-r--r--g10/keydb.h45
-rw-r--r--g10/keygen.c253
-rw-r--r--g10/main.h35
-rw-r--r--g10/mainproc.c275
-rw-r--r--g10/mdfilter.c70
-rw-r--r--g10/options.h68
-rw-r--r--g10/overwrite.c79
-rw-r--r--g10/packet.h214
-rw-r--r--g10/parse-packet.c662
-rw-r--r--g10/passphrase.c126
-rw-r--r--g10/plaintext.c114
-rw-r--r--g10/pubkey-enc.c130
-rw-r--r--g10/seckey-cert.c157
-rw-r--r--g10/seskey.c101
-rw-r--r--g10/sig-check.c213
26 files changed, 4975 insertions, 0 deletions
diff --git a/g10/Makefile.am b/g10/Makefile.am
new file mode 100644
index 000000000..e01940b99
--- /dev/null
+++ b/g10/Makefile.am
@@ -0,0 +1,33 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir)/include
+
+bin_PROGRAMS = g10
+
+g10_SOURCES = g10.c \
+ build-packet.c \
+ compressed.c \
+ encode.c \
+ encr-data.c \
+ filter.h \
+ free-packet.c \
+ getkey.c \
+ keydb.h \
+ keygen.c \
+ main.h \
+ mainproc.c \
+ mdfilter.c \
+ options.h \
+ overwrite.c \
+ packet.h \
+ parse-packet.c \
+ passphrase.c \
+ plaintext.c \
+ pubkey-enc.c \
+ seckey-cert.c \
+ seskey.c \
+ sig-check.c
+
+
+LDADD = -L ../cipher -L ../mpi -L ../util -lcipher -lmpi -lutil
+
diff --git a/g10/Makefile.in b/g10/Makefile.in
new file mode 100644
index 000000000..d7f9ae267
--- /dev/null
+++ b/g10/Makefile.in
@@ -0,0 +1,285 @@
+# Makefile.in generated automatically by automake 1.0 from Makefile.am
+
+# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+
+SHELL = /bin/sh
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+INCLUDES = -I$(top_srcdir)/include
+
+bin_PROGRAMS = g10
+
+g10_SOURCES = g10.c \
+ build-packet.c \
+ compressed.c \
+ encode.c \
+ encr-data.c \
+ filter.h \
+ free-packet.c \
+ getkey.c \
+ keydb.h \
+ keygen.c \
+ main.h \
+ mainproc.c \
+ mdfilter.c \
+ options.h \
+ overwrite.c \
+ packet.h \
+ parse-packet.c \
+ passphrase.c \
+ plaintext.c \
+ pubkey-enc.c \
+ seckey-cert.c \
+ seskey.c \
+ sig-check.c
+
+LDADD = -L ../cipher -L ../mpi -L ../util -lcipher -lmpi -lutil
+mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
+CONFIG_HEADER = ../config.h
+PROGRAMS = $(bin_PROGRAMS)
+
+
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+LINK = $(CC) $(LDFLAGS) -o $@
+g10_OBJECTS = g10.o build-packet.o compressed.o encode.o encr-data.o \
+free-packet.o getkey.o keygen.o mainproc.o mdfilter.o overwrite.o \
+parse-packet.o passphrase.o plaintext.o pubkey-enc.o seckey-cert.o \
+seskey.o sig-check.o
+EXTRA_g10_SOURCES =
+g10_LDADD = $(LDADD)
+DIST_COMMON = Makefile.am Makefile.in
+
+
+PACKAGE = @PACKAGE@
+VERSION = @VERSION@
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFOS) $(MANS) $(EXTRA_DIST) $(DATA)
+DEP_DISTFILES = $(DIST_COMMON) $(SOURCES) $(BUILT_SOURCES) $(HEADERS) \
+ $(TEXINFOS) $(INFO_DEPS) $(MANS) $(EXTRA_DIST) $(DATA)
+
+TAR = tar
+DEP_FILES = $(srcdir)/.deps/build-packet.P $(srcdir)/.deps/compressed.P \
+$(srcdir)/.deps/encode.P $(srcdir)/.deps/encr-data.P \
+$(srcdir)/.deps/free-packet.P $(srcdir)/.deps/g10.P \
+$(srcdir)/.deps/getkey.P $(srcdir)/.deps/keygen.P \
+$(srcdir)/.deps/mainproc.P $(srcdir)/.deps/mdfilter.P \
+$(srcdir)/.deps/overwrite.P $(srcdir)/.deps/parse-packet.P \
+$(srcdir)/.deps/passphrase.P $(srcdir)/.deps/plaintext.P \
+$(srcdir)/.deps/pubkey-enc.P $(srcdir)/.deps/seckey-cert.P \
+$(srcdir)/.deps/seskey.P $(srcdir)/.deps/sig-check.P
+SOURCES = $(g10_SOURCES)
+OBJECTS = $(g10_OBJECTS)
+
+default: all
+
+
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in
+ cd $(top_srcdir) && automake $(subdir)/Makefile
+
+Makefile: $(top_builddir)/config.status Makefile.in
+ cd $(top_builddir) && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= ./config.status
+
+mostlyclean-binPROGRAMS:
+
+clean-binPROGRAMS:
+ rm -f $(bin_PROGRAMS)
+
+distclean-binPROGRAMS:
+
+maintainer-clean-binPROGRAMS:
+
+install-binPROGRAMS: $(bin_PROGRAMS)
+ $(mkinstalldirs) $(bindir)
+ list="$(bin_PROGRAMS)"; for p in $$list; do \
+ if test -f $$p; then \
+ $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`; \
+ else :; fi; \
+ done
+
+uninstall-binPROGRAMS:
+ list="$(bin_PROGRAMS)"; for p in $$list; do \
+ rm -f $(bindir)/`echo $$p|sed '$(transform)'`; \
+ done
+
+.c.o:
+ $(COMPILE) $<
+
+mostlyclean-compile:
+ rm -f *.o core
+
+clean-compile:
+
+distclean-compile:
+ rm -f *.tab.c
+
+maintainer-clean-compile:
+$(g10_OBJECTS): ../config.h
+
+g10: $(g10_OBJECTS) $(g10_DEPENDENCIES)
+ $(LINK) $(g10_OBJECTS) $(g10_LDADD) $(LIBS)
+
+ID: $(HEADERS) $(SOURCES)
+ here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
+
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
+ here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+ rm -f TAGS ID
+
+maintainer-clean-tags:
+
+subdir = g10
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+distdir: $(DEP_DISTFILES)
+ @for file in `cd $(srcdir) && echo $(DISTFILES)`; do \
+ test -f $(distdir)/$$file \
+ || ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
+ || cp -p $(srcdir)/$$file $(distdir)/$$file; \
+ done
+
+# This fragment is probably only useful for maintainers. It relies on
+# GNU make and gcc. It is only included in the generated Makefile.in
+# if `automake' is not passed the `--include-deps' flag.
+
+MKDEP = gcc -MM $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
+
+-include $(srcdir)/.deps/.P
+$(srcdir)/.deps/.P: $(BUILT_SOURCES)
+ cd $(srcdir) && test -d .deps || mkdir .deps
+ echo > $@
+
+-include $(DEP_FILES)
+$(DEP_FILES): $(srcdir)/.deps/.P
+
+$(srcdir)/.deps/%.P: $(srcdir)/%.c
+ @echo "mkdeps $< > $@"
+ @re=`echo 's,^$(srcdir)//*,,g;s, $(srcdir)//*, ,g' | sed 's,\.,\\\\.,g'`; \
+ $(MKDEP) $< | sed "$$re" > $@-tmp
+ @if test -n "$o"; then \
+ sed 's/\.o:/$$o:/' $@-tmp > $@; \
+ rm $@-tmp; \
+ else \
+ mv $@-tmp $@; \
+ fi
+
+# End of maintainer-only section
+info:
+
+dvi:
+
+check: all
+
+installcheck:
+
+install-exec: install-binPROGRAMS
+
+install-data:
+
+install: install-exec install-data all
+ @:
+
+uninstall: uninstall-binPROGRAMS
+
+all: $(PROGRAMS) Makefile
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
+installdirs:
+ $(mkinstalldirs) $(bindir)
+
+
+mostlyclean-generic:
+ test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
+
+clean-generic:
+ test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ rm -f Makefile $(DISTCLEANFILES)
+ rm -f config.cache config.log $(CONFIG_HEADER) stamp-h
+
+maintainer-clean-generic:
+ test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+ test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+mostlyclean: mostlyclean-binPROGRAMS mostlyclean-compile \
+ mostlyclean-tags mostlyclean-generic
+
+clean: clean-binPROGRAMS clean-compile clean-tags clean-generic \
+ mostlyclean
+
+distclean: distclean-binPROGRAMS distclean-compile distclean-tags \
+ distclean-generic clean
+ rm -f config.status
+
+maintainer-clean: maintainer-clean-binPROGRAMS maintainer-clean-compile \
+ maintainer-clean-tags maintainer-clean-generic \
+ distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+
+.PHONY: default mostlyclean-binPROGRAMS distclean-binPROGRAMS \
+clean-binPROGRAMS maintainer-clean-binPROGRAMS uninstall-binPROGRAMS \
+install-binPROGRAMS mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile tags mostlyclean-tags distclean-tags \
+clean-tags maintainer-clean-tags distdir info dvi check installcheck \
+install-exec install-data install uninstall all installdirs \
+mostlyclean-generic distclean-generic clean-generic \
+maintainer-clean-generic clean mostlyclean distclean maintainer-clean
+
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/g10/build-packet.c b/g10/build-packet.c
new file mode 100644
index 000000000..b6e1b6fd4
--- /dev/null
+++ b/g10/build-packet.c
@@ -0,0 +1,386 @@
+/* build-packet.c - assemble packets and write them
+ * 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 <string.h>
+#include <assert.h>
+
+#include "packet.h"
+#include "errors.h"
+#include "iobuf.h"
+#include "mpi.h"
+#include "util.h"
+#include "cipher.h"
+#include "memory.h"
+#include "options.h"
+
+
+static int do_comment( IOBUF out, int ctb, PKT_comment *rem );
+static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid );
+static int do_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pk );
+static int do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *pk );
+static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc );
+static u32 calc_plaintext( PKT_plaintext *pt );
+static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt );
+static int do_encr_data( IOBUF out, int ctb, PKT_encr_data *ed );
+
+static int calc_header_length( u32 len );
+static int write_16(IOBUF inp, u16 a);
+static int write_32(IOBUF inp, u32 a);
+static int write_header( IOBUF out, int ctb, u32 len );
+static int write_version( IOBUF out, int ctb );
+
+/****************
+ * Build a packet and write it to INP
+ * Returns: 0 := okay
+ * >0 := error
+ * Note: Caller must free the packet
+ */
+int
+build_packet( IOBUF out, PACKET *pkt )
+{
+ int rc=0, ctb;
+
+ if( DBG_PACKET )
+ log_debug("build_packet() type=%d\n", pkt->pkttype );
+ assert( pkt->pkt.generic );
+ ctb = 0x80 | ((pkt->pkttype & 15)<<2);
+ switch( pkt->pkttype ) {
+ case PKT_USER_ID:
+ rc = do_user_id( out, ctb, pkt->pkt.user_id );
+ break;
+ case PKT_COMMENT:
+ rc = do_comment( out, ctb, pkt->pkt.comment );
+ break;
+ case PKT_PUBKEY_CERT:
+ rc = do_pubkey_cert( out, ctb, pkt->pkt.pubkey_cert );
+ break;
+ case PKT_SECKEY_CERT:
+ rc = do_seckey_cert( out, ctb, pkt->pkt.seckey_cert );
+ break;
+ case PKT_PUBKEY_ENC:
+ rc = do_pubkey_enc( out, ctb, pkt->pkt.pubkey_enc );
+ break;
+ case PKT_PLAINTEXT:
+ rc = do_plaintext( out, ctb, pkt->pkt.plaintext );
+ break;
+ case PKT_ENCR_DATA:
+ rc = do_encr_data( out, ctb, pkt->pkt.encr_data );
+ break;
+ case PKT_SIGNATURE:
+ case PKT_RING_TRUST:
+ case PKT_COMPR_DATA:
+ default:
+ log_bug("invalid packet type in build_packet()");
+ break;
+ }
+
+ return rc;
+}
+
+/****************
+ * calculate the length of a packet described by PKT
+ */
+u32
+calc_packet_length( PACKET *pkt )
+{
+ u32 n=0;
+
+ assert( pkt->pkt.generic );
+ switch( pkt->pkttype ) {
+ case PKT_PLAINTEXT:
+ n = calc_plaintext( pkt->pkt.plaintext );
+ break;
+ case PKT_USER_ID:
+ case PKT_COMMENT:
+ case PKT_PUBKEY_CERT:
+ case PKT_SECKEY_CERT:
+ case PKT_PUBKEY_ENC:
+ case PKT_ENCR_DATA:
+ case PKT_SIGNATURE:
+ case PKT_RING_TRUST:
+ case PKT_COMPR_DATA:
+ default:
+ log_bug("invalid packet type in calc_packet_length()");
+ break;
+ }
+ n += calc_header_length(n);
+ return n;
+}
+
+
+static int
+do_comment( IOBUF out, int ctb, PKT_comment *rem )
+{
+ write_header(out, ctb, rem->len);
+ if( iobuf_write( out, rem->data, rem->len ) )
+ return G10ERR_WRITE_FILE;
+ return 0;
+}
+
+static int
+do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
+{
+ write_header(out, ctb, uid->len);
+ if( iobuf_write( out, uid->name, uid->len ) )
+ return G10ERR_WRITE_FILE;
+ return 0;
+}
+
+static int
+do_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pkc )
+{
+ int rc = 0;
+ IOBUF a = iobuf_temp();
+
+ write_version( a, ctb );
+ write_32(a, pkc->timestamp );
+ write_16(a, pkc->valid_days );
+ iobuf_put(a, pkc->pubkey_algo );
+ if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_encode(a, pkc->d.rsa.rsa_n );
+ mpi_encode(a, pkc->d.rsa.rsa_e );
+ }
+ else {
+ rc = G10ERR_PUBKEY_ALGO;
+ goto leave;
+ }
+
+ write_header(out, ctb, iobuf_get_temp_length(a) );
+ if( iobuf_write_temp( out, a ) )
+ rc = G10ERR_WRITE_FILE;
+
+ leave:
+ iobuf_close(a);
+ return rc;
+}
+
+static int
+do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *skc )
+{
+ int rc = 0;
+ IOBUF a = iobuf_temp();
+
+ write_version( a, ctb );
+ write_32(a, skc->timestamp );
+ write_16(a, skc->valid_days );
+ iobuf_put(a, skc->pubkey_algo );
+ if( skc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_encode(a, skc->d.rsa.rsa_n );
+ mpi_encode(a, skc->d.rsa.rsa_e );
+ iobuf_put(a, skc->d.rsa.protect_algo );
+ skc->d.rsa.calc_csum = 0;
+ if( skc->d.rsa.protect_algo ) {
+ assert( skc->d.rsa.is_protected == 1 );
+ assert( skc->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH );
+ iobuf_write(a, skc->d.rsa.protect.blowfish.iv, 8 );
+
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum );
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum );
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum );
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum );
+ }
+ else { /* Not protected: You fool you! */
+ assert( !skc->d.rsa.is_protected );
+ mpi_encode_csum(a, skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum );
+ mpi_encode_csum(a, skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum );
+ mpi_encode_csum(a, skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum );
+ mpi_encode_csum(a, skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum );
+ }
+
+ write_16(a, skc->d.rsa.calc_csum );
+ }
+ else {
+ rc = G10ERR_PUBKEY_ALGO;
+ goto leave;
+ }
+
+ write_header(out, ctb, iobuf_get_temp_length(a) );
+ if( iobuf_write_temp( out, a ) )
+ rc = G10ERR_WRITE_FILE;
+
+ leave:
+ iobuf_close(a);
+ return rc;
+}
+
+static int
+do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
+{
+ int rc = 0;
+ IOBUF a = iobuf_temp();
+
+ write_version( a, ctb );
+ write_32(a, enc->keyid[0] );
+ write_32(a, enc->keyid[1] );
+ iobuf_put(a,enc->pubkey_algo );
+ if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_encode(a, enc->d.rsa.rsa_integer );
+ }
+ else {
+ rc = G10ERR_PUBKEY_ALGO;
+ goto leave;
+ }
+
+ write_header(out, ctb, iobuf_get_temp_length(a) );
+ if( iobuf_write_temp( out, a ) )
+ rc = G10ERR_WRITE_FILE;
+
+ leave:
+ iobuf_close(a);
+ return rc;
+}
+
+
+static u32
+calc_plaintext( PKT_plaintext *pt )
+{
+ return pt->len? (1 + 1 + pt->namelen + 4 + pt->len) : 0;
+}
+
+static int
+do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
+{
+ int c, i, rc = 0;
+ u32 n;
+
+ write_header(out, ctb, calc_plaintext( pt ) );
+ iobuf_put(out, pt->mode );
+ iobuf_put(out, pt->namelen );
+ for(i=0; i < pt->namelen; i++ )
+ iobuf_put(out, pt->name[i] );
+ if( write_32(out, pt->timestamp ) )
+ rc = G10ERR_WRITE_FILE;
+
+ n = 0;
+ while( (c=iobuf_get(pt->buf)) != -1 ) {
+ if( iobuf_put(out, c) ) {
+ rc = G10ERR_WRITE_FILE;
+ break;
+ }
+ n++;
+ }
+ if( !pt->len )
+ iobuf_set_block_mode(out, 0 ); /* write end marker */
+ else if( n != pt->len )
+ log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n",
+ (ulong)n, (ulong)pt->len );
+
+ return rc;
+}
+
+
+
+static int
+do_encr_data( IOBUF out, int ctb, PKT_encr_data *ed )
+{
+ int rc = 0;
+ u32 n;
+
+ n = ed->len ? (ed->len + 10) : 0;
+ write_header(out, ctb, n );
+
+ /* This is all. The caller has to write the real data */
+
+ return rc;
+}
+
+
+
+
+static int
+write_16(IOBUF out, u16 a)
+{
+ iobuf_put(out, a>>8);
+ if( iobuf_put(out,a) )
+ return -1;
+ return 0;
+}
+
+static int
+write_32(IOBUF out, u32 a)
+{
+ iobuf_put(out, a>> 24);
+ iobuf_put(out, a>> 16);
+ iobuf_put(out, a>> 8);
+ if( iobuf_put(out, a) )
+ return -1;
+ return 0;
+}
+
+
+/****************
+ * calculate the length of a header
+ */
+static int
+calc_header_length( u32 len )
+{
+ if( !len )
+ return 1; /* only the ctb */
+ else if( len < 256 )
+ return 2;
+ else if( len < 65536 )
+ return 3;
+ else
+ return 5;
+}
+
+/****************
+ * Write the CTB and the packet length
+ */
+static int
+write_header( IOBUF out, int ctb, u32 len )
+{
+ if( !len )
+ ctb |= 3;
+ else if( len < 256 )
+ ;
+ else if( len < 65536 )
+ ctb |= 1;
+ else
+ ctb |= 2;
+ if( iobuf_put(out, ctb ) )
+ return -1;
+ if( !len ) {
+ iobuf_set_block_mode(out, 5 /*8196*/ );
+ }
+ else {
+ if( ctb & 2 ) {
+ iobuf_put(out, len >> 24 );
+ iobuf_put(out, len >> 16 );
+ }
+ if( ctb & 3 )
+ iobuf_put(out, len >> 8 );
+ if( iobuf_put(out, len ) )
+ return -1;
+ }
+ return 0;
+}
+
+static int
+write_version( IOBUF out, int ctb )
+{
+ if( iobuf_put( out, 3 ) )
+ return -1;
+ return 0;
+}
+
diff --git a/g10/checksig.c b/g10/checksig.c
new file mode 100644
index 000000000..7f00d5801
--- /dev/null
+++ b/g10/checksig.c
@@ -0,0 +1,96 @@
+/* checksig.c - check a signature
+ * 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 "util.h"
+#include "cipher.h"
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: checksig textfile sigfile\n");
+ exit(1);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ IOBUF a;
+ PACKET pkt;
+ PKT_signature *sig;
+ int rc, result, c;
+ FILE *fp;
+ MD5HANDLE md5;
+
+ if( argc != 3 )
+ usage();
+ argc--; argv++;
+
+
+ if( !(a = iobuf_open(argv[1])) )
+ log_fatal("can't open '%s'\n", argv[1]);
+
+ init_packet(&pkt);
+ while( (rc=parse_packet(a, &pkt)) != -1 ) {
+ if( !rc && pkt.pkttype == PKT_SECKEY_ENC ) {
+ sig = pkt.pkt.signature;
+ printf("sig: keyid=%08lX%08lX: ", sig->keyid[0], sig->keyid[1] );
+ if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) {
+ if( !(fp = fopen(*argv, "rb")) )
+ log_fatal("can't open '%s'\n", *argv);
+ md5 = md5_open(0);
+ while( (c=getc(fp)) != EOF )
+ md5_putchar(md5, c );
+ fclose(fp);
+ result = md5_signature_check( sig, md5 );
+ md5_close(md5);
+ }
+ else
+ result = G10ERR_DIGEST_ALGO;
+ }
+ else
+ result = G10ERR_PUBKEY_ALGO;
+
+ if( !result )
+ fputs( "signature is good", stdout );
+ else if( result == G10ERR_DIGEST_ALGO )
+ printf( "Unknown digest algorithm %d", sig->d.rsa.digest_algo);
+ else if( result == G10ERR_PUBKEY_ALGO )
+ printf( "Unknown pubkey algorithm %d", sig->pubkey_algo);
+ else
+ fputs( g10_errstr(result), stdout);
+ putchar('\n');
+ }
+ free_packet(&pkt);
+ }
+
+ iobuf_close(a);
+ return 0;
+}
+
+
diff --git a/g10/compressed.c b/g10/compressed.c
new file mode 100644
index 000000000..cc0eafcfa
--- /dev/null
+++ b/g10/compressed.c
@@ -0,0 +1,114 @@
+/* compressed.c - process an compressed packet
+ * 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 <string.h>
+#include <unistd.h>
+#include <errno.h>
+/*#include <zlib.h>*/
+#include "util.h"
+#include "memory.h"
+#include "packet.h"
+
+
+/****************
+ * Handle a compressed packet
+ */
+int
+handle_compressed( PKT_compressed *zd )
+{
+ return -1;
+ #if 0
+ int c, zrc, rc = 0;
+ z_stream *zs = NULL;
+ unsigned inbufsize = 4096;
+ unsigned outbufsize = 16384;
+ unsigned n;
+ byte *inbuf = NULL;
+ byte *outbuf = NULL;
+
+ if( zd->algorithm != 1 ) {
+ rc =G10ERR_COMPR_ALGO;
+ goto leave;
+ }
+
+ zs = m_alloc_clear( sizeof *zs );
+ if( (zrc = inflateInit( zs )) != Z_OK ) {
+ log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
+ zrc == Z_MEM_ERROR ? "out of core" :
+ zrc == Z_VERSION_ERROR ? "invalid lib version" :
+ "unknown error" );
+ }
+
+ inbuf = m_alloc( inbufsize );
+ outbuf = m_alloc( outbufsize ); /* Fixme: put it in secure space? */
+
+ zs->next_in = inbuf;
+ zs->avail_in = inbufsize;
+ zs->next_out = outbuf;
+ zs->avail_out = outbufsize;
+
+ n = 0;
+ inbuf[n++] = 0x58;
+ inbuf[n++] = 0x09;
+ for(; n < inbufsize && (c=iobuf_get(zd->buf)) != -1 ; n++ )
+ inbuf[n] = c;
+ if( n ) {
+ { int i;
+ printf("start of compressed packet (n=%u):\n", n);
+ for(i=0; i < 32 && i < n; i++ )
+ printf(" %02x", inbuf[i] );
+ putchar('\n');
+ }
+ zrc = inflate( zs, Z_PARTIAL_FLUSH );
+ switch( zrc ) {
+ case Z_OK:
+ log_info("inflate returned okay\n");
+ break;
+ case Z_STREAM_END:
+ log_info("inflate returned stream-end\n");
+ break;
+ case Z_NEED_DICT:
+ case Z_DATA_ERROR:
+ case Z_STREAM_ERROR:
+ case Z_MEM_ERROR:
+ case Z_BUF_ERROR:
+ default:
+ if( zs->msg )
+ log_error("zlib inflate problem: %s\n", zs->msg );
+ else
+ log_error("zlib inflate problem: rc=%d\n", zrc );
+ break;
+ }
+ }
+
+ leave:
+ if( zs ) {
+ inflateEnd(zs);
+ m_free(zs);
+ }
+ m_free(inbuf);
+ m_free(outbuf);
+ return rc;
+ #endif
+}
+
diff --git a/g10/encode.c b/g10/encode.c
new file mode 100644
index 000000000..5b599ef00
--- /dev/null
+++ b/g10/encode.c
@@ -0,0 +1,470 @@
+/* encode.c - encode/sign data
+ * 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 <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "options.h"
+#include "packet.h"
+#include "errors.h"
+#include "iobuf.h"
+#include "keydb.h"
+#include "memory.h"
+#include "util.h"
+#include "main.h"
+
+
+
+
+static int encode_simple( const char *filename, int mode );
+static IOBUF open_outfile( const char *iname );
+static int armor_filter( void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *ret_len);
+static int compress_filter( void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *ret_len);
+static int cipher_filter( void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *ret_len);
+
+
+
+typedef struct {
+ DEK *dek;
+ PKT_encr_data ed;
+ BLOWFISH_context *bf_ctx;
+ int header;
+} cipher_filter_context_t;
+
+
+
+
+
+
+/****************
+ * Encode FILENAME only with the symmetric cipher. Take input from
+ * stdin if FILENAME is NULL.
+ */
+int
+encode_symmetric( const char *filename )
+{
+ return encode_simple( filename, 1 );
+}
+
+/****************
+ * Encode FILENAME as literal data packet only. Take input from
+ * stdin if FILENAME is NULL.
+ */
+int
+encode_store( const char *filename )
+{
+ return encode_simple( filename, 0 );
+}
+
+static void
+write_comment( IOBUF out, const char *s )
+{
+ PACKET pkt;
+ size_t n = strlen(s);
+ int rc;
+
+ pkt.pkttype = PKT_COMMENT;
+ pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n - 1 );
+ pkt.pkt.comment->len = n;
+ strcpy(pkt.pkt.comment->data, s);
+ if( (rc = build_packet( out, &pkt )) )
+ log_error("build_packet(comment) failed: %s\n", g10_errstr(rc) );
+ free_packet( &pkt );
+}
+
+
+static int
+encode_simple( const char *filename, int mode )
+{
+ IOBUF inp, out;
+ PACKET pkt;
+ PKT_plaintext *pt;
+ int rc = 0;
+ u32 filesize;
+ cipher_filter_context_t cfx;
+
+ memset( &cfx, 0, sizeof cfx);
+
+ /* prepare iobufs */
+ if( !(inp = iobuf_open(filename)) ) {
+ log_error("can't open %s: %s\n", filename? filename: "[stdin]",
+ strerror(errno) );
+ return G10ERR_OPEN_FILE;
+ }
+
+ cfx.dek = NULL;
+ if( mode ) {
+ cfx.dek = m_alloc_secure( sizeof *cfx.dek );
+ cfx.dek->algo = DEFAULT_CIPHER_ALGO;
+ if( (rc = make_dek_from_passphrase( cfx.dek , 2 )) ) {
+ m_free(cfx.dek);
+ iobuf_close(inp);
+ log_error("error creating passphrase: %s\n", g10_errstr(rc) );
+ return rc;
+ }
+ }
+
+ if( !(out = open_outfile( filename )) ) {
+ iobuf_close(inp);
+ m_free(cfx.dek);
+ return G10ERR_CREATE_FILE; /* or user said: do not overwrite */
+ }
+
+ if( opt.armor )
+ iobuf_push_filter( out, armor_filter, NULL );
+
+ write_comment( out, "#Created by G10 pre-release " VERSION );
+
+ if( opt.compress )
+ iobuf_push_filter( out, compress_filter, NULL );
+
+
+ /* setup the inner packet */
+ if( filename ) {
+ pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
+ pt->namelen = strlen(filename);
+ memcpy(pt->name, filename, pt->namelen );
+ if( !(filesize = iobuf_get_filelength(inp)) )
+ log_info("warning: '%s' is an empty file\n", filename );
+ }
+ else { /* no filename */
+ pt = m_alloc( sizeof *pt - 1 );
+ pt->namelen = 0;
+ filesize = 0; /* stdin */
+ }
+ pt->timestamp = make_timestamp();
+ pt->mode = 'b';
+ pt->len = filesize;
+ pt->buf = inp;
+ pkt.pkttype = PKT_PLAINTEXT;
+ pkt.pkt.plaintext = pt;
+ cfx.ed.len = filesize? calc_packet_length( &pkt ) : 0;
+ cfx.ed.buf = NULL; /* not used! */
+
+ /* register the cipher filter */
+ if( mode )
+ iobuf_push_filter( out, cipher_filter, &cfx );
+
+ /* do the work */
+ if( (rc = build_packet( out, &pkt )) )
+ log_error("build_packet failed: %s\n", g10_errstr(rc) );
+
+ /* finish the stuff */
+ iobuf_close(inp);
+ iobuf_close(out); /* fixme: check returncode */
+ pt->buf = NULL;
+ free_packet(&pkt);
+ m_free(cfx.dek);
+ return rc;
+}
+
+/****************
+ * Encrypt the file with the given userids (or ask if none
+ * is supplied).
+ */
+int
+encode_crypt( const char *filename, STRLIST remusr )
+{
+ IOBUF inp, out;
+ PACKET pkt;
+ PKT_plaintext *pt;
+ PKT_pubkey_cert *pkc = NULL;
+ PKT_pubkey_enc *enc = NULL;
+ int last_rc, rc = 0;
+ u32 filesize;
+ cipher_filter_context_t cfx;
+ int any_names = 0;
+ STRLIST local_remusr = NULL;
+ char *ustr;
+
+ memset( &cfx, 0, sizeof cfx);
+
+ if( !remusr ) {
+ remusr = NULL; /* fixme: ask */
+ local_remusr = remusr;
+ }
+
+ /* prepare iobufs */
+ if( !(inp = iobuf_open(filename)) ) {
+ log_error("can't open %s: %s\n", filename? filename: "[stdin]",
+ strerror(errno) );
+ free_strlist(local_remusr);
+ return G10ERR_OPEN_FILE;
+ }
+ else if( opt.verbose )
+ log_error("reding from '%s'\n", filename? filename: "[stdin]");
+
+ if( !(out = open_outfile( filename )) ) {
+ iobuf_close(inp);
+ free_strlist(local_remusr);
+ return G10ERR_CREATE_FILE; /* or user said: do not overwrite */
+ }
+
+ if( opt.armor )
+ iobuf_push_filter( out, armor_filter, NULL );
+
+ write_comment( out, "#Created by G10 pre-release " VERSION );
+
+ if( opt.compress )
+ iobuf_push_filter( out, compress_filter, NULL );
+
+ /* create a session key */
+ cfx.dek = m_alloc_secure( sizeof *cfx.dek );
+ cfx.dek->algo = DEFAULT_CIPHER_ALGO;
+ make_session_key( cfx.dek );
+ if( DBG_CIPHER )
+ log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
+
+ /* loop over all user ids and build public key packets for each */
+ for(last_rc=0 ; remusr; remusr = remusr->next ) {
+ if( pkc )
+ free_pubkey_cert( pkc );
+ pkc = m_alloc_clear( sizeof *pkc );
+ pkc->pubkey_algo = DEFAULT_PUBKEY_ALGO;
+
+ if( (rc = get_pubkey_by_name( pkc, remusr->d )) ) {
+ last_rc = rc;
+ log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
+ continue;
+ }
+ /* build the pubkey packet */
+ enc = m_alloc_clear( sizeof *enc );
+ enc->pubkey_algo = pkc->pubkey_algo;
+ if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ RSA_public_key pkey;
+
+ mpi_get_keyid( pkc->d.rsa.rsa_n, enc->keyid );
+ enc->d.rsa.rsa_integer = encode_session_key( cfx.dek,
+ mpi_get_nbits(pkc->d.rsa.rsa_n) );
+ pkey.n = pkc->d.rsa.rsa_n;
+ pkey.e = pkc->d.rsa.rsa_e;
+ if( DBG_CIPHER )
+ log_mpidump("Plain DEK frame: ", enc->d.rsa.rsa_integer);
+ rsa_public( enc->d.rsa.rsa_integer, enc->d.rsa.rsa_integer, &pkey);
+ if( DBG_CIPHER )
+ log_mpidump("Encry DEK frame: ", enc->d.rsa.rsa_integer);
+ if( opt.verbose ) {
+ ustr = get_user_id_string( enc->keyid );
+ log_info("RSA enciphered for: %s\n", ustr );
+ m_free(ustr);
+ }
+ }
+ else {
+ last_rc = rc = G10ERR_PUBKEY_ALGO;
+ log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
+ free_pubkey_enc(enc);
+ continue;
+ }
+ /* and write it */
+ init_packet(&pkt);
+ pkt.pkttype = PKT_PUBKEY_ENC;
+ pkt.pkt.pubkey_enc = enc;
+ if( (rc = build_packet( out, &pkt )) ) {
+ last_rc = rc;
+ log_error("build pubkey_enc packet failed: %s\n", g10_errstr(rc) );
+ free_pubkey_enc(enc);
+ continue;
+ }
+ /* okay: a pubkey packet has been written */
+ free_pubkey_enc(enc);
+ any_names = 1;
+ }
+ if( pkc ) {
+ free_pubkey_cert( pkc );
+ pkc = NULL;
+ }
+ if( !any_names ) {
+ log_error("no valid keys - aborting further processing\n");
+ iobuf_close(inp);
+ iobuf_cancel(out);
+ m_free(cfx.dek); /* free and burn the session key */
+ free_strlist(local_remusr);
+ return last_rc;
+ }
+
+ /* setup the inner packet */
+ if( filename ) {
+ pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
+ pt->namelen = strlen(filename);
+ memcpy(pt->name, filename, pt->namelen );
+ if( !(filesize = iobuf_get_filelength(inp)) )
+ log_info("warning: '%s' is an empty file\n", filename );
+ }
+ else { /* no filename */
+ pt = m_alloc( sizeof *pt - 1 );
+ pt->namelen = 0;
+ filesize = 0; /* stdin */
+ }
+ pt->timestamp = make_timestamp();
+ pt->mode = 'b';
+ pt->len = filesize;
+ pt->buf = inp;
+ init_packet(&pkt);
+ pkt.pkttype = PKT_PLAINTEXT;
+ pkt.pkt.plaintext = pt;
+ cfx.ed.len = filesize? calc_packet_length( &pkt ) : 0;
+ cfx.ed.buf = NULL; /* not used! */
+
+ /* register the cipher filter */
+ iobuf_push_filter( out, cipher_filter, &cfx );
+
+ /* do the work */
+ if( (rc = build_packet( out, &pkt )) )
+ log_error("build_packet failed: %s\n", g10_errstr(rc) );
+
+ /* finish the stuff */
+ iobuf_close(inp);
+ iobuf_close(out); /* fixme: check returncode */
+ pt->buf = NULL;
+ free_packet(&pkt);
+ m_free(cfx.dek);
+ free_strlist(local_remusr);
+ return rc;
+}
+
+
+/****************
+ * Make an output filename for the inputfile INAME.
+ * Returns an
+ */
+static IOBUF
+open_outfile( const char *iname )
+{
+ IOBUF a = NULL;
+ int rc;
+
+ if( (!iname && !opt.outfile) || opt.outfile_is_stdout ) {
+ if( !(a = iobuf_create(NULL)) )
+ log_error("can't open [stdout]: %s\n", strerror(errno) );
+ else if( opt.verbose )
+ log_info("writing to stdout\n");
+ }
+ else {
+ char *buf=NULL;
+ const char *name;
+
+ if( opt.outfile )
+ name = opt.outfile;
+ else {
+ buf = m_alloc(strlen(iname)+4+1);
+ strcpy(stpcpy(buf,iname), ".g10");
+ name = buf;
+ }
+ if( !(rc=overwrite_filep( name )) ) {
+ if( !(a = iobuf_create( name )) )
+ log_error("can't create %s: %s\n", name, strerror(errno) );
+ else if( opt.verbose )
+ log_info("writing to '%s'\n", name );
+ }
+ else if( rc != -1 )
+ log_error("oops: overwrite_filep(%s): %s\n", name, g10_errstr(rc) );
+ m_free(buf);
+ }
+ return a;
+}
+
+static int
+armor_filter( void *opaque, int control,
+ IOBUF chain, byte *buf, size_t *ret_len)
+{
+ if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "armor_filter";
+ }
+ return 0;
+}
+
+static int
+compress_filter( void *opaque, int control,
+ IOBUF a, byte *buf, size_t *ret_len)
+{
+ size_t size = *ret_len;
+ int rc=0;
+
+ if( control == IOBUFCTRL_FLUSH ) {
+ assert(a);
+ if( iobuf_write( a, buf, size ) )
+ rc = G10ERR_WRITE_FILE;
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "compress_filter";
+ }
+ return rc;
+}
+
+
+/****************
+ * The filter is used to encipher data.
+ */
+static int
+cipher_filter( void *opaque, int control,
+ IOBUF a, byte *buf, size_t *ret_len)
+{
+ size_t size = *ret_len;
+ cipher_filter_context_t *cfx = opaque;
+ int rc=0;
+
+ if( control == IOBUFCTRL_FLUSH ) {
+ assert(a);
+ if( !cfx->header ) {
+ PACKET pkt;
+ byte temp[10];
+
+ pkt.pkttype = PKT_ENCR_DATA;
+ pkt.pkt.encr_data = &cfx->ed;
+ if( build_packet( a, &pkt ))
+ log_bug("build_packet(ENCR_DATA) failed\n");
+ randomize_buffer( temp, 8, 1 );
+ temp[8] = temp[6];
+ temp[9] = temp[7];
+ if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH ) {
+ cfx->bf_ctx = m_alloc_secure( sizeof *cfx->bf_ctx );
+ blowfish_setkey( cfx->bf_ctx, cfx->dek->key, cfx->dek->keylen );
+ blowfish_setiv( cfx->bf_ctx, NULL );
+ blowfish_encode_cfb( cfx->bf_ctx, temp, temp, 10);
+ }
+ else
+ log_bug("no cipher algo %d\n", cfx->dek->algo);
+
+ iobuf_write(a, temp, 10);
+ cfx->header=1;
+ }
+
+ if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH )
+ blowfish_encode_cfb( cfx->bf_ctx, buf, buf, size);
+ if( iobuf_write( a, buf, size ) )
+ rc = G10ERR_WRITE_FILE;
+ }
+ else if( control == IOBUFCTRL_FREE ) {
+ if( cfx->dek->algo == CIPHER_ALGO_BLOWFISH )
+ m_free(cfx->bf_ctx);
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "cipher_filter";
+ }
+ return rc;
+}
+
diff --git a/g10/encr-data.c b/g10/encr-data.c
new file mode 100644
index 000000000..5c047e90d
--- /dev/null
+++ b/g10/encr-data.c
@@ -0,0 +1,122 @@
+/* encr-data.c - process an encrypted data packet
+ * 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 <string.h>
+#include <assert.h>
+#include "util.h"
+#include "memory.h"
+#include "packet.h"
+#include "mpi.h"
+#include "cipher.h"
+
+
+static int decode_filter( void *opaque, int control, IOBUF a,
+ byte *buf, size_t *ret_len);
+
+typedef struct {
+ BLOWFISH_context *bf_ctx;
+} decode_filter_ctx_t;
+
+
+
+/****************
+ * Decrypt the data, specified by ED with the key DEK.
+ */
+int
+decrypt_data( PKT_encr_data *ed, DEK *dek )
+{
+ decode_filter_ctx_t dfx;
+ byte *p;
+ int c, i;
+ byte temp[16];
+
+
+ if( dek->algo != CIPHER_ALGO_BLOWFISH )
+ return G10ERR_CIPHER_ALGO;
+ if( ed->len && ed->len < 10 )
+ log_bug("Nanu\n"); /* oops: found a bug */
+
+ dfx.bf_ctx = m_alloc_secure( sizeof *dfx.bf_ctx );
+ blowfish_setkey( dfx.bf_ctx, dek->key, dek->keylen );
+ blowfish_setiv( dfx.bf_ctx, NULL );
+
+ if( ed->len ) {
+ iobuf_set_limit( ed->buf, ed->len );
+
+ for(i=0; i < 10 && ed->len; i++, ed->len-- )
+ temp[i] = iobuf_get(ed->buf);
+ }
+ else {
+ for(i=0; i < 10; i++ )
+ if( (c=iobuf_get(ed->buf)) == -1 )
+ break;
+ else
+ temp[i] = c;
+ }
+ blowfish_decode_cfb( dfx.bf_ctx, temp, temp, 10);
+ p = temp;
+ if( p[6] != p[8] || p[7] != p[9] ) {
+ m_free(dfx.bf_ctx);
+ return G10ERR_BAD_KEY;
+ }
+ iobuf_push_filter( ed->buf, decode_filter, &dfx );
+ proc_packets(ed->buf);
+ iobuf_pop_filter( ed->buf, decode_filter, &dfx );
+ if( ed->len )
+ iobuf_set_limit( ed->buf, 0 ); /* disable the readlimit */
+ else
+ iobuf_clear_eof( ed->buf );
+ ed->buf = NULL;
+ m_free(dfx.bf_ctx);
+ return 0;
+}
+
+static int
+decode_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len)
+{
+ decode_filter_ctx_t *fc = opaque;
+ size_t n, size = *ret_len;
+ int rc = 0;
+ int c;
+
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ assert(a);
+ for(n=0; n < size; n++ ) {
+ if( (c = iobuf_get(a)) == -1 )
+ break;
+ buf[n] = c;
+ }
+
+ if( n )
+ blowfish_decode_cfb( fc->bf_ctx, buf, buf, n);
+ else
+ rc = -1; /* eof */
+ *ret_len = n;
+ }
+ else if( control == IOBUFCTRL_DESC ) {
+ *(char**)buf = "decode_filter";
+ }
+ return rc;
+}
+
+
diff --git a/g10/filter.h b/g10/filter.h
new file mode 100644
index 000000000..8cbb26af7
--- /dev/null
+++ b/g10/filter.h
@@ -0,0 +1,35 @@
+/* filter.h
+ * 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
+ */
+#ifndef G10_FILTER_H
+#define G10_FILTER_H
+
+#include "cipher.h"
+
+typedef struct {
+ MD5HANDLE md5; /* if !NULL create md5 */
+ RMDHANDLE rmd160; /* if !NULL create rmd160 */
+ size_t maxbuf_size;
+} md_filter_context_t;
+
+
+/*-- mdfilter.c --*/
+int md_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len);
+
+#endif /*G10_FILTER_H*/
diff --git a/g10/free-packet.c b/g10/free-packet.c
new file mode 100644
index 000000000..f4f38baa4
--- /dev/null
+++ b/g10/free-packet.c
@@ -0,0 +1,198 @@
+/* free-packet.c - cleanup stuff for 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 <string.h>
+#include <assert.h>
+
+#include "packet.h"
+#include "iobuf.h"
+#include "mpi.h"
+#include "util.h"
+#include "cipher.h"
+#include "memory.h"
+
+
+void
+free_pubkey_enc( PKT_pubkey_enc *enc )
+{
+ mpi_free( enc->d.rsa.rsa_integer );
+ m_free(enc);
+}
+
+void
+free_seckey_enc( PKT_signature *enc )
+{
+ mpi_free( enc->d.rsa.rsa_integer );
+ m_free(enc);
+}
+
+void
+free_pubkey_cert( PKT_pubkey_cert *cert )
+{
+ mpi_free( cert->d.rsa.rsa_n );
+ mpi_free( cert->d.rsa.rsa_e );
+ md5_close( cert->mfx.md5 );
+ rmd160_close( cert->mfx.rmd160 );
+ m_free(cert);
+}
+
+PKT_pubkey_cert *
+copy_pubkey_cert( PKT_pubkey_cert *d, PKT_pubkey_cert *s )
+{
+ if( !d )
+ d = m_alloc(sizeof *d);
+ memcpy( d, s, sizeof *d );
+ d->d.rsa.rsa_n = mpi_copy( s->d.rsa.rsa_n );
+ d->d.rsa.rsa_e = mpi_copy( s->d.rsa.rsa_e );
+ d->mfx.md5 = NULL;
+ d->mfx.rmd160 =NULL;
+ return d;
+}
+
+void
+free_seckey_cert( PKT_seckey_cert *cert )
+{
+ mpi_free( cert->d.rsa.rsa_n );
+ mpi_free( cert->d.rsa.rsa_e );
+ if( cert->d.rsa.is_protected ) {
+ m_free( cert->d.rsa.rsa_d );
+ m_free( cert->d.rsa.rsa_p );
+ m_free( cert->d.rsa.rsa_q );
+ m_free( cert->d.rsa.rsa_u );
+ }
+ else {
+ mpi_free( cert->d.rsa.rsa_d );
+ mpi_free( cert->d.rsa.rsa_p );
+ mpi_free( cert->d.rsa.rsa_q );
+ mpi_free( cert->d.rsa.rsa_u );
+ }
+ m_free(cert);
+}
+
+void
+free_comment( PKT_comment *rem )
+{
+ m_free(rem);
+}
+
+void
+free_user_id( PKT_user_id *uid )
+{
+ m_free(uid);
+}
+
+void
+free_compressed( PKT_compressed *zd )
+{
+ if( zd->buf ) { /* have to skip some bytes */
+ /* don't have any informations about the length, so
+ * we assume this is the last packet */
+ while( iobuf_get(zd->buf) != -1 )
+ ;
+ }
+ m_free(zd);
+}
+
+void
+free_encr_data( PKT_encr_data *ed )
+{
+ if( ed->buf ) { /* have to skip some bytes */
+ if( iobuf_in_block_mode(ed->buf) ) {
+ while( iobuf_get(ed->buf) != -1 )
+ ;
+ iobuf_set_block_mode(ed->buf, 0);
+ }
+ else {
+ for( ; ed->len; ed->len-- ) /* skip the packet */
+ iobuf_get(ed->buf);
+ }
+ }
+ m_free(ed);
+}
+
+
+void
+free_plaintext( PKT_plaintext *pt )
+{
+ if( pt->buf ) { /* have to skip some bytes */
+ if( iobuf_in_block_mode(pt->buf) ) {
+ while( iobuf_get(pt->buf) != -1 )
+ ;
+ iobuf_set_block_mode(pt->buf, 0);
+ }
+ else {
+ for( ; pt->len; pt->len-- ) /* skip the packet */
+ iobuf_get(pt->buf);
+ }
+ }
+ m_free(pt);
+}
+
+/****************
+ * Free the packet in pkt.
+ */
+void
+free_packet( PACKET *pkt )
+{
+ if( !pkt || !pkt->pkt.generic )
+ return;
+
+ if( DBG_MEMORY )
+ log_debug("free_packet() type=%d\n", pkt->pkttype );
+
+ switch( pkt->pkttype ) {
+ case PKT_SIGNATURE:
+ free_seckey_enc( pkt->pkt.signature );
+ break;
+ case PKT_PUBKEY_ENC:
+ free_pubkey_enc( pkt->pkt.pubkey_enc );
+ break;
+ case PKT_PUBKEY_CERT:
+ free_pubkey_cert( pkt->pkt.pubkey_cert );
+ break;
+ case PKT_SECKEY_CERT:
+ free_seckey_cert( pkt->pkt.seckey_cert );
+ break;
+ case PKT_COMMENT:
+ free_comment( pkt->pkt.comment );
+ break;
+ case PKT_USER_ID:
+ free_user_id( pkt->pkt.user_id );
+ break;
+ case PKT_COMPR_DATA:
+ free_compressed( pkt->pkt.compressed);
+ break;
+ case PKT_ENCR_DATA:
+ free_encr_data( pkt->pkt.encr_data );
+ break;
+ case PKT_PLAINTEXT:
+ free_plaintext( pkt->pkt.plaintext );
+ break;
+ default:
+ m_free( pkt->pkt.generic );
+ break;
+ }
+ pkt->pkt.generic = NULL;
+}
+
+
diff --git a/g10/g10.c b/g10/g10.c
new file mode 100644
index 000000000..1cf1d769a
--- /dev/null
+++ b/g10/g10.c
@@ -0,0 +1,219 @@
+/* g10.c - The G10 re-install utility
+ * 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 "util.h"
+#include "main.h"
+#include "options.h"
+#include "keydb.h"
+#include "mpi.h"
+#include "cipher.h"
+
+
+const char *
+strusage( int level )
+{
+ const char *p;
+ switch( level ) {
+ case 10:
+ case 0: p = "g10 - v" VERSION "; "
+ "Copyright 1997 Werner Koch (dd9jn)" ; break;
+ case 13: p = "g10"; break;
+ case 14: p = VERSION; break;
+ case 1:
+ case 11: p = "Usage: g10 [options] [files] (-h for help)";
+ break;
+ case 2:
+ case 12: p =
+ "\nSyntax: g10 [options] [files]\n"
+ "sign, check, encrypt or decrypt\n"
+ "default operation depends on the input data\n";
+ break;
+ default: p = default_strusage(level);
+ }
+ return p;
+}
+
+static void
+set_debug(void)
+{
+ if( opt.debug & DBG_MEMORY_VALUE )
+ memory_debug_mode = 1;
+ if( opt.debug & DBG_MEMSTAT_VALUE )
+ memory_stat_debug_mode = 1;
+ if( opt.debug & DBG_MPI_VALUE )
+ mpi_debug_mode = 1;
+ if( opt.debug & DBG_CIPHER_VALUE )
+ cipher_debug_mode = 1;
+}
+
+
+int
+main( int argc, char **argv )
+{
+ static ARGPARSE_OPTS opts[] = {
+ { 'a', "armor", 0, "create ascii armored output"},
+ { 'v', "verbose", 0, "verbose" },
+ { 'z', NULL, 1, "set compress level (0 disables)" },
+ { 'b', "batch", 0, "batch mode: never ask" },
+ { 'n', "dry-run", 0, "don't make any changes" },
+ { 'c', "symmetric", 0, "do only a symmetric encryption" },
+ { 'o', "output", 2, "use as output file" },
+ { 501, "yes", 0, "assume yes on most questions"},
+ { 502, "no", 0, "assume no on most questions"},
+ { 503, "make-key", 0, "generate a new key pair" },
+ { 504, "add-key", 0, "add key to the public keyring" },
+ { 505, "delete-key",0, "remove key from public keyring" },
+ { 506, "sign-key" ,0, "make a signature on a key in the keyring" },
+ { 507, "store", 0, "store only" },
+ { 508, "check-key" ,0, "check signatures on a key in the keyring" },
+ { 509, "keyring" ,2, "add this keyring to the list of keyrings" },
+ { 's', "sign", 0, "make a signature"},
+ { 'e', "encrypt", 0, "encrypt data" },
+ { 'd', "decrypt", 0, "decrypt data (default)" },
+ { 'c', "check", 0, "check a signature (default)" },
+ { 'l', "local-user",2, "use this user-id to sign or decrypt" },
+ { 'r', "remote-user", 2, "use this user-id for encryption" },
+ { 510, "debug" ,4|16, "set debugging flags" },
+ { 511, "debug-all" ,0, "enable full debugging"},
+ { 512, "cache-all" ,0, "hold everything in memory"},
+ { 513, "gen-prime" , 1, "generate a prime of length n" },
+ { 514, "gen-key" , 0, "generate a key pair" },
+ {0} };
+ ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
+ IOBUF a;
+ int rc;
+ enum { aNull, aSym, aStore, aEncr, aPrimegen, aKeygen,
+ } action = aNull;
+ const char *fname, *fname_print;
+ STRLIST sl, remusr= NULL;
+ int nrings=0;
+
+ opt.compress = -1; /* defaults to default compression level */
+ while( arg_parse( &pargs, opts) ) {
+ switch( pargs.r_opt ) {
+ case 'v': opt.verbose++; break;
+ case 'z':
+ opt.compress = pargs.r.ret_int;
+ break;
+ case 'a': opt.armor = 1; break;
+ case 'c': action = aSym; break;
+ case 'e': action = aEncr; break;
+ case 'o': opt.outfile = pargs.r.ret_str;
+ if( opt.outfile[0] == '-' && !opt.outfile[1] )
+ opt.outfile_is_stdout = 1;
+ break;
+ case 'b': opt.batch = 1; break;
+ case 501: opt.answer_yes = 1; break;
+ case 502: opt.answer_no = 1; break;
+ case 507: action = aStore; break;
+ case 508: opt.check_sigs = 1; break;
+ case 509: add_keyring(pargs.r.ret_str); nrings++; break;
+ case 510: opt.debug |= pargs.r.ret_ulong; break;
+ case 511: opt.debug = ~0; break;
+ case 512: opt.cache_all = 1; break;
+ case 'r': /* store the remote users */
+ sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str));
+ strcpy(sl->d, pargs.r.ret_str);
+ sl->next = remusr;
+ remusr = sl;
+ break;
+ case 513: action = aPrimegen; break;
+ case 514: action = aKeygen; break;
+ default : pargs.err = 2; break;
+ }
+ }
+ set_debug();
+ if( opt.verbose > 1 )
+ set_packet_list_mode(1);
+
+ if( !nrings ) { /* add default rings */
+ add_keyring("../keys/ring.pgp");
+ add_keyring("../keys/pubring.g10");
+ }
+
+ if( argc ) {
+ fname_print = fname = *argv;
+ }
+ else {
+ fname_print = "[stdin]";
+ fname = NULL;
+ }
+
+ switch( action ) {
+ case aStore: /* only store the file */
+ if( argc > 1 )
+ usage(1);
+ if( (rc = encode_store(fname)) )
+ log_error("encode_store('%s'): %s\n",
+ fname_print, g10_errstr(rc) );
+ break;
+
+ case aSym: /* encrypt the given file only with the symmetric cipher */
+ if( argc > 1 )
+ usage(1);
+ if( (rc = encode_symmetric(fname)) )
+ log_error("encode_symmetric('%s'): %s\n",
+ fname_print, g10_errstr(rc) );
+ break;
+
+ case aEncr: /* encrypt the given file */
+ if( argc > 1 )
+ usage(1);
+ if( (rc = encode_crypt(fname,remusr)) )
+ log_error("encode_crypt('%s'): %s\n",
+ fname_print, g10_errstr(rc) );
+ break;
+
+ case aPrimegen:
+ if( argc )
+ usage(1);
+ mpi_print( stdout, generate_random_prime( pargs.r.ret_int ), 1);
+ putchar('\n');
+ break;
+
+ case aKeygen: /* generate a key (interactive) */
+ if( argc )
+ usage(1);
+ generate_keypair();
+ break;
+
+ default:
+ if( argc > 1 )
+ usage(1);
+ if( !(a = iobuf_open(fname)) )
+ log_fatal("can't open '%s'\n", fname_print);
+ proc_packets( a );
+ iobuf_close(a);
+ break;
+ }
+
+ /* cleanup */
+ FREE_STRLIST(remusr);
+ return 0;
+}
+
+
diff --git a/g10/getkey.c b/g10/getkey.c
new file mode 100644
index 000000000..0bd14063b
--- /dev/null
+++ b/g10/getkey.c
@@ -0,0 +1,475 @@
+/* getkey.c - Get a key from the database
+ * 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 <string.h>
+#include <assert.h>
+#include "util.h"
+#include "packet.h"
+#include "memory.h"
+#include "iobuf.h"
+#include "keydb.h"
+#include "options.h"
+
+#define MAX_PKC_CACHE_ENTRIES 500
+
+
+typedef struct keyid_list {
+ struct keyid_list *next;
+ u32 keyid[2];
+} *keyid_list_t;
+
+typedef struct user_id_db {
+ struct user_id_db *next;
+ u32 keyid[2];
+ int len;
+ char name[1];
+} *user_id_db_t;
+
+typedef struct pkc_cache_entry {
+ struct pkc_cache_entry *next;
+ u32 keyid[2];
+ PKT_pubkey_cert *pkc;
+} *pkc_cache_entry_t;
+
+static STRLIST keyrings;
+
+static keyid_list_t unknown_keyids;
+static user_id_db_t user_id_db;
+static pkc_cache_entry_t pkc_cache;
+static int pkc_cache_entries; /* number of entries in pkc cache */
+
+
+static int scan_keyring( PKT_pubkey_cert *pkc, u32 *keyid,
+ const char *name, const char *filename );
+static int scan_secret_keyring( PACKET *pkt, u32 *keyid, const char *filename);
+
+
+void
+add_keyring( const char *name )
+{
+ STRLIST sl;
+
+ /* FIXME: check wether this one is available etc */
+ /* my be we should do this later */
+ sl = m_alloc( sizeof *sl + strlen(name) );
+ strcpy(sl->d, name );
+ sl->next = keyrings;
+ keyrings = sl;
+}
+
+
+void
+cache_pubkey_cert( PKT_pubkey_cert *pkc )
+{
+ pkc_cache_entry_t ce;
+ u32 keyid[2];
+
+ if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_get_keyid( pkc->d.rsa.rsa_n, keyid );
+ }
+ else
+ return; /* don't know how to get the keyid */
+
+ for( ce = pkc_cache; ce; ce = ce->next )
+ if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] ) {
+ if( DBG_CACHE )
+ log_debug("cache_pubkey_cert: already in cache\n");
+ return;
+ }
+
+ if( pkc_cache_entries > MAX_PKC_CACHE_ENTRIES ) {
+ /* FIMXE: use another algorithm to free some cache slots */
+ if( pkc_cache_entries == MAX_PKC_CACHE_ENTRIES ) {
+ pkc_cache_entries++;
+ log_info("too many entries in pkc cache - disabled\n");
+ }
+ ce = pkc_cache;
+ free_pubkey_cert( ce->pkc );
+ }
+ else {
+ pkc_cache_entries++;
+ ce = m_alloc( sizeof *ce );
+ ce->next = pkc_cache;
+ pkc_cache = ce;
+ }
+ ce->pkc = copy_pubkey_cert( NULL, pkc );
+ ce->keyid[0] = keyid[0];
+ ce->keyid[1] = keyid[1];
+}
+
+
+/****************
+ * Store the association of keyid and userid
+ */
+void
+cache_user_id( PKT_user_id *uid, u32 *keyid )
+{
+ user_id_db_t r;
+
+ for(r=user_id_db; r; r = r->next )
+ if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
+ if( DBG_CACHE )
+ log_debug("cache_user_id: already in cache\n");
+ return;
+ }
+
+ r = m_alloc( sizeof *r + uid->len-1 );
+ r->keyid[0] = keyid[0];
+ r->keyid[1] = keyid[1];
+ r->len = uid->len;
+ memcpy(r->name, uid->name, r->len);
+ r->next = user_id_db;
+ user_id_db = r;
+}
+
+
+
+/****************
+ * Get a public key and store it into the allocated pkc
+ * can be called with PKC set to NULL to just read it into some
+ * internal structures.
+ */
+int
+get_pubkey( PKT_pubkey_cert *pkc, u32 *keyid )
+{
+ keyid_list_t kl;
+ int internal = 0;
+ int rc = 0;
+ pkc_cache_entry_t ce;
+ STRLIST sl;
+
+
+ if( opt.cache_all && !pkc_cache ) {
+ log_info("reading all entries ...\n");
+ for(sl = keyrings; sl; sl = sl->next )
+ if( !scan_keyring( NULL, NULL, NULL, sl->d ) )
+ goto leave;
+ log_info("cached %d entries\n", pkc_cache_entries);
+ }
+
+
+ /* lets see wether we checked the keyid already */
+ for( kl = unknown_keyids; kl; kl = kl->next )
+ if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
+ return G10ERR_NO_PUBKEY; /* already checked and not found */
+
+ /* 1. Try to get it from our cache */
+ for( ce = pkc_cache; ce; ce = ce->next )
+ if( ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1] ) {
+ if( pkc )
+ copy_pubkey_cert( pkc, ce->pkc );
+ return 0;
+ }
+
+ /* more init stuff */
+ if( !pkc ) {
+ pkc = m_alloc_clear( sizeof *pkc );
+ internal++;
+ }
+
+
+ /* 2. Try to get it from the keyrings */
+ for(sl = keyrings; sl; sl = sl->next )
+ if( !scan_keyring( pkc, keyid, NULL, sl->d ) )
+ goto leave;
+
+ /* 3. Try to get it from a key server */
+
+ /* 4. not found: store it for future reference */
+ kl = m_alloc( sizeof *kl );
+ kl->keyid[0] = keyid[0];
+ kl->keyid[1] = keyid[1];
+ kl->next = unknown_keyids;
+ unknown_keyids = kl;
+ rc = G10ERR_NO_PUBKEY;
+
+ leave:
+ if( !rc )
+ cache_pubkey_cert( pkc );
+ if( internal )
+ m_free(pkc);
+ return rc;
+}
+
+
+/****************
+ * Try to get the pubkey by the userid. This functions looks for the
+ * first pubkey certificate which has the given name in a user_id.
+ * if pkc has the pubkey algo set, the function will only return
+ * a pubkey with that algo.
+ */
+int
+get_pubkey_by_name( PKT_pubkey_cert *pkc, const char *name )
+{
+ int internal = 0;
+ int rc = 0;
+ STRLIST sl;
+
+ if( !pkc ) {
+ pkc = m_alloc_clear( sizeof *pkc );
+ internal++;
+ }
+
+ /* 2. Try to get it from the keyrings */
+ for(sl = keyrings; sl; sl = sl->next )
+ if( !scan_keyring( pkc, NULL, name, sl->d ) )
+ goto leave;
+
+ /* 3. Try to get it from a key server */
+
+ /* 4. not found: store it for future reference */
+ rc = G10ERR_NO_PUBKEY;
+
+ leave:
+ if( internal )
+ m_free(pkc);
+ return rc;
+}
+
+
+/****************
+ * Get a secret key and store it into skey
+ */
+int
+get_seckey( RSA_secret_key *skey, u32 *keyid )
+{
+ int rc=0;
+ PACKET pkt;
+
+ init_packet( &pkt );
+ if( !(rc=scan_secret_keyring( &pkt, keyid, "../keys/secring.g10" ) ) )
+ goto found;
+ /* fixme: look at other places */
+ goto leave;
+
+ found:
+ /* get the secret key (this may prompt for a passprase to
+ * unlock the secret key
+ */
+ if( (rc = check_secret_key( pkt.pkt.seckey_cert )) )
+ goto leave;
+ if( pkt.pkt.seckey_cert->pubkey_algo != PUBKEY_ALGO_RSA ) {
+ rc = G10ERR_PUBKEY_ALGO; /* unsupport algorithm */
+ goto leave;
+ }
+ /* copy the stuff to SKEY. skey is then the owner */
+ skey->e = pkt.pkt.seckey_cert->d.rsa.rsa_e;
+ skey->n = pkt.pkt.seckey_cert->d.rsa.rsa_n;
+ skey->p = pkt.pkt.seckey_cert->d.rsa.rsa_p;
+ skey->q = pkt.pkt.seckey_cert->d.rsa.rsa_q;
+ skey->d = pkt.pkt.seckey_cert->d.rsa.rsa_d;
+ skey->u = pkt.pkt.seckey_cert->d.rsa.rsa_u;
+ /* set all these to NULL, so that free_packet will not destroy
+ * these integers. */
+ pkt.pkt.seckey_cert->d.rsa.rsa_e = NULL;
+ pkt.pkt.seckey_cert->d.rsa.rsa_n = NULL;
+ pkt.pkt.seckey_cert->d.rsa.rsa_p = NULL;
+ pkt.pkt.seckey_cert->d.rsa.rsa_q = NULL;
+ pkt.pkt.seckey_cert->d.rsa.rsa_d = NULL;
+ pkt.pkt.seckey_cert->d.rsa.rsa_u = NULL;
+
+ leave:
+ free_packet(&pkt);
+ return rc;
+}
+
+
+/****************
+ * scan the keyring and look for either the keyid or the name.
+ */
+static int
+scan_keyring( PKT_pubkey_cert *pkc, u32 *keyid,
+ const char *name, const char *filename )
+{
+ int rc=0;
+ int found = 0;
+ IOBUF a;
+ PACKET pkt;
+ int save_mode;
+ u32 akeyid[2];
+ PKT_pubkey_cert *last_pk = NULL;
+
+ assert( !keyid || !name );
+
+ if( opt.cache_all && (name || keyid) )
+ return G10ERR_NO_PUBKEY;
+
+ if( !(a = iobuf_open( filename ) ) ) {
+ log_debug("scan_keyring: can't open '%s'\n", filename );
+ return G10ERR_KEYRING_OPEN;
+ }
+
+ if( name )
+ log_debug("scan_keyring %s for '%s'\n", filename, name );
+ else if( keyid )
+ log_debug("scan_keyring %s for %08lx %08lx\n", filename,
+ keyid[0], keyid[1] );
+ else
+ log_debug("scan_keyring %s (all)\n", filename );
+
+ save_mode = set_packet_list_mode(0);
+ init_packet(&pkt);
+ while( (rc=parse_packet(a, &pkt)) != -1 ) {
+ if( rc )
+ ; /* e.g. unknown packet */
+ else if( keyid && found && pkt.pkttype == PKT_PUBKEY_CERT ) {
+ log_error("Hmmm, pubkey without an user id in '%s'\n", filename);
+ goto leave;
+ }
+ else if( keyid && pkt.pkttype == PKT_PUBKEY_CERT ) {
+ switch( pkt.pkt.pubkey_cert->pubkey_algo ) {
+ case PUBKEY_ALGO_RSA:
+ mpi_get_keyid( pkt.pkt.pubkey_cert->d.rsa.rsa_n , akeyid );
+ if( akeyid[0] == keyid[0] && akeyid[1] == keyid[1] ) {
+ copy_pubkey_cert( pkc, pkt.pkt.pubkey_cert );
+ found++;
+ }
+ break;
+ default:
+ log_error("cannot handle pubkey algo %d\n",
+ pkt.pkt.pubkey_cert->pubkey_algo);
+ }
+ }
+ else if( keyid && found && pkt.pkttype == PKT_USER_ID ) {
+ cache_user_id( pkt.pkt.user_id, keyid );
+ goto leave;
+ }
+ else if( name && pkt.pkttype == PKT_PUBKEY_CERT ) {
+ if( last_pk )
+ free_pubkey_cert(last_pk);
+ last_pk = pkt.pkt.pubkey_cert;
+ pkt.pkt.pubkey_cert = NULL;
+ }
+ else if( name && pkt.pkttype == PKT_USER_ID ) {
+ if( memistr( pkt.pkt.user_id->name, pkt.pkt.user_id->len, name )) {
+ if( !last_pk )
+ log_error("Ooops: no pubkey for userid '%.*s'\n",
+ pkt.pkt.user_id->len, pkt.pkt.user_id->name);
+ else if( pkc->pubkey_algo &&
+ pkc->pubkey_algo != last_pk->pubkey_algo )
+ log_info("skipping id '%.*s': want algo %d, found %d\n",
+ pkt.pkt.user_id->len, pkt.pkt.user_id->name,
+ pkc->pubkey_algo, last_pk->pubkey_algo );
+ else {
+ copy_pubkey_cert( pkc, last_pk );
+ goto leave;
+ }
+ }
+ }
+ else if( !keyid && !name && pkt.pkttype == PKT_PUBKEY_CERT ) {
+ if( last_pk )
+ free_pubkey_cert(last_pk);
+ last_pk = pkt.pkt.pubkey_cert;
+ pkt.pkt.pubkey_cert = NULL;
+ }
+ else if( !keyid && !name && pkt.pkttype == PKT_USER_ID ) {
+ if( !last_pk )
+ log_error("Ooops: no pubkey for userid '%.*s'\n",
+ pkt.pkt.user_id->len, pkt.pkt.user_id->name);
+ else {
+ if( last_pk->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_get_keyid( last_pk->d.rsa.rsa_n , akeyid );
+ cache_user_id( pkt.pkt.user_id, akeyid );
+ }
+ cache_pubkey_cert( last_pk );
+ }
+ }
+ free_packet(&pkt);
+ }
+ rc = G10ERR_NO_PUBKEY;
+
+ leave:
+ if( last_pk )
+ free_pubkey_cert(last_pk);
+ free_packet(&pkt);
+ iobuf_close(a);
+ set_packet_list_mode(save_mode);
+ return rc;
+}
+
+
+/****************
+ * This is the function to get a secret key. We use an extra function,
+ * so that we can easily add special handling for secret keyrings
+ * PKT returns the secret key certificate.
+ */
+static int
+scan_secret_keyring( PACKET *pkt, u32 *keyid, const char *filename )
+{
+ IOBUF a;
+ int save_mode, rc;
+ u32 akeyid[2];
+
+ if( !(a = iobuf_open( filename ) ) ) {
+ log_debug("scan_secret_keyring: can't open '%s'\n", filename );
+ return G10ERR_KEYRING_OPEN;
+ }
+
+ save_mode = set_packet_list_mode(0);
+ init_packet(pkt);
+ while( (rc=parse_packet(a, pkt)) != -1 ) {
+ if( rc )
+ ;
+ else if( pkt->pkttype == PKT_SECKEY_CERT ) {
+ mpi_get_keyid( pkt->pkt.seckey_cert->d.rsa.rsa_n , akeyid );
+ if( akeyid[0] == keyid[0] && akeyid[1] == keyid[1] ) {
+ iobuf_close(a);
+ set_packet_list_mode(save_mode);
+ return 0; /* got it */
+ }
+ }
+ free_packet(pkt);
+ }
+
+ iobuf_close(a);
+ set_packet_list_mode(save_mode);
+ return G10ERR_NO_SECKEY;
+}
+
+
+
+/****************
+ * Return a string with a printable representation of the user_id.
+ * this string must be freed by m_free.
+ */
+char*
+get_user_id_string( u32 *keyid )
+{
+ user_id_db_t r;
+ char *p;
+ int pass=0;
+ /* try it two times; second pass reads from keyrings */
+ do {
+ for(r=user_id_db; r; r = r->next )
+ if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
+ p = m_alloc( r->len + 10 );
+ sprintf(p, "%08lX %.*s", keyid[1], r->len, r->name );
+ return p;
+ }
+ } while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
+ p = m_alloc( 15 );
+ sprintf(p, "%08lX [?]", keyid[1] );
+ return p;
+}
+
+
diff --git a/g10/keydb.h b/g10/keydb.h
new file mode 100644
index 000000000..641cd4cbc
--- /dev/null
+++ b/g10/keydb.h
@@ -0,0 +1,45 @@
+/* keydb.h - Key database
+ * 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
+ */
+
+#ifndef G10_KEYDB_H
+#define G10_KEYDB_H
+
+#include "types.h"
+#include "cipher.h"
+
+
+/*-- passphrase.h --*/
+DEK *get_passphrase_hash( u32 *keyid, char *text );
+int make_dek_from_passphrase( DEK *dek, int mode );
+
+/*-- getkey.c --*/
+void add_keyring( const char *name );
+void cache_pubkey_cert( PKT_pubkey_cert *pkc );
+void cache_user_id( PKT_user_id *uid, u32 *keyid );
+int get_pubkey( PKT_pubkey_cert *pkc, u32 *keyid );
+int get_pubkey_by_name( PKT_pubkey_cert *pkc, const char *name );
+int get_seckey( RSA_secret_key *skey, u32 *keyid );
+char*get_user_id_string( u32 *keyid );
+
+
+
+
+
+#endif /*G10_KEYDB_H*/
diff --git a/g10/keygen.c b/g10/keygen.c
new file mode 100644
index 000000000..0d5db8d85
--- /dev/null
+++ b/g10/keygen.c
@@ -0,0 +1,253 @@
+/* keygen.c - generate a key pair
+ * 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 <string.h>
+#include <errno.h>
+#include <assert.h>
+#include "util.h"
+#include "main.h"
+#include "packet.h"
+#include "cipher.h"
+#include "ttyio.h"
+#include "options.h"
+
+static int
+answer_is_yes( const char *s )
+{
+ if( !stricmp(s, "yes") )
+ return 1;
+ if( *s == 'y' && !s[1] )
+ return 1;
+ if( *s == 'Y' && !s[1] )
+ return 1;
+ return 0;
+}
+
+
+static void
+write_comment( IOBUF out, const char *s )
+{
+ PACKET pkt;
+ size_t n = strlen(s);
+ int rc;
+
+ pkt.pkttype = PKT_COMMENT;
+ pkt.pkt.comment = m_alloc( sizeof *pkt.pkt.comment + n - 1 );
+ pkt.pkt.comment->len = n;
+ strcpy(pkt.pkt.comment->data, s);
+ if( (rc = build_packet( out, &pkt )) )
+ log_error("build_packet(comment) failed: %s\n", g10_errstr(rc) );
+ free_packet( &pkt );
+}
+
+static void
+write_uid( IOBUF out, const char *s )
+{
+ PACKET pkt;
+ size_t n = strlen(s);
+ int rc;
+
+ pkt.pkttype = PKT_USER_ID;
+ pkt.pkt.user_id = m_alloc( sizeof *pkt.pkt.user_id + n - 1 );
+ pkt.pkt.user_id->len = n;
+ strcpy(pkt.pkt.user_id->name, s);
+ if( (rc = build_packet( out, &pkt )) )
+ log_error("build_packet(user_id) failed: %s\n", g10_errstr(rc) );
+ free_packet( &pkt );
+}
+
+
+static int
+gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io)
+{
+ int rc;
+ PACKET pkt1, pkt2;
+ PKT_seckey_cert *skc;
+ PKT_pubkey_cert *pkc;
+ RSA_public_key pk;
+ RSA_secret_key sk;
+
+ rsa_generate( &pk, &sk, nbits );
+
+ skc = m_alloc( sizeof *skc );
+ pkc = m_alloc( sizeof *pkc );
+ skc->timestamp = pkc->timestamp = make_timestamp();
+ skc->valid_days = pkc->valid_days = 0; /* fixme: make it configurable*/
+ skc->pubkey_algo = pkc->pubkey_algo = PUBKEY_ALGO_RSA;
+ memset(&pkc->mfx, 0, sizeof pkc->mfx);
+ pkc->d.rsa.rsa_n = pk.n;
+ pkc->d.rsa.rsa_e = pk.e;
+ skc->d.rsa.rsa_n = sk.n;
+ skc->d.rsa.rsa_e = sk.e;
+ skc->d.rsa.rsa_d = sk.d;
+ skc->d.rsa.rsa_p = sk.p;
+ skc->d.rsa.rsa_q = sk.q;
+ skc->d.rsa.rsa_u = sk.u;
+ skc->d.rsa.calc_csum = 0;
+ skc->d.rsa.is_protected = 0; /* FIXME!!! */
+ skc->d.rsa.protect_algo = 0; /* should be blowfish */
+ /*memcpy(skc->d.rsa.protect.blowfish.iv,"12345678", 8);*/
+
+ init_packet(&pkt1);
+ pkt1.pkttype = PKT_PUBKEY_CERT;
+ pkt1.pkt.pubkey_cert = pkc;
+ init_packet(&pkt2);
+ pkt2.pkttype = PKT_SECKEY_CERT;
+ pkt2.pkt.seckey_cert = skc;
+
+ if( (rc = build_packet( pub_io, &pkt1 )) ) {
+ log_error("build pubkey_cert packet failed: %s\n", g10_errstr(rc) );
+ goto leave;
+ }
+ if( (rc = build_packet( sec_io, &pkt2 )) ) {
+ log_error("build seckey_cert packet failed: %s\n", g10_errstr(rc) );
+ goto leave;
+ }
+
+ leave:
+ free_packet(&pkt1);
+ free_packet(&pkt2);
+ return rc;
+}
+
+
+/****************
+ * Generate a keypair
+ */
+void
+generate_keypair()
+{
+ char *answer;
+ unsigned nbits;
+ char *pub_fname = "./pubring.g10";
+ char *sec_fname = "./secring.g10";
+ char *uid = NULL;
+ IOBUF pub_io = NULL;
+ IOBUF sec_io = NULL;
+ int rc;
+
+ if( opt.batch || opt.answer_yes || opt.answer_no )
+ log_fatal("Key generation can only be used in interactive mode\n");
+
+ tty_printf("About to generate a new keypair:\n"
+ " minimum keysize is 768 bits\n"
+ " default keysize is 1024 bits\n"
+ " highest suggested keysize is 2048 bits\n" );
+ for(;;) {
+ answer = tty_get("What keysize do you want? (256) ");
+ tty_kill_prompt();
+ nbits = *answer? atoi(answer): 256;
+ m_free(answer);
+ if( nbits < 128 ) /* FIXME: change this to 768 */
+ tty_printf("keysize too small; please select a larger one\n");
+ else if( nbits > 2048 ) {
+ tty_printf("Keysizes larger than 2048 are not suggested, because "
+ "computations take REALLY long!\n");
+ answer = tty_get("Are you sure, that you want this keysize? ");
+ tty_kill_prompt();
+ if( answer_is_yes(answer) ) {
+ m_free(answer);
+ tty_printf("Okay, but keep in mind that your monitor "
+ "and keyboard radiation is also very vulnerable "
+ "to attacks!\n");
+ break;
+ }
+ m_free(answer);
+ }
+ else
+ break;
+ }
+ tty_printf("Requested keysize is %u bits\n", nbits );
+ if( (nbits % 32) ) {
+ nbits = ((nbits + 31) / 32) * 32;
+ tty_printf("rounded up to %u bits\n", nbits );
+ }
+ tty_printf( "\nYou need a User-ID to identify your key; please use your name and your\n"
+ "email address in this suggested format:\n"
+ " \"Heinrich Heine <heinrichh@uni-duesseldorf.de>\n" );
+ uid = NULL;
+ for(;;) {
+ m_free(uid);
+ tty_printf("\n");
+ uid = tty_get("Your User-ID: ");
+ tty_kill_prompt();
+ if( strlen(uid) < 5 )
+ tty_printf("Please enter a string of at least 5 characters\n");
+ else {
+ tty_printf("You selected this USER-ID:\n \"%s\"\n\n", uid);
+ answer = tty_get("Is this correct? ");
+ tty_kill_prompt();
+ if( answer_is_yes(answer) ) {
+ m_free(answer);
+ break;
+ }
+ m_free(answer);
+ }
+ }
+
+ /* now check wether we a are allowed to write the keyrings */
+ if( !(rc=overwrite_filep( pub_fname )) ) {
+ if( !(pub_io = iobuf_create( pub_fname )) )
+ log_error("can't create %s: %s\n", pub_fname, strerror(errno) );
+ else if( opt.verbose )
+ log_info("writing to '%s'\n", pub_fname );
+ }
+ else if( rc != -1 ) {
+ log_error("Oops: overwrite_filep(%s): %s\n", pub_fname, g10_errstr(rc) );
+ m_free(uid);
+ return;
+ }
+ else {
+ m_free(uid);
+ return;
+ }
+ if( !(rc=overwrite_filep( sec_fname )) ) {
+ if( !(sec_io = iobuf_create( sec_fname )) )
+ log_error("can't create %s: %s\n", sec_fname, strerror(errno) );
+ else if( opt.verbose )
+ log_info("writing to '%s'\n", sec_fname );
+ }
+ else if( rc != -1 ) {
+ log_error("Oops: overwrite_filep(%s): %s\n", sec_fname, g10_errstr(rc) );
+ m_free(uid);
+ return;
+ }
+ else {
+ iobuf_cancel(pub_io);
+ m_free(uid);
+ return;
+ }
+
+
+ write_comment( pub_io, "#public key created by G10 pre-release " VERSION );
+ write_comment( sec_io, "#secret key created by G10 pre-release " VERSION );
+
+ gen_rsa(nbits, pub_io, sec_io);
+ write_uid(pub_io, uid );
+ write_uid(sec_io, uid );
+ m_free(uid);
+
+ iobuf_close(pub_io);
+ iobuf_close(sec_io);
+}
+
diff --git a/g10/main.h b/g10/main.h
new file mode 100644
index 000000000..398dc40f1
--- /dev/null
+++ b/g10/main.h
@@ -0,0 +1,35 @@
+/* main.h
+ * 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
+ */
+#ifndef G10_MAIN_H
+#define G10_MAIN_H
+#include "types.h"
+
+/*-- encode.c --*/
+int encode_symmetric( const char *filename );
+int encode_store( const char *filename );
+int encode_crypt( const char *filename, STRLIST remusr );
+
+/*-- keygen.c --*/
+void generate_keypair(void);
+
+/*-- overwrite.c --*/
+int overwrite_filep( const char *fname );
+
+#endif /*G10_MAIN_H*/
diff --git a/g10/mainproc.c b/g10/mainproc.c
new file mode 100644
index 000000000..0055200b4
--- /dev/null
+++ b/g10/mainproc.c
@@ -0,0 +1,275 @@
+/* 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"
+
+
+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];
+
+ 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_RSA ) {
+ mpi_get_keyid( pkt->pkc_parent->d.rsa.rsa_n, 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 != 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 ) {
+ result = -1;
+ printstr(lvl0, "sig: from %s\n", ustr );
+ }
+ 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 ) {
+ 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 ) {
+ 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 )
+ 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_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);
+ result = handle_plaintext( pt );
+ 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 );
+ return 0;
+}
+
+
diff --git a/g10/mdfilter.c b/g10/mdfilter.c
new file mode 100644
index 000000000..b6cd86110
--- /dev/null
+++ b/g10/mdfilter.c
@@ -0,0 +1,70 @@
+/* mdfilter.c - filter data and calculate a message digest
+ * 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 <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "errors.h"
+#include "iobuf.h"
+#include "memory.h"
+#include "util.h"
+#include "filter.h"
+
+
+
+/****************
+ * The filter is used to collect a message digest
+ */
+int
+md_filter( void *opaque, int control,
+ IOBUF a, byte *buf, size_t *ret_len)
+{
+ size_t size = *ret_len;
+ md_filter_context_t *mfx = opaque;
+ int i, c, rc=0;
+
+ if( control == IOBUFCTRL_UNDERFLOW ) {
+ if( size > mfx->maxbuf_size )
+ size = mfx->maxbuf_size;
+ for(i=0; i < size; i++ ) {
+ if( (c = iobuf_get(a)) == -1 )
+ break;
+ buf[i] = c;
+ }
+
+ if( i ) {
+ if( mfx->md5 )
+ md5_write(mfx->md5, buf, i );
+ if( mfx->rmd160 )
+ rmd160_write(mfx->rmd160, buf, i );
+ }
+ else
+ rc = -1; /* eof */
+ *ret_len = i;
+ }
+ else if( control == IOBUFCTRL_DESC )
+ *(char**)buf = "md_filter";
+ return rc;
+}
+
diff --git a/g10/options.h b/g10/options.h
new file mode 100644
index 000000000..f2a17de85
--- /dev/null
+++ b/g10/options.h
@@ -0,0 +1,68 @@
+/* options.h
+ * 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
+ */
+#ifndef G10_OPTIONS_H
+#define G10_OPTIONS_H
+
+struct {
+ int verbose;
+ unsigned debug;
+ int armor;
+ int compress;
+ char *outfile;
+ int outfile_is_stdout;
+ int batch; /* run in batch mode */
+ int answer_yes; /* answer yes on most questions */
+ int answer_no; /* answer no on most questions */
+ int check_sigs; /* check key signatures */
+ int cache_all;
+ int reserved2;
+ int reserved3;
+ int reserved4;
+ int reserved5;
+ int reserved6;
+ int reserved7;
+ int reserved8;
+ int reserved9;
+ int reserved10;
+ int reserved11;
+ int reserved12;
+ int reserved13;
+ int reserved14;
+ int reserved15;
+} opt;
+
+
+#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
+#define DBG_MPI_VALUE 2 /* debug mpi details */
+#define DBG_CIPHER_VALUE 4 /* debug cipher handling */
+ /* (may reveal sensitive data) */
+#define DBG_FILTER_VALUE 8 /* debug internal filter handling */
+#define DBG_IOBUF_VALUE 16 /* debug iobuf stuff */
+#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
+#define DBG_CACHE_VALUE 64 /* debug the cacheing */
+#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
+
+
+#define DBG_PACKET (opt.debug & DBG_PACKET_VALUE)
+#define DBG_FILTER (opt.debug & DBG_FILTER_VALUE)
+#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
+
+
+#endif /*G10_OPTIONS_H*/
diff --git a/g10/overwrite.c b/g10/overwrite.c
new file mode 100644
index 000000000..a98dd3be7
--- /dev/null
+++ b/g10/overwrite.c
@@ -0,0 +1,79 @@
+/* overwrite.c
+ * 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 <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include "util.h"
+#include "memory.h"
+#include "ttyio.h"
+#include "options.h"
+#include "main.h"
+
+
+/****************
+ * Check wether FNAME exists and ask if it's okay to overwrite an
+ * existing one.
+ * Returns: -1 : Do not overwrite
+ * 0 : it's okay to overwrite or the file does not exist
+ * >0 : other error
+ */
+int
+overwrite_filep( const char *fname )
+{
+ if( !access( fname, F_OK ) ) {
+ char *p;
+ int okay;
+ int first = 1;
+
+ if( opt.answer_yes )
+ okay = 1;
+ else if( opt.answer_no || opt.batch )
+ okay = 2;
+ else
+ okay = 0;
+
+ while( !okay ) {
+ if( !okay )
+ if( first ) {
+ tty_printf("File '%s' exists. ", fname);
+ first = 0;
+ }
+ p = tty_get("Overwrite (y/N)? ");
+ tty_kill_prompt();
+ if( (*p == 'y' || *p == 'Y') && !p[1] )
+ okay = 1;
+ else if( !*p || ((*p == 'n' || *p == 'N') && !p[1]) )
+ okay = 2;
+ else
+ okay = 0;
+ m_free(p);
+ }
+ if( okay == 2 )
+ return -1;
+ /* fixme: add some backup stuff */
+ }
+ return 0;
+}
+
+
diff --git a/g10/packet.h b/g10/packet.h
new file mode 100644
index 000000000..6ac57cab0
--- /dev/null
+++ b/g10/packet.h
@@ -0,0 +1,214 @@
+/* packet.h - packet read/write stuff
+ * 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
+ */
+
+#ifndef G10_PACKET_H
+#define G10_PACKET_H
+
+#include "types.h"
+#include "iobuf.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "filter.h"
+
+
+#define PKT_PUBKEY_ENC 1 /* public key encrypted packet */
+#define PKT_SIGNATURE 2 /* secret key encrypted packet */
+#define PKT_SECKEY_CERT 5 /* secret key certificate */
+#define PKT_PUBKEY_CERT 6 /* public key certificate */
+#define PKT_COMPR_DATA 8 /* compressed data packet */
+#define PKT_ENCR_DATA 9 /* conventional encrypted data */
+#define PKT_PLAINTEXT 11 /* plaintext data with filename and mode */
+#define PKT_RING_TRUST 12 /* keyring trust packet */
+#define PKT_USER_ID 13 /* user id packet */
+#define PKT_COMMENT 14 /* comment packet */
+
+typedef struct packet_struct PACKET;
+
+typedef struct {
+ u32 keyid[2]; /* 64 bit keyid */
+ byte pubkey_algo; /* algorithm used for public key scheme */
+ union {
+ struct {
+ MPI rsa_integer; /* integer containing the DEK */
+ } rsa;
+ } d;
+} PKT_pubkey_enc;
+
+
+typedef struct {
+ u32 keyid[2]; /* 64 bit keyid */
+ u32 timestamp; /* signature made */
+ byte sig_class; /* sig classification, append for MD calculation*/
+ byte pubkey_algo; /* algorithm used for public key scheme */
+ /* (PUBKEY_ALGO_xxx) */
+ union {
+ struct {
+ byte digest_algo; /* algorithm used for digest (DIGEST_ALGO_xxxx) */
+ byte digest_start[2]; /* first 2 byte of the digest */
+ MPI rsa_integer; /* the encrypted digest */
+ } rsa;
+ } d;
+} PKT_signature;
+
+
+typedef struct {
+ u32 timestamp; /* certificate made */
+ u16 valid_days; /* valid for this number of days */
+ byte pubkey_algo; /* algorithm used for public key scheme */
+ md_filter_context_t mfx;
+ union {
+ struct {
+ MPI rsa_n; /* public modulus */
+ MPI rsa_e; /* public exponent */
+ } rsa;
+ } d;
+} PKT_pubkey_cert;
+
+typedef struct {
+ u32 timestamp; /* certificate made */
+ u16 valid_days; /* valid for this number of days */
+ byte pubkey_algo; /* algorithm used for public key scheme */
+ union {
+ struct {
+ MPI rsa_n; /* public modulus */
+ MPI rsa_e; /* public exponent */
+ MPI rsa_d; /* secret descryption exponent */
+ MPI rsa_p; /* secret first prime number */
+ MPI rsa_q; /* secret second prime number */
+ MPI rsa_u; /* secret multiplicative inverse */
+ u16 csum; /* checksum */
+ u16 calc_csum; /* and a place to store the calculated csum */
+ byte is_protected; /* The above infos are protected and must */
+ /* be deciphered before use */
+ byte protect_algo; /* cipher used to protect the secret informations*/
+ union { /* information for the protection */
+ struct {
+ byte iv[8]; /* initialization vector for CFB mode */
+ /* when protected, the MPIs above are pointers
+ * to plain storage */
+ } idea;
+ struct {
+ byte iv[8];
+ } blowfish;
+ } protect;
+ } rsa;
+ } d;
+} PKT_seckey_cert;
+
+
+typedef struct {
+ int len; /* length of data */
+ char data[1];
+} PKT_comment;
+
+typedef struct {
+ int len; /* length of the name */
+ char name[1];
+} PKT_user_id;
+
+typedef struct {
+ u32 len; /* reserved */
+ byte algorithm;
+ IOBUF buf; /* IOBUF reference */
+} PKT_compressed;
+
+typedef struct {
+ u32 len; /* length of encrypted data */
+ IOBUF buf; /* IOBUF reference */
+} PKT_encr_data;
+
+typedef struct {
+ u32 len; /* length of encrypted data */
+ IOBUF buf; /* IOBUF reference */
+ int mode;
+ u32 timestamp;
+ int namelen;
+ char name[1];
+} PKT_plaintext;
+
+/* combine all packets into a union */
+struct packet_struct {
+ int pkttype;
+ PKT_pubkey_cert *pkc_parent; /* the pubkey to which it belongs */
+ PKT_seckey_cert *skc_parent; /* the seckey to which it belongs */
+ PKT_user_id *user_parent; /* the user_id to which it belongs */
+ union {
+ void *generic;
+ PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */
+ PKT_signature *signature; /* PKT_SIGNATURE */
+ PKT_pubkey_cert *pubkey_cert; /* PKT_PUBKEY_CERT */
+ PKT_seckey_cert *seckey_cert; /* PKT_SECKEY_CERT */
+ PKT_comment *comment; /* PKT_COMMENT */
+ PKT_user_id *user_id; /* PKT_USER_ID */
+ PKT_compressed *compressed; /* PKT_COMPRESSED */
+ PKT_encr_data *encr_data; /* PKT_ENCR_DATA */
+ PKT_plaintext *plaintext; /* PKT_PLAINTEXT */
+ } pkt;
+};
+
+#define init_packet(a) do { (a)->pkttype = 0; \
+ (a)->pkc_parent = NULL; \
+ (a)->skc_parent = NULL; \
+ (a)->user_parent = NULL; \
+ (a)->pkt.generic = NULL; \
+ } while(0)
+
+/*-- mainproc.c --*/
+int proc_packets( IOBUF a );
+
+/*-- parse-packet.c --*/
+int set_packet_list_mode( int mode );
+int parse_packet( IOBUF inp, PACKET *ret_pkt);
+
+/*-- build-packet.c --*/
+int build_packet( IOBUF inp, PACKET *pkt );
+u32 calc_packet_length( PACKET *pkt );
+
+/*-- free-packet.c --*/
+void free_pubkey_enc( PKT_pubkey_enc *enc );
+void free_seckey_enc( PKT_signature *enc );
+void free_pubkey_cert( PKT_pubkey_cert *cert );
+void free_seckey_cert( PKT_seckey_cert *cert );
+void free_user_id( PKT_user_id *uid );
+void free_comment( PKT_comment *rem );
+void free_packet( PACKET *pkt );
+PKT_pubkey_cert *copy_pubkey_cert( PKT_pubkey_cert *d, PKT_pubkey_cert *s );
+
+
+/*-- sig-check.c --*/
+int signature_check( PKT_signature *sig, MD_HANDLE digest );
+
+/*-- seckey-cert.c --*/
+int check_secret_key( PKT_seckey_cert *cert );
+
+/*-- pubkey-enc.c --*/
+int get_session_key( PKT_pubkey_enc *k, DEK *dek );
+
+/*-- compressed.c --*/
+int handle_compressed( PKT_compressed *zd );
+
+/*-- encr-data.c --*/
+int decrypt_data( PKT_encr_data *ed, DEK *dek );
+int encrypt_data( PKT_encr_data *ed, DEK *dek );
+
+/*-- plaintext.c --*/
+int handle_plaintext( PKT_plaintext *pt );
+
+#endif /*G10_PACKET_H*/
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
new file mode 100644
index 000000000..7c6b85782
--- /dev/null
+++ b/g10/parse-packet.c
@@ -0,0 +1,662 @@
+/* parse-packet.c - read 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 <string.h>
+#include <assert.h>
+
+#include "packet.h"
+#include "iobuf.h"
+#include "mpi.h"
+#include "util.h"
+#include "cipher.h"
+#include "memory.h"
+#include "filter.h"
+#include "options.h"
+
+static mpi_print_mode = 0;
+static list_mode = 0;
+
+static void skip_packet( IOBUF inp, int pkttype, unsigned long pktlen );
+static void skip_rest( IOBUF inp, unsigned long pktlen );
+static int parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen,
+ PACKET *packet );
+static int parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
+ PKT_signature *sig );
+static int parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen,
+ byte *hdr, int hdrlen, PACKET *packet );
+static int parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen,
+ PACKET *packet );
+static void parse_comment( IOBUF inp, int pkttype, unsigned long pktlen );
+static void parse_trust( IOBUF inp, int pkttype, unsigned long pktlen );
+static int parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen,
+ PACKET *pkt );
+static int parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen,
+ PACKET *packet );
+static int parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen,
+ PACKET *packet );
+
+static u16
+checksum( byte *p )
+{
+ u16 n, a;
+
+ n = *p++ << 8;
+ n |= *p++;
+ for(a=0; n; n-- )
+ a += *p++;
+ return a;
+}
+
+static unsigned short
+read_16(IOBUF inp)
+{
+ unsigned short a;
+ a = iobuf_get_noeof(inp) << 8;
+ a |= iobuf_get_noeof(inp);
+ return a;
+}
+
+static unsigned long
+read_32(IOBUF inp)
+{
+ unsigned long a;
+ a = iobuf_get_noeof(inp) << 24;
+ a |= iobuf_get_noeof(inp) << 16;
+ a |= iobuf_get_noeof(inp) << 8;
+ a |= iobuf_get_noeof(inp);
+ return a;
+}
+
+int
+set_packet_list_mode( int mode )
+{
+ int old = list_mode;
+ list_mode = mode;
+ mpi_print_mode = DBG_MPI;
+ return old;
+}
+
+/****************
+ * Parse a Packet and return it in packet
+ * Returns: 0 := valid packet in pkt
+ * -1 := no more packets
+ * >0 := error
+ * Note: The function may return an error and a partly valid packet;
+ * caller must free this packet.
+ */
+int
+parse_packet( IOBUF inp, PACKET *pkt )
+{
+ int rc, ctb, pkttype, lenbytes;
+ unsigned long pktlen;
+ byte hdr[5];
+ int hdrlen;
+
+ assert( !pkt->pkt.generic );
+ if( (ctb = iobuf_get(inp)) == -1 )
+ return -1;
+ hdrlen=0;
+ hdr[hdrlen++] = ctb;
+ if( !(ctb & 0x80) ) {
+ log_error("invalid packet at '%s'\n", iobuf_where(inp) );
+ return G10ERR_INVALID_PACKET;
+ }
+ /* we handle the pgp 3 extensions here, so that we can skip such packets*/
+ pkttype = ctb & 0x40 ? (ctb & 0x3f) : ((ctb>>2)&0xf);
+ lenbytes = (ctb & 0x40) || ((ctb&3)==3)? 0 : (1<<(ctb & 3));
+ pktlen = 0;
+ if( !lenbytes ) {
+ pktlen = 0; /* don't know the value */
+ iobuf_set_block_mode(inp, 1);
+ }
+ else {
+ for( ; lenbytes; lenbytes-- ) {
+ pktlen <<= 8;
+ pktlen |= hdr[hdrlen++] = iobuf_get_noeof(inp);
+ }
+ }
+
+ if( DBG_PACKET )
+ log_debug("parse_packet(iob=%d): type=%d length=%lu\n",
+ iobuf_id(inp), pkttype, pktlen );
+ pkt->pkttype = pkttype;
+ rc = G10ERR_UNKNOWN_PACKET; /* default to no error */
+ switch( pkttype ) {
+ case PKT_PUBKEY_CERT:
+ pkt->pkt.pubkey_cert = m_alloc_clear(sizeof *pkt->pkt.pubkey_cert );
+ rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt );
+ break;
+ case PKT_SECKEY_CERT:
+ pkt->pkt.seckey_cert = m_alloc_clear(sizeof *pkt->pkt.seckey_cert );
+ rc = parse_certificate(inp, pkttype, pktlen, hdr, hdrlen, pkt );
+ break;
+ case PKT_PUBKEY_ENC:
+ rc = parse_publickey(inp, pkttype, pktlen, pkt );
+ break;
+ case PKT_SIGNATURE:
+ pkt->pkt.signature = m_alloc_clear(sizeof *pkt->pkt.signature );
+ rc = parse_signature(inp, pkttype, pktlen, pkt->pkt.signature );
+ m_check(pkt->pkt.signature);
+ break;
+ case PKT_USER_ID:
+ rc = parse_user_id(inp, pkttype, pktlen, pkt );
+ break;
+ case PKT_COMMENT:
+ parse_comment(inp, pkttype, pktlen);
+ break;
+ case PKT_RING_TRUST:
+ parse_trust(inp, pkttype, pktlen);
+ break;
+ case PKT_PLAINTEXT:
+ rc = parse_plaintext(inp, pkttype, pktlen, pkt );
+ break;
+ case PKT_COMPR_DATA:
+ rc = parse_compressed(inp, pkttype, pktlen, pkt );
+ break;
+ case PKT_ENCR_DATA:
+ rc = parse_encrypted(inp, pkttype, pktlen, pkt );
+ break;
+ default:
+ skip_packet(inp, pkttype, pktlen);
+ break;
+ }
+
+ return rc;
+}
+
+
+static void
+skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
+{
+ if( list_mode )
+ printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen );
+ skip_rest(inp,pktlen);
+}
+
+static void
+skip_rest( IOBUF inp, unsigned long pktlen )
+{
+ if( iobuf_in_block_mode(inp) ) {
+ while( iobuf_get(inp) != -1 )
+ ;
+ }
+ else {
+ for( ; pktlen; pktlen-- )
+ iobuf_get(inp);
+ }
+}
+
+
+static int
+parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
+{
+ int version;
+ unsigned n;
+ PKT_pubkey_enc *k;
+
+ k = packet->pkt.pubkey_enc = m_alloc(sizeof *packet->pkt.pubkey_enc );
+ if( pktlen < 12 ) {
+ log_error("packet(%d) too short\n", pkttype);
+ goto leave;
+ }
+ version = iobuf_get_noeof(inp); pktlen--;
+ if( version != 2 && version != 3 ) {
+ log_error("packet(%d) with unknown version %d\n", pkttype, version);
+ goto leave;
+ }
+ k->keyid[0] = read_32(inp); pktlen -= 4;
+ k->keyid[1] = read_32(inp); pktlen -= 4;
+ k->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
+ if( list_mode )
+ printf(":public key packet: keyid %08lX%08lX\n",
+ k->keyid[0], k->keyid[1]);
+ if( k->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ n = pktlen;
+ k->d.rsa.rsa_integer = mpi_decode(inp, &n ); pktlen -=n;
+ if( list_mode ) {
+ printf("\trsa integer: ");
+ mpi_print(stdout, k->d.rsa.rsa_integer, mpi_print_mode );
+ putchar('\n');
+ }
+ }
+ else if( list_mode )
+ printf("\tunknown algorithm %d\n", k->pubkey_algo );
+
+
+ leave:
+ skip_rest(inp, pktlen);
+ return 0;
+}
+
+
+static int
+parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
+ PKT_signature *sig )
+{
+ int version, md5_len;
+ unsigned n;
+
+ if( pktlen < 16 ) {
+ log_error("packet(%d) too short\n", pkttype);
+ goto leave;
+ }
+ version = iobuf_get_noeof(inp); pktlen--;
+ if( version != 2 && version != 3 ) {
+ log_error("packet(%d) with unknown version %d\n", pkttype, version);
+ goto leave;
+ }
+ m_check(sig);
+ md5_len = iobuf_get_noeof(inp); pktlen--;
+ sig->sig_class = iobuf_get_noeof(inp); pktlen--;
+ sig->timestamp = read_32(inp); pktlen -= 4;
+ sig->keyid[0] = read_32(inp); pktlen -= 4;
+ sig->keyid[1] = read_32(inp); pktlen -= 4;
+ sig->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
+ m_check(sig);
+ if( list_mode )
+ printf(":signature packet: keyid %08lX%08lX\n"
+ "\tversion %d, created %lu, md5len %d, sigclass %02x\n",
+ sig->keyid[0], sig->keyid[1],
+ version, sig->timestamp, md5_len, sig->sig_class );
+ if( sig->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ if( pktlen < 5 ) {
+ log_error("packet(%d) too short\n", pkttype);
+ goto leave;
+ }
+ m_check(sig);
+ sig->d.rsa.digest_algo = iobuf_get_noeof(inp); pktlen--;
+ sig->d.rsa.digest_start[0] = iobuf_get_noeof(inp); pktlen--;
+ sig->d.rsa.digest_start[1] = iobuf_get_noeof(inp); pktlen--;
+ m_check(sig);
+ n = pktlen;
+ sig->d.rsa.rsa_integer = mpi_decode(inp, &n ); pktlen -=n;
+ if( list_mode ) {
+ printf("\tdigest algo %d, begin of digest %02x %02x\n",
+ sig->d.rsa.digest_algo,
+ sig->d.rsa.digest_start[0], sig->d.rsa.digest_start[1] );
+ printf("\trsa integer: ");
+ mpi_print(stdout, sig->d.rsa.rsa_integer, mpi_print_mode );
+ putchar('\n');
+ }
+ }
+ else if( list_mode )
+ printf("\tunknown algorithm %d\n", sig->pubkey_algo );
+ m_check(sig);
+
+
+ leave:
+ skip_rest(inp, pktlen);
+ return 0;
+}
+
+
+
+
+static int
+parse_certificate( IOBUF inp, int pkttype, unsigned long pktlen,
+ byte *hdr, int hdrlen, PACKET *pkt )
+{
+ int i, version, algorithm;
+ unsigned n;
+ unsigned long timestamp;
+ unsigned short valid_period;
+ MPI rsa_pub_mod, rsa_pub_exp;
+
+ if( pkttype == PKT_PUBKEY_CERT ) {
+ pkt->pkt.pubkey_cert->mfx.md5 = md5_open(0);
+ pkt->pkt.pubkey_cert->mfx.rmd160 = rmd160_open(0);
+ pkt->pkt.pubkey_cert->mfx.maxbuf_size = 1;
+ md5_write(pkt->pkt.pubkey_cert->mfx.md5, hdr, hdrlen);
+ rmd160_write(pkt->pkt.pubkey_cert->mfx.rmd160, hdr, hdrlen);
+ iobuf_push_filter( inp, md_filter, &pkt->pkt.pubkey_cert->mfx );
+ }
+
+ if( pktlen < 12 ) {
+ log_error("packet(%d) too short\n", pkttype);
+ goto leave;
+ }
+ version = iobuf_get_noeof(inp); pktlen--;
+ if( version != 2 && version != 3 ) {
+ log_error("packet(%d) with unknown version %d\n", pkttype, version);
+ goto leave;
+ }
+
+ timestamp = read_32(inp); pktlen -= 4;
+ valid_period = read_16(inp); pktlen -= 2;
+ algorithm = iobuf_get_noeof(inp); pktlen--;
+ if( list_mode )
+ printf(":%s key certification packet:\n"
+ "\tversion %d, created %lu, valid for %hu days\n",
+ pkttype == PKT_PUBKEY_CERT? "public": "secret",
+ version, timestamp, valid_period );
+ if( pkttype == PKT_SECKEY_CERT ) {
+ pkt->pkt.seckey_cert->timestamp = timestamp;
+ pkt->pkt.seckey_cert->valid_days = valid_period;
+ pkt->pkt.seckey_cert->pubkey_algo = algorithm;
+ }
+ else {
+ pkt->pkt.pubkey_cert->timestamp = timestamp;
+ pkt->pkt.pubkey_cert->valid_days = valid_period;
+ pkt->pkt.pubkey_cert->pubkey_algo = algorithm;
+ }
+
+ if( algorithm == PUBKEY_ALGO_RSA ) {
+ n = pktlen; rsa_pub_mod = mpi_decode(inp, &n ); pktlen -=n;
+ n = pktlen; rsa_pub_exp = mpi_decode(inp, &n ); pktlen -=n;
+ if( list_mode ) {
+ printf( "\tpublic modulus n: ");
+ mpi_print(stdout, rsa_pub_mod, mpi_print_mode );
+ printf("\n\tpublic exponent e: ");
+ mpi_print(stdout, rsa_pub_exp, mpi_print_mode );
+ putchar('\n');
+ }
+ if( pkttype == PKT_PUBKEY_CERT ) {
+ pkt->pkt.pubkey_cert->d.rsa.rsa_n = rsa_pub_mod;
+ pkt->pkt.pubkey_cert->d.rsa.rsa_e = rsa_pub_exp;
+ }
+ else {
+ PKT_seckey_cert *cert = pkt->pkt.seckey_cert;
+ byte temp[8];
+ byte *mpibuf;
+
+ pkt->pkt.seckey_cert->d.rsa.rsa_n = rsa_pub_mod;
+ pkt->pkt.seckey_cert->d.rsa.rsa_e = rsa_pub_exp;
+ cert->d.rsa.protect_algo = iobuf_get_noeof(inp); pktlen--;
+ if( list_mode )
+ printf( "\tprotect algo: %d\n", cert->d.rsa.protect_algo);
+ if( cert->d.rsa.protect_algo ) {
+ cert->d.rsa.is_protected = 1;
+ for(i=0; i < 8 && pktlen; i++, pktlen-- )
+ temp[i] = iobuf_get_noeof(inp);
+ if( list_mode ) {
+ printf( "\tprotect IV: ");
+ for(i=0; i < 8; i++ )
+ printf(" %02x", temp[i] );
+ putchar('\n');
+ }
+ if( cert->d.rsa.protect_algo == CIPHER_ALGO_IDEA )
+ memcpy(cert->d.rsa.protect.idea.iv, temp, 8 );
+ else if( cert->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH )
+ memcpy(cert->d.rsa.protect.blowfish.iv, temp, 8 );
+ }
+ else
+ cert->d.rsa.is_protected = 0;
+
+ n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2);
+ cert->d.rsa.rsa_d = (MPI)mpibuf;
+
+ n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2);
+ cert->d.rsa.rsa_p = (MPI)mpibuf;
+
+ n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2);
+ cert->d.rsa.rsa_q = (MPI)mpibuf;
+
+ n = pktlen; mpibuf = mpi_read(inp, &n ); pktlen -=n; assert(n>=2);
+ cert->d.rsa.rsa_u = (MPI)mpibuf;
+
+ cert->d.rsa.csum = read_16(inp); pktlen -= 2;
+ cert->d.rsa.calc_csum = 0;
+ if( list_mode ) {
+ printf("\t[secret values d,p,q,u are not shown]\n"
+ "\tchecksum: %04hx\n", cert->d.rsa.csum);
+ }
+ if( !cert->d.rsa.is_protected ) { /* convert buffer to MPIs */
+ #define X(a) do { \
+ mpibuf = (byte*)cert->d.rsa.rsa_##a; \
+ cert->d.rsa.calc_csum += checksum( mpibuf ); \
+ cert->d.rsa.rsa_##a = mpi_decode_buffer( mpibuf ); \
+ m_free( mpibuf ); \
+ } while(0)
+ X(d);
+ X(p);
+ X(q);
+ X(u);
+ #undef X
+ log_mpidump("rsa n=", cert->d.rsa.rsa_n );
+ log_mpidump("rsa e=", cert->d.rsa.rsa_e );
+ log_mpidump("rsa d=", cert->d.rsa.rsa_d );
+ log_mpidump("rsa p=", cert->d.rsa.rsa_p );
+ log_mpidump("rsa q=", cert->d.rsa.rsa_q );
+ log_mpidump("rsa u=", cert->d.rsa.rsa_u );
+ }
+ }
+ }
+ else if( list_mode )
+ printf("\tunknown algorithm %d\n", algorithm );
+
+
+ leave:
+ if( pkttype == PKT_PUBKEY_CERT )
+ iobuf_pop_filter( inp, md_filter, &pkt->pkt.pubkey_cert->mfx );
+ skip_rest(inp, pktlen);
+ return 0;
+}
+
+
+static int
+parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
+{
+ byte *p;
+
+ packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id + pktlen - 1);
+ packet->pkt.user_id->len = pktlen;
+ p = packet->pkt.user_id->name;
+ for( ; pktlen; pktlen--, p++ )
+ *p = iobuf_get_noeof(inp);
+
+ if( list_mode ) {
+ int n = packet->pkt.user_id->len;
+ printf(":user id packet: \"");
+ for(p=packet->pkt.user_id->name; n; p++, n-- ) {
+ if( *p >= ' ' && *p <= 'z' )
+ putchar(*p);
+ else
+ printf("\\x%02x", *p );
+ }
+ printf("\"\n");
+ }
+ return 0;
+}
+
+static void
+parse_comment( IOBUF inp, int pkttype, unsigned long pktlen )
+{
+ if( list_mode ) {
+ printf(":comment packet: \"" );
+ for( ; pktlen; pktlen-- ) {
+ int c;
+ c = iobuf_get_noeof(inp);
+ if( c >= ' ' && c <= 'z' )
+ putchar(c);
+ else
+ printf("\\x%02x", c );
+ }
+ printf("\"\n");
+ }
+ skip_rest(inp, pktlen);
+}
+
+
+static void
+parse_trust( IOBUF inp, int pkttype, unsigned long pktlen )
+{
+ int c;
+
+ c = iobuf_get_noeof(inp);
+ if( list_mode )
+ printf(":trust packet: flag=%02x\n", c );
+ #if 0 /* fixme: depending on the context we have different interpretations*/
+ if( prev_packet_is_a_key_packet ) {
+ int ot = c & 7; /* ownertrust bits (for the key owner) */
+
+ !ot ? "undefined" :
+ ot == 1 ? "unknown" : /* we don't know the owner of this key */
+ ot == 2 ? "no" : /* usually we do not trust this key owner */
+ /* to sign other keys */
+ ot == 5 ? "usually" : /* usually we trust this key owner to sign */
+ ot == 6 ? "always" : /* always trust this key owner to sign */
+ ot == 7 ? "ultimate" : /* also present in the secret keyring */
+ "" /* reserved value */
+ if( c & (1<<5) )
+ "key is disabled"
+ if( c & (1<<7) )
+ "buckstop"
+ else if( prev_packet_is_user_is_packet ) {
+ int kl = c & 3; /* keylegit bits */
+ 0 = "unknown, undefined, or uninitialized trust"
+ 1 = "we do not trust this key's ownership"
+ 2 = "we have marginal confidence of this key's ownership"
+ 3 = "we completely trust this key's ownership."
+ /* This one (3) requires either:
+ * - 1 ultimately trusted signature (SIGTRUST=7)
+ * - COMPLETES_NEEDED completely trusted signatures (SIGTRUST=6)
+ * - MARGINALS_NEEDED marginally trusted signatures (SIGTRUST=5)
+ */
+ if( c & 0x80 )
+ "warnonly"
+ else if( prev_packet_is_a_signature ) {
+ Bits 0-2 - SIGTRUST bits - Trust bits for this signature. Value is
+ copied directly from OWNERTRUST bits of signer:
+ 000 - undefined, or uninitialized trust.
+ 001 - unknown
+ 010 - We do not trust this signature.
+ 011 - reserved
+ 100 - reserved
+ 101 - We reasonably trust this signature.
+ 110 - We completely trust this signature.
+ 111 - ultimately trusted signature (from the owner of the ring)
+ Bit 6 - CHECKED bit - This means that the key checking pass (pgp -kc,
+ also invoked automatically whenever keys are added to the
+ keyring) has tested this signature and found it good. If
+ this bit is not set, the maintenance pass considers this
+ signature untrustworthy.
+ Bit 7 - CONTIG bit - Means this signature leads up a contiguous trusted
+ certification path all the way back to the ultimately-
+ trusted keyring owner, where the buck stops. This bit is derived
+ from other trust packets. It is currently not used for anything
+ in PGP.
+ }
+ #endif
+}
+
+
+static int
+parse_plaintext( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
+{
+ int mode, namelen;
+ PKT_plaintext *pt;
+ byte *p;
+ int c, i;
+
+ if( pktlen && pktlen < 6 ) {
+ log_error("packet(%d) too short (%lu)\n", pkttype, (ulong)pktlen);
+ goto leave;
+ }
+ mode = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
+ namelen = iobuf_get_noeof(inp); if( pktlen ) pktlen--;
+ pt = pkt->pkt.plaintext = m_alloc(sizeof *pkt->pkt.plaintext + namelen -1);
+ pt->mode = mode;
+ pt->namelen = namelen;
+ if( pktlen ) {
+ for( i=0; pktlen > 4 && i < namelen; pktlen--, i++ )
+ pt->name[i] = iobuf_get_noeof(inp);
+ }
+ else {
+ for( i=0; i < namelen; i++ )
+ if( (c=iobuf_get(inp)) == -1 )
+ break;
+ else
+ pt->name[i] = c;
+ }
+ pt->timestamp = read_32(inp); if( pktlen) pktlen -= 4;
+ pt->len = pktlen;
+ pt->buf = inp;
+ pktlen = 0;
+
+ if( list_mode ) {
+ printf(":literal data packet:\n"
+ "\tmode %c, created %lu, name=\"",
+ mode >= ' ' && mode <'z'? mode : '?',
+ pt->timestamp );
+ for(p=pt->name,i=0; i < namelen; p++, i++ ) {
+ if( *p >= ' ' && *p <= 'z' )
+ putchar(*p);
+ else
+ printf("\\x%02x", *p );
+ }
+ printf("\",\n\traw data: %lu bytes\n", pt->len );
+ }
+
+ leave:
+ return 0;
+}
+
+
+static int
+parse_compressed( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
+{
+ PKT_compressed *zd;
+ int algorithm;
+
+ /* pktlen is here 0, but data follows
+ * (this should be the last object in a file or
+ * the compress algorithm should know the length)
+ */
+ zd = pkt->pkt.compressed = m_alloc(sizeof *pkt->pkt.compressed );
+ zd->len = 0; /* not yet used */
+ zd->algorithm = iobuf_get_noeof(inp);
+ zd->buf = inp;
+ algorithm = iobuf_get_noeof(inp);
+ if( list_mode )
+ printf(":compressed packet: algo=%d\n", zd->algorithm);
+ return 0;
+}
+
+
+static int
+parse_encrypted( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *pkt )
+{
+ PKT_encr_data *ed;
+
+ ed = pkt->pkt.encr_data = m_alloc(sizeof *pkt->pkt.encr_data );
+ ed->len = pktlen;
+ ed->buf = NULL;
+ if( pktlen && pktlen < 10 ) {
+ log_error("packet(%d) too short\n", pkttype);
+ skip_rest(inp, pktlen);
+ goto leave;
+ }
+ if( list_mode )
+ if( pktlen )
+ printf(":encrypted data packet:\n\tlength: %lu\n", pktlen-10);
+ else
+ printf(":encrypted data packet:\n\tlength: unknown\n");
+
+ ed->buf = inp;
+ pktlen = 0;
+
+ leave:
+ return 0;
+}
+
+
diff --git a/g10/passphrase.c b/g10/passphrase.c
new file mode 100644
index 000000000..c95b27bbd
--- /dev/null
+++ b/g10/passphrase.c
@@ -0,0 +1,126 @@
+/* passphrase.c - Get a passphrase
+ * 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 <string.h>
+#include <assert.h>
+#include "util.h"
+#include "memory.h"
+#include "ttyio.h"
+#include "cipher.h"
+
+
+static int hash_passphrase( DEK *dek, char *pw );
+
+
+/****************
+ * Get a passphrase for the secret key with KEYID, display TEXT
+ * if the user needs to enter the passphrase.
+ * Returns: m_alloced md5 passphrase hash; caller must free
+ */
+DEK *
+get_passphrase_hash( u32 *keyid, char *text )
+{
+ char *p=NULL, *pw;
+ DEK *dek;
+
+ if( keyid ) {
+ tty_printf("Need a pass phrase to unlock the secret key!\n");
+ tty_printf("KeyID: %08lX\n\n", keyid[1] );
+ }
+ if( keyid && (p=getenv("PGPPATHPHRASE")) ) {
+ pw = m_alloc_secure(strlen(p)+1);
+ strcpy(pw,p);
+ tty_printf("Taking it from $PGPPATHPHRASE !\n", keyid[1] );
+ }
+ else
+ pw = tty_get_hidden("Enter pass phrase: " );
+ dek = m_alloc_secure( sizeof *dek );
+ dek->algo = CIPHER_ALGO_BLOWFISH;
+ if( hash_passphrase( dek, pw ) )
+ log_bug("get_passphrase_hash\n");
+ m_free(pw); /* is allocated in secure memory, so it will be burned */
+ if( !p ) {
+ tty_kill_prompt();
+ tty_printf("\n\n");
+ }
+ return dek;
+}
+
+
+/****************
+ * This function is used to construct a DEK from a user input.
+ * It uses the default CIPHER
+ */
+int
+make_dek_from_passphrase( DEK *dek, int mode )
+{
+ char *pw, *pw2;
+ int rc=0;
+
+ pw = tty_get_hidden("Enter pass phrase: " );
+ tty_kill_prompt();
+ if( mode == 2 ) {
+ pw2 = tty_get_hidden("Repeat pass phrase: " );
+ if( strcmp(pw, pw2) ) {
+ m_free(pw2);
+ m_free(pw);
+ return G10ERR_PASSPHRASE;
+ }
+ m_free(pw2);
+ }
+ rc = hash_passphrase( dek, pw );
+ m_free(pw);
+ return rc;
+}
+
+
+static int
+hash_passphrase( DEK *dek, char *pw )
+{
+ int rc = 0;
+
+ dek->keylen = 0;
+ if( dek->algo == CIPHER_ALGO_IDEA ) {
+ MD5HANDLE md5;
+
+ md5 = md5_open(1);
+ md5_write( md5, pw, strlen(pw) );
+ md5_final( md5 );
+ dek->keylen = 16;
+ memcpy( dek->key, md5_read(md5), dek->keylen );
+ md5_close(md5);
+ }
+ else if( dek->algo == CIPHER_ALGO_BLOWFISH ) {
+ RMDHANDLE rmd;
+
+ rmd = rmd160_open(1);
+ rmd160_write( rmd, pw, strlen(pw) );
+ dek->keylen = 20;
+ memcpy( dek->key, rmd160_final(rmd), dek->keylen );
+ rmd160_close(rmd);
+ }
+ else
+ rc = G10ERR_UNSUPPORTED;
+ return rc;
+}
+
diff --git a/g10/plaintext.c b/g10/plaintext.c
new file mode 100644
index 000000000..be8047bd0
--- /dev/null
+++ b/g10/plaintext.c
@@ -0,0 +1,114 @@
+/* plaintext.c - process an plaintext packet
+ * 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 <string.h>
+#include <errno.h>
+#include "util.h"
+#include "memory.h"
+#include "options.h"
+#include "packet.h"
+#include "ttyio.h"
+
+
+/****************
+ * Handle a plaintext packet
+ */
+int
+handle_plaintext( PKT_plaintext *pt )
+{
+ char *fname;
+ FILE *fp = NULL;
+ int rc = 0;
+ int c;
+
+ /* create the filename as C string */
+ if( opt.outfile ) {
+ fname = m_alloc( strlen( opt.outfile ) + 1);
+ strcpy(fname, opt.outfile );
+ }
+ else {
+ fname = m_alloc( pt->namelen +1 );
+ memcpy( fname, pt->name, pt->namelen );
+ fname[pt->namelen] = 0;
+ }
+
+ if( !*fname ) { /* no filename given */
+ if( opt.outfile_is_stdout )
+ fp = stdout;
+ else {
+ log_error("no outputfile given\n");
+ goto leave;
+ }
+ }
+ else if( overwrite_filep( fname ) )
+ goto leave;
+
+ if( fp )
+ ;
+ else if( !(fp = fopen(fname,"wb")) ) {
+ log_error("Error creating '%s': %s\n", fname, strerror(errno) );
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+
+ if( pt->len ) {
+ for( ; pt->len; pt->len-- ) {
+ if( (c = iobuf_get(pt->buf)) == -1 ) {
+ log_error("Problem reading source\n");
+ rc = G10ERR_READ_FILE;
+ goto leave;
+ }
+ if( putc( c, fp ) == EOF ) {
+ log_error("Error writing to '%s': %s\n", fname, strerror(errno) );
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ }
+ }
+ else {
+ while( (c = iobuf_get(pt->buf)) != -1 ) {
+ if( putc( c, fp ) == EOF ) {
+ log_error("Error writing to '%s': %s\n",
+ fname, strerror(errno) );
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ }
+ iobuf_clear_eof(pt->buf);
+ }
+
+ if( fp && fp != stdout && fclose(fp) ) {
+ log_error("Error closing '%s': %s\n", fname, strerror(errno) );
+ fp = NULL;
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ fp = NULL;
+
+ leave:
+ if( fp && fp != stdout )
+ fclose(fp);
+ m_free(fname);
+ return rc;
+}
+
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
new file mode 100644
index 000000000..18c737c2d
--- /dev/null
+++ b/g10/pubkey-enc.c
@@ -0,0 +1,130 @@
+/* pubkey-enc.c - public key encoded packet handling
+ * 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 <string.h>
+#include <assert.h>
+#include "util.h"
+#include "memory.h"
+#include "packet.h"
+#include "mpi.h"
+#include "keydb.h"
+#include "cipher.h"
+
+
+/****************
+ * Get the session key from a pubkey enc paket and return
+ * it in DEK, which should have been allocated in secure memory.
+ */
+int
+get_session_key( PKT_pubkey_enc *k, DEK *dek )
+{
+ int i, j, c, rc = 0;
+ RSA_secret_key *skey = m_alloc_secure( sizeof *skey );
+ MPI dek_frame = mpi_alloc_secure(40);
+ u16 csum, csum2;
+
+ if( k->pubkey_algo != PUBKEY_ALGO_RSA ) {
+ rc = G10ERR_PUBKEY_ALGO; /* unsupported algorithm */
+ goto leave;
+ }
+
+ /* get the secret key for the given public key
+ * and decode the rsa_integer
+ */
+ if( (rc = get_seckey( skey, k->keyid )) )
+ goto leave;
+
+ if( DBG_CIPHER )
+ log_mpidump("Encr DEK frame:", k->d.rsa.rsa_integer );
+ rsa_secret( dek_frame, k->d.rsa.rsa_integer, skey );
+ /* Now get the DEK (data encryption key) from the dek_frame
+ *
+ * Old versions encode the DEK in in this format (msb is left):
+ *
+ * 0 1 DEK(16 bytes) CSUM(2 bytes) 0 RND(n bytes) 2
+ *
+ * Later versions encode the DEK like this:
+ *
+ * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
+ *
+ * RND are non-zero randow bytes.
+ * A is the cipher algorithm ( 1 for IDEA, 42 for blowfish )
+ * DEK is the encryption key (session key) with length k
+ * (16 for idea, 42 for blowfish)
+ * CSUM
+ */
+ if( DBG_CIPHER )
+ log_mpidump("DEK frame:", dek_frame );
+ for(i=0; mpi_getbyte(dek_frame, i) != -1; i++ )
+ ;
+ for(i--; i >= 0 && !(c=mpi_getbyte(dek_frame, i)); i--)
+ ; /* Skip leading zeroes */
+ if( i < 16 )
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
+ if( c == 1 && mpi_getbyte(dek_frame,0) == 2 ) {
+ log_error("old encoding of DEK is not supported\n");
+ rc = G10ERR_CIPHER_ALGO;
+ goto leave;
+ }
+ if( c != 2 ) /* somethink is wrong */
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
+ /* look for the zeor byte */
+ for(i--; i > 4 ; i-- )
+ if( !mpi_getbyte(dek_frame,i) )
+ break;
+ if( i <= 4 ) /* zero byte not found */
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
+ /* next byte indicates the used cipher */
+ switch( mpi_getbyte(dek_frame, --i ) ) {
+ case 1:
+ rc = G10ERR_NI_CIPHER;
+ goto leave;
+ case 42:
+ if( i != 22 ) /* length of blowfish is 20 (+2 bytes checksum) */
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
+ dek->algo = CIPHER_ALGO_BLOWFISH;
+ break;
+ default:
+ rc = G10ERR_CIPHER_ALGO;
+ goto leave;
+ }
+ /* copy the key to DEK and compare the checksum */
+ csum = mpi_getbyte(dek_frame, 1) << 8;
+ csum |= mpi_getbyte(dek_frame, 0);
+ dek->keylen = i - 2;
+ for( i--, csum2=0, j=0; i > 1; i-- )
+ csum2 += dek->key[j++] = mpi_getbyte(dek_frame, i);
+ if( csum != csum2 ) {
+ rc = G10ERR_WRONG_SECKEY;
+ goto leave;
+ }
+ if( DBG_CIPHER )
+ log_hexdump("DEK is:", dek->key, dek->keylen );
+
+ leave:
+ mpi_free(dek_frame);
+ m_free(skey);
+ return rc;
+}
+
+
diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c
new file mode 100644
index 000000000..3cae571ab
--- /dev/null
+++ b/g10/seckey-cert.c
@@ -0,0 +1,157 @@
+/* seckey-cert.c - secret key certifucate packet handling
+ * 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 <string.h>
+#include <assert.h>
+#include "util.h"
+#include "memory.h"
+#include "packet.h"
+#include "mpi.h"
+#include "keydb.h"
+#include "cipher.h"
+
+
+static u16
+checksum( byte *p )
+{
+ u16 n, a;
+
+ n = *p++ << 8;
+ n |= *p++;
+ for(a=0; n; n-- )
+ a += *p++;
+ return a;
+}
+
+
+/****************
+ * Check the secret key certificate
+ */
+int
+check_secret_key( PKT_seckey_cert *cert )
+{
+ IDEA_context idea_ctx; /* FIXME: allocate this in secure space ! */
+ byte iv[8];
+ byte *mpibuf;
+ u16 n;
+ MPI temp_mpi;
+ int res;
+ u32 keyid[2];
+
+#if IDEA_BLOCKSIZE != 8 || BLOWFISH_BLOCKSIZE != 8
+ #error unsupportted blocksize
+#endif
+
+ if( cert->pubkey_algo != PUBKEY_ALGO_RSA )
+ return G10ERR_PUBKEY_ALGO; /* unsupport algorithm */
+
+ if( cert->d.rsa.is_protected ) { /* remove the protection */
+ DEK *dek = NULL;
+ BLOWFISH_context *blowfish_ctx=NULL;
+
+ switch( cert->d.rsa.protect_algo ) {
+ case CIPHER_ALGO_NONE:
+ log_bug("unprotect seckey_cert is flagged protected\n");
+ break;
+ case CIPHER_ALGO_IDEA:
+ case CIPHER_ALGO_BLOWFISH:
+ mpi_get_keyid( cert->d.rsa.rsa_n , keyid );
+ dek = get_passphrase_hash( keyid, NULL );
+
+ /* idea_setkey( &idea_ctx, dpw );*/
+ m_free(dek); /* pw is in secure memory, so m_free() burns it */
+ memset( iv, 0, BLOWFISH_BLOCKSIZE );
+ if( cert->d.rsa.protect_algo == CIPHER_ALGO_IDEA ) {
+ idea_setiv( &idea_ctx, iv );
+ /* fixme: is it save to leave the IV unencrypted in the
+ * certificate or should we move it to secure storage? */
+ idea_decode_cfb( &idea_ctx, cert->d.rsa.protect.idea.iv,
+ cert->d.rsa.protect.idea.iv, 8 );
+ }
+ else {
+ blowfish_ctx = m_alloc_secure( sizeof *blowfish_ctx );
+ blowfish_setiv( blowfish_ctx, iv );
+ blowfish_decode_cfb( blowfish_ctx,
+ cert->d.rsa.protect.blowfish.iv,
+ cert->d.rsa.protect.blowfish.iv, 8 );
+ }
+ cert->d.rsa.calc_csum = 0;
+ #define X(a) do { \
+ mpibuf = (byte*)cert->d.rsa.rsa_##a; \
+ n = ((mpibuf[0] << 8) | mpibuf[1])-2; \
+ if( blowfish_ctx ) \
+ blowfish_decode_cfb( blowfish_ctx, \
+ mpibuf+4, mpibuf+4, n ); \
+ else \
+ idea_decode_cfb( &idea_ctx, mpibuf+4, mpibuf+4, n );\
+ cert->d.rsa.calc_csum += checksum( mpibuf ); \
+ cert->d.rsa.rsa_##a = mpi_decode_buffer( mpibuf ); \
+ m_free( mpibuf ); \
+ } while(0)
+ X(d);
+ X(p);
+ X(q);
+ X(u);
+ #undef X
+ m_free( blowfish_ctx );
+ cert->d.rsa.is_protected = 0;
+ #if 0
+ #define X(a) do { printf("\tRSA " #a ": "); \
+ mpi_print(stdout, cert->d.rsa.rsa_##a, 1 ); \
+ putchar('\n'); \
+ } while(0)
+ X(n);
+ X(e);
+ X(d);
+ X(p);
+ X(q);
+ X(u);
+ #undef X
+ #endif
+ /* now let's see wether we have used the right passphrase */
+ if( cert->d.rsa.calc_csum != cert->d.rsa.csum )
+ return G10ERR_BAD_PASS;
+ temp_mpi = mpi_alloc(40);
+ mpi_mul(temp_mpi, cert->d.rsa.rsa_p, cert->d.rsa.rsa_q );
+ res = mpi_cmp( temp_mpi, cert->d.rsa.rsa_n );
+ mpi_free(temp_mpi);
+ if( res )
+ return G10ERR_BAD_PASS;
+ break;
+
+ default:
+ return G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
+ }
+ }
+ /* must check the checksum here, because we didn't do it when
+ * parsing an unprotected certificate */
+ if( cert->d.rsa.calc_csum != cert->d.rsa.csum ) {
+ log_error("checksum in secret key certificate is wrong\n");
+ log_debug("stored csum=%04hx calculated csum=%04hx\n",
+ cert->d.rsa.csum, cert->d.rsa.calc_csum );
+ return G10ERR_CHECKSUM;
+ }
+ return 0;
+}
+
+
diff --git a/g10/seskey.c b/g10/seskey.c
new file mode 100644
index 000000000..d81697296
--- /dev/null
+++ b/g10/seskey.c
@@ -0,0 +1,101 @@
+/* seskey.c - make sesssion keys
+ * 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 <string.h>
+#include <assert.h>
+#include "util.h"
+#include "cipher.h"
+#include "mpi.h"
+
+
+
+/****************
+ * Make a session key and put it into DEK
+ */
+void
+make_session_key( DEK *dek )
+{
+ switch( dek->algo ) {
+ case CIPHER_ALGO_BLOWFISH:
+ dek->keylen = 20;
+ randomize_buffer( dek->key, dek->keylen, 1 );
+ break;
+
+ default: log_bug("invalid algo %d in make_session_key()\n");
+ }
+}
+
+
+/****************
+ * Encode the session key. NBITS is the number of bits which should be used
+ * for packing teh session key.
+ * returns: A mpi with the session key (caller must free)
+ */
+MPI
+encode_session_key( DEK *dek, unsigned nbits )
+{
+ int nframe = (nbits+7) / 8;
+ byte *p;
+ MPI frame;
+ int i,n,c;
+ u16 csum;
+
+ /* the current limitation is, that we can only use a session key
+ * which length is a multiple of BITS_PER_MPI_LIMB
+ * I think we can live with that.
+ */
+ if( dek->keylen + 7 > nframe || (nbits % BITS_PER_MPI_LIMB) || !nframe )
+ log_bug("can't encode a %d bit key in a %d bits frame\n",
+ dek->keylen*8, nbits );
+
+ /* We encode the session key in this way:
+ *
+ * 0 2 RND(n bytes) 0 A DEK(k bytes) CSUM(2 bytes)
+ *
+ * RND are non-zero random bytes.
+ * A is the cipher algorithm ( 42 for Blowfish )
+ * DEK is the encryption key (session key) length k depends on the
+ * cipher algorithm (20 is used with blowfish).
+ * CSUM is the 16 bit checksum over the DEK
+ */
+ frame = mpi_alloc_secure( nframe / BYTES_PER_MPI_LIMB );
+ csum = 0;
+ for( p = dek->key, i=0; i < dek->keylen; i++ )
+ csum += *p++;
+ mpi_putbyte(frame, 0, csum );
+ mpi_putbyte(frame, 1, csum >> 8 );
+ for(n=2,i=dek->keylen-1, p = dek->key; i >= 0; i--, n++ )
+ mpi_putbyte(frame, n, p[i] );
+ mpi_putbyte(frame, n++, dek->algo );
+ mpi_putbyte(frame, n++, 0 );
+ while( n < nframe-2 ) {
+ while( !(c = get_random_byte(1)) )
+ ;
+ mpi_putbyte(frame, n++, c );
+ }
+ mpi_putbyte(frame, n++, 2 );
+ mpi_putbyte(frame, n++, 0 );
+ assert( n == nframe );
+ return frame;
+}
+
diff --git a/g10/sig-check.c b/g10/sig-check.c
new file mode 100644
index 000000000..41ac89341
--- /dev/null
+++ b/g10/sig-check.c
@@ -0,0 +1,213 @@
+/* sig-check.c - Check a signature
+ * 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 <string.h>
+#include <assert.h>
+#include "util.h"
+#include "packet.h"
+#include "memory.h"
+#include "mpi.h"
+#include "keydb.h"
+#include "cipher.h"
+
+
+/****************
+ * Check the signature which is contained in the rsa_integer.
+ * The md5handle should be currently open, so that this function
+ * is able to append some data, before getting the digest.
+ */
+int
+signature_check( PKT_signature *sig, MD_HANDLE digest )
+{
+ PKT_pubkey_cert *pkc = m_alloc_clear( sizeof *pkc );
+ MPI result = mpi_alloc(35);
+ int rc=0, i, j, c, old_enc;
+ byte *dp;
+
+
+ if( get_pubkey( pkc, sig->keyid ) ) {
+ rc = G10ERR_NO_PUBKEY;
+ goto leave;
+ }
+
+ if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ RSA_public_key pkey;
+ pkey.n = pkc->d.rsa.rsa_n;
+ pkey.e = pkc->d.rsa.rsa_e;
+ rsa_public( result, sig->d.rsa.rsa_integer, &pkey );
+ }
+ else {
+ log_debug("signature_check: unsupported pubkey algo %d\n",
+ pkc->pubkey_algo );
+ rc = G10ERR_PUBKEY_ALGO;
+ goto leave;
+ }
+
+
+ /* Now RESULT contains the deciphered session key.
+ *
+ * The session key is stored in different ways:
+ *
+ * Old versions encodes the digest in in this format (msb is left):
+ *
+ * 0 1 MD5(16 bytes) 0 PAD(n bytes) 1
+ *
+ * Later versions encodes the digest like this:
+ *
+ * 0 1 PAD(n bytes) 0 ASN(18 bytes) MD(16 bytes)
+ *
+ * RIPE MD 160 digests are encoded like this:
+ *
+ * 0 42 PAD(n bytes) 0 ASN(18 bytes) MD(20 bytes)
+ *
+ * FIXME: we should use another ASN!
+ *
+ * PAD consists of FF bytes.
+ * ASN is here the constant: 3020300c06082a864886f70d020505000410
+ */
+ old_enc = 0;
+ for(i=j=0; (c=mpi_getbyte(result, i)) != -1; i++ ) {
+ if( !j ) {
+ if( !i && c != 1 )
+ break;
+ else if( i && c == 0xff )
+ ; /* skip the padding */
+ else if( i && !c )
+ j++;
+ else
+ break;
+ }
+ else if( ++j == 18 && c != 1 )
+ break;
+ else if( j == 19 && c == 0 ) {
+ old_enc++;
+ break;
+ }
+ }
+ if( old_enc ) {
+ log_error("old encoding scheme is not supported\n");
+ rc = G10ERR_GENERAL;
+ goto leave;
+ }
+
+ if( sig->d.rsa.digest_algo == DIGEST_ALGO_RMD160 ) {
+ static byte asn[18] = /* stored reverse FIXME: need other values*/
+ { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86,
+ 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 };
+
+ for(i=20,j=0; j < 18 && (c=mpi_getbyte(result, i)) != -1; i++, j++ )
+ if( asn[j] != c )
+ break;
+ if( j != 18 ) { /* ASN is wrong */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ if( !c ) {
+ for(; (c=mpi_getbyte(result, i)) != -1; i++ )
+ if( c != 0xff )
+ break;
+ if( c != 42 || mpi_getbyte(result, i) ) {
+ /* Padding or leading bytes in signature is wrong */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ if( mpi_getbyte(result, 19) != sig->d.rsa.digest_start[0]
+ || mpi_getbyte(result, 18) != sig->d.rsa.digest_start[1] ) {
+ /* Wrong key used to check the signature */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ }
+
+ /* complete the digest */
+ rmd160_putchar( digest.u.rmd, sig->sig_class );
+ { u32 a = sig->timestamp;
+ rmd160_putchar( digest.u.rmd, (a >> 24) & 0xff );
+ rmd160_putchar( digest.u.rmd, (a >> 16) & 0xff );
+ rmd160_putchar( digest.u.rmd, (a >> 8) & 0xff );
+ rmd160_putchar( digest.u.rmd, a & 0xff );
+ }
+ dp = rmd160_final( digest.u.rmd );
+ for(i=19; i >= 0; i--, dp++ )
+ if( mpi_getbyte( result, i ) != *dp ) {
+ rc = G10ERR_BAD_SIGN;
+ goto leave;
+ }
+ }
+ else if( sig->d.rsa.digest_algo == DIGEST_ALGO_MD5 ) {
+ static byte asn[18] = /* stored reverse */
+ { 0x10, 0x04, 0x00, 0x05, 0x05, 0x02, 0x0d, 0xf7, 0x86,
+ 0x48, 0x86, 0x2a, 0x08, 0x06, 0x0c, 0x30, 0x20, 0x30 };
+
+ for(i=16,j=0; j < 18 && (c=mpi_getbyte(result, i)) != -1; i++, j++ )
+ if( asn[j] != c )
+ break;
+ if( j != 18 ) { /* ASN is wrong */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ if( !c ) {
+ for(; (c=mpi_getbyte(result, i)) != -1; i++ )
+ if( c != 0xff )
+ break;
+ if( c != 1 || mpi_getbyte(result, i) ) {
+ /* Padding or leading bytes in signature is wrong */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ if( mpi_getbyte(result, 15) != sig->d.rsa.digest_start[0]
+ || mpi_getbyte(result, 14) != sig->d.rsa.digest_start[1] ) {
+ /* Wrong key used to check the signature */
+ rc = G10ERR_BAD_PUBKEY;
+ goto leave;
+ }
+ }
+
+ /* complete the digest */
+ md5_putchar( digest.u.md5, sig->sig_class );
+ { u32 a = sig->timestamp;
+ md5_putchar( digest.u.md5, (a >> 24) & 0xff );
+ md5_putchar( digest.u.md5, (a >> 16) & 0xff );
+ md5_putchar( digest.u.md5, (a >> 8) & 0xff );
+ md5_putchar( digest.u.md5, a & 0xff );
+ }
+ md5_final( digest.u.md5 );
+ dp = md5_read( digest.u.md5 );
+ for(i=15; i >= 0; i--, dp++ )
+ if( mpi_getbyte( result, i ) != *dp ) {
+ rc = G10ERR_BAD_SIGN;
+ goto leave;
+ }
+ }
+ else {
+ rc = G10ERR_DIGEST_ALGO;
+ goto leave;
+ }
+
+ leave:
+ mpi_free( result );
+ if( pkc )
+ free_pubkey_cert( pkc );
+ return rc;
+}
+