aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--INSTALL26
-rw-r--r--README50
-rw-r--r--TODO12
-rw-r--r--cipher/Makefile.am2
-rw-r--r--cipher/Makefile.in3
-rw-r--r--configure.in16
-rw-r--r--g10/encode.c2
-rw-r--r--g10/g10.c47
-rw-r--r--g10/getkey.c13
-rw-r--r--g10/kbnode.c63
-rw-r--r--g10/keydb.h13
-rw-r--r--g10/keygen.c363
-rw-r--r--g10/keyid.c12
-rw-r--r--g10/main.h4
-rw-r--r--g10/mainproc.c14
-rw-r--r--g10/options.h2
-rw-r--r--g10/ringedit.c130
-rw-r--r--g10/seskey.c2
-rw-r--r--include/iobuf.h1
-rw-r--r--include/ttyio.h1
-rw-r--r--mpi/Makefile.am4
-rw-r--r--mpi/Makefile.in110
-rw-r--r--mpi/config.links51
-rw-r--r--util/argparse.c3
-rw-r--r--util/iobuf.c49
-rw-r--r--util/miscutil.c2
-rw-r--r--util/ttyio.c22
27 files changed, 750 insertions, 267 deletions
diff --git a/INSTALL b/INSTALL
index e69de29bb..2fb9f9871 100644
--- a/INSTALL
+++ b/INSTALL
@@ -0,0 +1,26 @@
+
+ 1) Configure for your machine:
+
+ ./configure
+
+ or use
+
+ ./configure --enable-m-debug
+
+ to ebanle the integrated malloc debugging stuff.
+
+
+ 2) Run make:
+
+ make
+
+
+ 3) Install
+
+ make install
+
+
+ 4) You end up with a binary "g10" in /usr/local/bin
+
+
+
diff --git a/README b/README
index e69de29bb..931839083 100644
--- a/README
+++ b/README
@@ -0,0 +1,50 @@
+
+ G10 - The GNU Enryption and Signing Tool
+ ------------------------------------------
+
+
+ THIS IS VERSION IS ONLY a TEST VERSION ! YOU SHOULD NOT
+ USE IT FOR OTHER PURPOSES THAN EVALUATING THE CURRENT CODE.
+
+ * The data format may change in the next version!
+
+ * The code to generate keys is not secure!
+
+ * Some features are not implemented
+
+
+ I provide this version as a reality check to start discussion.
+ Please subscribe to [email protected] be sending a mail with
+ the word "subscribe" in the body to "[email protected]".
+
+
+ See the file COPYING for copyright and warranty information.
+
+
+ Due to the fact that G10 does not use use any patented algorithm,
+ it cannot be compatible to old PGP versions, because those use
+ IDEA (which is worldwide patented) and RSA (which is patented in
+ the United States until Sep 20, 2000). I'm sorry about this, but
+ this is the world we have created (e.g. by using propiertary software).
+
+
+ Because the OpenPGP standard is still a draft, G10 is not yet
+ compatible to it (or PGP 5) - but it will. The data structures
+ used are compatible with PGP 2.x, so it can parse an list such files
+ and PGP should be able to parse data created by G10 and complain
+ about unsupported alogorithms.
+
+ The default algorithms used by G10 are ElGamal for public-key
+ encryption and signing; Blowfish with a 160 bit key for protecting
+ the secret-key components, conventional and session encryption;
+ RIPE MD-160 to create message digest. DSA, SHA-1 and CAST are
+ also implemented, but not used on default. I decided not
+ to use DSA as default signing algorithm, cecause it allows only for
+ 1024 bit keys and this may be not enough in a couple of years.
+
+ Key generation takes a long time and should be improved!
+
+
+
+
+
diff --git a/TODO b/TODO
index 486b40fc0..429148048 100644
--- a/TODO
+++ b/TODO
@@ -8,14 +8,10 @@
* keyring editing
* add trust stuff
* make ttyio.c work (hide passwords etc..)
- * add option file handling.
* use correct ASN values for DEK encoding
* add checking of armor trailers
* add real secure memory
* look for a way to reuse RSA signatures
- * find a way to remove the armor filter after it
- has detected, that the data is not armored.
- * Use the Chinese Remainder Theorem to speed up RSA calculations.
* remove all "Fixmes"
* speed up the RIPE-MD-160
* add signal handling
@@ -33,3 +29,11 @@
* complete cipher/cast.c
* complete cipher/dsa.c
+ * define a standard way to specify keyid/userid and other stuff
+ to identify a user. We could look at the first character and
+ say: If it's a digit, a keyid follows (need to add a zero in
+ case the keyid starts with A..F); if it is a left angle bracket,
+ this is a email address and should be used, all others are substrings
+ of the userid.
+ [can be handles in get_pubkey_by_name()]
+
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 40b131dd9..52de7fab5 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -24,6 +24,6 @@ cipher_SOURCES = blowfish.c \
md.c \
smallprime.c
-cipher_LIBADD = rsa.o
+##cipher_LIBADD = rsa.o
diff --git a/cipher/Makefile.in b/cipher/Makefile.in
index 8391d9e9c..2747e165f 100644
--- a/cipher/Makefile.in
+++ b/cipher/Makefile.in
@@ -60,8 +60,6 @@ cipher_SOURCES = blowfish.c \
dsa.c \
md.c \
smallprime.c
-
-cipher_LIBADD = rsa.o
mkinstalldirs = $(top_srcdir)/scripts/mkinstalldirs
CONFIG_HEADER = ../config.h
LIBRARIES = $(noinst_LIBRARIES)
@@ -80,6 +78,7 @@ LIBS = @LIBS@
COMPILE = $(CC) -c $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
LINK = $(CC) $(LDFLAGS) -o $@
+cipher_LIBADD =
cipher_OBJECTS = blowfish.o elgamal.o gost.o md5.o primegen.o random.o \
rmd160.o sha1.o dsa.o md.o smallprime.o
EXTRA_cipher_SOURCES =
diff --git a/configure.in b/configure.in
index 4575bc888..2c09e1a18 100644
--- a/configure.in
+++ b/configure.in
@@ -22,21 +22,20 @@ fi
CFLAGS="-g"
dnl
-AC_CANONICAL_HOST
+AC_CANONICAL_SYSTEM
AC_MSG_CHECKING(cached information)
-hostcheck="$host"
+hostcheck="$target"
AC_CACHE_VAL(ac_cv_mpi_hostcheck, [ ac_cv_mpi_hostcheck="$hostcheck" ])
if test "$ac_cv_mpi_hostcheck" != "$hostcheck"; then
AC_MSG_RESULT(changed)
AC_MSG_WARN(config.cache exists!)
AC_MSG_ERROR(you must do 'make distclean' first to compile for
-different host or different parameters.)
+different target or different parameters.)
else
AC_MSG_RESULT(ok)
fi
-
dnl Checks for programs.
AC_PROG_MAKE_SET
@@ -71,8 +70,12 @@ AC_CHECK_FUNCS(strerror strtol strtoul)
dnl setup assembler stuff
-
-
+if test -f ./mpi/config.links ; then
+ . ./mpi/config.links
+ AC_LINK_FILES( ${mpi_ln_src}, ${mpi_ln_dst} )
+else
+ AC_MSG_ERROR([mpi/config.links missing!])
+fi
@@ -91,6 +94,7 @@ fi
AC_SUBST(add_cipher_SOURCES)
AC_OUTPUT([ Makefile scripts/Makefile util/Makefile mpi/Makefile \
+ mpi/generic/Makefile mpi/i386/Makefile \
cipher/Makefile \
include/Makefile \
g10/Makefile tools/Makefile ],
diff --git a/g10/encode.c b/g10/encode.c
index 3bcdbe909..53d03c038 100644
--- a/g10/encode.c
+++ b/g10/encode.c
@@ -218,7 +218,7 @@ encode_crypt( const char *filename, STRLIST remusr )
pkc = m_alloc_clear( sizeof *pkc );
pkc->pubkey_algo = DEFAULT_PUBKEY_ALGO;
- if( (rc = get_pubkey_by_name( pkc, remusr->d )) ) {
+ if( (rc = get_pubkey_byname( pkc, remusr->d )) ) {
last_rc = rc;
log_error("skipped '%s': %s\n", remusr->d, g10_errstr(rc) );
continue;
diff --git a/g10/g10.c b/g10/g10.c
index 495875ce2..777220aa1 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -125,20 +125,21 @@ main( int argc, char **argv )
{ 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, "\rgenerate a prime of length n" },
- { 514, "test" , 0, "\rdevelopment usage" },
+ { 513, "gen-prime" , 1, "\r" },
+ { 514, "test" , 0, "\r" },
{ 515, "change-passphrase", 0, "change the passphrase of your secret keyring"},
{ 515, "fingerprint", 0, "show the fingerprints"},
{ 516, "print-mds" , 0, "print all message digests"},
{ 517, "secret-keyring" ,2, "add this secret keyring to the list" },
{ 518, "config" , 2, "use this config file" },
+ { 519, "no-armor", 0, "\r"},
{0} };
ARGPARSE_ARGS pargs;
IOBUF a;
int rc;
enum { aNull, aSym, aStore, aEncr, aPrimegen, aKeygen, aSign, aSignEncr,
- aTest, aPrintMDs,
+ aTest, aPrintMDs, aSignKey,
} action = aNull;
int orig_argc;
char **orig_argv;
@@ -189,7 +190,7 @@ main( int argc, char **argv )
configfp = fopen( configname, "r" );
if( !configfp ) {
if( default_config ) {
- if( parse_verbose )
+ if( parse_verbose > 1 )
log_info("note: no default option file '%s'\n", configname );
}
else
@@ -197,7 +198,7 @@ main( int argc, char **argv )
configname, strerror(errno) );
m_free(configname); configname = NULL;
}
- if( parse_verbose )
+ if( parse_verbose > 1 )
log_info("reading options from '%s'\n", configname );
default_config = 0;
}
@@ -209,7 +210,7 @@ main( int argc, char **argv )
opt.list_sigs=1;
break;
case 'z': opt.compress = pargs.r.ret_int; break;
- case 'a': opt.armor = 1; break;
+ case 'a': opt.armor = 1; opt.no_armor=0; break;
case 'c': action = aSym; break;
case 'o': opt.outfile = pargs.r.ret_str;
if( opt.outfile[0] == '-' && !opt.outfile[1] )
@@ -235,6 +236,7 @@ main( int argc, char **argv )
case 501: opt.answer_yes = 1; break;
case 502: opt.answer_no = 1; break;
case 503: action = aKeygen; break;
+ case 506: action = aSignKey; break;
case 507: action = aStore; break;
case 508: opt.check_sigs = 1; opt.list_sigs = 1; break;
case 509: add_keyring(pargs.r.ret_str); nrings++; break;
@@ -254,6 +256,7 @@ main( int argc, char **argv )
goto next_pass;
}
break;
+ case 519: opt.no_armor=1; opt.armor=0; break;
default : errors++; pargs.err = configfp? 1:2; break;
}
}
@@ -270,7 +273,7 @@ main( int argc, char **argv )
set_debug();
if( opt.verbose > 1 )
set_packet_list_mode(1);
- if( !opt.batch && isatty(fileno(stdin)) ) {
+ if( opt.verbose && isatty(fileno(stdin)) ) {
if( *(s=strusage(10)) )
fputs(s, stderr);
if( *(s=strusage(30)) )
@@ -278,11 +281,14 @@ main( int argc, char **argv )
}
if( !sec_nrings ) { /* add default secret rings */
- add_keyring("../keys/secring.g10");
+ char *p = make_filename("~/.g10", "secring.g10", NULL );
+ add_secret_keyring(p);
+ m_free(p);
}
- if( !nrings ) { /* add default rings */
- add_keyring("../keys/ring.pgp");
- add_keyring("../keys/pubring.g10");
+ if( !nrings ) { /* add default ring */
+ char *p = make_filename("~/.g10", "pubring.g10", NULL );
+ add_keyring(p);
+ m_free(p);
}
if( argc ) {
@@ -323,10 +329,21 @@ main( int argc, char **argv )
log_error("sign_file('%s'): %s\n", fname_print, g10_errstr(rc) );
break;
+
case aSignEncr: /* sign and encrypt the given file */
usage(1); /* FIXME */
break;
+
+ case aSignKey: /* sign the key given as argument */
+ if( argc != 1 )
+ usage(1);
+ /* note: fname is the user id! */
+ if( (rc = sign_key(fname, locusr)) )
+ log_error("sign_key('%s'): %s\n", fname_print, g10_errstr(rc) );
+ break;
+
+
case aPrimegen:
if( argc )
usage(1);
@@ -356,9 +373,11 @@ main( int argc, char **argv )
usage(1);
if( !(a = iobuf_open(fname)) )
log_fatal("can't open '%s'\n", fname_print);
- /* push the armor filter, so it can peek at the input data */
- memset( &afx, 0, sizeof afx);
- iobuf_push_filter( a, armor_filter, &afx );
+ if( !opt.no_armor ) {
+ /* push the armor filter, so it can peek at the input data */
+ memset( &afx, 0, sizeof afx);
+ iobuf_push_filter( a, armor_filter, &afx );
+ }
proc_packets( a );
iobuf_close(a);
break;
diff --git a/g10/getkey.c b/g10/getkey.c
index b079cca19..67b86ccf3 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -83,9 +83,9 @@ add_keyring( const char *name )
* combine it with the keyblock stuff from ringedit.c
* For now we will simple add the filename as keyblock resource
*/
- rc = add_keyblock_resource( name );
+ rc = add_keyblock_resource( name, 0 );
if( rc )
- log_error("keyblock resource '%s': %s\n", name, rc );
+ log_error("keyblock resource '%s': %s\n", name, g10_errstr(rc) );
}
void
@@ -245,7 +245,7 @@ get_pubkey( PKT_public_cert *pkc, u32 *keyid )
* a pubkey with that algo.
*/
int
-get_pubkey_by_name( PKT_public_cert *pkc, const char *name )
+get_pubkey_byname( PKT_public_cert *pkc, const char *name )
{
int internal = 0;
int rc = 0;
@@ -304,7 +304,7 @@ get_seckey( PKT_secret_cert *skc, u32 *keyid )
* If NAME is NULL use the default certificate
*/
int
-get_seckey_by_name( PKT_secret_cert *skc, const char *name )
+get_seckey_byname( PKT_secret_cert *skc, const char *name, int unprotect )
{
STRLIST sl;
int rc=0;
@@ -319,8 +319,9 @@ get_seckey_by_name( PKT_secret_cert *skc, const char *name )
/* get the secret key (this may prompt for a passprase to
* unlock the secret key
*/
- if( (rc = check_secret_key( skc )) )
- goto leave;
+ if( unprotect )
+ if( (rc = check_secret_key( skc )) )
+ goto leave;
leave:
return rc;
diff --git a/g10/kbnode.c b/g10/kbnode.c
index d148cb450..a4ac40dc5 100644
--- a/g10/kbnode.c
+++ b/g10/kbnode.c
@@ -57,6 +57,36 @@ release_kbnode( KBNODE n )
/****************
+ * Append NODE to ROOT, ROOT must exist!
+ */
+void
+add_kbnode( KBNODE root, KBNODE node )
+{
+ KBNODE n1;
+
+ for(n1=root; n1->next; n1 = n1->next)
+ ;
+ n1->next = node;
+}
+
+/****************
+ * Append NODE to ROOT as child of ROOT
+ */
+void
+add_kbnode_as_child( KBNODE root, KBNODE node )
+{
+ KBNODE n1;
+
+ if( !(n1=root->child) )
+ root->child = node;
+ else {
+ for( ; n1->next; n1 = n1->next)
+ ;
+ n1->next = node;
+ }
+}
+
+/****************
* Return the parent node of KBNODE from the tree with ROOT
*/
KBNODE
@@ -72,8 +102,39 @@ find_kbparent( KBNODE root, KBNODE node )
}
}
}
- log_bug(NULL);
+ return NULL;
}
+/****************
+ * Walk through a tree of kbnodes. This functions returns
+ * the next kbnode for each call; before using the function the first
+ * time, the caller must set CONTEXT to NULL (This has simply the effect
+ * to start with ROOT).
+ */
+KBNODE
+walk_kbtree( KBNODE root, KBNODE *context )
+{
+ KBNODE n;
+
+ if( !*context ) {
+ *context = root;
+ return root;
+ }
+
+ n = *context;
+ if( n->child ) {
+ n = n->child;
+ *context = n;
+ }
+ else if( n->next ) {
+ n = n->next;
+ *context = n;
+ }
+ else if( (n = find_kbparent( root, n )) ) {
+ n = n->next;
+ *context = n;
+ }
+ return n;
+}
diff --git a/g10/keydb.h b/g10/keydb.h
index a81b258d7..58e62da48 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -66,13 +66,14 @@ void add_secret_keyring( const char *name );
void cache_public_cert( PKT_public_cert *pkc );
void cache_user_id( PKT_user_id *uid, u32 *keyid );
int get_pubkey( PKT_public_cert *pkc, u32 *keyid );
-int get_pubkey_by_name( PKT_public_cert *pkc, const char *name );
+int get_pubkey_byname( PKT_public_cert *pkc, const char *name );
int get_seckey( PKT_secret_cert *skc, u32 *keyid );
-int get_seckey_by_name( PKT_secret_cert *skc, const char *name );
+int get_seckey_byname( PKT_secret_cert *skc, const char *name, int unlock );
char*get_user_id_string( u32 *keyid );
char*get_user_id( u32 *keyid, size_t *rn );
/*-- keyid.c --*/
+int pubkey_letter( int algo );
u32 keyid_from_skc( PKT_secret_cert *skc, u32 *keyid );
u32 keyid_from_pkc( PKT_public_cert *pkc, u32 *keyid );
u32 keyid_from_sig( PKT_signature *sig, u32 *keyid );
@@ -87,14 +88,18 @@ byte *fingerprint_from_pkc( PKT_public_cert *pkc, size_t *ret_len );
/*-- kbnode.c --*/
KBNODE new_kbnode( PACKET *pkt );
void release_kbnode( KBNODE n );
+void add_kbnode( KBNODE root, KBNODE node );
+void add_kbnode_as_child( KBNODE root, KBNODE node );
KBNODE find_kbparent( KBNODE root, KBNODE node );
+KBNODE walk_kbtree( KBNODE root, KBNODE *context );
/*-- ringedit.c --*/
-int add_keyblock_resource( const char *filename );
+int add_keyblock_resource( const char *filename, int force );
int get_keyblock_handle( const char *filename, KBPOS *kbpos );
int search_keyblock( PACKET *pkt, KBPOS *kbpos );
+int search_keyblock_byname( KBPOS *kbpos, const char *username );
int lock_keyblock( KBPOS *kbpos );
-int unlock_keyblock( KBPOS *kbpos );
+void unlock_keyblock( KBPOS *kbpos );
int read_keyblock( KBPOS *kbpos, KBNODE *ret_root );
int insert_keyblock( KBPOS *kbpos, KBNODE root );
int delete_keyblock( KBPOS *kbpos );
diff --git a/g10/keygen.c b/g10/keygen.c
index a4ed697c4..47bc2b14f 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -30,6 +30,7 @@
#include "cipher.h"
#include "ttyio.h"
#include "options.h"
+#include "keydb.h"
#if 0
#define TEST_ALGO 1
@@ -88,52 +89,128 @@ checksum_mpi( MPI a )
static void
-write_uid( IOBUF out, const char *s, PKT_user_id **upkt )
+write_uid( KBNODE root, const char *s )
{
- PACKET pkt;
+ PACKET *pkt = m_alloc_clear(sizeof *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) );
- if( upkt ) {
- *upkt = pkt.pkt.user_id;
- pkt.pkt.user_id = NULL;
- }
- free_packet( &pkt );
+ 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);
+ add_kbnode( root, new_kbnode( pkt ) );
}
static int
-write_selfsig( IOBUF out, PKT_public_cert *pkc, PKT_user_id *uid,
- PKT_secret_cert *skc )
+write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_cert *skc )
{
- PACKET pkt;
+ PACKET *pkt;
PKT_signature *sig;
+ PKT_user_id *uid;
int rc=0;
+ KBNODE kbctx, node;
+ PKT_public_cert *pkc;
if( opt.verbose )
log_info("writing self signature\n");
+ /* get the uid packet from the tree */
+ for( kbctx=NULL; (node=walk_kbtree( root, &kbctx)) ; ) {
+ if( node->pkt->pkttype == PKT_USER_ID )
+ break;
+ }
+ if( !node )
+ log_bug(NULL); /* no user id packet in tree */
+ uid = node->pkt->pkt.user_id;
+ /* get the pkc packet from the pub_tree */
+ for( kbctx=NULL; (node=walk_kbtree( pub_root, &kbctx)) ; ) {
+ if( node->pkt->pkttype == PKT_PUBLIC_CERT )
+ break;
+ }
+ if( !node )
+ log_bug(NULL);
+ pkc = node->pkt->pkt.public_cert;
+
+ /* and make the signature */
rc = make_keysig_packet( &sig, pkc, uid, skc, 0x13, DIGEST_ALGO_RMD160 );
if( rc ) {
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
}
- pkt.pkttype = PKT_SIGNATURE;
- pkt.pkt.signature = sig;
- if( (rc = build_packet( out, &pkt )) )
- log_error("build_packet(signature) failed: %s\n", g10_errstr(rc) );
- free_packet( &pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
+ pkt->pkttype = PKT_SIGNATURE;
+ pkt->pkt.signature = sig;
+ add_kbnode( root, new_kbnode( pkt ) );
return rc;
}
+static int
+gen_elg(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
+ PKT_secret_cert **ret_skc )
+{
+ int rc;
+ PACKET *pkt;
+ PKT_secret_cert *skc;
+ PKT_public_cert *pkc;
+ ELG_public_key pk;
+ ELG_secret_key sk;
+ unsigned nbytes;
+
+ elg_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_ELGAMAL;
+ memset(&pkc->mfx, 0, sizeof pkc->mfx);
+ pkc->d.elg.p = pk.p;
+ pkc->d.elg.g = pk.g;
+ pkc->d.elg.y = pk.y;
+ skc->d.elg.p = sk.p;
+ skc->d.elg.g = sk.g;
+ skc->d.elg.y = sk.y;
+ skc->d.elg.x = sk.x;
+
+ skc->d.elg.csum = checksum_mpi( skc->d.elg.x );
+ /* return an unprotected version of the skc */
+ *ret_skc = copy_secret_cert( NULL, skc );
+
+ if( !dek ) {
+ skc->d.elg.is_protected = 0;
+ skc->d.elg.protect_algo = 0;
+ }
+ else {
+ skc->d.elg.is_protected = 0;
+ skc->d.elg.protect_algo = CIPHER_ALGO_BLOWFISH;
+ randomize_buffer(skc->d.elg.protect.blowfish.iv, 8, 1);
+ rc = protect_secret_key( skc, dek );
+ if( rc ) {
+ log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
+ free_public_cert(pkc);
+ free_secret_cert(skc);
+ return rc;
+ }
+ }
+
+ pkt = m_alloc_clear(sizeof *pkt);
+ pkt->pkttype = PKT_PUBLIC_CERT;
+ pkt->pkt.public_cert = pkc;
+ add_kbnode(pub_root, new_kbnode( pkt ));
+
+ pkt = m_alloc_clear(sizeof *pkt);
+ pkt->pkttype = PKT_SECRET_CERT;
+ pkt->pkt.secret_cert = skc;
+ add_kbnode(sec_root, new_kbnode( pkt ));
+
+ return 0;
+}
+
+
+
#ifdef HAVE_RSA_CIPHER
static int
gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek,
@@ -210,79 +287,12 @@ gen_rsa(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek,
}
#endif /*HAVE_RSA_CIPHER*/
+
static int
-gen_elg(unsigned nbits, IOBUF pub_io, IOBUF sec_io, DEK *dek,
- PKT_public_cert **ret_pkc, PKT_secret_cert **ret_skc )
+gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
+ PKT_secret_cert **ret_skc )
{
- int rc;
- PACKET pkt1, pkt2;
- PKT_secret_cert *skc, *unprotected_skc;
- PKT_public_cert *pkc;
- ELG_public_key pk;
- ELG_secret_key sk;
- unsigned nbytes;
-
- init_packet(&pkt1);
- init_packet(&pkt2);
-
- elg_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_ELGAMAL;
- memset(&pkc->mfx, 0, sizeof pkc->mfx);
- pkc->d.elg.p = pk.p;
- pkc->d.elg.g = pk.g;
- pkc->d.elg.y = pk.y;
- skc->d.elg.p = sk.p;
- skc->d.elg.g = sk.g;
- skc->d.elg.y = sk.y;
- skc->d.elg.x = sk.x;
-
- skc->d.elg.csum = checksum_mpi( skc->d.elg.x );
- unprotected_skc = copy_secret_cert( NULL, skc );
- if( !dek ) {
- skc->d.elg.is_protected = 0;
- skc->d.elg.protect_algo = 0;
- }
- else {
- skc->d.elg.is_protected = 0;
- skc->d.elg.protect_algo = CIPHER_ALGO_BLOWFISH;
- randomize_buffer(skc->d.elg.protect.blowfish.iv, 8, 1);
- rc = protect_secret_key( skc, dek );
- if( rc ) {
- log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
- goto leave;
- }
- }
-
- pkt1.pkttype = PKT_PUBLIC_CERT;
- pkt1.pkt.public_cert = pkc;
- pkt2.pkttype = PKT_SECRET_CERT;
- pkt2.pkt.secret_cert = skc;
-
- if( (rc = build_packet( pub_io, &pkt1 )) ) {
- log_error("build public_cert packet failed: %s\n", g10_errstr(rc) );
- goto leave;
- }
- if( (rc = build_packet( sec_io, &pkt2 )) ) {
- log_error("build secret_cert packet failed: %s\n", g10_errstr(rc) );
- goto leave;
- }
- *ret_pkc = pkt1.pkt.public_cert;
- pkt1.pkt.public_cert = NULL;
- *ret_skc = unprotected_skc;
- unprotected_skc = NULL;
-
-
- leave:
- free_packet(&pkt1);
- free_packet(&pkt2);
- if( unprotected_skc )
- free_secret_cert( unprotected_skc );
- return rc;
+ return G10ERR_GENERAL;
}
@@ -295,14 +305,14 @@ generate_keypair()
{
char *answer;
unsigned nbits;
- char *pub_fname = "./pubring.g10";
- char *sec_fname = "./secring.g10";
+ char *pub_fname = NULL;
+ char *sec_fname = NULL;
char *uid = NULL;
IOBUF pub_io = NULL;
IOBUF sec_io = NULL;
- PKT_public_cert *pkc = NULL;
+ KBNODE pub_root = NULL;
+ KBNODE sec_root = NULL;
PKT_secret_cert *skc = NULL;
- PKT_user_id *upkt = NULL;
DEK *dek = NULL;
int rc;
int algo;
@@ -315,8 +325,9 @@ generate_keypair()
tty_printf("Please select the algorithm to use:\n"
" (1) ElGamal is the suggested one.\n"
#ifdef HAVE_RSA_CIPHER
- " (2) RSA cannot be used inthe U.S.\n"
+ " (2) RSA cannot be used in the U.S.\n"
#endif
+ " (3) DSA can only be used for signatures.\n"
);
#endif
@@ -324,7 +335,11 @@ generate_keypair()
#ifdef TEST_ALGO
algo = TEST_ALGO;
#else
- answer = tty_get("Your selection? (1,2) ");
+ answer = tty_get("Your selection? (1"
+ #ifdef HAVE_RSA_CIPHER
+ ",2"
+ #endif
+ ",3) ");
tty_kill_prompt();
algo = *answer? atoi(answer): 1;
m_free(answer);
@@ -341,6 +356,11 @@ generate_keypair()
break;
}
#endif
+ else if( algo == 3 ) {
+ algo = PUBKEY_ALGO_DSA;
+ algo_name = "DSA";
+ break;
+ }
}
@@ -361,7 +381,9 @@ generate_keypair()
nbits = *answer? atoi(answer): 1024;
m_free(answer);
#endif
- if( nbits < 128 ) /* FIXME: change this to 768 */
+ if( algo == PUBKEY_ALGO_DSA && (nbits < 512 || nbits > 1024) )
+ tty_printf("DSA does only allow keysizes from 512 to 1024\n");
+ else 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 "
@@ -381,7 +403,11 @@ generate_keypair()
break;
}
tty_printf("Requested keysize is %u bits\n", nbits );
- if( (nbits % 32) ) {
+ if( algo == PUBKEY_ALGO_DSA && (nbits % 64) ) {
+ nbits = ((nbits + 63) / 64) * 64;
+ tty_printf("rounded up to %u bits\n", nbits );
+ }
+ else if( (nbits % 32) ) {
nbits = ((nbits + 31) / 32) * 32;
tty_printf("rounded up to %u bits\n", nbits );
}
@@ -435,74 +461,103 @@ generate_keypair()
}
- /* 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;
+ /* now check wether we a are allowed to write to the keyrings */
+ pub_fname = make_filename("~/.g10", "pubring.g10", NULL );
+ sec_fname = make_filename("~/.g10", "secring.g10", NULL );
+ if( opt.verbose ) {
+ tty_printf("writing public certificate to '%s'\n", pub_fname );
+ tty_printf("writing secret certificate to '%s'\n", sec_fname );
}
- write_comment( pub_io, "#public key created by G10 pre-release " VERSION );
- write_comment( sec_io, "#secret key created by G10 pre-release " VERSION );
+ /* we create the packets as a tree of kbnodes. Because the structure
+ * we create is known in advance we simply generate a linked list
+ * The first packet is a comment packet, followed by the userid and
+ * the self signature.
+ */
+ pub_root = make_comment_node("#created by G10 pre-release " VERSION );
+ sec_root = make_comment_node("#created by G10 pre-release " VERSION );
if( algo == PUBKEY_ALGO_ELGAMAL )
- rc = gen_elg(nbits, pub_io, sec_io, dek, &pkc, &skc);
+ rc = gen_elg(nbits, pub_root, sec_root, dek, &skc );
#ifdef HAVE_RSA_CIPHER
else if( algo == PUBKEY_ALGO_RSA )
- rc = gen_rsa(nbits, pub_io, sec_io, dek, &pkc, &skc);
+ rc = gen_rsa(nbits, pub_io, sec_io, dek, &skc );
#endif
+ else if( algo == PUBKEY_ALGO_DSA )
+ rc = gen_dsa(nbits, pub_root, sec_root, dek, &skc );
else
log_bug(NULL);
if( !rc )
- write_uid(pub_io, uid, &upkt );
+ write_uid(pub_root, uid );
+ if( !rc )
+ write_uid(sec_root, uid );
if( !rc )
- write_uid(sec_io, uid, NULL );
+ rc = write_selfsig(pub_root, pub_root, skc);
if( !rc )
- rc = write_selfsig(pub_io, pkc, upkt, skc );
+ rc = write_selfsig(sec_root, pub_root, skc);
- if( rc ) {
- iobuf_cancel(pub_io);
- iobuf_cancel(sec_io);
- tty_printf("Key generation failed: %s\n", g10_errstr(rc) );
- }
- else {
- iobuf_close(pub_io);
- iobuf_close(sec_io);
- tty_printf("public and secret key created and signed.\n" );
+ if( !rc ) {
+ KBPOS pub_kbpos;
+ KBPOS sec_kbpos;
+ int rc1 = -1;
+ int rc2 = -1;
+
+ /* we can now write the certificates */
+ /* FIXME: should we check wether the user-id already exists? */
+
+ if( get_keyblock_handle( pub_fname, &pub_kbpos ) ) {
+ if( add_keyblock_resource( pub_fname, 1 ) ) {
+ log_error("can add keyblock file '%s'\n", pub_fname );
+ rc = G10ERR_CREATE_FILE;
+ }
+ else if( get_keyblock_handle( pub_fname, &pub_kbpos ) ) {
+ log_error("can get keyblock handle for '%s'\n", pub_fname );
+ rc = G10ERR_CREATE_FILE;
+ }
+ }
+ if( rc )
+ ;
+ else if( get_keyblock_handle( sec_fname, &sec_kbpos ) ) {
+ if( add_keyblock_resource( sec_fname, 1 ) ) {
+ log_error("can add keyblock file '%s'\n", sec_fname );
+ rc = G10ERR_CREATE_FILE;
+ }
+ else if( get_keyblock_handle( sec_fname, &sec_kbpos ) ) {
+ log_error("can get keyblock handle for '%s'\n", sec_fname );
+ rc = G10ERR_CREATE_FILE;
+ }
+ }
+
+ if( rc )
+ ;
+ else if( (rc=rc1=lock_keyblock( &pub_kbpos )) )
+ log_error("can't lock public keyring: %s\n", g10_errstr(rc) );
+ else if( (rc=rc2=lock_keyblock( &sec_kbpos )) )
+ log_error("can't lock secret keyring: %s\n", g10_errstr(rc) );
+ else if( (rc=insert_keyblock( &pub_kbpos, pub_root )) )
+ log_error("can't write public key: %s\n", g10_errstr(rc) );
+ else if( (rc=insert_keyblock( &sec_kbpos, sec_root )) )
+ log_error("can't write secret key: %s\n", g10_errstr(rc) );
+ else {
+ tty_printf("public and secret key created and signed.\n" );
+ }
+
+ if( !rc1 )
+ unlock_keyblock( &pub_kbpos );
+ if( !rc2 )
+ unlock_keyblock( &sec_kbpos );
}
- if( pkc )
- free_public_cert( pkc );
- if( skc )
- free_secret_cert( skc );
- if( upkt )
- free_user_id( upkt );
+
+
+ if( rc )
+ tty_printf("Key generation failed: %s\n", g10_errstr(rc) );
+ release_kbnode( pub_root );
+ release_kbnode( sec_root );
+ if( skc ) /* the unprotected secret certificate */
+ free_secret_cert(skc);
m_free(uid);
m_free(dek);
+ m_free(pub_fname);
+ m_free(sec_fname);
}
diff --git a/g10/keyid.c b/g10/keyid.c
index e3a16d86b..307e28c61 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -33,6 +33,18 @@
#include "keydb.h"
+int
+pubkey_letter( int algo )
+{
+ switch( algo ) {
+ case PUBKEY_ALGO_RSA: return 'R' ;
+ case PUBKEY_ALGO_RSA_E: return 'r' ;
+ case PUBKEY_ALGO_RSA_S: return 's' ;
+ case PUBKEY_ALGO_ELGAMAL: return 'G' ;
+ case PUBKEY_ALGO_DSA: return 'D' ;
+ default: return '?';
+ }
+}
/****************
diff --git a/g10/main.h b/g10/main.h
index 8be922b8a..13e20a750 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -22,6 +22,7 @@
#include "types.h"
#include "iobuf.h"
#include "cipher.h"
+#include "keydb.h"
#define DEFAULT_CIPHER_ALGO CIPHER_ALGO_BLOWFISH
#define DEFAULT_PUBKEY_ALGO PUBKEY_ALGO_ELGAMAL
@@ -34,6 +35,7 @@ int encode_crypt( const char *filename, STRLIST remusr );
/*-- sign.c --*/
int sign_file( const char *filename, int detached, STRLIST locusr );
+int sign_key( const char *username, STRLIST locusr );
/*-- keygen.c --*/
void generate_keypair(void);
@@ -49,5 +51,7 @@ MPI encode_rmd160_value( byte *md, unsigned len, unsigned nbits );
MPI encode_md5_value( byte *md, unsigned len, unsigned nbits );
MPI encode_md_value( MD_HANDLE *md, unsigned nbits );
+/*-- comment.c --*/
+KBNODE make_comment_node( const char *s );
#endif /*G10_MAIN_H*/
diff --git a/g10/mainproc.c b/g10/mainproc.c
index a8b621289..8bee0de09 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -56,19 +56,6 @@ typedef struct {
static void list_node( CTX c, KBNODE node );
static void proc_tree( CTX c, KBNODE node );
-static int
-pubkey_letter( int algo )
-{
- switch( algo ) {
- case PUBKEY_ALGO_RSA: return 'R' ;
- case PUBKEY_ALGO_RSA_E: return 'r' ;
- case PUBKEY_ALGO_RSA_S: return 's' ;
- case PUBKEY_ALGO_ELGAMAL: return 'G' ;
- case PUBKEY_ALGO_DSA: return 'D' ;
- default: return '?';
- }
-}
-
static void
release_cert( CTX c )
@@ -509,7 +496,6 @@ proc_packets( IOBUF a )
CTX c = m_alloc_clear( sizeof *c );
PACKET *pkt = m_alloc( sizeof *pkt );
int rc, result;
- char *ustr;
int lvl0, lvl1;
u32 keyid[2];
int newpkt;
diff --git a/g10/options.h b/g10/options.h
index a23412fc8..3be6c92c3 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -34,7 +34,7 @@ struct {
int cache_all;
int fingerprint; /* list fingerprints */
int list_sigs; /* list signatures */
- int reserved4;
+ int no_armor;
int reserved5;
int reserved6;
int reserved7;
diff --git a/g10/ringedit.c b/g10/ringedit.c
index e4380c3d1..10aa7c947 100644
--- a/g10/ringedit.c
+++ b/g10/ringedit.c
@@ -60,9 +60,10 @@ struct resource_table_struct {
char *fname;
IOBUF iobuf;
};
+typedef struct resource_table_struct RESTBL;
#define MAX_RESOURCES 10
-static struct resource_table_struct resource_table[MAX_RESOURCES];
+static RESTBL resource_table[MAX_RESOURCES];
static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf );
@@ -72,14 +73,14 @@ static int keyring_delete( KBPOS *kbpos );
-static int
+static RESTBL *
check_pos( KBPOS *kbpos )
{
if( kbpos->resno < 0 || kbpos->resno >= MAX_RESOURCES )
- return G10ERR_GENERAL;
+ return NULL;
if( !resource_table[kbpos->resno].used )
- return G10ERR_GENERAL;
- return 0;
+ return NULL;
+ return resource_table + kbpos->resno;
}
@@ -92,7 +93,7 @@ check_pos( KBPOS *kbpos )
* Register a resource (which currently may ionly be a keyring file).
*/
int
-add_keyblock_resource( const char *filename )
+add_keyblock_resource( const char *filename, int force )
{
IOBUF iobuf;
int i;
@@ -104,7 +105,7 @@ add_keyblock_resource( const char *filename )
return G10ERR_RESOURCE_LIMIT;
iobuf = iobuf_open( filename );
- if( !iobuf )
+ if( !iobuf && !force )
return G10ERR_OPEN_FILE;
resource_table[i].used = 1;
resource_table[i].fname = m_strdup(filename);
@@ -170,6 +171,31 @@ search_keyblock( PACKET *pkt, KBPOS *kbpos )
}
+/****************
+ * Combined function to search for a username and get the position
+ * of the keyblock.
+ */
+int
+search_keyblock_byname( KBPOS *kbpos, const char *username )
+{
+ PACKET pkt;
+ PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
+ int rc;
+
+ rc = get_pubkey_byname( pkc, username );
+ if( rc ) {
+ free_public_cert(pkc);
+ return rc;
+ }
+
+ init_packet( &pkt );
+ pkt.pkttype = PKT_PUBLIC_CERT;
+ pkt.pkt.public_cert = pkc;
+ rc = search_keyblock( &pkt, kbpos );
+ free_public_cert(pkc);
+ return rc;
+}
+
/****************
* Lock the keyblock; wait until it's available
@@ -182,22 +208,19 @@ lock_keyblock( KBPOS *kbpos )
{
int rc;
- if( (rc=check_pos(kbpos)) )
- return rc;
+ if( !check_pos(kbpos) )
+ return G10ERR_GENERAL;
return 0;
}
/****************
* Release a lock on a keyblock
*/
-int
+void
unlock_keyblock( KBPOS *kbpos )
{
- int rc;
-
- if( (rc=check_pos(kbpos)) )
- return rc;
- return 0;
+ if( !check_pos(kbpos) )
+ log_bug(NULL);
}
/****************
@@ -206,10 +229,8 @@ unlock_keyblock( KBPOS *kbpos )
int
read_keyblock( KBPOS *kbpos, KBNODE *ret_root )
{
- int rc;
-
- if( (rc=check_pos(kbpos)) )
- return rc;
+ if( !check_pos(kbpos) )
+ return G10ERR_GENERAL;
return keyring_read( kbpos, ret_root );
}
@@ -222,8 +243,8 @@ insert_keyblock( KBPOS *kbpos, KBNODE root )
{
int rc;
- if( (rc=check_pos(kbpos)) )
- return rc;
+ if( !check_pos(kbpos) )
+ return G10ERR_GENERAL;
rc = keyring_insert( kbpos, root );
@@ -241,8 +262,8 @@ delete_keyblock( KBPOS *kbpos )
{
int rc;
- if( (rc=check_pos(kbpos)) )
- return rc;
+ if( !check_pos(kbpos) )
+ return G10ERR_GENERAL;
rc = keyring_delete( kbpos );
@@ -358,13 +379,26 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
{
PACKET *pkt;
int rc;
+ RESTBL *rentry;
KBNODE root = NULL;
KBNODE node, n1, n2;
IOBUF a;
- if( (rc=check_pos(kbpos)) )
- return rc;
- a = resource_table[kbpos->resno].iobuf;
+ if( !(rentry=check_pos(kbpos)) )
+ return G10ERR_GENERAL;
+
+ a = iobuf_open( rentry->fname );
+ if( !a ) {
+ log_error("can't open '%s'\n", rentry->fname );
+ return G10ERR_OPEN_FILE;
+ }
+
+ if( iobuf_seek( a, kbpos->offset ) ) {
+ log_error("can't seek to %lu: %s\n", kbpos->offset, g10_errstr(rc));
+ iobuf_close(a);
+ return G10ERR_KEYRING_OPEN;
+ }
+
pkt = m_alloc( sizeof *pkt );
init_packet(pkt);
@@ -377,7 +411,7 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
case PKT_PUBLIC_CERT:
case PKT_SECRET_CERT:
if( root )
- break;
+ goto ready;
root = new_kbnode( pkt );
pkt = m_alloc( sizeof *pkt );
init_packet(pkt);
@@ -386,8 +420,8 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
case PKT_USER_ID:
if( !root ) {
log_error("read_keyblock: orphaned user id\n" );
- rc = G10ERR_INV_KEYRING; /* or wron kbpos */
- break;
+ rc = G10ERR_INV_KEYRING; /* or wrong kbpos */
+ goto ready;
}
/* append the user id */
node = new_kbnode( pkt );
@@ -434,6 +468,7 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
break;
}
}
+ ready:
kbpos->last_block = rc == -1; /* flag, that this is the last block */
if( rc == -1 && root )
rc = 0;
@@ -446,14 +481,49 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
}
free_packet( pkt );
m_free( pkt );
+ iobuf_close(a);
return rc;
}
+/****************
+ * Insert the keyblock described by ROOT into the keyring described
+ * by KBPOS. This actually appends the data to the keyfile.
+ */
static int
keyring_insert( KBPOS *kbpos, KBNODE root )
{
- return -1;
+ RESTBL *rentry;
+ IOBUF fp;
+ KBNODE kbctx, node;
+ int rc;
+
+ if( !(rentry = check_pos( kbpos )) )
+ return G10ERR_GENERAL;
+
+ /* FIXME: we must close the file if it's already open, due to
+ * 2 reasons:
+ * - cannot open the same file twice on DOSish OSes
+ * - must sync with iobufs somehow
+ */
+ /* open the file for append */
+ fp = iobuf_append( rentry->fname );
+ if( !fp ) {
+ log_error("can't append to '%s'\n", rentry->fname );
+ return G10ERR_OPEN_FILE;
+ }
+
+ kbctx=NULL;
+ while( (node = walk_kbtree( root, &kbctx )) ) {
+ if( (rc = build_packet( fp, node->pkt )) ) {
+ log_error("build_packet(%d) failed: %s\n",
+ node->pkt->pkttype, g10_errstr(rc) );
+ return G10ERR_WRITE_FILE;
+ }
+ }
+ iobuf_close(fp);
+
+ return 0;
}
static int
diff --git a/g10/seskey.c b/g10/seskey.c
index cf34295e5..325234c45 100644
--- a/g10/seskey.c
+++ b/g10/seskey.c
@@ -49,7 +49,7 @@ make_session_key( DEK *dek )
/****************
* Encode the session key. NBITS is the number of bits which should be used
- * for packing teh session key.
+ * for packing the session key.
* returns: A mpi with the session key (caller must free)
*/
MPI
diff --git a/include/iobuf.h b/include/iobuf.h
index f2e6b3f21..71819c805 100644
--- a/include/iobuf.h
+++ b/include/iobuf.h
@@ -64,6 +64,7 @@ IOBUF iobuf_alloc(int usage, size_t bufsize);
IOBUF iobuf_temp(void);
IOBUF iobuf_open( const char *fname );
IOBUF iobuf_create( const char *fname );
+IOBUF iobuf_append( const char *fname );
int iobuf_close( IOBUF iobuf );
int iobuf_cancel( IOBUF iobuf );
diff --git a/include/ttyio.h b/include/ttyio.h
index 80f66d842..6d599870f 100644
--- a/include/ttyio.h
+++ b/include/ttyio.h
@@ -21,6 +21,7 @@
#define G10_TTYIO_H
void tty_printf( const char *fmt, ... );
+void tty_print_string( byte *p, size_t n );
char *tty_get( const char *prompt );
char *tty_get_hidden( const char *prompt );
void tty_kill_prompt(void);
diff --git a/mpi/Makefile.am b/mpi/Makefile.am
index f05972caf..33e1ac456 100644
--- a/mpi/Makefile.am
+++ b/mpi/Makefile.am
@@ -5,6 +5,10 @@ CFLAGS += -O2
SUFFIXES = .S .s
+SUBDIRS = generic i386
+EXTRA_DIST = config.links
+
+
noinst_LIBRARIES = mpi
noinst_HEADERS = sysdep.h
diff --git a/mpi/Makefile.in b/mpi/Makefile.in
index d51dcd0f6..382a222cd 100644
--- a/mpi/Makefile.in
+++ b/mpi/Makefile.in
@@ -42,6 +42,9 @@ INCLUDES = -I$(top_srcdir)/include
SUFFIXES = .S .s
+SUBDIRS = generic i386
+EXTRA_DIST = config.links
+
noinst_LIBRARIES = mpi
noinst_HEADERS = sysdep.h
@@ -158,13 +161,45 @@ libmpi.a: $(mpi_OBJECTS) $(mpi_LIBADD)
$(AR) cru libmpi.a $(mpi_OBJECTS) $(mpi_LIBADD)
$(RANLIB) libmpi.a
-ID: $(HEADERS) $(SOURCES)
- here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS)
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+
+@SET_MAKE@
+
+all-recursive install-data-recursive install-exec-recursive \
+installdirs-recursive install-recursive uninstall-recursive \
+check-recursive installcheck-recursive info-recursive dvi-recursive \
+mostlyclean-recursive clean-recursive distclean-recursive \
+maintainer-clean-recursive:
+ for subdir in $(SUBDIRS); do \
+ target=`echo $@ | sed s/-recursive//`; \
+ echo making $$target in $$subdir; \
+ (cd $$subdir && $(MAKE) $$target) \
+ || case "$(MFLAGS)" in *k*) fail=yes;; *) exit 1;; esac; \
+ done && test -z "$$fail"
tags: TAGS
-TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES)
- here=`pwd` && cd $(srcdir) && etags $(ETAGS_ARGS) $(SOURCES) $(HEADERS) -o $$here/TAGS
+tags-recursive:
+ list="$(SUBDIRS)"; for subdir in $$list; do \
+ (cd $$subdir && $(MAKE) tags); \
+ done
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(CONFIG_HEADER) \
+ $(TAGS_DEPENDENCIES)
+ tags=; \
+ here=`pwd`; \
+ for subdir in $(SUBDIRS); do \
+ test -f $$subdir/TAGS && { \
+ tags="$$tags -i $$here/$$subdir/TAGS"; \
+ }; \
+ done; \
+ test -z "$(ETAGS_ARGS)$(CONFIG_HEADER)$(SOURCES)$(HEADERS)$$tags" \
+ || etags $(ETAGS_ARGS) $$tags $(CONFIG_HEADER) $(SOURCES) $(HEADERS)
mostlyclean-tags:
@@ -183,6 +218,14 @@ distdir: $(DEP_DISTFILES)
|| ln $(srcdir)/$$file $(distdir)/$$file 2> /dev/null \
|| cp -p $(srcdir)/$$file $(distdir)/$$file; \
done
+ for subdir in $(SUBDIRS); do \
+ test -d $(distdir)/$$subdir \
+ || mkdir $(distdir)/$$subdir \
+ || exit 1; \
+ chmod 777 $(distdir)/$$subdir; \
+ (cd $$subdir && $(MAKE) distdir=../$(distdir)/$$subdir distdir) \
+ || exit 1; \
+ 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
@@ -210,28 +253,30 @@ $(srcdir)/.deps/%.P: $(srcdir)/%.c
fi
# End of maintainer-only section
-info:
+info: info-recursive
+
+dvi: dvi-recursive
-dvi:
+check: all check-recursive
-check: all
+installcheck: installcheck-recursive
-installcheck:
+all-am: $(LIBFILES) $(HEADERS) Makefile
-install-exec:
+install-exec: install-exec-recursive
-install-data:
+install-data: install-data-recursive
-install: install-exec install-data all
+install: install-recursive
@:
-uninstall:
+uninstall: uninstall-recursive
-all: $(LIBFILES) $(HEADERS) Makefile
+all: all-recursive all-am
install-strip:
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
-installdirs:
+installdirs: installdirs-recursive
mostlyclean-generic:
@@ -247,29 +292,42 @@ distclean-generic:
maintainer-clean-generic:
test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
-mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \
+mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \
mostlyclean-tags mostlyclean-generic
-clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
- mostlyclean
+clean-am: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \
+ mostlyclean-am
-distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \
- distclean-generic clean
- rm -f config.status
+distclean-am: distclean-noinstLIBRARIES distclean-compile \
+ distclean-tags distclean-generic clean-am
-maintainer-clean: maintainer-clean-noinstLIBRARIES \
+maintainer-clean-am: maintainer-clean-noinstLIBRARIES \
maintainer-clean-compile maintainer-clean-tags \
- maintainer-clean-generic distclean
+ maintainer-clean-generic distclean-am
+
+mostlyclean: mostlyclean-am mostlyclean-recursive
+
+clean: clean-am clean-recursive
+
+distclean: distclean-am distclean-recursive
+ rm -f config.status
+
+maintainer-clean: maintainer-clean-am maintainer-clean-recursive
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
.PHONY: default mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \
clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \
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-compile install-data-recursive \
+uninstall-data-recursive install-exec-recursive \
+uninstall-exec-recursive installdirs-recursive uninstalldirs-recursive \
+all-recursive check-recursive installcheck-recursive info-recursive \
+dvi-recursive mostlyclean-recursive distclean-recursive clean-recursive \
+maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
+distclean-tags clean-tags maintainer-clean-tags distdir info dvi check \
+installcheck all-am install-exec install-data install uninstall all \
+installdirs mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean
CFLAGS += -O2
diff --git a/mpi/config.links b/mpi/config.links
new file mode 100644
index 000000000..e48cf7a08
--- /dev/null
+++ b/mpi/config.links
@@ -0,0 +1,51 @@
+# sourced my ../configure to get the list of files to link
+# this should set $mpi_ln_src and mpi_ln_dst.
+# Note: this is called from the above directory.
+
+echo '# created by config.links - do not edit' >./mpi/asm-syntax.h
+
+case "${target}" in
+ i[3456]86*-*-*)
+ echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
+ echo '#include "./i386/syntax.h"' >>./mpi/asm-syntax.h
+ path="i386"
+ ;;
+ i[56]86*-*-* | pentium-*-* | pentiumpro-*-*)
+ echo '#define ELF_SYNTAX' >>./mpi/asm-syntax.h
+ echo '#include "./i586/syntax.h"' >>./mpi/asm-syntax.h
+ path="i586"
+ ;;
+ *)
+ echo '/* No assembler modules configured */' >>./mpi/asm-syntax.h
+ path=""
+ ;;
+esac
+
+
+# fixme: grep these modules from Makefile.in
+mpi_ln_modules="mpih-add1 mpih-mul1 mpih-mul2 mpih-mul3 \
+ mpih-shift mpih-sub1"
+
+mpi_ln_objects=
+mpi_ln_src=
+mpi_ln_dst=
+
+# try to get file to link from the assembler subdirectory and
+# if this fails get it from the generic subdirectory.
+path="$path generic"
+for fn in $mpi_ln_modules ; do
+ mpi_ln_objects="$mpi_ln_objects $fn.o"
+ for dir in $path ; do
+ rm -f ./mpi/$fn.[Sc]
+ if test -f ./mpi/$dir/$fn.S ; then
+ mpi_ln_src="$mpi_ln_src mpi/$dir/$fn.S"
+ mpi_ln_dst="$mpi_ln_dst mpi/$fn.S"
+ break;
+ elif test -f ./mpi/$dir/$fn.c ; then
+ mpi_ln_src="$mpi_ln_src mpi/$dir/$fn.c"
+ mpi_ln_dst="$mpi_ln_dst mpi/$fn.c"
+ break;
+ fi
+ done
+done
+
diff --git a/util/argparse.c b/util/argparse.c
index 10cfd5c1d..80b7fcd3d 100644
--- a/util/argparse.c
+++ b/util/argparse.c
@@ -194,6 +194,7 @@ optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
char keyword[100];
char *buffer = NULL;
size_t buflen = 0;
+ int inverse=0;
if( !fp ) /* same as arg_parse() in this case */
return arg_parse( arg, opts );
@@ -216,6 +217,8 @@ optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
break;
index = i;
arg->r_opt = opts[index].short_opt;
+ if( inverse )
+ arg->r_opt = -arg->r_opt;
if( !opts[index].short_opt )
arg->r_opt = -2; /* unknown option */
else if( (opts[index].flags & 8) ) /* no optional argument */
diff --git a/util/iobuf.c b/util/iobuf.c
index da8fea479..1c35db6a8 100644
--- a/util/iobuf.c
+++ b/util/iobuf.c
@@ -371,6 +371,36 @@ iobuf_create( const char *fname )
}
/****************
+ * append to a iobuf if the file does not exits; create it.
+ * cannont be used for stdout.
+ */
+IOBUF
+iobuf_append( const char *fname )
+{
+ IOBUF a;
+ FILE *fp;
+ file_filter_ctx_t *fcx;
+ size_t len;
+
+ if( !fname )
+ return NULL;
+ else if( !(fp = fopen(fname, "ab")) )
+ return NULL;
+ a = iobuf_alloc(2, 8192 );
+ fcx = m_alloc( sizeof *fcx + strlen(fname) );
+ fcx->fp = fp;
+ strcpy(fcx->fname, fname );
+ a->filter = file_filter;
+ a->filter_ov = fcx;
+ file_filter( fcx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len );
+ file_filter( fcx, IOBUFCTRL_INIT, NULL, NULL, &len );
+ if( DBG_IOBUF )
+ log_debug("iobuf-%d.%d: append '%s'\n", a->no, a->subno, a->desc );
+
+ return a;
+}
+
+/****************
* Register an i/o filter.
*/
int
@@ -709,8 +739,25 @@ iobuf_tell( IOBUF a )
int
iobuf_seek( IOBUF a, ulong newpos )
{
+ file_filter_ctx_t *b = NULL;
- return -1;
+ for( ; a; a = a->chain ) {
+ if( !a->chain && a->filter == file_filter ) {
+ b = a->filter_ov;
+ break;
+ }
+ }
+ if( !a )
+ return -1;
+
+ if( fseek( b->fp, newpos, SEEK_SET ) ) {
+ log_error("can't seek to %lu: %s\n", newpos, strerror(errno) );
+ return -1;
+ }
+
+ /* FIXME: flush all buffers (and remove filters?)*/
+
+ return 0;
}
diff --git a/util/miscutil.c b/util/miscutil.c
index 18fff2c08..327eae860 100644
--- a/util/miscutil.c
+++ b/util/miscutil.c
@@ -46,7 +46,7 @@ print_string( FILE *fp, byte *p, size_t n )
else if( !*p )
putc('0', fp);
else
- printf("x%02x", *p );
+ fprintf(fp, "x%02x", *p );
}
else
putc(*p, fp);
diff --git a/util/ttyio.c b/util/ttyio.c
index 39ad5a666..74d31d1af 100644
--- a/util/ttyio.c
+++ b/util/ttyio.c
@@ -60,6 +60,28 @@ tty_printf( const char *fmt, ... )
}
+/****************
+ * Print a string, but filter all control characters out.
+ */
+void
+tty_print_string( byte *p, size_t n )
+{
+ for( ; n; n--, p++ )
+ if( iscntrl( *p ) ) {
+ putc('\\', stderr);
+ if( *p == '\n' )
+ putc('n', stderr);
+ else if( !*p )
+ putc('0', stderr);
+ else
+ fprintf(stderr, "x%02x", *p );
+ }
+ else
+ putc(*p, stderr);
+}
+
+
+
char *
tty_get( const char *prompt )
{