1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-02-02 16:43:03 +01:00

See ChangeLog: Wed Mar 8 18:44:59 CET 2000 Werner Koch

This commit is contained in:
Werner Koch 2000-03-08 17:42:19 +00:00
parent f818c5ea6b
commit 0154d59f4d
4 changed files with 502 additions and 71 deletions

View File

@ -1,3 +1,22 @@
2000-03-08 10:38:38 Werner Koch (wk@habibti.openit.de)
* keygen.c (ask_algo): Removed is_v4 return value and the commented
code to create Elg keys in a v3 packet. Removed the rounding
of key sizes here.
(do_create): Likewise removed arg v4_packet.
(gen_elg): Likewise removed arg version. Now rounding keysizes here.
(gen_dsa): Rounding keysize now here.
(release_parameter_list): New
(get_parameter*): New.
(proc_parameter_file): New.
(read_parameter_file): New.
(generate_keypair): Splitted. Now uses read_parameter_file when in
batch mode. Additional argument to specify a parameter file.
(do_generate_keypair): Main bulk of above fucntion and uses the
parameter list.
(do_create): Don't print long notice in batch mode.
* g10.c (main): Allow batched key generation.
Thu Mar 2 15:37:46 CET 2000 Werner Koch <wk@gnupg.de>
* pubkey-enc.c (get_it): Print a note about unknown cipher algos.

View File

@ -1258,10 +1258,17 @@ main( int argc, char **argv )
wrong_args(_("-k[v][v][v][c] [user-id] [keyring]") );
break;
case aKeygen: /* generate a key (interactive) */
case aKeygen: /* generate a key */
if( opt.batch ) {
if( argc > 1 )
wrong_args("--gen-key [parameterfile]");
generate_keypair( argc? *argv : NULL );
}
else {
if( argc )
wrong_args("--gen-key");
generate_keypair();
generate_keypair(NULL);
}
break;
case aFastImport:

View File

