diff options
author | Werner Koch <wk@gnupg.org> | 1997-11-18 15:06:00 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 1997-11-18 15:06:00 +0100 |
commit | 5393dd53c5e06f0458949217317601b2eaed8350 (patch) | |
tree | c4b8d021851c32a611165c5fc215ad88604b5a94 /g10 | |
parent | New repository initialized by cvs2svn. (diff) | |
download | gnupg2-5393dd53c5e06f0458949217317601b2eaed8350.tar.xz gnupg2-5393dd53c5e06f0458949217317601b2eaed8350.zip |
initially checkin
Diffstat (limited to 'g10')
-rw-r--r-- | g10/Makefile.am | 33 | ||||
-rw-r--r-- | g10/Makefile.in | 285 | ||||
-rw-r--r-- | g10/build-packet.c | 386 | ||||
-rw-r--r-- | g10/checksig.c | 96 | ||||
-rw-r--r-- | g10/compressed.c | 114 | ||||
-rw-r--r-- | g10/encode.c | 470 | ||||
-rw-r--r-- | g10/encr-data.c | 122 | ||||
-rw-r--r-- | g10/filter.h | 35 | ||||
-rw-r--r-- | g10/free-packet.c | 198 | ||||
-rw-r--r-- | g10/g10.c | 219 | ||||
-rw-r--r-- | g10/getkey.c | 475 | ||||
-rw-r--r-- | g10/keydb.h | 45 | ||||
-rw-r--r-- | g10/keygen.c | 253 | ||||
-rw-r--r-- | g10/main.h | 35 | ||||
-rw-r--r-- | g10/mainproc.c | 275 | ||||
-rw-r--r-- | g10/mdfilter.c | 70 | ||||
-rw-r--r-- | g10/options.h | 68 | ||||
-rw-r--r-- | g10/overwrite.c | 79 | ||||
-rw-r--r-- | g10/packet.h | 214 | ||||
-rw-r--r-- | g10/parse-packet.c | 662 | ||||
-rw-r--r-- | g10/passphrase.c | 126 | ||||
-rw-r--r-- | g10/plaintext.c | 114 | ||||
-rw-r--r-- | g10/pubkey-enc.c | 130 | ||||
-rw-r--r-- | g10/seckey-cert.c | 157 | ||||
-rw-r--r-- | g10/seskey.c | 101 | ||||
-rw-r--r-- | g10/sig-check.c | 213 |
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; +} + |