aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/ChangeLog27
-rw-r--r--g10/Makefile.in1
-rw-r--r--g10/encode.c2
-rw-r--r--g10/export.c100
-rw-r--r--g10/g10.c232
-rw-r--r--g10/import.c35
-rw-r--r--g10/kbnode.c9
-rw-r--r--g10/keydb.h3
-rw-r--r--g10/keygen.c14
-rw-r--r--g10/parse-packet.c2
-rw-r--r--g10/pubkey-enc.c68
-rw-r--r--g10/ringedit.c141
-rw-r--r--g10/sign.c4
13 files changed, 483 insertions, 155 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
new file mode 100644
index 000000000..2bfa48b74
--- /dev/null
+++ b/g10/ChangeLog
@@ -0,0 +1,27 @@
+Fri Feb 13 20:18:14 1998 Werner Koch ([email protected])
+
+ * ringedit.c (enum_keyblocks, keyring_enum): New.
+
+Fri Feb 13 19:33:40 1998 Werner Koch ([email protected])
+
+ * export.c: Add functionality.
+
+ * keygen.c (generate_keypair): Moved the leading comment behind the
+ key packet.
+ * kbnode.c (walk_kbnode): Fixed.
+
+ * g10.c (main): listing armored keys now work.
+
+Fri Feb 13 16:17:43 1998 Werner Koch ([email protected])
+
+ * parse-packet.c (parse_publickey, parse_signature): Fixed calls
+ to mpi_read used for ELG b.
+
+Fri Feb 13 15:13:23 1998 Werner Koch ([email protected])
+
+ * g10.c (main): changed formatting of help output.
+
+Thu Feb 12 22:24:42 1998 Werner Koch (wk@frodo)
+
+ * pubkey-enc.c (get_session_key): rewritten
+
diff --git a/g10/Makefile.in b/g10/Makefile.in
index 63ffc3e6b..afbeebf8f 100644
--- a/g10/Makefile.in
+++ b/g10/Makefile.in
@@ -85,7 +85,6 @@ POSUB = @POSUB@
RANLIB = @RANLIB@
VERSION = @VERSION@
ZLIBS = @ZLIBS@
-ZLIB_SUBDIR = @ZLIB_SUBDIR@
INCLUDES = -I$(top_srcdir)/include
EXTRA_DIST = OPTIONS pubring.g10
diff --git a/g10/encode.c b/g10/encode.c
index 04aebefdb..eea7345fa 100644
--- a/g10/encode.c
+++ b/g10/encode.c
@@ -182,7 +182,7 @@ encode_crypt( const char *filename, STRLIST remusr )
goto leave;
}
else if( opt.verbose )
- log_error("reading from '%s'\n", filename? filename: "[stdin]");
+ log_info("reading from '%s'\n", filename? filename: "[stdin]");
if( !(out = open_outfile( filename, opt.armor? 1:0 )) ) {
rc = G10ERR_CREATE_FILE; /* or user said: do not overwrite */
diff --git a/g10/export.c b/g10/export.c
index d45c1285f..619d69958 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -31,17 +31,109 @@
#include "keydb.h"
#include "memory.h"
#include "util.h"
+#include "main.h"
/****************
- * Make a new keyring from all internal keyrings (if no user is given)
- * or for all selected users.
+ * Export the public keys (to standard out or --outout).
+ * Depending on opt.armor the output is armored.
+ * If USERS is NULL, the complete ring wil. be exported.
*/
int
export_pubkeys( STRLIST users )
{
- log_fatal("Not yet implemented");
- return 0;
+ int rc = 0;
+ armor_filter_context_t afx;
+ compress_filter_context_t zfx;
+ IOBUF out = NULL;
+ PACKET pkt;
+ KBNODE keyblock = NULL;
+ KBNODE kbctx, node;
+ KBPOS kbpos;
+ STRLIST sl;
+ int all = !users;
+ int any=0;
+
+ memset( &afx, 0, sizeof afx);
+ memset( &zfx, 0, sizeof zfx);
+ init_packet( &pkt );
+
+ if( !(out = open_outfile( NULL, 0 )) ) {
+ rc = G10ERR_CREATE_FILE;
+ goto leave;
+ }
+
+ if( opt.armor ) {
+ afx.what = 1;
+ iobuf_push_filter( out, armor_filter, &afx );
+ }
+ if( opt.compress )
+ iobuf_push_filter( out, compress_filter, &zfx );
+
+ if( all ) {
+ rc = enum_keyblocks( 0, &kbpos, &keyblock );
+ if( rc ) {
+ if( rc != -1 )
+ log_error("enum_keyblocks(open) failed: %s\n", g10_errstr(rc) );
+ goto leave;
+ }
+ all = 2;
+ }
+
+ /* use the correct sequence. strlist_last,prev do work correct with
+ * NULL pointers :-) */
+ for( sl=strlist_last(users); sl || all ; sl=strlist_prev( users, sl )) {
+ if( all ) { /* get the next user */
+ rc = enum_keyblocks( 1, &kbpos, &keyblock );
+ if( rc == -1 ) /* EOF */
+ break;
+ if( rc ) {
+ log_error("enum_keyblocks(read) failed: %s\n", g10_errstr(rc));
+ break;
+ }
+ }
+ else {
+ /* search the userid */
+ rc = find_keyblock_byname( &kbpos, sl->d );
+ if( rc ) {
+ log_error("%s: user not found: %s\n", sl->d, g10_errstr(rc) );
+ rc = 0;
+ continue;
+ }
+ /* read the keyblock */
+ rc = read_keyblock( &kbpos, &keyblock );
+ }
+
+ if( rc ) {
+ log_error("certificate read problem: %s\n", g10_errstr(rc));
+ goto leave;
+ }
+
+ /* and write it */
+ for( kbctx=NULL; (node = walk_kbnode( keyblock, &kbctx, 0 )); ) {
+ if( (rc = build_packet( out, node->pkt )) ) {
+ log_error("build_packet(%d) failed: %s\n",
+ node->pkt->pkttype, g10_errstr(rc) );
+ rc = G10ERR_WRITE_FILE;
+ goto leave;
+ }
+ }
+ any++;
+ }
+ if( rc == -1 )
+ rc = 0;
+
+ leave:
+ if( all == 2 )
+ enum_keyblocks( 2, &kbpos, &keyblock ); /* close */
+ release_kbnode( keyblock );
+ if( rc || !any )
+ iobuf_cancel(out);
+ else
+ iobuf_close(out);
+ if( !any )
+ log_info("warning: nothing exported\n");
+ return rc;
}
diff --git a/g10/g10.c b/g10/g10.c
index b5ce5f7f0..4fbc0f7ab 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -41,11 +41,85 @@
#include "status.h"
+static ARGPARSE_OPTS opts[] = {
+
+ { 300, NULL, 0, N_("\vCommands:\n ") },
+
+ { 's', "sign", 0, N_("make a signature")},
+ { 539, "clearsign", 0, N_("make a clear text signature") },
+ { 'b', "detach-sign", 0, N_("make a detached signature")},
+ { 'e', "encrypt", 0, N_("encrypt data")},
+ { 'c', "symmetric", 0, N_("encryption only with symmetric cipher")},
+ { 507, "store", 0, N_("store only")},
+ { 'd', "decrypt", 0, N_("decrypt data (default)")},
+ { 'k', "list-keys", 0, N_("list keys")},
+ { 508, "check-keys",0, N_("check signatures on a key in the keyring")},
+ { 515, "fingerprint", 0, N_("show the fingerprints")},
+ { 521, "list-packets",0,N_("list only the sequence of packets")},
+ { 503, "gen-key", 0, N_("generate a new key pair")},
+ { 506, "sign-key" ,0, N_("make a signature on a key in the keyring")},
+ { 505, "delete-key",0, N_("remove key from the public keyring")},
+ { 524, "edit-sig" ,0, N_("edit a key signature")},
+ { 525, "change-passphrase", 0, N_("change the passphrase of your secret keyring")},
+ { 537, "export" , 0, N_("export keys") },
+ { 530, "import", 0 , N_("import/merge keys")},
+
+ { 301, NULL, 0, N_("\v\nOptions:\n ") },
+
+ { 'a', "armor", 0, N_("create ascii armored output")},
+ { 'o', "output", 2, N_("use as output file")},
+ { 'u', "local-user",2, N_("use this user-id to sign or decrypt")},
+ { 'r', "remote-user", 2, N_("use this user-id for encryption")},
+ { 'v', "verbose", 0, N_("verbose") },
+ { 'z', NULL, 1, N_("set compress level (0 disables)") },
+ { 't', "textmode", 0, N_("use canonical text mode")},
+ { 'n', "dry-run", 0, N_("don't make any changes") },
+ { 500, "batch", 0, N_("batch mode: never ask")},
+ { 501, "yes", 0, N_("assume yes on most questions")},
+ { 502, "no", 0, N_("assume no on most questions")},
+ { 509, "keyring" ,2, N_("add this keyring to the list of keyrings")},
+ { 517, "secret-keyring" ,2, N_("add this secret keyring to the list")},
+ { 518, "options" , 2, N_("read options from file")},
+
+ { 510, "debug" ,4|16, N_("set debugging flags")},
+ { 511, "debug-all" ,0, N_("enable full debugging")},
+ { 512, "status-fd" ,1, N_("write status info to this fd") },
+ { 534, "no-comment", 0, N_("do not write comment packets")},
+ { 535, "completes-needed", 1, N_("(default is 1)")},
+ { 536, "marginals-needed", 1, N_("(default is 3)")},
+ { 527, "cipher-algo", 2 , N_("select default cipher algorithm")},
+ { 528, "pubkey-algo", 2 , N_("select default puplic key algorithm")},
+ { 529, "digest-algo", 2 , N_("select default message digest algorithm")},
+
+ { 302, NULL, 0, N_("\v\nExamples:\n\n"
+ " -se -r Bob [file] sign and encrypt for user Bob\n"
+ " -sat [file] make a clear text signature\n"
+ " -sb [file] make a detached signature\n"
+ " -k [userid] show keys\n"
+ " -kc [userid] show fingerprint\n" ) },
+
+ /* hidden options */
+ { 532, "quick-random", 0, "\r"},
+ { 526, "no-verbose", 0, "\r"},
+ { 538, "trustdb-name", 2, "\r" },
+ { 540, "no-secmem-warning", 0, "\r" }, /* used only by regression tests */
+ { 519, "no-armor", 0, "\r"},
+ { 520, "no-default-keyring", 0, "\r" },
+ { 522, "no-greeting", 0, "\r" },
+ { 523, "passphrase-fd",1, "\r" },
+ { 541, "no-operation", 0, "\r" }, /* used by regression tests */
+
+
+{0} };
+
+
+
+
enum cmd_values { aNull = 0,
aSym, aStore, aEncr, aKeygen, aSign, aSignEncr,
aSignKey, aClearsign, aListPackets, aEditSig,
aKMode, aKModeC, aChangePass, aImport,
- aExport,
+ aExport, aCheckKeys,
aNOP };
@@ -59,7 +133,7 @@ strusage( int level )
switch( level ) {
case 10:
case 0: p = "g10 - v" VERSION "; "
- "Copyright 1997 Werner Koch (dd9jn)\n" ; break;
+ "Copyright 1998 Werner Koch (dd9jn)\n" ; break;
case 13: p = "g10"; break;
case 14: p = VERSION; break;
case 1:
@@ -105,7 +179,7 @@ i18n_init(void)
static void
wrong_args( const char *text)
{
- fputs(_("Usage: g10 [options] "),stderr);
+ fputs(_("usage: g10 [options] "),stderr);
fputs(text,stderr);
putc('\n',stderr);
g10_exit(2);
@@ -152,63 +226,28 @@ set_cmd( enum cmd_values *ret_cmd, enum cmd_values new_cmd )
}
+
+static void
+check_opts(void)
+{
+ if( !opt.def_cipher_algo || check_cipher_algo(opt.def_cipher_algo) )
+ log_error(_("selected cipher algorithm is invalid\n"));
+ if( !opt.def_pubkey_algo || check_pubkey_algo(opt.def_pubkey_algo) )
+ log_error(_("selected pubkey algorithm is invalid\n"));
+ if( !opt.def_digest_algo || check_digest_algo(opt.def_digest_algo) )
+ log_error(_("selected digest algorithm is invalid\n"));
+ if( opt.completes_needed < 1 )
+ log_error(_("completes-needed must be greater than 0\n"));
+ if( opt.marginals_needed < 2 )
+ log_error(_("marginals-needed must be greater than 1\n"));
+}
+
+
+
+
void
main( int argc, char **argv )
{
- static ARGPARSE_OPTS opts[] = {
- { 'a', "armor", 0, N_("create ascii armored output")},
- { 'v', "verbose", 0, N_("verbose") },
- { 'z', NULL, 1, N_("set compress level (0 disables)") },
- { 'n', "dry-run", 0, N_("don't make any changes") },
- { 'c', "symmetric", 0, N_("do only a symmetric encryption")},
- { 'o', "output", 2, N_("use as output file")},
- { 500, "batch", 0, N_("batch mode: never ask")},
- { 501, "yes", 0, N_("assume yes on most questions")},
- { 502, "no", 0, N_("assume no on most questions")},
- { 503, "gen-key", 0, N_("generate a new key pair")},
- { 504, "add-key", 0, N_("add key to the public keyring")},
- { 505, "delete-key",0, N_("remove key from public keyring")},
- { 506, "sign-key" ,0, N_("make a signature on a key in the keyring")},
- { 507, "store", 0, N_("store only")},
- { 508, "check-key" ,0, N_("check signatures on a key in the keyring")},
- { 509, "keyring" ,2, N_("add this keyring to the list of keyrings")},
- { 's', "sign", 0, N_("make a signature")},
- { 't', "textmode", 0, N_("use canonical text mode")},
- { 'b', "detach-sign", 0, N_("make a detached signature")},
- { 'e', "encrypt", 0, N_("encrypt data")},
- { 'd', "decrypt", 0, N_("decrypt data (default)")},
- { 'u', "local-user",2, N_("use this user-id to sign or decrypt")},
- { 'r', "remote-user", 2, N_("use this user-id for encryption")},
- { 'k', NULL , 0, N_("list keys")},
- { 510, "debug" ,4|16, N_("set debugging flags")},
- { 511, "debug-all" ,0, N_("enable full debugging")},
- { 512, "status-fd" ,1, N_("write status info to this fd") },
- { 515, "fingerprint", 0, N_("show the fingerprints")},
- { 517, "secret-keyring" ,2, N_("add this secret keyring to the list")},
- { 518, "options" , 2, N_("read options from file")},
- { 519, "no-armor", 0, "\r"},
- { 520, "no-default-keyring", 0, "\r" },
- { 521, "list-packets",0,N_("list only the sequence of packets")},
- { 522, "no-greeting", 0, "\r" },
- { 523, "passphrase-fd",1, "\r" },
- { 524, "edit-sig" ,0, N_("edit a key signature")},
- { 525, "change-passphrase", 0, N_("change the passphrase of your secret keyring")},
- { 526, "no-verbose", 0, "\r"},
- { 527, "cipher-algo", 2 , N_("select default cipher algorithm")},
- { 528, "pubkey-algo", 2 , N_("select default puplic key algorithm")},
- { 529, "digest-algo", 2 , N_("select default message digest algorithm")},
- { 530, "import", 0 , N_("put public keys into the trustdb")},
- { 532, "quick-random", 0, "\r"},
- { 534, "no-comment", 0, N_("do not write comment packets")},
- { 535, "completes-needed", 1, N_("(default is 1)")},
- { 536, "marginals-needed", 1, N_("(default is 3)")},
- { 537, "export", 0, N_("export all or the given keys") },
- { 538, "trustdb-name", 2, "\r" },
- { 539, "clearsign", 0, N_("make a clear text signature") },
- { 540, "no-secmem-warning", 0, "\r" }, /* used only by regression tests */
- { 541, "no-operation", 0, "\r" }, /* used by regression tests */
-
- {0} };
ARGPARSE_ARGS pargs;
IOBUF a;
int rc=0;
@@ -236,6 +275,7 @@ main( int argc, char **argv )
* secmem_init() somewhere after the option parsing
*/
+ log_set_name("g10");
i18n_init();
opt.compress = -1; /* defaults to standard compress level */
opt.def_cipher_algo = CIPHER_ALGO_BLOWFISH;
@@ -278,9 +318,11 @@ main( int argc, char **argv )
if( parse_debug )
log_info(_("note: no default option file '%s'\n"), configname );
}
- else
- log_fatal(_("option file '%s': %s\n"),
+ else {
+ log_error(_("option file '%s': %s\n"),
configname, strerror(errno) );
+ g10_exit(1);
+ }
m_free(configname); configname = NULL;
}
if( parse_debug && configname )
@@ -291,9 +333,7 @@ main( int argc, char **argv )
while( optfile_parse( configfp, configname, &configlineno,
&pargs, opts) ) {
switch( pargs.r_opt ) {
- case 'v': opt.verbose++;
- opt.list_sigs=1;
- break;
+ case 'v': opt.verbose++; opt.list_sigs=1; break;
case 'z': opt.compress = pargs.r.ret_int; break;
case 'a': opt.armor = 1; opt.no_armor=0; break;
case 'd': break; /* it is default */
@@ -322,7 +362,8 @@ main( int argc, char **argv )
case 503: set_cmd( &cmd, aKeygen); break;
case 506: set_cmd( &cmd, aSignKey); break;
case 507: set_cmd( &cmd, aStore); break;
- case 508: opt.check_sigs = 1; opt.list_sigs = 1; break;
+ case 508: set_cmd( &cmd, aCheckKeys);
+ opt.check_sigs = 1; opt.list_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;
@@ -374,27 +415,8 @@ main( int argc, char **argv )
goto next_pass;
}
m_free( configname ); configname = NULL;
- if( !opt.def_cipher_algo || check_cipher_algo(opt.def_cipher_algo) ) {
- log_error(_("selected cipher algorithm is invalid\n"));
- errors++;
- }
- if( !opt.def_pubkey_algo || check_pubkey_algo(opt.def_pubkey_algo) ) {
- log_error(_("selected pubkey algorithm is invalid\n"));
- errors++;
- }
- if( !opt.def_digest_algo || check_digest_algo(opt.def_digest_algo) ) {
- log_error(_("selected digest algorithm is invalid\n"));
- errors++;
- }
- if( opt.completes_needed < 1 ) {
- log_error(_("completes-needed must be greater than 0\n"));
- errors++;
- }
- if( opt.marginals_needed < 2 ) {
- log_error(_("marginals-needed must be greater than 1\n"));
- errors++;
- }
- if( errors )
+ check_opts();
+ if( log_get_errorcount(0) )
g10_exit(2);
if( greeting ) {
@@ -541,6 +563,7 @@ main( int argc, char **argv )
g10_errstr(rc) );
break;
+ case aCheckKeys:
case aKMode: /* list keyring */
if( !argc ) { /* list the default public keyrings */
int i, seq=0;
@@ -563,14 +586,23 @@ main( int argc, char **argv )
}
}
+ else if( cmd == aCheckKeys ) {
+ log_error("will be soon: --check-keys user-ids\n");
+ }
else if( argc == 1) { /* list the given keyring */
if( !(a = iobuf_open(fname)) )
- log_fatal(_("can't open '%s'\n"), fname_print);
- proc_packets( a );
- iobuf_close(a);
+ log_error(_("can't open '%s'\n"), fname_print);
+ else {
+ if( !opt.no_armor ) {
+ memset( &afx, 0, sizeof afx);
+ iobuf_push_filter( a, armor_filter, &afx );
+ }
+ proc_packets( a );
+ iobuf_close(a);
+ }
}
else
- wrong_args(_("-k[v][v][v][c] [keyring]"));
+ wrong_args(_("-k[v][v][v][c] [keyring]") );
break;
case aKeygen: /* generate a key (interactive) */
@@ -607,18 +639,20 @@ main( int argc, char **argv )
if( argc > 1 )
wrong_args(_("[filename]"));
if( !(a = iobuf_open(fname)) )
- log_fatal(_("can't open '%s'\n"), fname_print);
- 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 );
- }
- if( cmd == aListPackets ) {
- set_packet_list_mode(1);
- opt.list_packets=1;
+ log_error(_("can't open '%s'\n"), fname_print);
+ else {
+ 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 );
+ }
+ if( cmd == aListPackets ) {
+ set_packet_list_mode(1);
+ opt.list_packets=1;
+ }
+ proc_packets( a );
+ iobuf_close(a);
}
- proc_packets( a );
- iobuf_close(a);
break;
}
diff --git a/g10/import.c b/g10/import.c
index 2cba74a5b..0474152d7 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -35,15 +35,34 @@
/****************
- * Import the public keys from the given filename.
- * Import is a somewhat misleading name, as we (only) add informations
- * about the public keys into aout trustdb.
+ * Import the public keys from the given filename. Input may be armored.
+ * This function rejects alls keys which are not valid self signed on at
+ * least one userid. Only user ids which are self signed will be imported.
+ * Other signatures are not not checked.
+ *
+ * Actually this functtion does a merge, it works like this:
+ * FIXME: add handling for revocation certs
+ *
+ * - get the keyblock
+ * - check self-signatures and remove all userids and their isgnatures
+ * without/invalid self-signatures.
+ * - reject the keyblock, if we have no valid userid.
+ * - See wether we have this key already in one of our pubrings.
+ * If not, simply add it to the default keyring.
+ * - Compare the key and the self-signatures of the new and the one in
+ * our keyring. If they are differen something weird is going on;
+ * ask what to do.
+ * - See wether we have only non-self-signature on one user id; if not
+ * ask the user what to do.
+ * - compare the signatures: If we already have this signature, check
+ * that they compare okay, if not issue a warning and ask the user.
+ * (consider to look at the timestamp and use the newest?)
+ * - Simply add the signature. Can't verify here because we may not have
+ * the signatures public key yet; verification is done when putting it
+ * into the trustdb, which is done automagically as soon as this pubkey
+ * is used.
+ * - Proceed with next signature.
*
- * NOTE: this function is not really needed and will be changed to
- * a function which reads a plain textfile, describing a public
- * key and its associated ownertrust. This can be used (together
- * with the export function) to make a backup of the assigned
- * ownertrusts.
*/
int
import_pubkeys( const char *filename )
diff --git a/g10/kbnode.c b/g10/kbnode.c
index dd4f0ce24..83ec50742 100644
--- a/g10/kbnode.c
+++ b/g10/kbnode.c
@@ -177,11 +177,12 @@ walk_kbnode( KBNODE root, KBNODE *context, int all )
do {
if( !*context ) {
*context = root;
- return root;
+ n = root;
+ }
+ else {
+ n = (*context)->next;
+ *context = n;
}
-
- n = (*context)->next;
- *context = n;
} while( !all && n && (n->private_flag & 1) );
return n;
diff --git a/g10/keydb.h b/g10/keydb.h
index ff0ecb528..ca54020cd 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -51,6 +51,8 @@ struct keyblock_pos_struct {
int resno; /* resource number */
ulong offset; /* position information */
unsigned count; /* length of the keyblock in packets */
+ IOBUF fp; /* used by enum_keyblocks */
+ PACKET *pkt; /* ditto */
};
typedef struct keyblock_pos_struct KBPOS;
@@ -144,6 +146,7 @@ int find_secret_keyblock_byname( KBPOS *kbpos, const char *username );
int lock_keyblock( KBPOS *kbpos );
void unlock_keyblock( KBPOS *kbpos );
int read_keyblock( KBPOS *kbpos, KBNODE *ret_root );
+int enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root );
int insert_keyblock( KBPOS *kbpos, KBNODE root );
int delete_keyblock( KBPOS *kbpos );
int update_keyblock( KBPOS *kbpos, KBNODE root );
diff --git a/g10/keygen.c b/g10/keygen.c
index f9e68a083..1c9a2efbe 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -535,11 +535,11 @@ generate_keypair()
/* 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.
+ * The first packet is a dummy comment packet which we flag
+ * as deleted. The very first packet must always be a CERT packet.
*/
- pub_root = make_comment_node("#created by G10 pre-release " VERSION );
- sec_root = make_comment_node("#created by G10 pre-release " VERSION );
+ pub_root = make_comment_node("#"); delete_kbnode(pub_root, pub_root);
+ sec_root = make_comment_node("#"); delete_kbnode(sec_root, sec_root);
tty_printf(_(
"We need to generate a lot of random bytes. It is a good idea to perform\n"
@@ -557,6 +557,12 @@ generate_keypair()
rc = gen_dsa(nbits, pub_root, sec_root, dek, &skc );
else
BUG();
+ if( !rc ) {
+ add_kbnode( pub_root,
+ make_comment_node("#created by G10 release " VERSION ));
+ add_kbnode( sec_root,
+ make_comment_node("#created by G10 release " VERSION ));
+ }
if( !rc )
write_uid(pub_root, uid );
if( !rc )
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 2e3cf21be..0e13f6d18 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -437,6 +437,7 @@ parse_publickey( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
if( k->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
n = pktlen;
k->d.elg.a = mpi_read(inp, &n, 0); pktlen -=n;
+ n = pktlen;
k->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n;
if( list_mode ) {
printf("\telg a: ");
@@ -502,6 +503,7 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
sig->d.elg.digest_start[1] = iobuf_get_noeof(inp); pktlen--;
n = pktlen;
sig->d.elg.a = mpi_read(inp, &n, 0 ); pktlen -=n;
+ n = pktlen;
sig->d.elg.b = mpi_read(inp, &n, 0 ); pktlen -=n;
if( list_mode ) {
printf("\tdigest algo %d, begin of digest %02x %02x\n",
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index 2f8fb45f4..0fcd9c21c 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -38,8 +38,10 @@
int
get_session_key( PKT_pubkey_enc *k, DEK *dek )
{
- int i, j, c, rc = 0;
- MPI dek_frame = mpi_alloc_secure(40);
+ int rc = 0;
+ MPI plain_dek = NULL;
+ byte *frame = NULL;
+ unsigned n, nframe;
u16 csum, csum2;
PKT_secret_cert *skc = m_alloc_clear( sizeof *skc );
@@ -58,7 +60,8 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek )
skey.g = skc->d.elg.g;
skey.y = skc->d.elg.y;
skey.x = skc->d.elg.x;
- elg_decrypt( dek_frame, k->d.elg.a, k->d.elg.b, &skey );
+ plain_dek = mpi_alloc_secure( mpi_get_nlimbs(skey.p) );
+ elg_decrypt( plain_dek, k->d.elg.a, k->d.elg.b, &skey );
memset( &skey, 0, sizeof skey );
}
#ifdef HAVE_RSA_CIPHER
@@ -74,7 +77,8 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek )
skey.q = skc->d.rsa.rsa_q;
skey.d = skc->d.rsa.rsa_d;
skey.u = skc->d.rsa.rsa_u;
- rsa_secret( dek_frame, k->d.rsa.rsa_integer, &skey );
+ plain_dek = mpi_alloc_secure( mpi_get_nlimbs(skey.n) );
+ rsa_secret( plain_dek, k->d.rsa.rsa_integer, &skey );
memset( &skey, 0, sizeof skey );
}
#endif/*HAVE_RSA_CIPHER*/
@@ -83,9 +87,10 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek )
goto leave;
}
free_secret_cert( skc ); skc = NULL;
+ frame = mpi_get_buffer( plain_dek, &nframe, NULL );
+ mpi_free( plain_dek ); plain_dek = NULL;
-
- /* Now get the DEK (data encryption key) from the dek_frame
+ /* Now get the DEK (data encryption key) from the frame
*
* Old versions encode the DEK in in this format (msb is left):
*
@@ -101,51 +106,53 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek )
* CSUM
*/
if( DBG_CIPHER )
- log_mpidump("DEK frame:", dek_frame );
- for(i=0; mpi_getbyte(dek_frame, i) != -1; i++ )
+ log_hexdump("DEK frame:", frame, nframe );
+ for(n=0; n < nframe && !frame[n]; n++ ) /* skip leading zeroes */
;
- for(i--; i >= 0 && !(c=mpi_getbyte(dek_frame, i)); i--)
- ; /* Skip leading zeroes */
- if( i < 16 )
+ if( n + 7 > nframe )
{ rc = G10ERR_WRONG_SECKEY; goto leave; }
- if( c == 1 && mpi_getbyte(dek_frame,0) == 2 ) {
+ if( frame[n] == 1 && frame[nframe-1] == 2 ) {
log_error("old encoding of DEK is not supported\n");
rc = G10ERR_CIPHER_ALGO;
goto leave;
}
- if( c != 2 ) /* somethink is wrong */
+ if( frame[n] != 2 ) /* somethink is wrong */
{ rc = G10ERR_WRONG_SECKEY; goto leave; }
- /* look for the zero byte */
- for(i--; i > 4 ; i-- )
- if( !mpi_getbyte(dek_frame,i) )
- break;
- if( i <= 4 ) /* zero byte not found */
+ for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */
+ ;
+ n++; /* and the zero byte */
+ if( n + 4 > nframe )
{ rc = G10ERR_WRONG_SECKEY; goto leave; }
- /* next byte indicates the used cipher */
- switch( mpi_getbyte(dek_frame, --i ) ) {
+
+ dek->keylen = nframe - (n+1) - 2;
+ dek->algo = frame[n++];
+ switch( dek->algo ) {
case CIPHER_ALGO_IDEA:
rc = G10ERR_NI_CIPHER;
goto leave;
case CIPHER_ALGO_BLOWFISH:
- if( i != 22 ) /* length of blowfish is 20 (+2 bytes checksum) */
+ if( dek->keylen != 20 )
{ rc = G10ERR_WRONG_SECKEY; goto leave; }
- dek->algo = CIPHER_ALGO_BLOWFISH;
break;
case CIPHER_ALGO_BLOWFISH128:
- if( i != 18 ) /* length of blowfish-128 is 16 (+2 bytes checksum) */
+ if( dek->keylen != 16 )
+ { rc = G10ERR_WRONG_SECKEY; goto leave; }
+ break;
+ case CIPHER_ALGO_CAST:
+ if( dek->keylen < 5 || dek->keylen > 16 )
{ rc = G10ERR_WRONG_SECKEY; goto leave; }
- dek->algo = CIPHER_ALGO_BLOWFISH128;
break;
default:
+ dek->algo = 0;
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);
+ csum = frame[nframe-2] << 8;
+ csum |= frame[nframe-1];
+ memcpy( dek->key, frame+n, dek->keylen );
+ for( csum2=0, n=0; n < dek->keylen; n++ )
+ csum2 += dek->key[n];
if( csum != csum2 ) {
rc = G10ERR_WRONG_SECKEY;
goto leave;
@@ -154,7 +161,8 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek )
log_hexdump("DEK is:", dek->key, dek->keylen );
leave:
- mpi_free(dek_frame);
+ mpi_free(plain_dek);
+ m_free(frame);
if( skc )
free_secret_cert( skc );
return rc;
diff --git a/g10/ringedit.c b/g10/ringedit.c
index 141d8cf7f..adba3db0b 100644
--- a/g10/ringedit.c
+++ b/g10/ringedit.c
@@ -77,6 +77,7 @@ static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf );
static int keyring_search2( PUBKEY_FIND_INFO info, KBPOS *kbpos,
const char *fname);
static int keyring_read( KBPOS *kbpos, KBNODE *ret_root );
+static int keyring_enum( KBPOS *kbpos, KBNODE *ret_root );
static int keyring_copy( KBPOS *kbpos, int mode, KBNODE root );
@@ -297,6 +298,78 @@ read_keyblock( KBPOS *kbpos, KBNODE *ret_root )
return keyring_read( kbpos, ret_root );
}
+
+/****************
+ * This functions can be used to read trough a complete keyring.
+ * Mode is: 0 = open
+ * 1 = read
+ * 2 = close
+ * all others are reserved!
+ * Note that you do not need a search prior to call this function,
+ * only handle is needed.
+ * NOTE: It is not alloed to do an insert/update/delte with this
+ * keyblock, if you want to do this, user search/read!
+ */
+int
+enum_keyblocks( int mode, KBPOS *kbpos, KBNODE *ret_root )
+{
+ int rc = 0;
+ RESTBL *rentry;
+
+ if( !mode || mode == 100 ) {
+ int i;
+ kbpos->fp = NULL;
+ if( !mode )
+ i = 0;
+ else
+ i = kbpos->resno+1;
+ for(; i < MAX_RESOURCES; i++ )
+ if( resource_table[i].used && !resource_table[i].secret )
+ break;
+ if( i == MAX_RESOURCES )
+ return -1; /* no resources */
+ kbpos->resno = i;
+ rentry = check_pos( kbpos );
+ kbpos->fp = iobuf_open( rentry->fname );
+ if( !kbpos->fp ) {
+ log_error("can't open '%s'\n", rentry->fname );
+ return G10ERR_OPEN_FILE;
+ }
+ kbpos->pkt = NULL;
+ }
+ else if( mode == 1 ) {
+ int cont;
+ do {
+ cont = 0;
+ if( !kbpos->fp )
+ return G10ERR_GENERAL;
+ rc = keyring_enum( kbpos, ret_root );
+ if( rc == -1 ) {
+ assert( !kbpos->pkt );
+ rentry = check_pos( kbpos );
+ assert(rentry);
+ /* close */
+ enum_keyblocks(2, kbpos, ret_root );
+ /* and open the next one */
+ rc = enum_keyblocks(100, kbpos, ret_root );
+ if( !rc )
+ cont = 1;
+ }
+ } while(cont);
+ }
+ else if( kbpos->fp ) {
+ iobuf_close( kbpos->fp );
+ kbpos->fp = NULL;
+ /* release pending packet */
+ free_packet( kbpos->pkt );
+ m_free( kbpos->pkt );
+ }
+ return rc;
+}
+
+
+
+
/****************
* Insert the keyblock described by ROOT into the keyring described
* by KBPOS. This actually appends the data to the keyfile.
@@ -551,9 +624,8 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
if( rc )
release_kbnode( root );
- else {
+ else
*ret_root = root;
- }
free_packet( pkt );
m_free( pkt );
iobuf_close(a);
@@ -561,6 +633,69 @@ keyring_read( KBPOS *kbpos, KBNODE *ret_root )
}
+static int
+keyring_enum( KBPOS *kbpos, KBNODE *ret_root )
+{
+ PACKET *pkt;
+ int rc;
+ RESTBL *rentry;
+ KBNODE root = NULL;
+ int in_cert = 0;
+
+ if( !(rentry=check_pos(kbpos)) )
+ return G10ERR_GENERAL;
+
+ if( kbpos->pkt ) {
+ root = new_kbnode( kbpos->pkt );
+ kbpos->pkt = NULL;
+ }
+
+ pkt = m_alloc( sizeof *pkt );
+ init_packet(pkt);
+ while( (rc=parse_packet(kbpos->fp, pkt)) != -1 ) {
+ if( rc ) { /* ignore errors */
+ if( rc != G10ERR_UNKNOWN_PACKET ) {
+ log_error("read_keyblock: read error: %s\n", g10_errstr(rc) );
+ rc = G10ERR_INV_KEYRING;
+ goto ready;
+ }
+ free_packet( pkt );
+ continue;
+ }
+ /* make a linked list of all packets */
+ switch( pkt->pkttype ) {
+ case PKT_PUBLIC_CERT:
+ case PKT_SECRET_CERT:
+ if( in_cert ) { /* store this packet */
+ kbpos->pkt = pkt;
+ pkt = NULL;
+ goto ready;
+ }
+ in_cert = 1;
+ default:
+ if( !root )
+ root = new_kbnode( pkt );
+ else
+ add_kbnode( root, new_kbnode( pkt ) );
+ pkt = m_alloc( sizeof *pkt );
+ init_packet(pkt);
+ break;
+ }
+ }
+ ready:
+ if( rc == -1 && root )
+ rc = 0;
+
+ if( rc )
+ release_kbnode( root );
+ else
+ *ret_root = root;
+ free_packet( pkt );
+ m_free( pkt );
+ return rc;
+}
+
+
/****************
* Peromf insert/delete/update operation.
@@ -579,6 +714,8 @@ keyring_copy( KBPOS *kbpos, int mode, KBNODE root )
if( !(rentry = check_pos( kbpos )) )
return G10ERR_GENERAL;
+ if( kbpos->fp )
+ BUG(); /* not allowed with such a handle */
/* open the source file */
fp = iobuf_open( rentry->fname );
diff --git a/g10/sign.c b/g10/sign.c
index 52718b390..d6777442a 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -796,14 +796,14 @@ edit_keysigs( const char *username )
/* search the userid */
rc = find_keyblock_byname( &kbpos, username );
if( rc ) {
- log_error("user '%s' not found\n", username );
+ log_error("%s: user not found\n", username );
goto leave;
}
/* read the keyblock */
rc = read_keyblock( &kbpos, &keyblock );
if( rc ) {
- log_error("error reading the certificate: %s\n", g10_errstr(rc) );
+ log_error("%s: certificate read problem: %s\n", username, g10_errstr(rc) );
goto leave;
}