@ -35,6 +35,37 @@
#include "status.h"
#include "i18n.h"
enum para_name {
pKEYTYPE,
pKEYLENGTH,
pSUBKEYTYPE,
pSUBKEYLENGTH,
pNAMEREAL,
pNAMEEMAIL,
pNAMECOMMENT,
pUSERID,
pEXPIREDATE,
pKEYEXPIRE, /* in n seconds */
pSUBKEYEXPIRE, /* in n seconds */
pPASSPHRASE,
pPASSPHRASE_DEK,
pPASSPHRASE_S2K
};
struct para_data_s {
struct para_data_s *next;
int lnr;
enum para_name key;
union {
DEK *dek;
STRING2KEY *s2k;
char value[1];
} u;
};
static void do_generate_keypair( struct para_data_s *para );
static void
write_uid( KBNODE root, const char *s )
@ -192,8 +223,7 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
static int
gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval,
int version )
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
{
int rc;
int i;
@ -204,6 +234,17 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
MPI *factors;
assert( is_ELGAMAL(algo) );
if( nbits < 512 ) {
nbits = 1024;
log_info(_("keysize invalid; using %u bits\n"), nbits );
}
if( (nbits % 32) ) {
nbits = ((nbits + 31) / 32) * 32;
log_info(_("keysize rounded up to %u bits\n"), nbits );
}
rc = pubkey_generate( algo, nbits, skey, &factors );
if( rc ) {
log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
@ -213,7 +254,7 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
sk = m_alloc_clear( sizeof *sk );
pk = m_alloc_clear( sizeof *pk );
sk->timestamp = pk->timestamp = make_timestamp();
sk->version = pk->version = version;
sk->version = pk->version = 4;
if( expireval ) {
sk->expiredate = pk->expiredate = sk->timestamp + expireval;
}
@ -267,7 +308,7 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
* Generate a DSA key
*/
static int
gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
{
int rc;
@ -278,8 +319,15 @@ gen_dsa(unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
MPI skey[5];
MPI *factors;
if( nbits > 1024 )
if( nbits > 1024 || nbits < 512 ) {
nbits = 1024;
log_info(_("keysize invalid; using %u bits\n"), nbits );
}
if( (nbits % 64) ) {
nbits = ((nbits + 63) / 64) * 64;
log_info(_("keysize rounded up to %u bits\n"), nbits );
}
rc = pubkey_generate( PUBKEY_ALGO_DSA, nbits, skey, &factors );
if( rc ) {
@ -379,7 +427,7 @@ check_valid_days( const char *s )
* Returns: 0 to create both a DSA and a ElGamal key.
*/
static int
ask_algo( int *ret_v4, int addmode )
ask_algo( int addmode )
{
char *answer;
int algo;
@ -391,11 +439,7 @@ ask_algo( int *ret_v4, int addmode )
if( addmode )
tty_printf( _(" (%d) ElGamal (encrypt only)\n"), 3 );
tty_printf( _(" (%d) ElGamal (sign and encrypt)\n"), 4 );
#if 0
tty_printf( _(" (%d) ElGamal in a v3 packet\n"), 5 );
#endif
*ret_v4 = 1;
for(;;) {
answer = cpr_get("keygen.algo",_("Your selection? "));
cpr_kill_prompt();
@ -420,13 +464,6 @@ ask_algo( int *ret_v4, int addmode )
algo = PUBKEY_ALGO_DSA;
break;
}
#if 0
else if( algo == 5 ) {
algo = PUBKEY_ALGO_ELGAMAL_E;
*ret_v4 = 0;
break;
}
#endif
else
tty_printf(_("Invalid selection.\n"));
}
@ -781,11 +818,11 @@ ask_passphrase( STRING2KEY **ret_s2k )
static int
do_create( int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root,
DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate,
int v4_packet )
DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate )
{
int rc=0;
if( !opt.batch )
tty_printf(_(
"We need to generate a lot of random bytes. It is a good idea to perform\n"
"some other action (type on the keyboard, move the mouse, utilize the\n"
@ -794,7 +831,7 @@ do_create( int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root,
if( algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E )
rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k,
sk, expiredate, v4_packet? 4:3 );
sk, expiredate );
else if( algo == PUBKEY_ALGO_DSA )
rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
else
@ -835,54 +872,409 @@ generate_user_id()
}
static void
release_parameter_list( struct para_data_s *r )
{
struct para_data_s *r2;
for( ; r ; r = r2 ) {
r2 = r->next;
if( r->key == pPASSPHRASE_DEK )
m_free( r->u.dek );
else if( r->key == pPASSPHRASE_S2K )
m_free( r->u.s2k );
m_free(r);
}
}
static struct para_data_s *
get_parameter( struct para_data_s *para, enum para_name key )
{
struct para_data_s *r;
for( r = para; r && r->key != key; r = r->next )
;
return r;
}
static const char *
get_parameter_value( struct para_data_s *para, enum para_name key )
{
struct para_data_s *r = get_parameter( para, key );
return (r && *r->u.value)? r->u.value : NULL;
}
static int
get_parameter_algo( struct para_data_s *para, enum para_name key )
{
struct para_data_s *r = get_parameter( para, key );
if( !r )
return -1;
if( isdigit( *r->u.value ) )
return atoi( r->u.value );
return string_to_pubkey_algo( r->u.value );
}
static u32
get_parameter_u32( struct para_data_s *para, enum para_name key )
{
struct para_data_s *r = get_parameter( para, key );
if( !r )
return 0;
return (unsigned int)strtoul( r->u.value, NULL, 10 );
}
static unsigned int
get_parameter_uint( struct para_data_s *para, enum para_name key )
{
return get_parameter_u32( para, key );
}
static DEK *
get_parameter_dek( struct para_data_s *para, enum para_name key )
{
struct para_data_s *r = get_parameter( para, key );
return r? r->u.dek : NULL;
}
static STRING2KEY *
get_parameter_s2k( struct para_data_s *para, enum para_name key )
{
struct para_data_s *r = get_parameter( para, key );
return r? r->u.s2k : NULL;
}
static int
proc_parameter_file( struct para_data_s *para, const char *fname )
{
struct para_data_s *r;
const char *s1, *s2, *s3;
size_t n;
char *p;
int i;
/* check that we have all required parameters */
assert( get_parameter( para, pKEYTYPE ) );
i = get_parameter_algo( para, pKEYTYPE );
if( i < 1 || check_pubkey_algo2( i, PUBKEY_USAGE_SIG ) ) {
r = get_parameter( para, pKEYTYPE );
log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
return -1;
}
i = get_parameter_algo( para, pSUBKEYTYPE );
if( i > 1 && check_pubkey_algo( i ) ) {
r = get_parameter( para, pSUBKEYTYPE );
log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
return -1;
}
if( !get_parameter_value( para, pUSERID ) ) {
/* create the formatted user ID */
s1 = get_parameter_value( para, pNAMEREAL );
s2 = get_parameter_value( para, pNAMECOMMENT );
s3 = get_parameter_value( para, pNAMEEMAIL );
if( s1 || s2 || s3 ) {
n = (s1?strlen(s1):0) + (s2?strlen(s2):0) + (s3?strlen(s3):0);
r = m_alloc_clear( sizeof *r + n + 20 );
r->key = pUSERID;
p = r->u.value;
if( s1 )
p = stpcpy(p, s1 );
if( s2 )
p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")");
if( s3 )
p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">");
r->next = para;
para = r;
}
}
r = get_parameter( para, pPASSPHRASE );
if( r && *r->u.value ) {
/* we have a plain text passphrase - create a DEK from it.
* It is a little bit ridiculous to keep it ih secure memory
* but becuase we do this alwasy, why not here */
STRING2KEY *s2k;
DEK *dek;
s2k = m_alloc_secure( sizeof *s2k );
s2k->mode = opt.s2k_mode;
s2k->hash_algo = opt.s2k_digest_algo;
set_next_passphrase( r->u.value );
dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 );
set_next_passphrase( NULL );
assert( dek );
memset( r->u.value, 0, strlen(r->u.value) );
r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_S2K;
r->u.s2k = s2k;
r->next = para;
para = r;
r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_DEK;
r->u.dek = dek;
r->next = para;
para = r;
}
do_generate_keypair( para );
return 0;
}
/****************
* Kludge to allow non interactive key generation controlled
* by a parameter file (which currently is only stdin)
* Note, that string parameters are expected to be in UTF-8
*/
static void
read_parameter_file( const char *fname )
{
static struct { const char *name;
enum para_name key;
} keywords[] = {
{ "Key-Type", pKEYTYPE},
{ "Key-Length", pKEYLENGTH },
{ "Subkey-Type", pSUBKEYTYPE },
{ "Subkey-Length", pSUBKEYLENGTH },
{ "Name-Real", pNAMEREAL },
{ "Name-Email", pNAMEEMAIL },
{ "Name-Comment", pNAMECOMMENT },
{ "Expire-Date", pEXPIREDATE },
{ "Passphrase", pPASSPHRASE },
{ NULL, 0 }
};
FILE *fp;
char line[1024], *p;
int lnr;
const char *err = NULL;
struct para_data_s *para, *r;
int i;
if( !fname || !*fname || !strcmp(fname,"-") ) {
fp = stdin;
fname = "-";
}
else {
fp = fopen( fname, "r" );
if( !fp ) {
log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
return;
}
}
lnr = 0;
err = NULL;
para = NULL;
while( fgets( line, DIM(line)-1, fp ) ) {
char *keyword, *value;
lnr++;
if( *line && line[strlen(line)-1] != '\n' ) {
err = "line too long";
break;
}
for( p = line; isspace(*p); p++ )
;
if( !*p || *p == '#' )
continue;
keyword = p;
if( *keyword == '%' ) {
/* for now these are all comments but in future they may be used
* to control certain aspects */
continue;
}
if( !(p = strchr( p, ':' )) || p == keyword ) {
err = "missing colon";
break;
}
*p++ = 0;
for( ; isspace(*p); p++ )
;
if( !*p ) {
err = "missing argument";
break;
}
value = p;
trim_trailing_ws( value, strlen(value) );
for(i=0; keywords[i].name; i++ ) {
if( !stricmp( keywords[i].name, keyword ) )
break;
}
if( !keywords[i].name ) {
err = "unknown keyword";
break;
}
if( keywords[i].key != pKEYTYPE && !para ) {
err = "parameter block does not start with \"Key-Type\"";
break;
}
if( keywords[i].key == pKEYTYPE && para ) {
proc_parameter_file( para, fname );
release_parameter_list( para );
para = NULL;
}
else {
for( r = para; r; r = r->next ) {
if( r->key == keywords[i].key )
break;
}
if( r ) {
err = "duplicate keyword";
break;
}
}
r = m_alloc_clear( sizeof *r + strlen( value ) );
r->lnr = lnr;
r->key = keywords[i].key;
strcpy( r->u.value, value );
r->next = para;
para = r;
}
if( err )
log_error("%s:%d: %s\n", fname, lnr, err );
else if( ferror(fp) ) {
log_error("%s:%d: read error: %s\n", fname, lnr, strerror(errno) );
}
else if( para ) {
proc_parameter_file( para, fname );
}
release_parameter_list( para );
if( strcmp( fname, "-" ) )
fclose(fp);
}
/****************
* Generate a keypair
* (fname is only used in batch mode)
*/
void
generate_keypair()
generate_keypair( const char *fname )
{
unsigned nbits;
char *pub_fname = NULL;
char *sec_fname = NULL;
unsigned int nbits;
char *uid = NULL;
KBNODE pub_root = NULL;
KBNODE sec_root = NULL;
PKT_secret_key *sk = NULL;
DEK *dek;
STRING2KEY *s2k;
int rc;
int algo;
u32 expire;
int v4;
int both = 0;
u32 expire;
struct para_data_s *para = NULL;
struct para_data_s *r;
if( opt.batch || opt.answer_yes || opt.answer_no ) {
log_error(_("Key generation can only be used in interactive mode\n"));
if( opt.batch ) {
read_parameter_file( fname );
return;
}
algo = ask_algo( &v4, 0 );
if( !algo ) {
algo = PUBKEY_ALGO_ELGAMAL_E;
algo = ask_algo( 0 );
if( !algo ) { /* default: DSA with ElG subkey of the specified size */
both = 1;
r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
r->next = para;
para = r;
tty_printf(_("DSA keypair will have 1024 bits.\n"));
r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYLENGTH;
strcpy( r->u.value, "1024" );
r->next = para;
para = r;
algo = PUBKEY_ALGO_ELGAMAL_E;
r = m_alloc_clear( sizeof *r + 20 );
r->key = pSUBKEYTYPE;
sprintf( r->u.value, "%d", algo );
r->next = para;
para = r;
}
else {
r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
sprintf( r->u.value, "%d", algo );
r->next = para;
para = r;
}
nbits = ask_keysize( algo );
r = m_alloc_clear( sizeof *r + 20 );
r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
sprintf( r->u.value, "%u", nbits);
r->next = para;
para = r;
expire = ask_expire_interval();
r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYEXPIRE;
sprintf( r->u.value, "%lu", (ulong)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 ) {
log_error(_("Key generation canceled.\n"));
release_parameter_list( para );
return;
}
r = m_alloc_clear( sizeof *r + strlen(uid) );
r->key = pUSERID;
strcpy( r->u.value, uid );
r->next = para;
para = r;
dek = ask_passphrase( &s2k );
if( dek ) {
r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_DEK;
r->u.dek = dek;
r->next = para;
para = r;
r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_S2K;
r->u.s2k = s2k;
r->next = para;
para = r;
}
proc_parameter_file( para, "[internal]" );
release_parameter_list( para );
}
/* now check whether we are allowed to write to the keyrings */
static void
do_generate_keypair( struct para_data_s *para )
{
char *pub_fname = NULL;
char *sec_fname = NULL;
KBNODE pub_root = NULL;
KBNODE sec_root = NULL;
PKT_secret_key *sk = NULL;
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( opt.verbose ) {
tty_printf(_("writing public certificate to `%s'\n"), pub_fname );
tty_printf(_("writing secret certificate to `%s'\n"), sec_fname );
log_info(_("writing public certificate to `%s'\n"), pub_fname );
log_info(_("writing secret certificate to `%s'\n"), sec_fname );
}
/* we create the packets as a tree of kbnodes. Because the structure
@ -893,24 +1285,31 @@ generate_keypair()
pub_root = make_comment_node("#"); delete_kbnode(pub_root);
sec_root = make_comment_node("#"); delete_kbnode(sec_root);
if( both )
rc = do_create( PUBKEY_ALGO_DSA, 1024, pub_root, sec_root,
dek, s2k, &sk, expire, 1);
else
rc = do_create( algo, nbits, pub_root, sec_root,
dek, s2k, &sk, expire, v4);
rc = do_create( get_parameter_algo( para, pKEYTYPE ),
get_parameter_uint( para, pKEYLENGTH ),
pub_root, sec_root,
get_parameter_dek( para, pPASSPHRASE_DEK ),
get_parameter_s2k( para, pPASSPHRASE_S2K ),
&sk,
get_parameter_u32( para, pKEYEXPIRE ) );
if( !rc && (s=get_parameter_value(para, pUSERID)) ) {
write_uid(pub_root, s );
if( !rc )
write_uid(pub_root, uid );
if( !rc )
write_uid(sec_root, uid );
write_uid(sec_root, s );
if( !rc )
rc = write_selfsig(pub_root, pub_root, sk);
if( !rc )
rc = write_selfsig(sec_root, pub_root, sk);
}
if( both ) {
rc = do_create( algo, nbits, pub_root, sec_root,
dek, s2k, NULL, expire, 1 );
if( get_parameter( para, pSUBKEYTYPE ) ) {
rc = do_create( get_parameter_algo( para, pSUBKEYTYPE ),
get_parameter_uint( para, pSUBKEYLENGTH ),
pub_root, sec_root,
get_parameter_dek( para, pPASSPHRASE_DEK ),
get_parameter_s2k( para, pPASSPHRASE_S2K ),
NULL,
get_parameter_u32( para, pSUBKEYEXPIRE ) );
if( !rc )
rc = write_keybinding(pub_root, pub_root, sk);
if( !rc )
@ -959,13 +1358,18 @@ generate_keypair()
else if( (rc=insert_keyblock( &sec_kbpos, sec_root )) )
log_error("can't write secret key: %s\n", g10_errstr(rc) );
else {
if( !opt.batch )
tty_printf(_("public and secret key created and signed.\n") );
if( algo == PUBKEY_ALGO_DSA )
if( !opt.batch
&& get_parameter_algo( para, pKEYTYPE ) == PUBKEY_ALGO_DSA
&& !get_parameter( para, pSUBKEYTYPE ) )
{
tty_printf(_("Note that this key cannot be used for "
"encryption. You may want to use\n"
"the command \"--edit-key\" to generate a "
"secondary key for this purpose.\n") );
}
}
if( !rc1 )
unlock_keyblock( &pub_kbpos );
@ -974,15 +1378,16 @@ generate_keypair()
}
if( rc )
if( rc ) {
if( opt.batch )
log_error(_("Key generation failed: %s\n"), g10_errstr(rc) );
else
tty_printf(_("Key generation failed: %s\n"), g10_errstr(rc) );
}
release_kbnode( pub_root );
release_kbnode( sec_root );
if( sk ) /* the unprotected secret key */
free_secret_key(sk);
m_free(uid);
m_free(dek);
m_free(s2k);
m_free(pub_fname);
m_free(sec_fname);
}
@ -998,7 +1403,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
int okay=0, rc=0;
KBNODE node;
PKT_secret_key *sk = NULL; /* this is the primary sk */
int v4, algo;
int algo;
u32 expire;
unsigned nbits;
char *passphrase = NULL;
@ -1049,7 +1454,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
goto leave;
algo = ask_algo( &v4, 1 );
algo = ask_algo( 1 );
assert(algo);
nbits = ask_keysize( algo );
expire = ask_expire_interval();
@ -1066,7 +1471,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
}
rc = do_create( algo, nbits, pub_keyblock, sec_keyblock,
dek, s2k, NULL, expire, v4 );
dek, s2k, NULL, expire );
if( !rc )
rc = write_keybinding(pub_keyblock, pub_keyblock, sk);
if( !rc )

View File

@ -92,7 +92,7 @@ void keyedit_menu( const char *username, STRLIST locusr, STRLIST cmds,
/*-- keygen.c --*/
u32 ask_expiredate(void);
void generate_keypair(void);
void generate_keypair( const char *fname );
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );