1997-11-18 15:06:00 +01:00
|
|
|
/* keygen.c - generate a key pair
|
2003-02-21 23:16:43 +01:00
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003
|
|
|
|
* Free Software Foundation, Inc.
|
1997-11-18 15:06:00 +01:00
|
|
|
*
|
1998-12-23 13:41:40 +01:00
|
|
|
* This file is part of GnuPG.
|
1997-11-18 15:06:00 +01:00
|
|
|
*
|
1998-12-23 13:41:40 +01:00
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
1997-11-18 15:06:00 +01:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
1998-12-23 13:41:40 +01:00
|
|
|
* GnuPG is distributed in the hope that it will be useful,
|
1997-11-18 15:06:00 +01:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
1998-01-12 11:18:17 +01:00
|
|
|
#include <ctype.h>
|
1997-11-18 15:06:00 +01:00
|
|
|
#include <errno.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include "util.h"
|
|
|
|
#include "main.h"
|
|
|
|
#include "packet.h"
|
2002-06-29 15:46:34 +02:00
|
|
|
#include "cipher.h"
|
1997-11-18 15:06:00 +01:00
|
|
|
#include "ttyio.h"
|
|
|
|
#include "options.h"
|
1997-12-16 20:15:09 +01:00
|
|
|
#include "keydb.h"
|
2002-06-29 15:46:34 +02:00
|
|
|
#include "trustdb.h"
|
1998-08-05 18:51:59 +02:00
|
|
|
#include "status.h"
|
1998-01-28 17:09:43 +01:00
|
|
|
#include "i18n.h"
|
1997-11-18 15:06:00 +01:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
#define MAX_PREFS 30
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
enum para_name {
|
|
|
|
pKEYTYPE,
|
|
|
|
pKEYLENGTH,
|
2002-06-29 15:46:34 +02:00
|
|
|
pKEYUSAGE,
|
2000-07-14 19:34:53 +02:00
|
|
|
pSUBKEYTYPE,
|
|
|
|
pSUBKEYLENGTH,
|
2002-06-29 15:46:34 +02:00
|
|
|
pSUBKEYUSAGE,
|
2000-07-14 19:34:53 +02:00
|
|
|
pNAMEREAL,
|
|
|
|
pNAMEEMAIL,
|
|
|
|
pNAMECOMMENT,
|
2002-06-29 15:46:34 +02:00
|
|
|
pPREFERENCES,
|
|
|
|
pREVOKER,
|
2000-07-14 19:34:53 +02:00
|
|
|
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 {
|
2002-06-29 15:46:34 +02:00
|
|
|
DEK *dek;
|
|
|
|
STRING2KEY *s2k;
|
|
|
|
u32 expire;
|
|
|
|
unsigned int usage;
|
|
|
|
struct revocation_key revkey;
|
|
|
|
char value[1];
|
2000-07-14 19:34:53 +02:00
|
|
|
} 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;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
struct opaque_data_usage_and_pk {
|
|
|
|
unsigned int usage;
|
|
|
|
PKT_public_key *pk;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static int prefs_initialized = 0;
|
|
|
|
static byte sym_prefs[MAX_PREFS];
|
|
|
|
static int nsym_prefs;
|
|
|
|
static byte hash_prefs[MAX_PREFS];
|
|
|
|
static int nhash_prefs;
|
|
|
|
static byte zip_prefs[MAX_PREFS];
|
|
|
|
static int nzip_prefs;
|
2003-02-23 00:58:39 +01:00
|
|
|
static int mdc_available,ks_modify;
|
2002-06-29 15:46:34 +02:00
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
static void do_generate_keypair( struct para_data_s *para,
|
|
|
|
struct output_control_s *outctrl );
|
|
|
|
static int write_keyblock( IOBUF out, KBNODE node );
|
|
|
|
|
1997-11-24 23:24:04 +01:00
|
|
|
|
1997-11-18 15:06:00 +01:00
|
|
|
static void
|
1997-12-16 20:15:09 +01:00
|
|
|
write_uid( KBNODE root, const char *s )
|
1997-11-18 15:06:00 +01:00
|
|
|
{
|
2002-06-29 15:46:34 +02:00
|
|
|
PACKET *pkt = m_alloc_clear(sizeof *pkt );
|
1997-11-18 15:06:00 +01:00
|
|
|
size_t n = strlen(s);
|
|
|
|
|
1997-12-16 20:15:09 +01:00
|
|
|
pkt->pkttype = PKT_USER_ID;
|
2002-06-29 15:46:34 +02:00
|
|
|
pkt->pkt.user_id = m_alloc_clear( sizeof *pkt->pkt.user_id + n - 1 );
|
1997-12-16 20:15:09 +01:00
|
|
|
pkt->pkt.user_id->len = n;
|
2002-06-29 15:46:34 +02:00
|
|
|
pkt->pkt.user_id->ref = 1;
|
1997-12-16 20:15:09 +01:00
|
|
|
strcpy(pkt->pkt.user_id->name, s);
|
|
|
|
add_kbnode( root, new_kbnode( pkt ) );
|
1997-11-18 15:06:00 +01:00
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
static void
|
|
|
|
do_add_key_flags (PKT_signature *sig, unsigned int use)
|
|
|
|
{
|
|
|
|
byte buf[1];
|
|
|
|
|
|
|
|
if (!use)
|
|
|
|
return;
|
|
|
|
|
|
|
|
buf[0] = 0;
|
|
|
|
if (use & PUBKEY_USAGE_SIG)
|
|
|
|
buf[0] |= 0x01 | 0x02;
|
|
|
|
if (use & PUBKEY_USAGE_ENC)
|
|
|
|
buf[0] |= 0x04 | 0x08;
|
|
|
|
build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
|
|
|
|
}
|
1997-11-18 15:06:00 +01:00
|
|
|
|
1998-06-25 12:19:08 +02:00
|
|
|
|
2002-12-01 21:59:04 +01:00
|
|
|
int
|
2002-12-04 19:50:10 +01:00
|
|
|
keygen_add_key_expire( PKT_signature *sig, void *opaque )
|
2002-12-01 21:59:04 +01:00
|
|
|
{
|
2002-12-04 19:50:10 +01:00
|
|
|
PKT_public_key *pk = opaque;
|
|
|
|
byte buf[8];
|
|
|
|
u32 u;
|
|
|
|
|
|
|
|
if( pk->expiredate ) {
|
|
|
|
if(pk->expiredate > pk->timestamp)
|
|
|
|
u= pk->expiredate - pk->timestamp;
|
|
|
|
else
|
|
|
|
u= 0;
|
|
|
|
|
|
|
|
buf[0] = (u >> 24) & 0xff;
|
|
|
|
buf[1] = (u >> 16) & 0xff;
|
|
|
|
buf[2] = (u >> 8) & 0xff;
|
|
|
|
buf[3] = u & 0xff;
|
|
|
|
build_sig_subpkt( sig, SIGSUBPKT_KEY_EXPIRE, buf, 4 );
|
|
|
|
}
|
2002-12-26 23:22:50 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Make sure we don't leave a key expiration subpacket lying
|
|
|
|
around */
|
|
|
|
delete_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE);
|
|
|
|
}
|
2002-12-01 21:59:04 +01:00
|
|
|
|
2002-12-04 19:50:10 +01:00
|
|
|
return 0;
|
1998-06-25 12:19:08 +02:00
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
static int
|
|
|
|
keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
|
|
|
|
{
|
2002-12-04 19:50:10 +01:00
|
|
|
struct opaque_data_usage_and_pk *oduap = opaque;
|
2002-06-29 15:46:34 +02:00
|
|
|
|
2002-12-04 19:50:10 +01:00
|
|
|
do_add_key_flags (sig, oduap->usage);
|
|
|
|
return keygen_add_key_expire (sig, oduap->pk);
|
2002-06-29 15:46:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2002-11-03 01:00:42 +01:00
|
|
|
set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
|
2002-06-29 15:46:34 +02:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2002-11-03 01:00:42 +01:00
|
|
|
for (i=0; i < *nbuf; i++ )
|
|
|
|
if (buf[i] == val)
|
|
|
|
{
|
|
|
|
log_info (_("preference `%s' duplicated\n"), item);
|
|
|
|
return -1;
|
2002-06-29 15:46:34 +02:00
|
|
|
}
|
2002-11-03 01:00:42 +01:00
|
|
|
|
|
|
|
if (*nbuf >= MAX_PREFS)
|
|
|
|
{
|
|
|
|
if(type==1)
|
|
|
|
log_info(_("too many cipher preferences\n"));
|
|
|
|
else if(type==2)
|
|
|
|
log_info(_("too many digest preferences\n"));
|
|
|
|
else if(type==3)
|
|
|
|
log_info(_("too many compression preferences\n"));
|
|
|
|
else
|
|
|
|
BUG();
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
return -1;
|
2002-11-03 01:00:42 +01:00
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
buf[(*nbuf)++] = val;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2003-02-21 23:16:43 +01:00
|
|
|
#ifdef USE_AES
|
2003-03-04 16:24:12 +01:00
|
|
|
#define AES "S9 S8 S7 "
|
2003-02-21 23:16:43 +01:00
|
|
|
#else
|
|
|
|
#define AES ""
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef USE_CAST5
|
|
|
|
#define CAST5 "S3 "
|
|
|
|
#else
|
|
|
|
#define CAST5 ""
|
|
|
|
#endif
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
/*
|
2002-11-03 01:00:42 +01:00
|
|
|
* Parse the supplied string and use it to set the standard
|
|
|
|
* preferences. The string may be in a form like the one printed by
|
|
|
|
* "pref" (something like: "S10 S3 H3 H2 Z2 Z1") or the actual
|
|
|
|
* cipher/hash/compress names. Use NULL to set the default
|
|
|
|
* preferences. Returns: 0 = okay
|
2002-06-29 15:46:34 +02:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
keygen_set_std_prefs (const char *string,int personal)
|
|
|
|
{
|
|
|
|
byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS];
|
2003-02-23 00:58:39 +01:00
|
|
|
int nsym=0, nhash=0, nzip=0, val, rc=0;
|
|
|
|
int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */
|
2002-06-29 15:46:34 +02:00
|
|
|
|
|
|
|
if (!string || !ascii_strcasecmp (string, "default")) {
|
|
|
|
if (opt.def_preference_list)
|
|
|
|
string=opt.def_preference_list;
|
|
|
|
else if ( !check_cipher_algo(CIPHER_ALGO_IDEA) )
|
2003-02-21 23:16:43 +01:00
|
|
|
string = AES CAST5 "S2 S1 H2 H3 Z2 Z1";
|
2002-06-29 15:46:34 +02:00
|
|
|
else
|
2003-02-21 23:16:43 +01:00
|
|
|
string = AES CAST5 "S2 H2 H3 Z2 Z1";
|
2002-06-29 15:46:34 +02:00
|
|
|
|
|
|
|
/* If we have it, IDEA goes *after* 3DES so it won't be used
|
|
|
|
unless we're encrypting along with a V3 key. Ideally, we
|
|
|
|
would only put the S1 preference in if the key was RSA and
|
|
|
|
<=2048 bits, as that is what won't break PGP2, but that is
|
|
|
|
difficult with the current code, and not really worth
|
|
|
|
checking as a non-RSA <=2048 bit key wouldn't be usable by
|
2003-01-07 16:30:02 +01:00
|
|
|
PGP2 anyway. -dms */
|
2002-06-29 15:46:34 +02:00
|
|
|
}
|
|
|
|
else if (!ascii_strcasecmp (string, "none"))
|
|
|
|
string = "";
|
|
|
|
|
2002-11-21 17:25:05 +01:00
|
|
|
if(strlen(string))
|
2002-11-03 01:00:42 +01:00
|
|
|
{
|
2002-11-21 17:25:05 +01:00
|
|
|
char *tok,*prefstring;
|
|
|
|
|
|
|
|
prefstring=m_strdup(string); /* need a writable string! */
|
|
|
|
|
|
|
|
while((tok=strsep(&prefstring," ,")))
|
2002-11-03 01:00:42 +01:00
|
|
|
{
|
2002-11-21 17:25:05 +01:00
|
|
|
if((val=string_to_cipher_algo(tok)))
|
|
|
|
{
|
|
|
|
if(set_one_pref(val,1,tok,sym,&nsym))
|
|
|
|
rc=-1;
|
|
|
|
}
|
|
|
|
else if((val=string_to_digest_algo(tok)))
|
|
|
|
{
|
|
|
|
if(set_one_pref(val,2,tok,hash,&nhash))
|
|
|
|
rc=-1;
|
|
|
|
}
|
|
|
|
else if((val=string_to_compress_algo(tok))>-1)
|
|
|
|
{
|
|
|
|
if(set_one_pref(val,3,tok,zip,&nzip))
|
|
|
|
rc=-1;
|
|
|
|
}
|
|
|
|
else if (ascii_strcasecmp(tok,"mdc")==0)
|
|
|
|
mdc=1;
|
|
|
|
else if (ascii_strcasecmp(tok,"no-mdc")==0)
|
|
|
|
mdc=0;
|
2003-02-23 00:58:39 +01:00
|
|
|
else if (ascii_strcasecmp(tok,"ks-modify")==0)
|
|
|
|
modify=1;
|
|
|
|
else if (ascii_strcasecmp(tok,"no-ks-modify")==0)
|
|
|
|
modify=0;
|
2002-11-21 17:25:05 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
log_info (_("invalid item `%s' in preference string\n"),tok);
|
2003-01-07 16:30:02 +01:00
|
|
|
|
|
|
|
/* Complain if IDEA is not available. */
|
|
|
|
if(ascii_strcasecmp(tok,"s1")==0
|
|
|
|
|| ascii_strcasecmp(tok,"idea")==0)
|
|
|
|
idea_cipher_warn(1);
|
|
|
|
|
2002-11-21 17:25:05 +01:00
|
|
|
rc=-1;
|
|
|
|
}
|
2002-11-03 01:00:42 +01:00
|
|
|
}
|
|
|
|
|
2002-11-21 17:25:05 +01:00
|
|
|
m_free(prefstring);
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
|
2002-11-03 01:00:42 +01:00
|
|
|
if(!rc)
|
2002-06-29 15:46:34 +02:00
|
|
|
{
|
|
|
|
if(personal)
|
|
|
|
{
|
|
|
|
if(personal==PREFTYPE_SYM)
|
|
|
|
{
|
|
|
|
m_free(opt.personal_cipher_prefs);
|
|
|
|
|
|
|
|
if(nsym==0)
|
|
|
|
opt.personal_cipher_prefs=NULL;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
opt.personal_cipher_prefs=
|
|
|
|
m_alloc(sizeof(prefitem_t *)*(nsym+1));
|
|
|
|
|
|
|
|
for (i=0; i<nsym; i++)
|
|
|
|
{
|
|
|
|
opt.personal_cipher_prefs[i].type = PREFTYPE_SYM;
|
|
|
|
opt.personal_cipher_prefs[i].value = sym[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
opt.personal_cipher_prefs[i].type = PREFTYPE_NONE;
|
|
|
|
opt.personal_cipher_prefs[i].value = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(personal==PREFTYPE_HASH)
|
|
|
|
{
|
|
|
|
m_free(opt.personal_digest_prefs);
|
|
|
|
|
|
|
|
if(nhash==0)
|
|
|
|
opt.personal_digest_prefs=NULL;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
opt.personal_digest_prefs=
|
|
|
|
m_alloc(sizeof(prefitem_t *)*(nhash+1));
|
|
|
|
|
|
|
|
for (i=0; i<nhash; i++)
|
|
|
|
{
|
|
|
|
opt.personal_digest_prefs[i].type = PREFTYPE_HASH;
|
|
|
|
opt.personal_digest_prefs[i].value = hash[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
opt.personal_digest_prefs[i].type = PREFTYPE_NONE;
|
|
|
|
opt.personal_digest_prefs[i].value = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(personal==PREFTYPE_ZIP)
|
|
|
|
{
|
|
|
|
m_free(opt.personal_compress_prefs);
|
|
|
|
|
|
|
|
if(nzip==0)
|
|
|
|
opt.personal_compress_prefs=NULL;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
opt.personal_compress_prefs=
|
|
|
|
m_alloc(sizeof(prefitem_t *)*(nzip+1));
|
|
|
|
|
|
|
|
for (i=0; i<nzip; i++)
|
|
|
|
{
|
|
|
|
opt.personal_compress_prefs[i].type = PREFTYPE_ZIP;
|
|
|
|
opt.personal_compress_prefs[i].value = zip[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
opt.personal_compress_prefs[i].type = PREFTYPE_NONE;
|
|
|
|
opt.personal_compress_prefs[i].value = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memcpy (sym_prefs, sym, (nsym_prefs=nsym));
|
|
|
|
memcpy (hash_prefs, hash, (nhash_prefs=nhash));
|
|
|
|
memcpy (zip_prefs, zip, (nzip_prefs=nzip));
|
|
|
|
mdc_available = mdc;
|
2003-02-23 00:58:39 +01:00
|
|
|
ks_modify = modify;
|
2002-06-29 15:46:34 +02:00
|
|
|
prefs_initialized = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2003-02-21 23:16:43 +01:00
|
|
|
#undef CAST5
|
|
|
|
#undef AES
|
|
|
|
|
2002-11-03 01:00:42 +01:00
|
|
|
/* Return a fake user ID containing the preferences. Caller must
|
|
|
|
free. */
|
|
|
|
PKT_user_id *keygen_get_std_prefs(void)
|
2002-06-29 15:46:34 +02:00
|
|
|
{
|
2002-11-03 01:00:42 +01:00
|
|
|
int i,j=0;
|
|
|
|
PKT_user_id *uid=m_alloc_clear(sizeof(PKT_user_id));
|
2002-06-29 15:46:34 +02:00
|
|
|
|
2002-11-03 01:00:42 +01:00
|
|
|
if(!prefs_initialized)
|
|
|
|
keygen_set_std_prefs(NULL,0);
|
2002-06-29 15:46:34 +02:00
|
|
|
|
2002-11-03 01:00:42 +01:00
|
|
|
uid->prefs=m_alloc((sizeof(prefitem_t *)*
|
|
|
|
(nsym_prefs+nhash_prefs+nzip_prefs+1)));
|
2002-06-29 15:46:34 +02:00
|
|
|
|
2002-11-03 01:00:42 +01:00
|
|
|
for(i=0;i<nsym_prefs;i++,j++)
|
|
|
|
{
|
|
|
|
uid->prefs[j].type=PREFTYPE_SYM;
|
|
|
|
uid->prefs[j].value=sym_prefs[i];
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
|
2002-11-03 01:00:42 +01:00
|
|
|
for(i=0;i<nhash_prefs;i++,j++)
|
|
|
|
{
|
|
|
|
uid->prefs[j].type=PREFTYPE_HASH;
|
|
|
|
uid->prefs[j].value=hash_prefs[i];
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
|
2002-11-03 01:00:42 +01:00
|
|
|
for(i=0;i<nzip_prefs;i++,j++)
|
|
|
|
{
|
|
|
|
uid->prefs[j].type=PREFTYPE_ZIP;
|
|
|
|
uid->prefs[j].value=zip_prefs[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
uid->prefs[j].type=PREFTYPE_NONE;
|
|
|
|
uid->prefs[j].value=0;
|
|
|
|
|
|
|
|
uid->mdc_feature=mdc_available;
|
2003-02-23 00:58:39 +01:00
|
|
|
uid->ks_modify=ks_modify;
|
2002-11-03 01:00:42 +01:00
|
|
|
|
|
|
|
return uid;
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
|
|
|
|
static void
|
|
|
|
add_feature_mdc (PKT_signature *sig,int enabled)
|
|
|
|
{
|
|
|
|
const byte *s;
|
|
|
|
size_t n;
|
|
|
|
int i;
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
|
|
|
|
/* Already set or cleared */
|
|
|
|
if (s && n &&
|
|
|
|
((enabled && (s[0] & 0x01)) || (!enabled && !(s[0] & 0x01))))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!s || !n) { /* create a new one */
|
|
|
|
n = 1;
|
|
|
|
buf = m_alloc_clear (n);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
buf = m_alloc (n);
|
|
|
|
memcpy (buf, s, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(enabled)
|
|
|
|
buf[0] |= 0x01; /* MDC feature */
|
|
|
|
else
|
|
|
|
buf[0] &= ~0x01;
|
|
|
|
|
|
|
|
/* Are there any bits set? */
|
|
|
|
for(i=0;i<n;i++)
|
|
|
|
if(buf[i]!=0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(i==n)
|
|
|
|
delete_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES);
|
|
|
|
else
|
|
|
|
build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n);
|
|
|
|
|
|
|
|
m_free (buf);
|
|
|
|
}
|
|
|
|
|
2003-02-23 00:58:39 +01:00
|
|
|
static void
|
|
|
|
add_keyserver_modify (PKT_signature *sig,int enabled)
|
|
|
|
{
|
|
|
|
const byte *s;
|
|
|
|
size_t n;
|
|
|
|
int i;
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
/* The keyserver modify flag is a negative flag (i.e. no-modify) */
|
|
|
|
enabled=!enabled;
|
|
|
|
|
|
|
|
s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n );
|
|
|
|
/* Already set or cleared */
|
|
|
|
if (s && n &&
|
|
|
|
((enabled && (s[0] & 0x80)) || (!enabled && !(s[0] & 0x80))))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!s || !n) { /* create a new one */
|
|
|
|
n = 1;
|
|
|
|
buf = m_alloc_clear (n);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
buf = m_alloc (n);
|
|
|
|
memcpy (buf, s, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(enabled)
|
|
|
|
buf[0] |= 0x80; /* no-modify flag */
|
|
|
|
else
|
|
|
|
buf[0] &= ~0x80;
|
|
|
|
|
|
|
|
/* Are there any bits set? */
|
|
|
|
for(i=0;i<n;i++)
|
|
|
|
if(buf[i]!=0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(i==n)
|
|
|
|
delete_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS);
|
|
|
|
else
|
|
|
|
build_sig_subpkt (sig, SIGSUBPKT_KS_FLAGS, buf, n);
|
|
|
|
|
|
|
|
m_free (buf);
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
int
|
|
|
|
keygen_upd_std_prefs( PKT_signature *sig, void *opaque )
|
|
|
|
{
|
|
|
|
if (!prefs_initialized)
|
|
|
|
keygen_set_std_prefs (NULL, 0);
|
|
|
|
|
|
|
|
if (nsym_prefs)
|
|
|
|
build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, sym_prefs, nsym_prefs);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM);
|
|
|
|
delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nhash_prefs)
|
|
|
|
build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH);
|
|
|
|
delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_HASH);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nzip_prefs)
|
|
|
|
build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, zip_prefs, nzip_prefs);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR);
|
|
|
|
delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_COMPR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure that the MDC feature flag is set if needed */
|
|
|
|
add_feature_mdc (sig,mdc_available);
|
2003-02-23 00:58:39 +01:00
|
|
|
add_keyserver_modify (sig,ks_modify);
|
2002-06-29 15:46:34 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1998-06-25 12:19:08 +02:00
|
|
|
|
|
|
|
/****************
|
|
|
|
* Add preference to the self signature packet.
|
|
|
|
* This is only called for packets with version > 3.
|
2002-06-29 15:46:34 +02:00
|
|
|
|
1998-06-25 12:19:08 +02:00
|
|
|
*/
|
1998-07-29 21:35:05 +02:00
|
|
|
int
|
|
|
|
keygen_add_std_prefs( PKT_signature *sig, void *opaque )
|
1998-06-25 12:19:08 +02:00
|
|
|
{
|
2002-06-29 15:46:34 +02:00
|
|
|
PKT_public_key *pk = opaque;
|
1998-06-25 12:19:08 +02:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
do_add_key_flags (sig, pk->pubkey_usage);
|
2002-12-04 19:50:10 +01:00
|
|
|
keygen_add_key_expire( sig, opaque );
|
2002-06-29 15:46:34 +02:00
|
|
|
keygen_upd_std_prefs (sig, opaque);
|
2000-10-11 19:26:49 +02:00
|
|
|
|
1998-06-25 12:19:08 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
int
|
|
|
|
keygen_add_revkey(PKT_signature *sig, void *opaque)
|
|
|
|
{
|
|
|
|
struct revocation_key *revkey=opaque;
|
|
|
|
byte buf[2+MAX_FINGERPRINT_LEN];
|
|
|
|
|
|
|
|
buf[0]=revkey->class;
|
|
|
|
buf[1]=revkey->algid;
|
|
|
|
memcpy(&buf[2],revkey->fpr,MAX_FINGERPRINT_LEN);
|
|
|
|
|
|
|
|
build_sig_subpkt(sig,SIGSUBPKT_REV_KEY,buf,2+MAX_FINGERPRINT_LEN);
|
1998-06-25 12:19:08 +02:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
/* All sigs with revocation keys set are nonrevocable */
|
|
|
|
sig->flags.revocable=0;
|
|
|
|
buf[0] = 0;
|
|
|
|
build_sig_subpkt( sig, SIGSUBPKT_REVOCABLE, buf, 1 );
|
|
|
|
|
|
|
|
parse_revkeys(sig);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
1998-06-25 12:19:08 +02:00
|
|
|
|
1997-12-09 13:46:23 +01:00
|
|
|
static int
|
2002-06-29 15:46:34 +02:00
|
|
|
write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
|
|
|
|
struct revocation_key *revkey )
|
|
|
|
{
|
|
|
|
PACKET *pkt;
|
|
|
|
PKT_signature *sig;
|
|
|
|
int rc=0;
|
|
|
|
KBNODE node;
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
|
|
|
if( opt.verbose )
|
|
|
|
log_info(_("writing direct signature\n"));
|
|
|
|
|
|
|
|
/* get the pk packet from the pub_tree */
|
|
|
|
node = find_kbnode( pub_root, PKT_PUBLIC_KEY );
|
|
|
|
if( !node )
|
|
|
|
BUG();
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
|
|
|
/* we have to cache the key, so that the verification of the signature
|
|
|
|
* creation is able to retrieve the public key */
|
|
|
|
cache_public_key (pk);
|
|
|
|
|
|
|
|
/* and make the signature */
|
|
|
|
rc = make_keysig_packet(&sig,pk,NULL,NULL,sk,0x1F,0,0,0,0,
|
|
|
|
keygen_add_revkey,revkey);
|
|
|
|
if( rc ) {
|
|
|
|
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
pkt = m_alloc_clear( sizeof *pkt );
|
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
pkt->pkt.signature = sig;
|
|
|
|
add_kbnode( root, new_kbnode( pkt ) );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
|
|
|
|
unsigned int use )
|
1997-12-09 13:46:23 +01:00
|
|
|
{
|
1997-12-16 20:15:09 +01:00
|
|
|
PACKET *pkt;
|
1997-12-09 13:46:23 +01:00
|
|
|
PKT_signature *sig;
|
1997-12-16 20:15:09 +01:00
|
|
|
PKT_user_id *uid;
|
1997-12-09 13:46:23 +01:00
|
|
|
int rc=0;
|
1998-02-11 04:25:44 +01:00
|
|
|
KBNODE node;
|
1998-06-29 14:30:57 +02:00
|
|
|
PKT_public_key *pk;
|
1997-12-09 13:46:23 +01:00
|
|
|
|
|
|
|
if( opt.verbose )
|
1998-01-28 17:09:43 +01:00
|
|
|
log_info(_("writing self signature\n"));
|
1997-12-09 13:46:23 +01:00
|
|
|
|
1998-02-11 04:25:44 +01:00
|
|
|
/* get the uid packet from the list */
|
|
|
|
node = find_kbnode( root, PKT_USER_ID );
|
1997-12-16 20:15:09 +01:00
|
|
|
if( !node )
|
1998-01-16 22:15:24 +01:00
|
|
|
BUG(); /* no user id packet in tree */
|
1997-12-16 20:15:09 +01:00
|
|
|
uid = node->pkt->pkt.user_id;
|
1998-06-29 14:30:57 +02:00
|
|
|
/* get the pk packet from the pub_tree */
|
|
|
|
node = find_kbnode( pub_root, PKT_PUBLIC_KEY );
|
1997-12-16 20:15:09 +01:00
|
|
|
if( !node )
|
1998-01-16 22:15:24 +01:00
|
|
|
BUG();
|
1998-06-29 14:30:57 +02:00
|
|
|
pk = node->pkt->pkt.public_key;
|
2002-06-29 15:46:34 +02:00
|
|
|
pk->pubkey_usage = use;
|
|
|
|
/* we have to cache the key, so that the verification of the signature
|
|
|
|
* creation is able to retrieve the public key */
|
|
|
|
cache_public_key (pk);
|
1997-12-16 20:15:09 +01:00
|
|
|
|
|
|
|
/* and make the signature */
|
2002-06-29 15:46:34 +02:00
|
|
|
rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0, 0, 0,
|
|
|
|
keygen_add_std_prefs, pk );
|
1998-05-26 15:38:00 +02:00
|
|
|
if( rc ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
|
1998-05-26 15:38:00 +02:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
pkt = m_alloc_clear( sizeof *pkt );
|
1998-05-26 15:38:00 +02:00
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
pkt->pkt.signature = sig;
|
|
|
|
add_kbnode( root, new_kbnode( pkt ) );
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2002-06-29 15:46:34 +02:00
|
|
|
write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
|
|
|
|
unsigned int use )
|
1998-05-26 15:38:00 +02:00
|
|
|
{
|
|
|
|
PACKET *pkt;
|
|
|
|
PKT_signature *sig;
|
|
|
|
int rc=0;
|
|
|
|
KBNODE node;
|
1998-06-29 14:30:57 +02:00
|
|
|
PKT_public_key *pk, *subpk;
|
2002-06-29 15:46:34 +02:00
|
|
|
struct opaque_data_usage_and_pk oduap;
|
1998-05-26 15:38:00 +02:00
|
|
|
|
|
|
|
if( opt.verbose )
|
|
|
|
log_info(_("writing key binding signature\n"));
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
/* get the pk packet from the pub_tree */
|
|
|
|
node = find_kbnode( pub_root, PKT_PUBLIC_KEY );
|
1998-05-26 15:38:00 +02:00
|
|
|
if( !node )
|
|
|
|
BUG();
|
1998-06-29 14:30:57 +02:00
|
|
|
pk = node->pkt->pkt.public_key;
|
2002-06-29 15:46:34 +02:00
|
|
|
/* we have to cache the key, so that the verification of the signature
|
|
|
|
* creation is able to retrieve the public key */
|
|
|
|
cache_public_key (pk);
|
|
|
|
|
1998-05-26 15:38:00 +02:00
|
|
|
/* find the last subkey */
|
1998-06-29 14:30:57 +02:00
|
|
|
subpk = NULL;
|
1998-05-26 15:38:00 +02:00
|
|
|
for(node=pub_root; node; node = node->next ) {
|
1998-06-29 14:30:57 +02:00
|
|
|
if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
|
|
|
|
subpk = node->pkt->pkt.public_key;
|
1998-05-26 15:38:00 +02:00
|
|
|
}
|
1998-06-29 14:30:57 +02:00
|
|
|
if( !subpk )
|
1998-05-26 15:38:00 +02:00
|
|
|
BUG();
|
|
|
|
|
|
|
|
/* and make the signature */
|
2002-06-29 15:46:34 +02:00
|
|
|
oduap.usage = use;
|
|
|
|
oduap.pk = subpk;
|
|
|
|
rc = make_keysig_packet( &sig, pk, NULL, subpk, sk, 0x18, 0, 0, 0, 0,
|
|
|
|
keygen_add_key_flags_and_expire, &oduap );
|
1997-12-09 13:46:23 +01:00
|
|
|
if( rc ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
|
1997-12-09 13:46:23 +01:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
pkt = m_alloc_clear( sizeof *pkt );
|
1997-12-16 20:15:09 +01:00
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
pkt->pkt.signature = sig;
|
|
|
|
add_kbnode( root, new_kbnode( pkt ) );
|
1997-12-09 13:46:23 +01:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-12-16 20:15:09 +01:00
|
|
|
static int
|
1998-06-25 12:19:08 +02:00
|
|
|
gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
|
2000-07-14 19:34:53 +02:00
|
|
|
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
|
1997-12-16 20:15:09 +01:00
|
|
|
{
|
|
|
|
int rc;
|
2002-06-29 15:46:34 +02:00
|
|
|
int i;
|
1997-12-16 20:15:09 +01:00
|
|
|
PACKET *pkt;
|
1998-06-29 14:30:57 +02:00
|
|
|
PKT_secret_key *sk;
|
|
|
|
PKT_public_key *pk;
|
2002-06-29 15:46:34 +02:00
|
|
|
MPI skey[4];
|
|
|
|
MPI *factors;
|
2000-01-27 17:50:45 +01:00
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
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 );
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
rc = pubkey_generate( algo, nbits, skey, &factors );
|
1998-06-13 19:00:02 +02:00
|
|
|
if( rc ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
|
1998-06-13 19:00:02 +02:00
|
|
|
return rc;
|
|
|
|
}
|
1997-12-16 20:15:09 +01:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
sk = m_alloc_clear( sizeof *sk );
|
|
|
|
pk = m_alloc_clear( sizeof *pk );
|
1998-06-29 14:30:57 +02:00
|
|
|
sk->timestamp = pk->timestamp = make_timestamp();
|
2000-07-14 19:34:53 +02:00
|
|
|
sk->version = pk->version = 4;
|
1998-11-20 18:42:18 +01:00
|
|
|
if( expireval ) {
|
|
|
|
sk->expiredate = pk->expiredate = sk->timestamp + expireval;
|
|
|
|
}
|
1998-06-29 14:30:57 +02:00
|
|
|
sk->pubkey_algo = pk->pubkey_algo = algo;
|
2002-06-29 15:46:34 +02:00
|
|
|
pk->pkey[0] = mpi_copy( skey[0] );
|
|
|
|
pk->pkey[1] = mpi_copy( skey[1] );
|
|
|
|
pk->pkey[2] = mpi_copy( skey[2] );
|
|
|
|
sk->skey[0] = skey[0];
|
|
|
|
sk->skey[1] = skey[1];
|
|
|
|
sk->skey[2] = skey[2];
|
|
|
|
sk->skey[3] = skey[3];
|
1998-06-29 14:30:57 +02:00
|
|
|
sk->is_protected = 0;
|
|
|
|
sk->protect.algo = 0;
|
|
|
|
|
2002-09-11 09:27:54 +02:00
|
|
|
sk->csum = checksum_mpi( sk->skey[3] );
|
1998-06-29 14:30:57 +02:00
|
|
|
if( ret_sk ) /* not a subkey: return an unprotected version of the sk */
|
|
|
|
*ret_sk = copy_secret_key( NULL, sk );
|
1997-12-16 20:15:09 +01:00
|
|
|
|
1997-12-19 12:41:47 +01:00
|
|
|
if( dek ) {
|
1998-06-29 14:30:57 +02:00
|
|
|
sk->protect.algo = dek->algo;
|
|
|
|
sk->protect.s2k = *s2k;
|
|
|
|
rc = protect_secret_key( sk, dek );
|
1997-12-16 20:15:09 +01:00
|
|
|
if( rc ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
|
1998-06-29 14:30:57 +02:00
|
|
|
free_public_key(pk);
|
|
|
|
free_secret_key(sk);
|
1997-12-16 20:15:09 +01:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
pkt = m_alloc_clear(sizeof *pkt);
|
1998-06-29 14:30:57 +02:00
|
|
|
pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
|
|
|
|
pkt->pkt.public_key = pk;
|
1997-12-16 20:15:09 +01:00
|
|
|
add_kbnode(pub_root, new_kbnode( pkt ));
|
|
|
|
|
1998-04-14 19:51:16 +02:00
|
|
|
/* don't know whether it makes sense to have the factors, so for now
|
1998-05-03 17:42:08 +02:00
|
|
|
* we store them in the secret keyring (but they are not secret) */
|
2002-06-29 15:46:34 +02:00
|
|
|
pkt = m_alloc_clear(sizeof *pkt);
|
1998-06-29 14:30:57 +02:00
|
|
|
pkt->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
|
|
|
|
pkt->pkt.secret_key = sk;
|
1997-12-16 20:15:09 +01:00
|
|
|
add_kbnode(sec_root, new_kbnode( pkt ));
|
2002-06-29 15:46:34 +02:00
|
|
|
for(i=0; factors[i]; i++ )
|
|
|
|
add_kbnode( sec_root,
|
|
|
|
make_mpi_comment_node("#:ELG_factor:", factors[i] ));
|
1997-12-16 20:15:09 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-05-05 22:34:20 +02:00
|
|
|
/****************
|
|
|
|
* Generate a DSA key
|
|
|
|
*/
|
1997-11-24 23:24:04 +01:00
|
|
|
static int
|
2000-07-14 19:34:53 +02:00
|
|
|
gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
|
1998-11-20 18:42:18 +01:00
|
|
|
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
|
1997-11-24 23:24:04 +01:00
|
|
|
{
|
1998-05-05 22:34:20 +02:00
|
|
|
int rc;
|
2002-06-29 15:46:34 +02:00
|
|
|
int i;
|
1998-05-05 22:34:20 +02:00
|
|
|
PACKET *pkt;
|
1998-06-29 14:30:57 +02:00
|
|
|
PKT_secret_key *sk;
|
|
|
|
PKT_public_key *pk;
|
2002-06-29 15:46:34 +02:00
|
|
|
MPI skey[5];
|
|
|
|
MPI *factors;
|
1998-05-05 22:34:20 +02:00
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
if( nbits > 1024 || nbits < 512 ) {
|
1998-05-05 22:34:20 +02:00
|
|
|
nbits = 1024;
|
2000-07-14 19:34:53 +02:00
|
|
|
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 );
|
|
|
|
}
|
1998-05-05 22:34:20 +02:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
rc = pubkey_generate( PUBKEY_ALGO_DSA, nbits, skey, &factors );
|
1998-06-13 19:00:02 +02:00
|
|
|
if( rc ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
|
1998-06-13 19:00:02 +02:00
|
|
|
return rc;
|
|
|
|
}
|
1998-05-05 22:34:20 +02:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
sk = m_alloc_clear( sizeof *sk );
|
|
|
|
pk = m_alloc_clear( sizeof *pk );
|
1998-06-29 14:30:57 +02:00
|
|
|
sk->timestamp = pk->timestamp = make_timestamp();
|
|
|
|
sk->version = pk->version = 4;
|
1998-11-20 18:42:18 +01:00
|
|
|
if( expireval ) {
|
|
|
|
sk->expiredate = pk->expiredate = sk->timestamp + expireval;
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
sk->pubkey_algo = pk->pubkey_algo = PUBKEY_ALGO_DSA;
|
|
|
|
pk->pkey[0] = mpi_copy( skey[0] );
|
|
|
|
pk->pkey[1] = mpi_copy( skey[1] );
|
|
|
|
pk->pkey[2] = mpi_copy( skey[2] );
|
|
|
|
pk->pkey[3] = mpi_copy( skey[3] );
|
|
|
|
sk->skey[0] = skey[0];
|
|
|
|
sk->skey[1] = skey[1];
|
|
|
|
sk->skey[2] = skey[2];
|
|
|
|
sk->skey[3] = skey[3];
|
|
|
|
sk->skey[4] = skey[4];
|
1998-06-29 14:30:57 +02:00
|
|
|
sk->is_protected = 0;
|
|
|
|
sk->protect.algo = 0;
|
|
|
|
|
2002-09-11 09:27:54 +02:00
|
|
|
sk->csum = checksum_mpi ( sk->skey[4] );
|
1998-06-29 14:30:57 +02:00
|
|
|
if( ret_sk ) /* not a subkey: return an unprotected version of the sk */
|
|
|
|
*ret_sk = copy_secret_key( NULL, sk );
|
1998-05-05 22:34:20 +02:00
|
|
|
|
|
|
|
if( dek ) {
|
1998-06-29 14:30:57 +02:00
|
|
|
sk->protect.algo = dek->algo;
|
|
|
|
sk->protect.s2k = *s2k;
|
|
|
|
rc = protect_secret_key( sk, dek );
|
1998-05-05 22:34:20 +02:00
|
|
|
if( rc ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
|
1998-06-29 14:30:57 +02:00
|
|
|
free_public_key(pk);
|
|
|
|
free_secret_key(sk);
|
1998-05-05 22:34:20 +02:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
pkt = m_alloc_clear(sizeof *pkt);
|
1998-06-29 14:30:57 +02:00
|
|
|
pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
|
|
|
|
pkt->pkt.public_key = pk;
|
1998-05-05 22:34:20 +02:00
|
|
|
add_kbnode(pub_root, new_kbnode( pkt ));
|
|
|
|
|
|
|
|
/* don't know whether it makes sense to have the factors, so for now
|
|
|
|
* we store them in the secret keyring (but they are not secret)
|
2002-06-29 15:46:34 +02:00
|
|
|
* p = 2 * q * f1 * f2 * ... * fn
|
|
|
|
* We store only f1 to f_n-1; fn can be calculated because p and q
|
|
|
|
* are known.
|
1998-05-05 22:34:20 +02:00
|
|
|
*/
|
2002-06-29 15:46:34 +02:00
|
|
|
pkt = m_alloc_clear(sizeof *pkt);
|
1998-06-29 14:30:57 +02:00
|
|
|
pkt->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
|
|
|
|
pkt->pkt.secret_key = sk;
|
1998-05-05 22:34:20 +02:00
|
|
|
add_kbnode(sec_root, new_kbnode( pkt ));
|
2002-06-29 15:46:34 +02:00
|
|
|
for(i=1; factors[i]; i++ ) /* the first one is q */
|
|
|
|
add_kbnode( sec_root,
|
|
|
|
make_mpi_comment_node("#:DSA_factor:", factors[i] ));
|
|
|
|
|
1998-05-05 22:34:20 +02:00
|
|
|
return 0;
|
1997-11-24 23:24:04 +01:00
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Generate an RSA key.
|
|
|
|
*/
|
2000-07-14 19:34:53 +02:00
|
|
|
static int
|
|
|
|
gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
|
|
|
|
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
PACKET *pkt;
|
|
|
|
PKT_secret_key *sk;
|
|
|
|
PKT_public_key *pk;
|
2002-06-29 15:46:34 +02:00
|
|
|
MPI skey[6];
|
2000-07-14 19:34:53 +02:00
|
|
|
MPI *factors;
|
|
|
|
|
|
|
|
assert( is_RSA(algo) );
|
|
|
|
|
|
|
|
if( nbits < 1024 ) {
|
|
|
|
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 ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
|
2000-07-14 19:34:53 +02:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
sk = m_alloc_clear( sizeof *sk );
|
|
|
|
pk = m_alloc_clear( sizeof *pk );
|
2000-07-14 19:34:53 +02:00
|
|
|
sk->timestamp = pk->timestamp = make_timestamp();
|
|
|
|
sk->version = pk->version = 4;
|
|
|
|
if( expireval ) {
|
|
|
|
sk->expiredate = pk->expiredate = sk->timestamp + expireval;
|
|
|
|
}
|
|
|
|
sk->pubkey_algo = pk->pubkey_algo = algo;
|
|
|
|
pk->pkey[0] = mpi_copy( skey[0] );
|
|
|
|
pk->pkey[1] = mpi_copy( skey[1] );
|
|
|
|
sk->skey[0] = skey[0];
|
|
|
|
sk->skey[1] = skey[1];
|
|
|
|
sk->skey[2] = skey[2];
|
|
|
|
sk->skey[3] = skey[3];
|
|
|
|
sk->skey[4] = skey[4];
|
|
|
|
sk->skey[5] = skey[5];
|
|
|
|
sk->is_protected = 0;
|
|
|
|
sk->protect.algo = 0;
|
|
|
|
|
2002-09-11 09:27:54 +02:00
|
|
|
sk->csum = checksum_mpi (sk->skey[2] );
|
|
|
|
sk->csum += checksum_mpi (sk->skey[3] );
|
|
|
|
sk->csum += checksum_mpi (sk->skey[4] );
|
|
|
|
sk->csum += checksum_mpi (sk->skey[5] );
|
2000-07-14 19:34:53 +02:00
|
|
|
if( ret_sk ) /* not a subkey: return an unprotected version of the sk */
|
|
|
|
*ret_sk = copy_secret_key( NULL, sk );
|
|
|
|
|
|
|
|
if( dek ) {
|
|
|
|
sk->protect.algo = dek->algo;
|
|
|
|
sk->protect.s2k = *s2k;
|
|
|
|
rc = protect_secret_key( sk, dek );
|
|
|
|
if( rc ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
|
2000-07-14 19:34:53 +02:00
|
|
|
free_public_key(pk);
|
|
|
|
free_secret_key(sk);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
pkt = m_alloc_clear(sizeof *pkt);
|
2000-07-14 19:34:53 +02:00
|
|
|
pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
|
|
|
|
pkt->pkt.public_key = pk;
|
|
|
|
add_kbnode(pub_root, new_kbnode( pkt ));
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
pkt = m_alloc_clear(sizeof *pkt);
|
2000-07-14 19:34:53 +02:00
|
|
|
pkt->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
|
|
|
|
pkt->pkt.secret_key = sk;
|
|
|
|
add_kbnode(sec_root, new_kbnode( pkt ));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
1997-11-18 15:06:00 +01:00
|
|
|
|
|
|
|
|
1998-04-02 12:30:03 +02:00
|
|
|
/****************
|
|
|
|
* check valid days:
|
|
|
|
* return 0 on error or the multiplier
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
check_valid_days( const char *s )
|
|
|
|
{
|
* parse-packet.c (parse_signature): No need to reserve 8 bytes for the
unhashed signature cache any longer.
* misc.c (pct_expando): Add two new expandos - signer's fingerprint (%g),
and signer's primary fingerprint (%p).
* Makefile.am: Include W32LIBS where appropriate.
* g10.c (main): Add --rfc2440 alias for --openpgp since in a few months,
they won't be the same thing.
* keyserver.c (parse_keyserver_uri): Accept "http" as an alias for "hkp",
since it is occasionally written that way. (keyserver_spawn): Use
ascii_isspace to avoid locale issues.
* keygen.c (ask_user_id): Make --allow-freeform-uid apply to the email
field as well as the name field, and allow mixing fields when it is set.
* options.skel: Use subkeys.pgp.net as the default keyserver.
* trustdb.c (validate_one_keyblock): Certifications on revoked or expired
uids do not count in the web of trust.
* signal.c (init_one_signal, pause_on_sigusr, do_block): Only use
sigprocmask() if we have sigset_t, and only use sigaction() if we have
struct sigaction. This is for Forte c89 on Solaris which seems to define
only the function call half of the two pairs by default.
(pause_on_sigusr): Typo. (do_block): If we can't use sigprocmask() and
sigset_t, try to get the number of signals from NSIG as well as MAXSIG,
and if we can't, fail with an explanation.
* signal.c, tdbio.c: Comment out the transaction code. It was not used in
this version, and was causing some build problems on quasi-posix platforms
(Solaris and Forte c89).
* keylist.c (list_keyblock_colon): Don't include validity values when
listing secret keys since they can be incorrect and/or misleading. This
is a temporary kludge, and will be handled properly in 1.9/2.0.
* mainproc.c (check_sig_and_print): Only show the "key available from"
preferred keyserver line if the key is not currently present.
* keyedit.c (sign_uids): Do not sign expired uids without --expert (same
behavior as revoked uids). Do not allow signing a user ID without a
self-signature. --expert overrides. Add additional prompt to the
signature level question. (menu_expire): When changing expiration dates,
don't replace selfsigs on revoked uids since this would effectively
unrevoke them. There is also no point in replacing expired selfsigs.
This is bug #181
* g10.c (add_notation_data): Make sure that only ascii is passed to
iscntrl. Noted by Christian Biere.
* getkey.c (classify_user_id2): Replaced isspace by spacep
* keygen.c (ask_user_id): Ditto. (get_parameter_algo): Ditto.
* keyedit.c (keyedit_menu): Ditto.
* tdbdump.c (import_ownertrust): Ditto. s/isxdigit/hexdigitp/.
* revoke.c (ask_revocation_reason):
* keyserver.c (keyserver_spawn): Dito.
2003-07-10 16:30:07 +02:00
|
|
|
if( !digitp(s) )
|
1998-04-02 12:30:03 +02:00
|
|
|
return 0;
|
|
|
|
for( s++; *s; s++)
|
* parse-packet.c (parse_signature): No need to reserve 8 bytes for the
unhashed signature cache any longer.
* misc.c (pct_expando): Add two new expandos - signer's fingerprint (%g),
and signer's primary fingerprint (%p).
* Makefile.am: Include W32LIBS where appropriate.
* g10.c (main): Add --rfc2440 alias for --openpgp since in a few months,
they won't be the same thing.
* keyserver.c (parse_keyserver_uri): Accept "http" as an alias for "hkp",
since it is occasionally written that way. (keyserver_spawn): Use
ascii_isspace to avoid locale issues.
* keygen.c (ask_user_id): Make --allow-freeform-uid apply to the email
field as well as the name field, and allow mixing fields when it is set.
* options.skel: Use subkeys.pgp.net as the default keyserver.
* trustdb.c (validate_one_keyblock): Certifications on revoked or expired
uids do not count in the web of trust.
* signal.c (init_one_signal, pause_on_sigusr, do_block): Only use
sigprocmask() if we have sigset_t, and only use sigaction() if we have
struct sigaction. This is for Forte c89 on Solaris which seems to define
only the function call half of the two pairs by default.
(pause_on_sigusr): Typo. (do_block): If we can't use sigprocmask() and
sigset_t, try to get the number of signals from NSIG as well as MAXSIG,
and if we can't, fail with an explanation.
* signal.c, tdbio.c: Comment out the transaction code. It was not used in
this version, and was causing some build problems on quasi-posix platforms
(Solaris and Forte c89).
* keylist.c (list_keyblock_colon): Don't include validity values when
listing secret keys since they can be incorrect and/or misleading. This
is a temporary kludge, and will be handled properly in 1.9/2.0.
* mainproc.c (check_sig_and_print): Only show the "key available from"
preferred keyserver line if the key is not currently present.
* keyedit.c (sign_uids): Do not sign expired uids without --expert (same
behavior as revoked uids). Do not allow signing a user ID without a
self-signature. --expert overrides. Add additional prompt to the
signature level question. (menu_expire): When changing expiration dates,
don't replace selfsigs on revoked uids since this would effectively
unrevoke them. There is also no point in replacing expired selfsigs.
This is bug #181
* g10.c (add_notation_data): Make sure that only ascii is passed to
iscntrl. Noted by Christian Biere.
* getkey.c (classify_user_id2): Replaced isspace by spacep
* keygen.c (ask_user_id): Ditto. (get_parameter_algo): Ditto.
* keyedit.c (keyedit_menu): Ditto.
* tdbdump.c (import_ownertrust): Ditto. s/isxdigit/hexdigitp/.
* revoke.c (ask_revocation_reason):
* keyserver.c (keyserver_spawn): Dito.
2003-07-10 16:30:07 +02:00
|
|
|
if( !digitp(s) )
|
1998-04-02 12:30:03 +02:00
|
|
|
break;
|
|
|
|
if( !*s )
|
|
|
|
return 1;
|
|
|
|
if( s[1] )
|
|
|
|
return 0; /* e.g. "2323wc" */
|
|
|
|
if( *s == 'd' || *s == 'D' )
|
|
|
|
return 1;
|
|
|
|
if( *s == 'w' || *s == 'W' )
|
|
|
|
return 7;
|
|
|
|
if( *s == 'm' || *s == 'M' )
|
|
|
|
return 30;
|
|
|
|
if( *s == 'y' || *s == 'Y' )
|
|
|
|
return 365;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-06-25 12:19:08 +02:00
|
|
|
/****************
|
1998-07-21 14:53:38 +02:00
|
|
|
* Returns: 0 to create both a DSA and a ElGamal key.
|
2002-06-29 15:46:34 +02:00
|
|
|
* and only if key flags are to be written the desired usage.
|
1998-06-25 12:19:08 +02:00
|
|
|
*/
|
1998-05-26 15:38:00 +02:00
|
|
|
static int
|
2002-06-29 15:46:34 +02:00
|
|
|
ask_algo (int addmode, unsigned int *r_usage)
|
1997-11-18 15:06:00 +01:00
|
|
|
{
|
|
|
|
char *answer;
|
1997-11-24 23:24:04 +01:00
|
|
|
int algo;
|
1998-01-28 17:09:43 +01:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
*r_usage = 0;
|
1998-06-25 12:19:08 +02:00
|
|
|
tty_printf(_("Please select what kind of key you want:\n"));
|
|
|
|
if( !addmode )
|
|
|
|
tty_printf(_(" (%d) DSA and ElGamal (default)\n"), 1 );
|
1998-12-10 20:20:47 +01:00
|
|
|
tty_printf( _(" (%d) DSA (sign only)\n"), 2 );
|
1998-10-06 14:10:02 +02:00
|
|
|
if( addmode )
|
|
|
|
tty_printf( _(" (%d) ElGamal (encrypt only)\n"), 3 );
|
2002-06-29 15:46:34 +02:00
|
|
|
if (opt.expert)
|
|
|
|
tty_printf( _(" (%d) ElGamal (sign and encrypt)\n"), 4 );
|
|
|
|
tty_printf( _(" (%d) RSA (sign only)\n"), 5 );
|
|
|
|
if (addmode)
|
|
|
|
tty_printf( _(" (%d) RSA (encrypt only)\n"), 6 );
|
|
|
|
if (opt.expert)
|
|
|
|
tty_printf( _(" (%d) RSA (sign and encrypt)\n"), 7 );
|
1997-11-24 23:24:04 +01:00
|
|
|
|
|
|
|
for(;;) {
|
1998-11-27 12:42:49 +01:00
|
|
|
answer = cpr_get("keygen.algo",_("Your selection? "));
|
1998-08-08 21:27:00 +02:00
|
|
|
cpr_kill_prompt();
|
1997-11-24 23:24:04 +01:00
|
|
|
algo = *answer? atoi(answer): 1;
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(answer);
|
1998-06-25 12:19:08 +02:00
|
|
|
if( algo == 1 && !addmode ) {
|
|
|
|
algo = 0; /* create both keys */
|
|
|
|
break;
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
else if( algo == 7 && opt.expert ) {
|
2002-12-11 18:50:38 +01:00
|
|
|
algo = PUBKEY_ALGO_RSA;
|
|
|
|
*r_usage = PUBKEY_USAGE_ENC | PUBKEY_USAGE_SIG;
|
|
|
|
break;
|
2002-06-29 15:46:34 +02:00
|
|
|
}
|
|
|
|
else if( algo == 6 && addmode ) {
|
|
|
|
algo = PUBKEY_ALGO_RSA;
|
|
|
|
*r_usage = PUBKEY_USAGE_ENC;
|
|
|
|
break;
|
|
|
|
}
|
2000-07-14 19:34:53 +02:00
|
|
|
else if( algo == 5 ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
algo = PUBKEY_ALGO_RSA;
|
|
|
|
*r_usage = PUBKEY_USAGE_SIG;
|
|
|
|
break;
|
2000-07-14 19:34:53 +02:00
|
|
|
}
|
2002-12-11 18:50:38 +01:00
|
|
|
else if( algo == 4 && opt.expert)
|
|
|
|
{
|
|
|
|
tty_printf(_(
|
|
|
|
"The use of this algorithm is only supported by GnuPG. You will not be\n"
|
|
|
|
"able to use this key to communicate with PGP users. This algorithm is also\n"
|
|
|
|
"very slow, and may not be as secure as the other choices.\n"));
|
|
|
|
|
|
|
|
if( cpr_get_answer_is_yes("keygen.algo.elg_se",
|
|
|
|
_("Create anyway? ")))
|
|
|
|
{
|
2002-06-29 15:46:34 +02:00
|
|
|
algo = PUBKEY_ALGO_ELGAMAL;
|
1998-12-10 20:20:47 +01:00
|
|
|
break;
|
2002-12-11 18:50:38 +01:00
|
|
|
}
|
1997-11-24 23:24:04 +01:00
|
|
|
}
|
1998-10-06 14:10:02 +02:00
|
|
|
else if( algo == 3 && addmode ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
algo = PUBKEY_ALGO_ELGAMAL_E;
|
1998-05-05 22:34:20 +02:00
|
|
|
break;
|
1997-12-23 18:30:18 +01:00
|
|
|
}
|
1998-12-10 20:20:47 +01:00
|
|
|
else if( algo == 2 ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
algo = PUBKEY_ALGO_DSA;
|
1998-06-25 12:19:08 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tty_printf(_("Invalid selection.\n"));
|
1997-11-24 23:24:04 +01:00
|
|
|
}
|
1998-05-26 15:38:00 +02:00
|
|
|
return algo;
|
|
|
|
}
|
1997-11-24 23:24:04 +01:00
|
|
|
|
|
|
|
|
1998-05-26 15:38:00 +02:00
|
|
|
static unsigned
|
|
|
|
ask_keysize( int algo )
|
|
|
|
{
|
|
|
|
char *answer;
|
|
|
|
unsigned nbits;
|
1997-11-24 23:24:04 +01:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
if (algo != PUBKEY_ALGO_DSA && algo != PUBKEY_ALGO_RSA) {
|
|
|
|
tty_printf (_("About to generate a new %s keypair.\n"
|
|
|
|
" minimum keysize is 768 bits\n"
|
|
|
|
" default keysize is 1024 bits\n"
|
|
|
|
" highest suggested keysize is 2048 bits\n"),
|
|
|
|
pubkey_algo_to_string(algo) );
|
|
|
|
}
|
|
|
|
|
1997-11-18 15:06:00 +01:00
|
|
|
for(;;) {
|
1998-11-27 12:42:49 +01:00
|
|
|
answer = cpr_get("keygen.size",
|
1998-08-08 21:27:00 +02:00
|
|
|
_("What keysize do you want? (1024) "));
|
|
|
|
cpr_kill_prompt();
|
1997-11-24 23:24:04 +01:00
|
|
|
nbits = *answer? atoi(answer): 1024;
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(answer);
|
|
|
|
if( algo == PUBKEY_ALGO_DSA && (nbits < 512 || nbits > 1024) )
|
1998-04-14 19:51:16 +02:00
|
|
|
tty_printf(_("DSA only allows keysizes from 512 to 1024\n"));
|
2002-06-29 15:46:34 +02:00
|
|
|
else if( algo == PUBKEY_ALGO_RSA && nbits < 1024 )
|
2000-07-14 19:34:53 +02:00
|
|
|
tty_printf(_("keysize too small;"
|
|
|
|
" 1024 is smallest value allowed for RSA.\n"));
|
2002-06-29 15:46:34 +02:00
|
|
|
else if( nbits < 768 )
|
|
|
|
tty_printf(_("keysize too small;"
|
|
|
|
" 768 is smallest value allowed.\n"));
|
1999-04-07 20:58:34 +02:00
|
|
|
else if( nbits > 4096 ) {
|
|
|
|
/* It is ridiculous and an annoyance to use larger key sizes!
|
|
|
|
* GnuPG can handle much larger sizes; but it takes an eternity
|
|
|
|
* to create such a key (but less than the time the Sirius
|
|
|
|
* Computer Corporation needs to process one of the usual
|
|
|
|
* complaints) and {de,en}cryption although needs some time.
|
|
|
|
* So, before you complain about this limitation, I suggest that
|
|
|
|
* you start a discussion with Marvin about this theme and then
|
|
|
|
* do whatever you want. */
|
|
|
|
tty_printf(_("keysize too large; %d is largest value allowed.\n"),
|
|
|
|
4096);
|
|
|
|
}
|
1998-08-05 18:51:59 +02:00
|
|
|
else if( nbits > 2048 && !cpr_enabled() ) {
|
1998-08-11 19:29:34 +02:00
|
|
|
tty_printf(
|
|
|
|
_("Keysizes larger than 2048 are not suggested because\n"
|
|
|
|
"computations take REALLY long!\n"));
|
1998-11-27 12:42:49 +01:00
|
|
|
if( cpr_get_answer_is_yes("keygen.size.huge.okay",_(
|
1998-07-29 21:35:05 +02:00
|
|
|
"Are you sure that you want this keysize? ")) ) {
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_("Okay, but keep in mind that your monitor "
|
|
|
|
"and keyboard radiation is also very vulnerable "
|
|
|
|
"to attacks!\n"));
|
1997-11-18 15:06:00 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_("Requested keysize is %u bits\n"), nbits );
|
2002-06-29 15:46:34 +02:00
|
|
|
if( algo == PUBKEY_ALGO_DSA && (nbits % 64) ) {
|
1997-12-16 20:15:09 +01:00
|
|
|
nbits = ((nbits + 63) / 64) * 64;
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_("rounded up to %u bits\n"), nbits );
|
1997-12-16 20:15:09 +01:00
|
|
|
}
|
|
|
|
else if( (nbits % 32) ) {
|
1997-11-18 15:06:00 +01:00
|
|
|
nbits = ((nbits + 31) / 32) * 32;
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_("rounded up to %u bits\n"), nbits );
|
1997-11-18 15:06:00 +01:00
|
|
|
}
|
1998-05-26 15:38:00 +02:00
|
|
|
return nbits;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
/****************
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
/* object == 0 for a key, and 1 for a sig */
|
|
|
|
u32
|
|
|
|
ask_expire_interval(int object)
|
1998-05-26 15:38:00 +02:00
|
|
|
{
|
|
|
|
char *answer;
|
|
|
|
int valid_days=0;
|
1998-11-20 18:42:18 +01:00
|
|
|
u32 interval = 0;
|
1997-11-24 23:24:04 +01:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
switch(object)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
tty_printf(_("Please specify how long the key should be valid.\n"
|
|
|
|
" 0 = key does not expire\n"
|
|
|
|
" <n> = key expires in n days\n"
|
|
|
|
" <n>w = key expires in n weeks\n"
|
|
|
|
" <n>m = key expires in n months\n"
|
|
|
|
" <n>y = key expires in n years\n"));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
tty_printf(_("Please specify how long the signature should be valid.\n"
|
|
|
|
" 0 = signature does not expire\n"
|
|
|
|
" <n> = signature expires in n days\n"
|
|
|
|
" <n>w = signature expires in n weeks\n"
|
|
|
|
" <n>m = signature expires in n months\n"
|
|
|
|
" <n>y = signature expires in n years\n"));
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
BUG();
|
|
|
|
}
|
|
|
|
|
1998-11-20 18:42:18 +01:00
|
|
|
/* Note: The elgamal subkey for DSA has no expiration date because
|
1998-10-18 17:21:22 +02:00
|
|
|
* it must be signed with the DSA key and this one has the expiration
|
1998-05-05 22:34:20 +02:00
|
|
|
* date */
|
|
|
|
|
1998-04-02 12:30:03 +02:00
|
|
|
answer = NULL;
|
|
|
|
for(;;) {
|
2000-07-14 19:34:53 +02:00
|
|
|
u32 curtime=make_timestamp();
|
1998-04-02 12:30:03 +02:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(answer);
|
|
|
|
if(object==0)
|
|
|
|
answer = cpr_get("keygen.valid",_("Key is valid for? (0) "));
|
|
|
|
else
|
|
|
|
answer = cpr_get("siggen.valid",_("Signature is valid for? (0) "));
|
1998-08-08 21:27:00 +02:00
|
|
|
cpr_kill_prompt();
|
1998-04-02 12:30:03 +02:00
|
|
|
trim_spaces(answer);
|
2000-07-14 19:34:53 +02:00
|
|
|
valid_days = parse_expire_string( answer );
|
|
|
|
if( valid_days < 0 ) {
|
1998-04-02 12:30:03 +02:00
|
|
|
tty_printf(_("invalid value\n"));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
1998-10-16 18:00:17 +02:00
|
|
|
if( !valid_days ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
tty_printf(_("%s does not expire at all\n"),
|
|
|
|
object==0?"Key":"Signature");
|
1998-11-20 18:42:18 +01:00
|
|
|
interval = 0;
|
1998-10-16 18:00:17 +02:00
|
|
|
}
|
1998-04-02 12:30:03 +02:00
|
|
|
else {
|
1998-11-20 18:42:18 +01:00
|
|
|
interval = valid_days * 86400L;
|
1998-06-26 11:45:36 +02:00
|
|
|
/* print the date when the key expires */
|
2002-06-29 15:46:34 +02:00
|
|
|
tty_printf(_("%s expires at %s\n"),
|
|
|
|
object==0?"Key":"Signature",
|
2000-07-14 19:34:53 +02:00
|
|
|
asctimestamp((ulong)(curtime + interval) ) );
|
2002-06-29 15:46:34 +02:00
|
|
|
/* FIXME: This check yields warning on alhas:
|
|
|
|
write a configure check and to this check here only for 32 bit machines */
|
2000-07-14 19:34:53 +02:00
|
|
|
if( (time_t)((ulong)(curtime+interval)) < 0 )
|
|
|
|
tty_printf(_("Your system can't display dates beyond 2038.\n"
|
|
|
|
"However, it will be correctly handled up to 2106.\n"));
|
1998-04-02 12:30:03 +02:00
|
|
|
}
|
|
|
|
|
1999-09-01 15:40:07 +02:00
|
|
|
if( cpr_enabled() || cpr_get_answer_is_yes("keygen.valid.okay",
|
|
|
|
_("Is this correct (y/n)? ")) )
|
1998-04-02 12:30:03 +02:00
|
|
|
break;
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(answer);
|
1998-11-20 18:42:18 +01:00
|
|
|
return interval;
|
1998-05-26 15:38:00 +02:00
|
|
|
}
|
1998-04-02 12:30:03 +02:00
|
|
|
|
1998-11-20 18:42:18 +01:00
|
|
|
u32
|
|
|
|
ask_expiredate()
|
|
|
|
{
|
2002-06-29 15:46:34 +02:00
|
|
|
u32 x = ask_expire_interval(0);
|
1998-11-20 18:42:18 +01:00
|
|
|
return x? make_timestamp() + x : 0;
|
|
|
|
}
|
1998-04-02 12:30:03 +02:00
|
|
|
|
1998-06-26 11:45:36 +02:00
|
|
|
static int
|
|
|
|
has_invalid_email_chars( const char *s )
|
|
|
|
{
|
1998-10-21 19:34:36 +02:00
|
|
|
int at_seen=0;
|
1999-02-28 19:14:18 +01:00
|
|
|
static char valid_chars[] = "01234567890_-."
|
|
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
1998-10-21 19:34:36 +02:00
|
|
|
|
1998-06-26 11:45:36 +02:00
|
|
|
for( ; *s; s++ ) {
|
|
|
|
if( *s & 0x80 )
|
|
|
|
return 1;
|
1998-10-21 19:34:36 +02:00
|
|
|
if( *s == '@' )
|
|
|
|
at_seen=1;
|
1999-02-28 19:14:18 +01:00
|
|
|
else if( !at_seen && !( !!strchr( valid_chars, *s ) || *s == '+' ) )
|
1998-10-21 19:34:36 +02:00
|
|
|
return 1;
|
1999-02-28 19:14:18 +01:00
|
|
|
else if( at_seen && !strchr( valid_chars, *s ) )
|
1998-06-26 11:45:36 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-05-26 15:38:00 +02:00
|
|
|
static char *
|
1998-07-29 21:35:05 +02:00
|
|
|
ask_user_id( int mode )
|
1998-05-26 15:38:00 +02:00
|
|
|
{
|
|
|
|
char *answer;
|
|
|
|
char *aname, *acomment, *amail, *uid;
|
1998-04-02 12:30:03 +02:00
|
|
|
|
1998-07-29 21:35:05 +02:00
|
|
|
if( !mode )
|
|
|
|
tty_printf( _("\n"
|
1998-01-07 21:47:46 +01:00
|
|
|
"You need a User-ID to identify your key; the software constructs the user id\n"
|
|
|
|
"from Real Name, Comment and Email Address in this form:\n"
|
1998-04-02 12:30:03 +02:00
|
|
|
" \"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>\"\n\n") );
|
1998-05-26 15:38:00 +02:00
|
|
|
uid = aname = acomment = amail = NULL;
|
1997-11-18 15:06:00 +01:00
|
|
|
for(;;) {
|
1998-01-07 21:47:46 +01:00
|
|
|
char *p;
|
2000-07-14 19:34:53 +02:00
|
|
|
int fail=0;
|
1998-01-07 21:47:46 +01:00
|
|
|
|
|
|
|
if( !aname ) {
|
|
|
|
for(;;) {
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(aname);
|
1998-11-27 12:42:49 +01:00
|
|
|
aname = cpr_get("keygen.name",_("Real name: "));
|
1998-01-07 21:47:46 +01:00
|
|
|
trim_spaces(aname);
|
1998-08-08 21:27:00 +02:00
|
|
|
cpr_kill_prompt();
|
2000-09-18 16:35:34 +02:00
|
|
|
|
|
|
|
if( opt.allow_freeform_uid )
|
|
|
|
break;
|
|
|
|
|
|
|
|
if( strpbrk( aname, "<>" ) )
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_("Invalid character in name\n"));
|
* parse-packet.c (parse_signature): No need to reserve 8 bytes for the
unhashed signature cache any longer.
* misc.c (pct_expando): Add two new expandos - signer's fingerprint (%g),
and signer's primary fingerprint (%p).
* Makefile.am: Include W32LIBS where appropriate.
* g10.c (main): Add --rfc2440 alias for --openpgp since in a few months,
they won't be the same thing.
* keyserver.c (parse_keyserver_uri): Accept "http" as an alias for "hkp",
since it is occasionally written that way. (keyserver_spawn): Use
ascii_isspace to avoid locale issues.
* keygen.c (ask_user_id): Make --allow-freeform-uid apply to the email
field as well as the name field, and allow mixing fields when it is set.
* options.skel: Use subkeys.pgp.net as the default keyserver.
* trustdb.c (validate_one_keyblock): Certifications on revoked or expired
uids do not count in the web of trust.
* signal.c (init_one_signal, pause_on_sigusr, do_block): Only use
sigprocmask() if we have sigset_t, and only use sigaction() if we have
struct sigaction. This is for Forte c89 on Solaris which seems to define
only the function call half of the two pairs by default.
(pause_on_sigusr): Typo. (do_block): If we can't use sigprocmask() and
sigset_t, try to get the number of signals from NSIG as well as MAXSIG,
and if we can't, fail with an explanation.
* signal.c, tdbio.c: Comment out the transaction code. It was not used in
this version, and was causing some build problems on quasi-posix platforms
(Solaris and Forte c89).
* keylist.c (list_keyblock_colon): Don't include validity values when
listing secret keys since they can be incorrect and/or misleading. This
is a temporary kludge, and will be handled properly in 1.9/2.0.
* mainproc.c (check_sig_and_print): Only show the "key available from"
preferred keyserver line if the key is not currently present.
* keyedit.c (sign_uids): Do not sign expired uids without --expert (same
behavior as revoked uids). Do not allow signing a user ID without a
self-signature. --expert overrides. Add additional prompt to the
signature level question. (menu_expire): When changing expiration dates,
don't replace selfsigs on revoked uids since this would effectively
unrevoke them. There is also no point in replacing expired selfsigs.
This is bug #181
* g10.c (add_notation_data): Make sure that only ascii is passed to
iscntrl. Noted by Christian Biere.
* getkey.c (classify_user_id2): Replaced isspace by spacep
* keygen.c (ask_user_id): Ditto. (get_parameter_algo): Ditto.
* keyedit.c (keyedit_menu): Ditto.
* tdbdump.c (import_ownertrust): Ditto. s/isxdigit/hexdigitp/.
* revoke.c (ask_revocation_reason):
* keyserver.c (keyserver_spawn): Dito.
2003-07-10 16:30:07 +02:00
|
|
|
else if( digitp(aname) )
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_("Name may not start with a digit\n"));
|
1998-01-07 21:47:46 +01:00
|
|
|
else if( strlen(aname) < 5 )
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_("Name must be at least 5 characters long\n"));
|
1998-01-07 21:47:46 +01:00
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( !amail ) {
|
|
|
|
for(;;) {
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(amail);
|
1998-11-27 12:42:49 +01:00
|
|
|
amail = cpr_get("keygen.email",_("Email address: "));
|
1998-01-07 21:47:46 +01:00
|
|
|
trim_spaces(amail);
|
1998-08-08 21:27:00 +02:00
|
|
|
cpr_kill_prompt();
|
* parse-packet.c (parse_signature): No need to reserve 8 bytes for the
unhashed signature cache any longer.
* misc.c (pct_expando): Add two new expandos - signer's fingerprint (%g),
and signer's primary fingerprint (%p).
* Makefile.am: Include W32LIBS where appropriate.
* g10.c (main): Add --rfc2440 alias for --openpgp since in a few months,
they won't be the same thing.
* keyserver.c (parse_keyserver_uri): Accept "http" as an alias for "hkp",
since it is occasionally written that way. (keyserver_spawn): Use
ascii_isspace to avoid locale issues.
* keygen.c (ask_user_id): Make --allow-freeform-uid apply to the email
field as well as the name field, and allow mixing fields when it is set.
* options.skel: Use subkeys.pgp.net as the default keyserver.
* trustdb.c (validate_one_keyblock): Certifications on revoked or expired
uids do not count in the web of trust.
* signal.c (init_one_signal, pause_on_sigusr, do_block): Only use
sigprocmask() if we have sigset_t, and only use sigaction() if we have
struct sigaction. This is for Forte c89 on Solaris which seems to define
only the function call half of the two pairs by default.
(pause_on_sigusr): Typo. (do_block): If we can't use sigprocmask() and
sigset_t, try to get the number of signals from NSIG as well as MAXSIG,
and if we can't, fail with an explanation.
* signal.c, tdbio.c: Comment out the transaction code. It was not used in
this version, and was causing some build problems on quasi-posix platforms
(Solaris and Forte c89).
* keylist.c (list_keyblock_colon): Don't include validity values when
listing secret keys since they can be incorrect and/or misleading. This
is a temporary kludge, and will be handled properly in 1.9/2.0.
* mainproc.c (check_sig_and_print): Only show the "key available from"
preferred keyserver line if the key is not currently present.
* keyedit.c (sign_uids): Do not sign expired uids without --expert (same
behavior as revoked uids). Do not allow signing a user ID without a
self-signature. --expert overrides. Add additional prompt to the
signature level question. (menu_expire): When changing expiration dates,
don't replace selfsigs on revoked uids since this would effectively
unrevoke them. There is also no point in replacing expired selfsigs.
This is bug #181
* g10.c (add_notation_data): Make sure that only ascii is passed to
iscntrl. Noted by Christian Biere.
* getkey.c (classify_user_id2): Replaced isspace by spacep
* keygen.c (ask_user_id): Ditto. (get_parameter_algo): Ditto.
* keyedit.c (keyedit_menu): Ditto.
* tdbdump.c (import_ownertrust): Ditto. s/isxdigit/hexdigitp/.
* revoke.c (ask_revocation_reason):
* keyserver.c (keyserver_spawn): Dito.
2003-07-10 16:30:07 +02:00
|
|
|
if( !*amail || opt.allow_freeform_uid )
|
1998-01-07 21:47:46 +01:00
|
|
|
break; /* no email address is okay */
|
1998-06-26 11:45:36 +02:00
|
|
|
else if( has_invalid_email_chars(amail)
|
1998-01-07 21:47:46 +01:00
|
|
|
|| string_count_chr(amail,'@') != 1
|
|
|
|
|| *amail == '@'
|
|
|
|
|| amail[strlen(amail)-1] == '@'
|
|
|
|
|| amail[strlen(amail)-1] == '.'
|
|
|
|
|| strstr(amail, "..") )
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_("Not a valid email address\n"));
|
1998-01-07 21:47:46 +01:00
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( !acomment ) {
|
|
|
|
for(;;) {
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(acomment);
|
1998-11-27 12:42:49 +01:00
|
|
|
acomment = cpr_get("keygen.comment",_("Comment: "));
|
1998-01-07 21:47:46 +01:00
|
|
|
trim_spaces(acomment);
|
1998-08-08 21:27:00 +02:00
|
|
|
cpr_kill_prompt();
|
1998-01-07 21:47:46 +01:00
|
|
|
if( !*acomment )
|
|
|
|
break; /* no comment is okay */
|
|
|
|
else if( strpbrk( acomment, "()" ) )
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_("Invalid character in comment\n"));
|
1998-01-07 21:47:46 +01:00
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(uid);
|
|
|
|
uid = p = m_alloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10);
|
1998-01-07 21:47:46 +01:00
|
|
|
p = stpcpy(p, aname );
|
|
|
|
if( *acomment )
|
|
|
|
p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")");
|
|
|
|
if( *amail )
|
|
|
|
p = stpcpy(stpcpy(stpcpy(p," <"), amail),">");
|
1998-01-16 22:15:24 +01:00
|
|
|
|
|
|
|
/* append a warning if we do not have dev/random
|
|
|
|
* or it is switched into quick testmode */
|
|
|
|
if( quick_random_gen(-1) )
|
|
|
|
strcpy(p, " (INSECURE!)" );
|
|
|
|
|
1999-03-02 16:48:37 +01:00
|
|
|
/* print a note in case that UTF8 mapping has to be done */
|
|
|
|
for(p=uid; *p; p++ ) {
|
|
|
|
if( *p & 0x80 ) {
|
|
|
|
tty_printf(_("You are using the `%s' character set.\n"),
|
|
|
|
get_native_charset() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1998-01-07 21:47:46 +01:00
|
|
|
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_("You selected this USER-ID:\n \"%s\"\n\n"), uid);
|
1998-04-14 19:51:16 +02:00
|
|
|
/* fixme: add a warning if this user-id already exists */
|
* parse-packet.c (parse_signature): No need to reserve 8 bytes for the
unhashed signature cache any longer.
* misc.c (pct_expando): Add two new expandos - signer's fingerprint (%g),
and signer's primary fingerprint (%p).
* Makefile.am: Include W32LIBS where appropriate.
* g10.c (main): Add --rfc2440 alias for --openpgp since in a few months,
they won't be the same thing.
* keyserver.c (parse_keyserver_uri): Accept "http" as an alias for "hkp",
since it is occasionally written that way. (keyserver_spawn): Use
ascii_isspace to avoid locale issues.
* keygen.c (ask_user_id): Make --allow-freeform-uid apply to the email
field as well as the name field, and allow mixing fields when it is set.
* options.skel: Use subkeys.pgp.net as the default keyserver.
* trustdb.c (validate_one_keyblock): Certifications on revoked or expired
uids do not count in the web of trust.
* signal.c (init_one_signal, pause_on_sigusr, do_block): Only use
sigprocmask() if we have sigset_t, and only use sigaction() if we have
struct sigaction. This is for Forte c89 on Solaris which seems to define
only the function call half of the two pairs by default.
(pause_on_sigusr): Typo. (do_block): If we can't use sigprocmask() and
sigset_t, try to get the number of signals from NSIG as well as MAXSIG,
and if we can't, fail with an explanation.
* signal.c, tdbio.c: Comment out the transaction code. It was not used in
this version, and was causing some build problems on quasi-posix platforms
(Solaris and Forte c89).
* keylist.c (list_keyblock_colon): Don't include validity values when
listing secret keys since they can be incorrect and/or misleading. This
is a temporary kludge, and will be handled properly in 1.9/2.0.
* mainproc.c (check_sig_and_print): Only show the "key available from"
preferred keyserver line if the key is not currently present.
* keyedit.c (sign_uids): Do not sign expired uids without --expert (same
behavior as revoked uids). Do not allow signing a user ID without a
self-signature. --expert overrides. Add additional prompt to the
signature level question. (menu_expire): When changing expiration dates,
don't replace selfsigs on revoked uids since this would effectively
unrevoke them. There is also no point in replacing expired selfsigs.
This is bug #181
* g10.c (add_notation_data): Make sure that only ascii is passed to
iscntrl. Noted by Christian Biere.
* getkey.c (classify_user_id2): Replaced isspace by spacep
* keygen.c (ask_user_id): Ditto. (get_parameter_algo): Ditto.
* keyedit.c (keyedit_menu): Ditto.
* tdbdump.c (import_ownertrust): Ditto. s/isxdigit/hexdigitp/.
* revoke.c (ask_revocation_reason):
* keyserver.c (keyserver_spawn): Dito.
2003-07-10 16:30:07 +02:00
|
|
|
if( !*amail && !opt.allow_freeform_uid
|
|
|
|
&& (strchr( aname, '@' ) || strchr( acomment, '@'))) {
|
2000-07-14 19:34:53 +02:00
|
|
|
fail = 1;
|
|
|
|
tty_printf(_("Please don't put the email address "
|
|
|
|
"into the real name or the comment\n") );
|
|
|
|
}
|
|
|
|
|
1998-01-07 21:47:46 +01:00
|
|
|
for(;;) {
|
2002-06-29 15:46:34 +02:00
|
|
|
const char *ansstr = _("NnCcEeOoQq");
|
1998-08-05 18:51:59 +02:00
|
|
|
|
1998-08-11 19:29:34 +02:00
|
|
|
if( strlen(ansstr) != 10 )
|
|
|
|
BUG();
|
1998-08-05 18:51:59 +02:00
|
|
|
if( cpr_enabled() ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
answer = m_strdup(ansstr+6);
|
1998-08-05 18:51:59 +02:00
|
|
|
answer[1] = 0;
|
|
|
|
}
|
|
|
|
else {
|
2000-07-14 19:34:53 +02:00
|
|
|
answer = cpr_get("keygen.userid.cmd", fail?
|
|
|
|
_("Change (N)ame, (C)omment, (E)mail or (Q)uit? ") :
|
|
|
|
_("Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? "));
|
1998-08-08 21:27:00 +02:00
|
|
|
cpr_kill_prompt();
|
1998-08-05 18:51:59 +02:00
|
|
|
}
|
1998-01-07 21:47:46 +01:00
|
|
|
if( strlen(answer) > 1 )
|
|
|
|
;
|
1998-07-29 21:35:05 +02:00
|
|
|
else if( *answer == ansstr[0] || *answer == ansstr[1] ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(aname); aname = NULL;
|
1998-01-07 21:47:46 +01:00
|
|
|
break;
|
|
|
|
}
|
1998-07-29 21:35:05 +02:00
|
|
|
else if( *answer == ansstr[2] || *answer == ansstr[3] ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(acomment); acomment = NULL;
|
1998-01-07 21:47:46 +01:00
|
|
|
break;
|
|
|
|
}
|
1998-07-29 21:35:05 +02:00
|
|
|
else if( *answer == ansstr[4] || *answer == ansstr[5] ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(amail); amail = NULL;
|
1998-01-07 21:47:46 +01:00
|
|
|
break;
|
|
|
|
}
|
1998-07-29 21:35:05 +02:00
|
|
|
else if( *answer == ansstr[6] || *answer == ansstr[7] ) {
|
2000-07-14 19:34:53 +02:00
|
|
|
if( fail ) {
|
|
|
|
tty_printf(_("Please correct the error first\n"));
|
|
|
|
}
|
|
|
|
else {
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(aname); aname = NULL;
|
|
|
|
m_free(acomment); acomment = NULL;
|
|
|
|
m_free(amail); amail = NULL;
|
2000-07-14 19:34:53 +02:00
|
|
|
break;
|
|
|
|
}
|
1997-11-18 15:06:00 +01:00
|
|
|
}
|
1998-07-29 21:35:05 +02:00
|
|
|
else if( *answer == ansstr[8] || *answer == ansstr[9] ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(aname); aname = NULL;
|
|
|
|
m_free(acomment); acomment = NULL;
|
|
|
|
m_free(amail); amail = NULL;
|
|
|
|
m_free(uid); uid = NULL;
|
1998-07-29 21:35:05 +02:00
|
|
|
break;
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(answer);
|
1997-11-18 15:06:00 +01:00
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(answer);
|
1998-01-07 21:47:46 +01:00
|
|
|
if( !amail && !acomment && !amail )
|
|
|
|
break;
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(uid); uid = NULL;
|
1997-11-18 15:06:00 +01:00
|
|
|
}
|
1998-11-03 20:38:58 +01:00
|
|
|
if( uid ) {
|
|
|
|
char *p = native_to_utf8( uid );
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free( uid );
|
1998-11-03 20:38:58 +01:00
|
|
|
uid = p;
|
|
|
|
}
|
1998-05-26 15:38:00 +02:00
|
|
|
return uid;
|
|
|
|
}
|
|
|
|
|
1997-12-09 13:46:23 +01:00
|
|
|
|
1998-05-26 15:38:00 +02:00
|
|
|
static DEK *
|
|
|
|
ask_passphrase( STRING2KEY **ret_s2k )
|
|
|
|
{
|
|
|
|
DEK *dek = NULL;
|
|
|
|
STRING2KEY *s2k;
|
2002-06-29 15:46:34 +02:00
|
|
|
const char *errtext = NULL;
|
1997-12-09 13:46:23 +01:00
|
|
|
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_("You need a Passphrase to protect your secret key.\n\n") );
|
1997-12-09 13:46:23 +01:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
s2k = m_alloc_secure( sizeof *s2k );
|
1997-12-20 18:23:29 +01:00
|
|
|
for(;;) {
|
1998-09-28 21:25:31 +02:00
|
|
|
s2k->mode = opt.s2k_mode;
|
|
|
|
s2k->hash_algo = opt.s2k_digest_algo;
|
2003-04-10 11:56:47 +02:00
|
|
|
dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k,2,
|
|
|
|
errtext, NULL);
|
1998-05-04 20:49:26 +02:00
|
|
|
if( !dek ) {
|
2003-04-10 11:56:47 +02:00
|
|
|
errtext = N_("passphrase not correctly repeated; try again");
|
|
|
|
tty_printf(_("%s.\n"), _(errtext));
|
1998-05-04 20:49:26 +02:00
|
|
|
}
|
|
|
|
else if( !dek->keylen ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(dek); dek = NULL;
|
|
|
|
m_free(s2k); s2k = NULL;
|
1998-01-28 17:09:43 +01:00
|
|
|
tty_printf(_(
|
1998-04-14 19:51:16 +02:00
|
|
|
"You don't want a passphrase - this is probably a *bad* idea!\n"
|
|
|
|
"I will do it anyway. You can change your passphrase at any time,\n"
|
1998-07-29 21:35:05 +02:00
|
|
|
"using this program with the option \"--edit-key\".\n\n"));
|
1997-12-20 18:23:29 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break; /* okay */
|
1997-12-09 13:46:23 +01:00
|
|
|
}
|
1998-05-26 15:38:00 +02:00
|
|
|
*ret_s2k = s2k;
|
|
|
|
return dek;
|
|
|
|
}
|
1997-12-09 13:46:23 +01:00
|
|
|
|
|
|
|
|
1998-05-26 15:38:00 +02:00
|
|
|
static int
|
2002-06-29 15:46:34 +02:00
|
|
|
do_create( int algo, unsigned int nbits, KBNODE pub_root, KBNODE sec_root,
|
2000-07-14 19:34:53 +02:00
|
|
|
DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate )
|
1998-05-26 15:38:00 +02:00
|
|
|
{
|
|
|
|
int rc=0;
|
1997-11-18 15:06:00 +01:00
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
if( !opt.batch )
|
|
|
|
tty_printf(_(
|
1997-12-20 18:23:29 +01:00
|
|
|
"We need to generate a lot of random bytes. It is a good idea to perform\n"
|
1999-03-14 19:35:18 +01:00
|
|
|
"some other action (type on the keyboard, move the mouse, utilize the\n"
|
1999-04-07 20:58:34 +02:00
|
|
|
"disks) during the prime generation; this gives the random number\n"
|
|
|
|
"generator a better chance to gain enough entropy.\n") );
|
1997-12-20 18:23:29 +01:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
if( algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E )
|
2000-07-14 19:34:53 +02:00
|
|
|
rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
|
2002-06-29 15:46:34 +02:00
|
|
|
else if( algo == PUBKEY_ALGO_DSA )
|
1998-10-16 18:00:17 +02:00
|
|
|
rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
|
2002-06-29 15:46:34 +02:00
|
|
|
else if( algo == PUBKEY_ALGO_RSA )
|
2000-07-14 19:34:53 +02:00
|
|
|
rc = gen_rsa(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
|
1997-11-24 23:24:04 +01:00
|
|
|
else
|
1998-01-16 22:15:24 +01:00
|
|
|
BUG();
|
1998-10-16 18:00:17 +02:00
|
|
|
|
* armor.c, g10.c, kbnode.c, misc.c, pkclist.c, sign.c, build-packet.c,
getkey.c, keydb.c, openfile.c, plaintext.c, status.c, gpgv.c, keygen.c,
options.h, sig-check.c, tdbio.h, encode.c, mainproc.c, parse-packet.c,
signal.c, textfilter.c: Edit all preprocessor instructions to remove
whitespace before the '#'. This is not required by C89, but there are some
compilers out there that don't like it.
2003-05-24 23:50:33 +02:00
|
|
|
#ifdef ENABLE_COMMENT_PACKETS
|
1998-02-13 21:58:50 +01:00
|
|
|
if( !rc ) {
|
|
|
|
add_kbnode( pub_root,
|
1998-02-24 19:50:46 +01:00
|
|
|
make_comment_node("#created by GNUPG v" VERSION " ("
|
1998-02-16 21:05:02 +01:00
|
|
|
PRINTABLE_OS_NAME ")"));
|
1998-02-13 21:58:50 +01:00
|
|
|
add_kbnode( sec_root,
|
1998-02-24 19:50:46 +01:00
|
|
|
make_comment_node("#created by GNUPG v" VERSION " ("
|
1998-02-16 21:05:02 +01:00
|
|
|
PRINTABLE_OS_NAME ")"));
|
1998-02-13 21:58:50 +01:00
|
|
|
}
|
* armor.c, g10.c, kbnode.c, misc.c, pkclist.c, sign.c, build-packet.c,
getkey.c, keydb.c, openfile.c, plaintext.c, status.c, gpgv.c, keygen.c,
options.h, sig-check.c, tdbio.h, encode.c, mainproc.c, parse-packet.c,
signal.c, textfilter.c: Edit all preprocessor instructions to remove
whitespace before the '#'. This is not required by C89, but there are some
compilers out there that don't like it.
2003-05-24 23:50:33 +02:00
|
|
|
#endif
|
1998-05-26 15:38:00 +02:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-07-29 21:35:05 +02:00
|
|
|
/****************
|
1999-06-16 20:25:37 +02:00
|
|
|
* Generate a new user id packet, or return NULL if canceled
|
1998-07-29 21:35:05 +02:00
|
|
|
*/
|
|
|
|
PKT_user_id *
|
|
|
|
generate_user_id()
|
|
|
|
{
|
|
|
|
PKT_user_id *uid;
|
|
|
|
char *p;
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
p = ask_user_id( 1 );
|
|
|
|
if( !p )
|
|
|
|
return NULL;
|
|
|
|
n = strlen(p);
|
2002-06-29 15:46:34 +02:00
|
|
|
uid = m_alloc_clear( sizeof *uid + n - 1 );
|
1998-07-29 21:35:05 +02:00
|
|
|
uid->len = n;
|
|
|
|
strcpy(uid->name, p);
|
2002-06-29 15:46:34 +02:00
|
|
|
uid->ref = 1;
|
1998-07-29 21:35:05 +02:00
|
|
|
return uid;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
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 )
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free( r->u.dek );
|
2000-07-14 19:34:53 +02:00
|
|
|
else if( r->key == pPASSPHRASE_S2K )
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free( r->u.s2k );
|
2000-07-14 19:34:53 +02:00
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free(r);
|
2000-07-14 19:34:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 )
|
|
|
|
{
|
2002-06-29 15:46:34 +02:00
|
|
|
int i;
|
2000-07-14 19:34:53 +02:00
|
|
|
struct para_data_s *r = get_parameter( para, key );
|
|
|
|
if( !r )
|
|
|
|
return -1;
|
* parse-packet.c (parse_signature): No need to reserve 8 bytes for the
unhashed signature cache any longer.
* misc.c (pct_expando): Add two new expandos - signer's fingerprint (%g),
and signer's primary fingerprint (%p).
* Makefile.am: Include W32LIBS where appropriate.
* g10.c (main): Add --rfc2440 alias for --openpgp since in a few months,
they won't be the same thing.
* keyserver.c (parse_keyserver_uri): Accept "http" as an alias for "hkp",
since it is occasionally written that way. (keyserver_spawn): Use
ascii_isspace to avoid locale issues.
* keygen.c (ask_user_id): Make --allow-freeform-uid apply to the email
field as well as the name field, and allow mixing fields when it is set.
* options.skel: Use subkeys.pgp.net as the default keyserver.
* trustdb.c (validate_one_keyblock): Certifications on revoked or expired
uids do not count in the web of trust.
* signal.c (init_one_signal, pause_on_sigusr, do_block): Only use
sigprocmask() if we have sigset_t, and only use sigaction() if we have
struct sigaction. This is for Forte c89 on Solaris which seems to define
only the function call half of the two pairs by default.
(pause_on_sigusr): Typo. (do_block): If we can't use sigprocmask() and
sigset_t, try to get the number of signals from NSIG as well as MAXSIG,
and if we can't, fail with an explanation.
* signal.c, tdbio.c: Comment out the transaction code. It was not used in
this version, and was causing some build problems on quasi-posix platforms
(Solaris and Forte c89).
* keylist.c (list_keyblock_colon): Don't include validity values when
listing secret keys since they can be incorrect and/or misleading. This
is a temporary kludge, and will be handled properly in 1.9/2.0.
* mainproc.c (check_sig_and_print): Only show the "key available from"
preferred keyserver line if the key is not currently present.
* keyedit.c (sign_uids): Do not sign expired uids without --expert (same
behavior as revoked uids). Do not allow signing a user ID without a
self-signature. --expert overrides. Add additional prompt to the
signature level question. (menu_expire): When changing expiration dates,
don't replace selfsigs on revoked uids since this would effectively
unrevoke them. There is also no point in replacing expired selfsigs.
This is bug #181
* g10.c (add_notation_data): Make sure that only ascii is passed to
iscntrl. Noted by Christian Biere.
* getkey.c (classify_user_id2): Replaced isspace by spacep
* keygen.c (ask_user_id): Ditto. (get_parameter_algo): Ditto.
* keyedit.c (keyedit_menu): Ditto.
* tdbdump.c (import_ownertrust): Ditto. s/isxdigit/hexdigitp/.
* revoke.c (ask_revocation_reason):
* keyserver.c (keyserver_spawn): Dito.
2003-07-10 16:30:07 +02:00
|
|
|
if( digitp( r->u.value ) )
|
2002-06-29 15:46:34 +02:00
|
|
|
i = atoi( r->u.value );
|
|
|
|
else
|
|
|
|
i = string_to_pubkey_algo( r->u.value );
|
|
|
|
if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S)
|
|
|
|
i = 0; /* we don't want to allow generation of these algorithms */
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* parse the usage parameter and set the keyflags. Return true on error.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
parse_parameter_usage (const char *fname,
|
|
|
|
struct para_data_s *para, enum para_name key)
|
|
|
|
{
|
|
|
|
struct para_data_s *r = get_parameter( para, key );
|
|
|
|
char *p, *pn;
|
|
|
|
unsigned int use;
|
|
|
|
|
|
|
|
if( !r )
|
|
|
|
return 0; /* none (this is an optional parameter)*/
|
|
|
|
|
|
|
|
use = 0;
|
|
|
|
pn = r->u.value;
|
|
|
|
while ( (p = strsep (&pn, " \t,")) ) {
|
|
|
|
if ( !*p)
|
|
|
|
;
|
|
|
|
else if ( !ascii_strcasecmp (p, "sign") )
|
|
|
|
use |= PUBKEY_USAGE_SIG;
|
|
|
|
else if ( !ascii_strcasecmp (p, "encrypt") )
|
|
|
|
use |= PUBKEY_USAGE_ENC;
|
|
|
|
else {
|
|
|
|
log_error("%s:%d: invalid usage list\n", fname, r->lnr );
|
|
|
|
return -1; /* error */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r->u.usage = use;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
parse_revocation_key (const char *fname,
|
|
|
|
struct para_data_s *para, enum para_name key)
|
|
|
|
{
|
|
|
|
struct para_data_s *r = get_parameter( para, key );
|
|
|
|
struct revocation_key revkey;
|
|
|
|
char *pn;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if( !r )
|
|
|
|
return 0; /* none (this is an optional parameter) */
|
|
|
|
|
|
|
|
pn = r->u.value;
|
|
|
|
|
|
|
|
revkey.class=0x80;
|
|
|
|
revkey.algid=atoi(pn);
|
|
|
|
if(!revkey.algid)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
/* Skip to the fpr */
|
|
|
|
while(*pn && *pn!=':')
|
|
|
|
pn++;
|
|
|
|
|
|
|
|
if(*pn!=':')
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
pn++;
|
|
|
|
|
|
|
|
for(i=0;i<MAX_FINGERPRINT_LEN && *pn;i++,pn+=2)
|
|
|
|
{
|
|
|
|
int c=hextobyte(pn);
|
|
|
|
if(c==-1)
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
revkey.fpr[i]=c;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* skip to the tag */
|
|
|
|
while(*pn && *pn!='s' && *pn!='S')
|
|
|
|
pn++;
|
|
|
|
|
|
|
|
if(ascii_strcasecmp(pn,"sensitive")==0)
|
|
|
|
revkey.class|=0x40;
|
|
|
|
|
|
|
|
memcpy(&r->u.revkey,&revkey,sizeof(struct revocation_key));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
log_error("%s:%d: invalid revocation key\n", fname, r->lnr );
|
|
|
|
return -1; /* error */
|
2000-07-14 19:34:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE )
|
|
|
|
return r->u.expire;
|
2002-06-29 15:46:34 +02:00
|
|
|
if( r->key == pKEYUSAGE || r->key == pSUBKEYUSAGE )
|
|
|
|
return r->u.usage;
|
2000-07-14 19:34:53 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
static struct revocation_key *
|
|
|
|
get_parameter_revkey( struct para_data_s *para, enum para_name key )
|
|
|
|
{
|
|
|
|
struct para_data_s *r = get_parameter( para, key );
|
|
|
|
return r? &r->u.revkey : NULL;
|
|
|
|
}
|
2000-07-14 19:34:53 +02:00
|
|
|
|
|
|
|
static int
|
|
|
|
proc_parameter_file( struct para_data_s *para, const char *fname,
|
2002-06-29 15:46:34 +02:00
|
|
|
struct output_control_s *outctrl )
|
2000-07-14 19:34:53 +02:00
|
|
|
{
|
|
|
|
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 );
|
2002-06-29 15:46:34 +02:00
|
|
|
if( i < 1 || check_pubkey_algo2( i, PUBKEY_USAGE_SIG ) ) {
|
2000-07-14 19:34:53 +02:00
|
|
|
r = get_parameter( para, pKEYTYPE );
|
|
|
|
log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
if (parse_parameter_usage (fname, para, pKEYUSAGE))
|
|
|
|
return -1;
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
i = get_parameter_algo( para, pSUBKEYTYPE );
|
2002-06-29 15:46:34 +02:00
|
|
|
if( i > 0 && check_pubkey_algo( i ) ) {
|
2000-07-14 19:34:53 +02:00
|
|
|
r = get_parameter( para, pSUBKEYTYPE );
|
|
|
|
log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
|
|
|
|
return -1;
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
if (i > 0 && parse_parameter_usage (fname, para, pSUBKEYUSAGE))
|
|
|
|
return -1;
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
|
|
|
|
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);
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r + n + 20 );
|
2000-07-14 19:34:53 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
/* Set preferences, if any. */
|
|
|
|
keygen_set_std_prefs(get_parameter_value( para, pPREFERENCES ), 0);
|
|
|
|
|
|
|
|
/* Set revoker, if any. */
|
|
|
|
if (parse_revocation_key (fname, para, pREVOKER))
|
|
|
|
return -1;
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
/* 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.
|
|
|
|
* 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;
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
s2k = m_alloc_secure( sizeof *s2k );
|
2000-07-14 19:34:53 +02:00
|
|
|
s2k->mode = opt.s2k_mode;
|
|
|
|
s2k->hash_algo = opt.s2k_digest_algo;
|
|
|
|
set_next_passphrase( r->u.value );
|
2003-04-10 11:56:47 +02:00
|
|
|
dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2,
|
|
|
|
NULL, NULL);
|
2000-07-14 19:34:53 +02:00
|
|
|
set_next_passphrase( NULL );
|
|
|
|
assert( dek );
|
|
|
|
memset( r->u.value, 0, strlen(r->u.value) );
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = pPASSPHRASE_S2K;
|
|
|
|
r->u.s2k = s2k;
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = pPASSPHRASE_DEK;
|
|
|
|
r->u.dek = dek;
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 */
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r + 20 );
|
2000-07-14 19:34:53 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* 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 },
|
2002-06-29 15:46:34 +02:00
|
|
|
{ "Key-Usage", pKEYUSAGE },
|
2000-07-14 19:34:53 +02:00
|
|
|
{ "Subkey-Type", pSUBKEYTYPE },
|
|
|
|
{ "Subkey-Length", pSUBKEYLENGTH },
|
2002-06-29 15:46:34 +02:00
|
|
|
{ "Subkey-Usage", pSUBKEYUSAGE },
|
2000-07-14 19:34:53 +02:00
|
|
|
{ "Name-Real", pNAMEREAL },
|
|
|
|
{ "Name-Email", pNAMEEMAIL },
|
|
|
|
{ "Name-Comment", pNAMECOMMENT },
|
|
|
|
{ "Expire-Date", pEXPIREDATE },
|
|
|
|
{ "Passphrase", pPASSPHRASE },
|
2002-06-29 15:46:34 +02:00
|
|
|
{ "Preferences", pPREFERENCES },
|
|
|
|
{ "Revoker", pREVOKER },
|
2000-07-14 19:34:53 +02:00
|
|
|
{ NULL, 0 }
|
|
|
|
};
|
|
|
|
FILE *fp;
|
|
|
|
char line[1024], *p;
|
|
|
|
int lnr;
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
for( p = line; isspace(*(byte*)p); p++ )
|
2000-07-14 19:34:53 +02:00
|
|
|
;
|
|
|
|
if( !*p || *p == '#' )
|
|
|
|
continue;
|
|
|
|
keyword = p;
|
|
|
|
if( *keyword == '%' ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
for( ; !isspace(*(byte*)p); p++ )
|
2000-07-14 19:34:53 +02:00
|
|
|
;
|
|
|
|
if( *p )
|
|
|
|
*p++ = 0;
|
2002-06-29 15:46:34 +02:00
|
|
|
for( ; isspace(*(byte*)p); p++ )
|
2000-07-14 19:34:53 +02:00
|
|
|
;
|
|
|
|
value = p;
|
|
|
|
trim_trailing_ws( value, strlen(value) );
|
2002-06-29 15:46:34 +02:00
|
|
|
if( !ascii_strcasecmp( keyword, "%echo" ) )
|
2000-07-14 19:34:53 +02:00
|
|
|
log_info("%s\n", value );
|
2002-06-29 15:46:34 +02:00
|
|
|
else if( !ascii_strcasecmp( keyword, "%dry-run" ) )
|
2000-07-14 19:34:53 +02:00
|
|
|
outctrl.dryrun = 1;
|
2002-06-29 15:46:34 +02:00
|
|
|
else if( !ascii_strcasecmp( keyword, "%commit" ) ) {
|
2000-07-14 19:34:53 +02:00
|
|
|
outctrl.lnr = lnr;
|
|
|
|
proc_parameter_file( para, fname, &outctrl );
|
|
|
|
release_parameter_list( para );
|
|
|
|
para = NULL;
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
else if( !ascii_strcasecmp( keyword, "%pubring" ) ) {
|
2000-07-14 19:34:53 +02:00
|
|
|
if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) )
|
|
|
|
; /* still the same file - ignore it */
|
|
|
|
else {
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free( outctrl.pub.newfname );
|
|
|
|
outctrl.pub.newfname = m_strdup( value );
|
2000-07-14 19:34:53 +02:00
|
|
|
outctrl.use_files = 1;
|
|
|
|
}
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
else if( !ascii_strcasecmp( keyword, "%secring" ) ) {
|
2000-07-14 19:34:53 +02:00
|
|
|
if( outctrl.sec.fname && !strcmp( outctrl.sec.fname, value ) )
|
|
|
|
; /* still the same file - ignore it */
|
|
|
|
else {
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free( outctrl.sec.newfname );
|
|
|
|
outctrl.sec.newfname = m_strdup( value );
|
2000-07-14 19:34:53 +02:00
|
|
|
outctrl.use_files = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
log_info("skipping control `%s' (%s)\n", keyword, value );
|
|
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if( !(p = strchr( p, ':' )) || p == keyword ) {
|
|
|
|
err = "missing colon";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( *p )
|
|
|
|
*p++ = 0;
|
2002-06-29 15:46:34 +02:00
|
|
|
for( ; isspace(*(byte*)p); p++ )
|
2000-07-14 19:34:53 +02:00
|
|
|
;
|
|
|
|
if( !*p ) {
|
|
|
|
err = "missing argument";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
value = p;
|
|
|
|
trim_trailing_ws( value, strlen(value) );
|
|
|
|
|
|
|
|
for(i=0; keywords[i].name; i++ ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
if( !ascii_strcasecmp( keywords[i].name, keyword ) )
|
2000-07-14 19:34:53 +02:00
|
|
|
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 ) {
|
|
|
|
outctrl.lnr = lnr;
|
|
|
|
proc_parameter_file( para, fname, &outctrl );
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r + strlen( value ) );
|
2000-07-14 19:34:53 +02:00
|
|
|
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 ) {
|
|
|
|
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 );
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free( outctrl.pub.fname );
|
|
|
|
m_free( outctrl.pub.newfname );
|
|
|
|
m_free( outctrl.sec.fname );
|
|
|
|
m_free( outctrl.sec.newfname );
|
2000-07-14 19:34:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
release_parameter_list( para );
|
|
|
|
if( strcmp( fname, "-" ) )
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-05-26 15:38:00 +02:00
|
|
|
/****************
|
|
|
|
* Generate a keypair
|
2000-07-14 19:34:53 +02:00
|
|
|
* (fname is only used in batch mode)
|
1998-05-26 15:38:00 +02:00
|
|
|
*/
|
|
|
|
void
|
2000-07-14 19:34:53 +02:00
|
|
|
generate_keypair( const char *fname )
|
1998-05-26 15:38:00 +02:00
|
|
|
{
|
2000-07-14 19:34:53 +02:00
|
|
|
unsigned int nbits;
|
1998-05-26 15:38:00 +02:00
|
|
|
char *uid = NULL;
|
|
|
|
DEK *dek;
|
|
|
|
STRING2KEY *s2k;
|
|
|
|
int algo;
|
2002-06-29 15:46:34 +02:00
|
|
|
unsigned int use;
|
1998-06-25 12:19:08 +02:00
|
|
|
int both = 0;
|
2000-07-14 19:34:53 +02:00
|
|
|
u32 expire;
|
|
|
|
struct para_data_s *para = NULL;
|
|
|
|
struct para_data_s *r;
|
|
|
|
struct output_control_s outctrl;
|
|
|
|
|
|
|
|
memset( &outctrl, 0, sizeof( outctrl ) );
|
1998-05-26 15:38:00 +02:00
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
if( opt.batch ) {
|
|
|
|
read_parameter_file( fname );
|
1998-05-26 15:38:00 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
algo = ask_algo( 0, &use );
|
2000-07-14 19:34:53 +02:00
|
|
|
if( !algo ) { /* default: DSA with ElG subkey of the specified size */
|
1998-06-25 12:19:08 +02:00
|
|
|
both = 1;
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r + 20 );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = pKEYTYPE;
|
2002-06-29 15:46:34 +02:00
|
|
|
sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->next = para;
|
|
|
|
para = r;
|
1998-06-25 12:19:08 +02:00
|
|
|
tty_printf(_("DSA keypair will have 1024 bits.\n"));
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r + 20 );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = pKEYLENGTH;
|
|
|
|
strcpy( r->u.value, "1024" );
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
algo = PUBKEY_ALGO_ELGAMAL_E;
|
|
|
|
r = m_alloc_clear( sizeof *r + 20 );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = pSUBKEYTYPE;
|
|
|
|
sprintf( r->u.value, "%d", algo );
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
|
|
|
}
|
|
|
|
else {
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r + 20 );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = pKEYTYPE;
|
|
|
|
sprintf( r->u.value, "%d", algo );
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
2002-06-29 15:46:34 +02:00
|
|
|
|
|
|
|
if (use) {
|
|
|
|
r = m_alloc_clear( sizeof *r + 20 );
|
|
|
|
r->key = pKEYUSAGE;
|
|
|
|
sprintf( r->u.value, "%s%s",
|
|
|
|
(use & PUBKEY_USAGE_SIG)? "sign ":"",
|
|
|
|
(use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
|
|
|
}
|
|
|
|
|
1998-06-25 12:19:08 +02:00
|
|
|
}
|
2000-07-14 19:34:53 +02:00
|
|
|
|
1998-05-26 15:38:00 +02:00
|
|
|
nbits = ask_keysize( algo );
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r + 20 );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
|
|
|
|
sprintf( r->u.value, "%u", nbits);
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
expire = ask_expire_interval(0);
|
|
|
|
r = m_alloc_clear( sizeof *r + 20 );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = pKEYEXPIRE;
|
|
|
|
r->u.expire = expire;
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r + 20 );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = pSUBKEYEXPIRE;
|
|
|
|
r->u.expire = expire;
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
|
|
|
|
1998-07-29 21:35:05 +02:00
|
|
|
uid = ask_user_id(0);
|
|
|
|
if( !uid ) {
|
1999-06-16 20:25:37 +02:00
|
|
|
log_error(_("Key generation canceled.\n"));
|
2000-07-14 19:34:53 +02:00
|
|
|
release_parameter_list( para );
|
1998-07-29 21:35:05 +02:00
|
|
|
return;
|
|
|
|
}
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r + strlen(uid) );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = pUSERID;
|
|
|
|
strcpy( r->u.value, uid );
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
|
|
|
|
1998-05-26 15:38:00 +02:00
|
|
|
dek = ask_passphrase( &s2k );
|
2000-07-14 19:34:53 +02:00
|
|
|
if( dek ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = pPASSPHRASE_DEK;
|
|
|
|
r->u.dek = dek;
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
2002-06-29 15:46:34 +02:00
|
|
|
r = m_alloc_clear( sizeof *r );
|
2000-07-14 19:34:53 +02:00
|
|
|
r->key = pPASSPHRASE_S2K;
|
|
|
|
r->u.s2k = s2k;
|
|
|
|
r->next = para;
|
|
|
|
para = r;
|
|
|
|
}
|
|
|
|
|
|
|
|
proc_parameter_file( para, "[internal]", &outctrl );
|
|
|
|
release_parameter_list( para );
|
|
|
|
}
|
1998-05-26 15:38:00 +02:00
|
|
|
|
|
|
|
|
2002-10-12 13:47:40 +02:00
|
|
|
static void
|
|
|
|
print_status_key_created (int letter, PKT_public_key *pk)
|
|
|
|
{
|
|
|
|
byte array[MAX_FINGERPRINT_LEN], *s;
|
|
|
|
char buf[MAX_FINGERPRINT_LEN*2+30], *p;
|
|
|
|
size_t i, n;
|
|
|
|
|
|
|
|
p = buf;
|
|
|
|
*p++ = letter;
|
|
|
|
*p++ = ' ';
|
|
|
|
fingerprint_from_pk (pk, array, &n);
|
|
|
|
s = array;
|
|
|
|
for (i=0; i < n ; i++, s++, p += 2)
|
|
|
|
sprintf (p, "%02X", *s);
|
|
|
|
*p = 0;
|
|
|
|
write_status_text (STATUS_KEY_CREATED, buf);
|
|
|
|
}
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
static void
|
|
|
|
do_generate_keypair( struct para_data_s *para,
|
|
|
|
struct output_control_s *outctrl )
|
|
|
|
{
|
|
|
|
KBNODE pub_root = NULL;
|
|
|
|
KBNODE sec_root = NULL;
|
|
|
|
PKT_secret_key *sk = NULL;
|
|
|
|
const char *s;
|
2002-06-29 15:46:34 +02:00
|
|
|
struct revocation_key *revkey;
|
2000-07-14 19:34:53 +02:00
|
|
|
int rc;
|
2002-06-29 15:46:34 +02:00
|
|
|
int did_sub = 0;
|
2000-07-14 19:34:53 +02:00
|
|
|
|
|
|
|
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;
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free( outctrl->pub.fname );
|
2000-07-14 19:34:53 +02:00
|
|
|
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;
|
2002-06-29 15:46:34 +02:00
|
|
|
m_free( outctrl->sec.fname );
|
2000-07-14 19:34:53 +02:00
|
|
|
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 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert( outctrl->pub.stream );
|
|
|
|
assert( outctrl->sec.stream );
|
2002-06-29 15:46:34 +02:00
|
|
|
if( opt.verbose ) {
|
|
|
|
log_info(_("writing public key to `%s'\n"), outctrl->pub.fname );
|
|
|
|
log_info(_("writing secret key to `%s'\n"), outctrl->sec.fname );
|
|
|
|
}
|
2000-07-14 19:34:53 +02:00
|
|
|
}
|
|
|
|
|
1998-05-26 15:38:00 +02:00
|
|
|
|
|
|
|
/* 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 dummy comment packet which we flag
|
1998-06-29 14:30:57 +02:00
|
|
|
* as deleted. The very first packet must always be a KEY packet.
|
1998-05-26 15:38:00 +02:00
|
|
|
*/
|
|
|
|
pub_root = make_comment_node("#"); delete_kbnode(pub_root);
|
|
|
|
sec_root = make_comment_node("#"); delete_kbnode(sec_root);
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
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 ) );
|
2002-06-29 15:46:34 +02:00
|
|
|
|
|
|
|
if(!rc && (revkey=get_parameter_revkey(para,pREVOKER)))
|
|
|
|
{
|
|
|
|
rc=write_direct_sig(pub_root,pub_root,sk,revkey);
|
|
|
|
if(!rc)
|
|
|
|
write_direct_sig(sec_root,pub_root,sk,revkey);
|
|
|
|
}
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
if( !rc && (s=get_parameter_value(para, pUSERID)) ) {
|
|
|
|
write_uid(pub_root, s );
|
|
|
|
if( !rc )
|
|
|
|
write_uid(sec_root, s );
|
|
|
|
if( !rc )
|
2002-06-29 15:46:34 +02:00
|
|
|
rc = write_selfsig(pub_root, pub_root, sk,
|
|
|
|
get_parameter_uint (para, pKEYUSAGE));
|
2000-07-14 19:34:53 +02:00
|
|
|
if( !rc )
|
2002-06-29 15:46:34 +02:00
|
|
|
rc = write_selfsig(sec_root, pub_root, sk,
|
|
|
|
get_parameter_uint (para, pKEYUSAGE));
|
2000-07-14 19:34:53 +02:00
|
|
|
}
|
1997-12-09 13:46:23 +01:00
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
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 ) );
|
1998-06-25 12:19:08 +02:00
|
|
|
if( !rc )
|
2002-06-29 15:46:34 +02:00
|
|
|
rc = write_keybinding(pub_root, pub_root, sk,
|
|
|
|
get_parameter_uint (para, pSUBKEYUSAGE));
|
1998-06-25 12:19:08 +02:00
|
|
|
if( !rc )
|
2002-06-29 15:46:34 +02:00
|
|
|
rc = write_keybinding(sec_root, pub_root, sk,
|
|
|
|
get_parameter_uint (para, pSUBKEYUSAGE));
|
|
|
|
did_sub = 1;
|
1998-06-25 12:19:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
if( !rc && outctrl->use_files ) { /* direct write to specified files */
|
|
|
|
rc = write_keyblock( outctrl->pub.stream, pub_root );
|
|
|
|
if( rc )
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error("can't write public key: %s\n", g10_errstr(rc) );
|
2000-07-14 19:34:53 +02:00
|
|
|
if( !rc ) {
|
|
|
|
rc = write_keyblock( outctrl->sec.stream, sec_root );
|
|
|
|
if( rc )
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error("can't write secret key: %s\n", g10_errstr(rc) );
|
2000-07-14 19:34:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else if( !rc ) { /* write to the standard keyrings */
|
2002-06-29 15:46:34 +02:00
|
|
|
KEYDB_HANDLE pub_hd = keydb_new (0);
|
|
|
|
KEYDB_HANDLE sec_hd = keydb_new (1);
|
|
|
|
|
|
|
|
/* FIXME: we may have to create the keyring first */
|
|
|
|
rc = keydb_locate_writable (pub_hd, NULL);
|
|
|
|
if (rc)
|
|
|
|
log_error (_("no writable public keyring found: %s\n"),
|
|
|
|
g10_errstr (rc));
|
|
|
|
|
|
|
|
if (!rc) {
|
|
|
|
rc = keydb_locate_writable (sec_hd, NULL);
|
|
|
|
if (rc)
|
|
|
|
log_error (_("no writable secret keyring found: %s\n"),
|
|
|
|
g10_errstr (rc));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rc && opt.verbose) {
|
|
|
|
log_info(_("writing public key to `%s'\n"),
|
|
|
|
keydb_get_resource_name (pub_hd));
|
|
|
|
log_info(_("writing secret key to `%s'\n"),
|
|
|
|
keydb_get_resource_name (sec_hd));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rc) {
|
|
|
|
rc = keydb_insert_keyblock (pub_hd, pub_root);
|
|
|
|
if (rc)
|
|
|
|
log_error (_("error writing public keyring `%s': %s\n"),
|
|
|
|
keydb_get_resource_name (pub_hd), g10_errstr(rc));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rc) {
|
|
|
|
rc = keydb_insert_keyblock (sec_hd, sec_root);
|
|
|
|
if (rc)
|
|
|
|
log_error (_("error writing secret keyring `%s': %s\n"),
|
|
|
|
keydb_get_resource_name (pub_hd), g10_errstr(rc));
|
|
|
|
}
|
|
|
|
|
|
|
|
keydb_release (pub_hd);
|
|
|
|
keydb_release (sec_hd);
|
|
|
|
|
|
|
|
if (!rc) {
|
|
|
|
int no_enc_rsa =
|
|
|
|
get_parameter_algo(para, pKEYTYPE) == PUBKEY_ALGO_RSA
|
|
|
|
&& get_parameter_uint( para, pKEYUSAGE )
|
|
|
|
&& !(get_parameter_uint( para,pKEYUSAGE) & PUBKEY_USAGE_ENC);
|
|
|
|
PKT_public_key *pk = find_kbnode (pub_root,
|
|
|
|
PKT_PUBLIC_KEY)->pkt->pkt.public_key;
|
|
|
|
|
|
|
|
update_ownertrust (pk,
|
|
|
|
((get_ownertrust (pk) & ~TRUST_MASK)
|
|
|
|
| TRUST_ULTIMATE ));
|
|
|
|
|
|
|
|
if (!opt.batch) {
|
|
|
|
tty_printf(_("public and secret key created and signed.\n") );
|
|
|
|
tty_printf(_("key marked as ultimately trusted.\n") );
|
|
|
|
tty_printf("\n");
|
|
|
|
list_keyblock(pub_root,0,1,NULL);
|
|
|
|
}
|
|
|
|
|
1997-12-16 20:15:09 +01:00
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
if( !opt.batch
|
2002-06-29 15:46:34 +02:00
|
|
|
&& ( get_parameter_algo( para, pKEYTYPE ) == PUBKEY_ALGO_DSA
|
|
|
|
|| no_enc_rsa )
|
2000-07-14 19:34:53 +02:00
|
|
|
&& !get_parameter( para, pSUBKEYTYPE ) )
|
|
|
|
{
|
1998-05-26 15:38:00 +02:00
|
|
|
tty_printf(_("Note that this key cannot be used for "
|
|
|
|
"encryption. You may want to use\n"
|
1999-01-19 19:37:41 +01:00
|
|
|
"the command \"--edit-key\" to generate a "
|
1998-05-26 15:38:00 +02:00
|
|
|
"secondary key for this purpose.\n") );
|
2000-07-14 19:34:53 +02:00
|
|
|
}
|
1997-12-16 20:15:09 +01:00
|
|
|
}
|
1997-12-09 13:46:23 +01:00
|
|
|
}
|
1997-12-16 20:15:09 +01:00
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
if( rc ) {
|
|
|
|
if( opt.batch )
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error("key generation failed: %s\n", g10_errstr(rc) );
|
2000-07-14 19:34:53 +02:00
|
|
|
else
|
2002-06-29 15:46:34 +02:00
|
|
|
tty_printf(_("Key generation failed: %s\n"), g10_errstr(rc) );
|
|
|
|
}
|
|
|
|
else {
|
2002-10-12 13:47:40 +02:00
|
|
|
PKT_public_key *pk = find_kbnode (pub_root,
|
|
|
|
PKT_PUBLIC_KEY)->pkt->pkt.public_key;
|
|
|
|
print_status_key_created (did_sub? 'B':'P', pk);
|
2000-07-14 19:34:53 +02:00
|
|
|
}
|
1997-12-16 20:15:09 +01:00
|
|
|
release_kbnode( pub_root );
|
|
|
|
release_kbnode( sec_root );
|
1998-06-29 14:30:57 +02:00
|
|
|
if( sk ) /* the unprotected secret key */
|
|
|
|
free_secret_key(sk);
|
1997-11-18 15:06:00 +01:00
|
|
|
}
|
|
|
|
|
1998-05-05 22:34:20 +02:00
|
|
|
|
|
|
|
/****************
|
|
|
|
* add a new subkey to an existing key.
|
1998-07-29 21:35:05 +02:00
|
|
|
* Returns true if a new key has been generated and put into the keyblocks.
|
1998-05-05 22:34:20 +02:00
|
|
|
*/
|
1998-07-29 21:35:05 +02:00
|
|
|
int
|
|
|
|
generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
|
1998-05-05 22:34:20 +02:00
|
|
|
{
|
1998-07-29 21:35:05 +02:00
|
|
|
int okay=0, rc=0;
|
1998-05-26 15:38:00 +02:00
|
|
|
KBNODE node;
|
1998-06-29 14:30:57 +02:00
|
|
|
PKT_secret_key *sk = NULL; /* this is the primary sk */
|
2000-07-14 19:34:53 +02:00
|
|
|
int algo;
|
2002-06-29 15:46:34 +02:00
|
|
|
unsigned int use;
|
1998-11-20 18:42:18 +01:00
|
|
|
u32 expire;
|
1998-05-26 15:38:00 +02:00
|
|
|
unsigned nbits;
|
|
|
|
char *passphrase = NULL;
|
|
|
|
DEK *dek = NULL;
|
|
|
|
STRING2KEY *s2k = NULL;
|
1999-01-12 11:20:24 +01:00
|
|
|
u32 cur_time;
|
1998-05-26 15:38:00 +02:00
|
|
|
|
1998-07-29 21:35:05 +02:00
|
|
|
/* break out the primary secret key */
|
1998-06-29 14:30:57 +02:00
|
|
|
node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
|
1998-05-26 15:38:00 +02:00
|
|
|
if( !node ) {
|
|
|
|
log_error("Oops; secret key not found anymore!\n");
|
|
|
|
goto leave;
|
|
|
|
}
|
|
|
|
|
1998-06-29 14:30:57 +02:00
|
|
|
/* make a copy of the sk to keep the protected one in the keyblock */
|
|
|
|
sk = copy_secret_key( NULL, node->pkt->pkt.secret_key );
|
1999-01-12 11:20:24 +01:00
|
|
|
|
|
|
|
cur_time = make_timestamp();
|
|
|
|
if( sk->timestamp > cur_time ) {
|
|
|
|
ulong d = sk->timestamp - cur_time;
|
|
|
|
log_info( d==1 ? _("key has been created %lu second "
|
|
|
|
"in future (time warp or clock problem)\n")
|
|
|
|
: _("key has been created %lu seconds "
|
|
|
|
"in future (time warp or clock problem)\n"), d );
|
2000-07-14 19:34:53 +02:00
|
|
|
if( !opt.ignore_time_conflict ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
rc = G10ERR_TIME_CONFLICT;
|
2000-07-14 19:34:53 +02:00
|
|
|
goto leave;
|
|
|
|
}
|
1999-01-12 11:20:24 +01:00
|
|
|
}
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
if (sk->version < 4) {
|
|
|
|
log_info (_("NOTE: creating subkeys for v3 keys "
|
|
|
|
"is not OpenPGP compliant\n"));
|
|
|
|
goto leave;
|
|
|
|
}
|
1999-01-12 11:20:24 +01:00
|
|
|
|
1998-05-26 15:38:00 +02:00
|
|
|
/* unprotect to get the passphrase */
|
1998-06-29 14:30:57 +02:00
|
|
|
switch( is_secret_key_protected( sk ) ) {
|
1998-05-26 15:38:00 +02:00
|
|
|
case -1:
|
2002-06-29 15:46:34 +02:00
|
|
|
rc = G10ERR_PUBKEY_ALGO;
|
1998-05-26 15:38:00 +02:00
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
tty_printf("This key is not protected.\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tty_printf("Key is protected.\n");
|
1998-09-11 07:47:32 +02:00
|
|
|
rc = check_secret_key( sk, 0 );
|
1998-05-26 15:38:00 +02:00
|
|
|
if( !rc )
|
|
|
|
passphrase = get_last_passphrase();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( rc )
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
2002-06-29 15:46:34 +02:00
|
|
|
algo = ask_algo( 1, &use );
|
1998-06-25 12:19:08 +02:00
|
|
|
assert(algo);
|
1998-05-26 15:38:00 +02:00
|
|
|
nbits = ask_keysize( algo );
|
2002-06-29 15:46:34 +02:00
|
|
|
expire = ask_expire_interval(0);
|
1998-11-27 12:42:49 +01:00
|
|
|
if( !cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
|
1998-08-08 21:27:00 +02:00
|
|
|
_("Really create? ") ) )
|
1998-07-29 21:35:05 +02:00
|
|
|
goto leave;
|
1998-05-26 15:38:00 +02:00
|
|
|
|
|
|
|
if( passphrase ) {
|
2002-06-29 15:46:34 +02:00
|
|
|
s2k = m_alloc_secure( sizeof *s2k );
|
1998-09-28 21:25:31 +02:00
|
|
|
s2k->mode = opt.s2k_mode;
|
|
|
|
s2k->hash_algo = opt.s2k_digest_algo;
|
1998-05-26 15:38:00 +02:00
|
|
|
set_next_passphrase( passphrase );
|
2003-04-10 11:56:47 +02:00
|
|
|
dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2,
|
|
|
|
NULL, NULL );
|
1998-05-26 15:38:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = do_create( algo, nbits, pub_keyblock, sec_keyblock,
|
2000-07-14 19:34:53 +02:00
|
|
|
dek, s2k, NULL, expire );
|
1998-05-26 15:38:00 +02:00
|
|
|
if( !rc )
|
2002-06-29 15:46:34 +02:00
|
|
|
rc = write_keybinding(pub_keyblock, pub_keyblock, sk, use);
|
1998-05-26 15:38:00 +02:00
|
|
|
if( !rc )
|
2002-06-29 15:46:34 +02:00
|
|
|
rc = write_keybinding(sec_keyblock, pub_keyblock, sk, use);
|
|
|
|
if( !rc ) {
|
1998-07-29 21:35:05 +02:00
|
|
|
okay = 1;
|
2002-06-29 15:46:34 +02:00
|
|
|
write_status_text (STATUS_KEY_CREATED, "S");
|
|
|
|
}
|
1998-05-26 15:38:00 +02:00
|
|
|
|
|
|
|
leave:
|
|
|
|
if( rc )
|
2002-06-29 15:46:34 +02:00
|
|
|
log_error(_("Key generation failed: %s\n"), g10_errstr(rc) );
|
|
|
|
m_free( passphrase );
|
|
|
|
m_free( dek );
|
|
|
|
m_free( s2k );
|
1998-06-29 14:30:57 +02:00
|
|
|
if( sk ) /* release the copy of the (now unprotected) secret key */
|
|
|
|
free_secret_key(sk);
|
1998-05-26 15:38:00 +02:00
|
|
|
set_next_passphrase( NULL );
|
1998-07-29 21:35:05 +02:00
|
|
|
return okay;
|
1998-05-05 22:34:20 +02:00
|
|
|
}
|
|
|
|
|
2000-07-14 19:34:53 +02:00
|
|
|
/****************
|
|
|
|
* 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",
|
2002-06-29 15:46:34 +02:00
|
|
|
node->pkt->pkttype, g10_errstr(rc) );
|
|
|
|
return G10ERR_WRITE_FILE;
|
2000-07-14 19:34:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|