1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-22 01:12:45 +02:00

See ChangeLog: Thu Mar 9 15:25:59 CET 2000 Werner Koch

This commit is contained in:
Werner Koch 2000-03-09 14:23:16 +00:00
parent 0154d59f4d
commit eb5727c51d
11 changed files with 389 additions and 57 deletions

2
NEWS
View File

@ -1,6 +1,8 @@
Noteworthy changes in the current test release
----------------------------------------------
* Add an experimental feature to do unattended key generation.
* The user is now asked for the reason of revocation as required
by the new OpenPGP draft.

View File

@ -1,3 +1,7 @@
2000-03-09 15:01:51 Werner Koch (wk@habibti.openit.de)
* DETAILS: Ad a short blurb about unattended key generation.
Wed Feb 9 15:33:44 CET 2000 Werner Koch <wk@gnupg.de>
* gpg.sgml: Describe --ignore-time-conflict.

View File

@ -231,6 +231,107 @@ Key generation
Crypto '97 proceedings p. 260.
Unattended key generation
=========================
There is an experimental feature which allows for unattended
generation of keys controlled by a parameter file.
This feature is not very well tested and does only make sense for some
very special applications. Please don't complain if we decide to chnage
the behaviour of this command.
To use this feature, you use --gen-key together with --batch and feed the
parameters either form stdin or from a file given on the commandline.
The format of this file is as follows:
o Text only, line length is limited to about 1000 chars.
o You must use UTF-8 encoding to specifiy non-ascii characters.
o Empty lines are ignored
o Leading and trailing spaces are ignored
o A hash sign as the first non white space character indicates a comment line
o Control statements are indicated by a leading percent sign, the
arguments are separated by white space from the keyword.
o Parameters are specified by a keyword, followed by a colon. Arguments
are speparated by white space.
o The first parameter must be "Key-Type", control statements
may be placed anywhere.
o Key generation takes place when either the end of the parameter file
is reached, the next "Key-Type" parameter is encountered or at the
controlstatement "%commit"
o Control staements:
%echo <text>
Print <text>
%dry-run
Suppress actual key generation (useful for syntax checking)
%commit
Perform the key generation. An implicit commit is done
at the next "Key-Type" parameter.
%pubring <filename>
%secring <filename>
Do not write the key to the default or commandline given
keyring but to <filename>. This must be given before the first
commit to take place, duplicate specification of the same filename
is ignored, the last filename before a commit is used.
The filename is used until a new filename is used (at commit points)
and all keys are written to that file. If a new filename is given,
this file is created (and overwrites an existing one).
Both control statements must be given.
o The order of the parameters does not matter except for "Key-Type"
which must be the first parameter. The paramtyers are only for the
generated keyblock and paramters from previous key generations are not
used. Some syntactically checks may be performed.
The currently defined parameters are:
Key-Type: <algo-number>|<algo-string>
Starts a new parameter block by giving the type of the
primary key. The algorithm must be capable of signing.
This is a required parameter.
Key-Length: <length-in-bits>
Length of the key in bits. Default is 1024
Subkey-Type: <algo-number>|<algo-string>
This generates a secondary key. Currently only one subkey
can be handled.
Subkey-Length: <length-in-bits>
Length of the subkey in bits. Default is 1024.
Passphrase: <string>
If you want to specify a passphrase for the secret key,
enter it here. Default is not to use any passphrase.
Name-Real: <string>
Name-Comment: <string>
Name-Email: <string>
The 3 parts of a key. Remember to use UTF-8 here.
If you don't give any of them, no user ID is created.
Expire-Date: <iso-date>|(<number>[d|w|m|y])
Set the expiration date for the key (and the subkey). It
may either be entered in ISO date format (2000-08-15) or as
number of days, weeks, month or years. Without a letter days
are assumed.
Here is an example:
$ cat >foo <<EOF
%echo Generating a standard key
Key-Type: DSA
Key-Length: 1024
Subkey-Type: ELG-E
Subkey-Length: 1024
Name-Real: Joe Tester
Name-Comment: with stupid passphrase
Name-Email: joe@foo.bar
Expire-Date: 0
Passphrase: abc
%pubring foo.pub
%secring foo.sec
# Do a commit here, so that we can later print "done" :-)
%commit
%echo done
EOF
$ gpg --batch --gen-key -a foo
[...]
$ gpg --no-default-keyring --secret-keyring foo.sec \
--keyring foo.pub --list-secret-keys
/home/wk/work/gnupg-stable/scratch/foo.sec
------------------------------------------
sec 1024D/915A878D 2000-03-09 Joe Tester (with stupid passphrase) <joe@foo.bar>
ssb 1024g/8F70E2C0 2000-03-09
Layout of the TrustDB
=====================

View File

@ -10,12 +10,12 @@ CVS Access
==========
Anonymous read-only CVS access is available:
cvs -z6 -d :pserver:anonymous@ftp.guug.de:/home/koch/cvs login
cvs -z6 -d :pserver:anonymous@cvs.guug.de:/home/koch/cvs login
use the password "anonymous". To check out the the complete
archive use:
cvs -z6 -d :pserver:anonymous@ftp.guug.de:/home/koch/cvs checkout gnupg
cvs -z6 -d :pserver:anonymous@cvs.guug.de:/home/koch/cvs checkout gnupg
This service is provided to help you in hunting bugs and not to deliver
stable snapshots; it may happen that it even does not compile, so please

View File

@ -235,8 +235,13 @@ useful for debugging.
<varlistentry>
<term>--gen-key</term>
<listitem><para>
Generate a new key pair. This command can only be
used interactive.
Generate a new key pair. This command is normally only used
interactive.
</para>
<para>
There is an experimental feature which allows to create keys
in batch mode. See the file <filename>doc/DETAILS</filename>
in the source distribution on how to use this.
</para></listitem></varlistentry>

View File

@ -1,3 +1,11 @@
2000-03-09 12:53:09 Werner Koch (wk@habibti.openit.de)
* keygen.c (ask_expire_interval): Movede parsig to ...
(parse_expire_string): ... this new function. And some new control
commands.
(proc_parameter_file): Add expire date parsing.
(do_generate_keypair): Allow the use of specified output files.
2000-03-08 10:38:38 Werner Koch (wk@habibti.openit.de)
* keygen.c (ask_algo): Removed is_v4 return value and the commented

View File

@ -201,7 +201,7 @@ do_export_stream( IOBUF out, STRLIST users, int secret, int onlyrfc, int *any )
if( secret == 2 && node->pkt->pkttype == PKT_SECRET_KEY ) {
/* we don't want to export the secret parts of the
* primary key, this is doen by using GNU protection mode 1001
* primary key, this is done by using GNU protection mode 1001
*/
int save_mode = node->pkt->pkt.secret_key->protect.s2k.mode;
node->pkt->pkt.secret_key->protect.s2k.mode = 1001;

View File

@ -1,5 +1,5 @@
/* g10.c - The GnuPG utility (main for gpg)
* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*

View File

@ -1,5 +1,5 @@
/* keygen.c - generate a key pair
* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -59,12 +59,33 @@ struct para_data_s {
union {
DEK *dek;
STRING2KEY *s2k;
u32 expire;
char value[1];
} u;
};
struct output_control_s {
int lnr;
int dryrun;
int use_files;
struct {
char *fname;
char *newfname;
IOBUF stream;
armor_filter_context_t afx;
} pub;
struct {
char *fname;
char *newfname;
IOBUF stream;
armor_filter_context_t afx;
} sec;
};
static void do_generate_keypair( struct para_data_s *para );
static void do_generate_keypair( struct para_data_s *para,
struct output_control_s *outctrl );
static int write_keyblock( IOBUF out, KBNODE node );
static void
@ -537,6 +558,41 @@ ask_keysize( int algo )
}
/****************
* Parse an expire string and return it's value in days.
* Returns -1 on error.
*/
static int
parse_expire_string( const char *string )
{
int mult;
u32 abs_date=0;
u32 curtime = make_timestamp();
int valid_days;
if( !*string )
valid_days = 0;
else if( (abs_date = scan_isodatestr(string)) && abs_date > curtime ) {
/* This calculation is not perfectly okay because we
* are later going to simply multiply by 86400 and don't
* correct for leapseconds. A solution would be to change
* the whole implemenation to work with dates and not intervals
* which are required for v3 keys.
*/
valid_days = abs_date/86400-curtime/86400+1;
}
else if( (mult=check_valid_days(string)) ) {
valid_days = atoi(string) * mult;
if( valid_days < 0 || valid_days > 39447 )
valid_days = 0;
}
else {
valid_days = -1;
}
return valid_days;
}
static u32
ask_expire_interval(void)
{
@ -556,32 +612,14 @@ ask_expire_interval(void)
answer = NULL;
for(;;) {
int mult;
u32 abs_date=0;
u32 curtime=0;;
u32 curtime=make_timestamp();
m_free(answer);
answer = cpr_get("keygen.valid",_("Key is valid for? (0) "));
cpr_kill_prompt();
trim_spaces(answer);
curtime = make_timestamp();
if( !*answer )
valid_days = 0;
else if( (abs_date = scan_isodatestr(answer)) && abs_date > curtime ) {
/* This calculation is not perfectly okay because we
* are later going to simply multiply by 86400 and don't
* correct for leapseconds. A solution would be to change
* the whole implemenation to work with dates and not intervals
* which are required for v3 keys.
*/
valid_days = abs_date/86400-curtime/86400+1;
}
else if( (mult=check_valid_days(answer)) ) {
valid_days = atoi(answer) * mult;
if( valid_days < 0 || valid_days > 39447 )
valid_days = 0;
}
else {
valid_days = parse_expire_string( answer );
if( valid_days < 0 ) {
tty_printf(_("invalid value\n"));
continue;
}
@ -924,6 +962,9 @@ get_parameter_u32( struct para_data_s *para, enum para_name key )
if( !r )
return 0;
if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE )
return r->u.expire;
return (unsigned int)strtoul( r->u.value, NULL, 10 );
}
@ -949,7 +990,8 @@ get_parameter_s2k( struct para_data_s *para, enum para_name key )
static int
proc_parameter_file( struct para_data_s *para, const char *fname )
proc_parameter_file( struct para_data_s *para, const char *fname,
struct output_control_s *outctrl )
{
struct para_data_s *r;
const char *s1, *s2, *s3;
@ -994,6 +1036,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname )
}
}
/* make DEK and S2K from the Passphrase */
r = get_parameter( para, pPASSPHRASE );
if( r && *r->u.value ) {
/* we have a plain text passphrase - create a DEK from it.
@ -1022,7 +1065,31 @@ proc_parameter_file( struct para_data_s *para, const char *fname )
r->next = para;
para = r;
}
do_generate_keypair( para );
/* make KEYEXPIRE from Expire-Date */
r = get_parameter( para, pEXPIREDATE );
if( r && *r->u.value ) {
i = parse_expire_string( r->u.value );
if( i < 0 ) {
log_error("%s:%d: invalid expire date\n", fname, r->lnr );
return -1;
}
r->u.expire = i * 86400L;
r->key = pKEYEXPIRE; /* change hat entry */
/* also set it for the subkey */
r = m_alloc_clear( sizeof *r + 20 );
r->key = pSUBKEYEXPIRE;
r->u.expire = i * 86400L;
r->next = para;
para = r;
}
if( !!outctrl->pub.newfname ^ !!outctrl->sec.newfname ) {
log_error("%s:%d: only one ring name is set\n", fname, outctrl->lnr );
return -1;
}
do_generate_keypair( para, outctrl );
return 0;
}
@ -1055,6 +1122,9 @@ read_parameter_file( const char *fname )
const char *err = NULL;
struct para_data_s *para, *r;
int i;
struct output_control_s outctrl;
memset( &outctrl, 0, sizeof( outctrl ) );
if( !fname || !*fname || !strcmp(fname,"-") ) {
fp = stdin;
@ -1085,8 +1155,46 @@ read_parameter_file( const char *fname )
continue;
keyword = p;
if( *keyword == '%' ) {
/* for now these are all comments but in future they may be used
* to control certain aspects */
for( ; !isspace(*p); p++ )
;
if( *p )
*p++ = 0;
for( ; isspace(*p); p++ )
;
value = p;
trim_trailing_ws( value, strlen(value) );
if( !stricmp( keyword, "%echo" ) )
log_info("%s\n", value );
else if( !stricmp( keyword, "%dry-run" ) )
outctrl.dryrun = 1;
else if( !stricmp( keyword, "%commit" ) ) {
outctrl.lnr = lnr;
proc_parameter_file( para, fname, &outctrl );
release_parameter_list( para );
para = NULL;
}
else if( !stricmp( keyword, "%pubring" ) ) {
if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) )
; /* still the same file - ignore it */
else {
m_free( outctrl.pub.newfname );
outctrl.pub.newfname = m_strdup( value );
outctrl.use_files = 1;
}
}
else if( !stricmp( keyword, "%secring" ) ) {
if( outctrl.sec.fname && !strcmp( outctrl.sec.fname, value ) )
; /* still the same file - ignore it */
else {
m_free( outctrl.sec.newfname );
outctrl.sec.newfname = m_strdup( value );
outctrl.use_files = 1;
}
}
else
log_info("skipping control `%s' (%s)\n", keyword, value );
continue;
}
@ -1095,7 +1203,8 @@ read_parameter_file( const char *fname )
err = "missing colon";
break;
}
*p++ = 0;
if( *p )
*p++ = 0;
for( ; isspace(*p); p++ )
;
if( !*p ) {
@ -1119,7 +1228,8 @@ read_parameter_file( const char *fname )
}
if( keywords[i].key == pKEYTYPE && para ) {
proc_parameter_file( para, fname );
outctrl.lnr = lnr;
proc_parameter_file( para, fname, &outctrl );
release_parameter_list( para );
para = NULL;
}
@ -1146,8 +1256,19 @@ read_parameter_file( const char *fname )
log_error("%s:%d: read error: %s\n", fname, lnr, strerror(errno) );
}
else if( para ) {
proc_parameter_file( para, fname );
outctrl.lnr = lnr;
proc_parameter_file( para, fname, &outctrl );
}
if( outctrl.use_files ) { /* close open streams */
iobuf_close( outctrl.pub.stream );
iobuf_close( outctrl.sec.stream );
m_free( outctrl.pub.fname );
m_free( outctrl.pub.newfname );
m_free( outctrl.sec.fname );
m_free( outctrl.sec.newfname );
}
release_parameter_list( para );
if( strcmp( fname, "-" ) )
fclose(fp);
@ -1170,6 +1291,9 @@ generate_keypair( const char *fname )
u32 expire;
struct para_data_s *para = NULL;
struct para_data_s *r;
struct output_control_s outctrl;
memset( &outctrl, 0, sizeof( outctrl ) );
if( opt.batch ) {
read_parameter_file( fname );
@ -1216,16 +1340,14 @@ generate_keypair( const char *fname )
expire = ask_expire_interval();
r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYEXPIRE;
sprintf( r->u.value, "%lu", (ulong)expire );
r->u.expire = expire;
r->next = para;
para = r;
r = m_alloc_clear( sizeof *r + 20 );
r->key = pSUBKEYEXPIRE;
r->u.expire = expire;
r->next = para;
para = r;
if( both ) {
r = m_alloc_clear( sizeof *r + 20 );
r->key = pSUBKEYEXPIRE;
sprintf( r->u.value, "%lu", (ulong)expire );
r->next = para;
para = r;
}
uid = ask_user_id(0);
if( !uid ) {
@ -1253,13 +1375,14 @@ generate_keypair( const char *fname )
para = r;
}
proc_parameter_file( para, "[internal]" );
proc_parameter_file( para, "[internal]", &outctrl );
release_parameter_list( para );
}
static void
do_generate_keypair( struct para_data_s *para )
do_generate_keypair( struct para_data_s *para,
struct output_control_s *outctrl )
{
char *pub_fname = NULL;
char *sec_fname = NULL;
@ -1269,12 +1392,68 @@ do_generate_keypair( struct para_data_s *para )
const char *s;
int rc;
/* check whether we are allowed to write to the keyrings */
pub_fname = make_filename(opt.homedir, "pubring.gpg", NULL );
sec_fname = make_filename(opt.homedir, "secring.gpg", NULL );
if( outctrl->dryrun ) {
log_info("dry-run mode - key generation skipped\n");
return;
}
if( outctrl->use_files ) {
if( outctrl->pub.newfname ) {
iobuf_close(outctrl->pub.stream);
outctrl->pub.stream = NULL;
m_free( outctrl->pub.fname );
outctrl->pub.fname = outctrl->pub.newfname;
outctrl->pub.newfname = NULL;
outctrl->pub.stream = iobuf_create( outctrl->pub.fname );
if( !outctrl->pub.stream ) {
log_error("can't create `%s': %s\n", outctrl->pub.newfname,
strerror(errno) );
return;
}
if( opt.armor ) {
outctrl->pub.afx.what = 1;
iobuf_push_filter( outctrl->pub.stream, armor_filter,
&outctrl->pub.afx );
}
}
if( outctrl->sec.newfname ) {
iobuf_close(outctrl->sec.stream);
outctrl->sec.stream = NULL;
m_free( outctrl->sec.fname );
outctrl->sec.fname = outctrl->sec.newfname;
outctrl->sec.newfname = NULL;
outctrl->sec.stream = iobuf_create( outctrl->sec.fname );
if( !outctrl->sec.stream ) {
log_error("can't create `%s': %s\n", outctrl->sec.newfname,
strerror(errno) );
return;
}
if( opt.armor ) {
outctrl->sec.afx.what = 5;
iobuf_push_filter( outctrl->sec.stream, armor_filter,
&outctrl->sec.afx );
}
}
pub_fname = outctrl->pub.fname; /* only for info output */
sec_fname = outctrl->sec.fname; /* only for info output */
assert( outctrl->pub.stream );
assert( outctrl->sec.stream );
}
else {
/* check whether we are allowed to write to the keyrings */
/* It is probably wrong to use the default names here
* but becuase I never gpt any complaints, we better leave
* it as it is. */
pub_fname = make_filename(opt.homedir, "pubring.gpg", NULL );
sec_fname = make_filename(opt.homedir, "secring.gpg", NULL );
}
if( opt.verbose ) {
log_info(_("writing public certificate to `%s'\n"), pub_fname );
log_info(_("writing secret certificate to `%s'\n"), sec_fname );
log_info(_("writing public key to `%s'\n"), pub_fname );
log_info(_("writing secret key to `%s'\n"), sec_fname );
}
/* we create the packets as a tree of kbnodes. Because the structure
@ -1317,7 +1496,18 @@ do_generate_keypair( struct para_data_s *para )
}
if( !rc ) {
if( !rc && outctrl->use_files ) { /* direct write to specified files */
rc = write_keyblock( outctrl->pub.stream, pub_root );
if( rc )
log_error("can't write public key: %s\n", g10_errstr(rc) );
if( !rc ) {
rc = write_keyblock( outctrl->sec.stream, sec_root );
if( rc )
log_error("can't write secret key: %s\n", g10_errstr(rc) );
}
}
else if( !rc ) { /* write to the standard keyrings */
KBPOS pub_kbpos;
KBPOS sec_kbpos;
int rc1 = -1;
@ -1377,10 +1567,9 @@ do_generate_keypair( struct para_data_s *para )
unlock_keyblock( &sec_kbpos );
}
if( rc ) {
if( opt.batch )
log_error(_("Key generation failed: %s\n"), g10_errstr(rc) );
log_error("key generation failed: %s\n", g10_errstr(rc) );
else
tty_printf(_("Key generation failed: %s\n"), g10_errstr(rc) );
}
@ -1388,8 +1577,10 @@ do_generate_keypair( struct para_data_s *para )
release_kbnode( sec_root );
if( sk ) /* the unprotected secret key */
free_secret_key(sk);
m_free(pub_fname);
m_free(sec_fname);
if( !outctrl->use_files ) {
m_free(pub_fname);
m_free(sec_fname);
}
}
@ -1491,3 +1682,20 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
return okay;
}
/****************
* Write a keyblock to an output stream
*/
static int
write_keyblock( IOBUF out, KBNODE node )
{
for( ; node ; node = node->next ) {
int rc = build_packet( out, node->pkt );
if( rc ) {
log_error("build_packet(%d) failed: %s\n",
node->pkt->pkttype, g10_errstr(rc) );
return G10ERR_WRITE_FILE;
}
}
return 0;
}

View File

@ -1,3 +1,7 @@
2000-03-09 14:04:22 Werner Koch (wk@habibti.openit.de)
* argparse.c (default_strusage): Changed year of default copyright.
Tue Mar 7 18:45:31 CET 2000 Werner Koch <wk@gnupg.de>
* secmem.c (lock_pool): No more warning for QNX. By Sam Roberts.

View File

@ -892,7 +892,7 @@ default_strusage( int level )
switch( level ) {
case 11: p = "foo"; break;
case 13: p = "0.0"; break;
case 14: p = "Copyright (C) 1999 Free Software Foundation, Inc."; break;
case 14: p = "Copyright (C) 2000 Free Software Foundation, Inc."; break;
case 15: p =
"This program comes with ABSOLUTELY NO WARRANTY.\n"
"This is free software, and you are welcome to redistribute it\n"