aboutsummaryrefslogtreecommitdiffstats
path: root/g10/keygen.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/keygen.c')
-rw-r--r--g10/keygen.c1301
1 files changed, 902 insertions, 399 deletions
diff --git a/g10/keygen.c b/g10/keygen.c
index 1e2accd0c..b8398b88a 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -1,5 +1,5 @@
/* keygen.c - generate a key pair
- * Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -26,23 +26,31 @@
#include <errno.h>
#include <assert.h>
#include "util.h"
-#include <gcrypt.h>
#include "main.h"
#include "packet.h"
+#include "cipher.h"
#include "ttyio.h"
#include "options.h"
#include "keydb.h"
+#include "trustdb.h"
#include "status.h"
#include "i18n.h"
+#define MAX_PREFS 30
+
+
enum para_name {
pKEYTYPE,
pKEYLENGTH,
+ pKEYUSAGE,
pSUBKEYTYPE,
pSUBKEYLENGTH,
+ pSUBKEYUSAGE,
pNAMEREAL,
pNAMEEMAIL,
pNAMECOMMENT,
+ pPREFERENCES,
+ pREVOKER,
pUSERID,
pEXPIREDATE,
pKEYEXPIRE, /* in n seconds */
@@ -57,10 +65,12 @@ struct para_data_s {
int lnr;
enum para_name key;
union {
- DEK *dek;
- STRING2KEY *s2k;
- u32 expire;
- char value[1];
+ DEK *dek;
+ STRING2KEY *s2k;
+ u32 expire;
+ unsigned int usage;
+ struct revocation_key revkey;
+ char value[1];
} u;
};
@@ -83,6 +93,21 @@ struct output_control_s {
};
+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;
+static int mdc_available;
+
static void do_generate_keypair( struct para_data_s *para,
struct output_control_s *outctrl );
static int write_keyblock( IOBUF out, KBNODE node );
@@ -91,16 +116,32 @@ static int write_keyblock( IOBUF out, KBNODE node );
static void
write_uid( KBNODE root, const char *s )
{
- PACKET *pkt = gcry_xcalloc( 1,sizeof *pkt );
+ PACKET *pkt = m_alloc_clear(sizeof *pkt );
size_t n = strlen(s);
pkt->pkttype = PKT_USER_ID;
- pkt->pkt.user_id = gcry_xcalloc( 1, sizeof *pkt->pkt.user_id + n - 1 );
+ pkt->pkt.user_id = m_alloc_clear( sizeof *pkt->pkt.user_id + n - 1 );
pkt->pkt.user_id->len = n;
+ pkt->pkt.user_id->ref = 1;
strcpy(pkt->pkt.user_id->name, s);
add_kbnode( root, new_kbnode( pkt ) );
}
+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);
+}
int
@@ -123,34 +164,318 @@ keygen_add_key_expire( PKT_signature *sig, void *opaque )
return 0;
}
+static int
+keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
+{
+ struct opaque_data_usage_and_pk *oduap = opaque;
+
+ do_add_key_flags (sig, oduap->usage);
+ return keygen_add_key_expire (sig, oduap->pk);
+}
+
+static int
+set_one_pref (ulong val, int type, int (*cf)(int), byte *buf, int *nbuf)
+{
+ int i;
+
+ if (cf (val)) {
+ log_info (_("preference %c%lu is not valid\n"), type, val);
+ if(type=='S' && val==CIPHER_ALGO_IDEA)
+ idea_cipher_warn(1);
+ return -1;
+ }
+ for (i=0; i < *nbuf; i++ ) {
+ if (buf[i] == val) {
+ log_info (_("preference %c%lu duplicated\n"), type, val);
+ return -1;
+ }
+ }
+ if (*nbuf >= MAX_PREFS) {
+ log_info (_("too many `%c' preferences\n"), type);
+ return -1;
+ }
+ buf[(*nbuf)++] = val;
+ return 0;
+}
+
+
+/*
+ * Parse the supplied string and use it to set the standard preferences.
+ * The String is expected to be in a forma like the one printed by "prefs",
+ * something like: "S10 S3 H3 H2 Z2 Z1". Use NULL to set the default
+ * preferences.
+ * Returns: 0 = okay
+ */
+int
+keygen_set_std_prefs (const char *string,int personal)
+{
+ byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS];
+ int nsym=0, nhash=0, nzip=0, mdc=1; /* mdc defaults on */
+ ulong val;
+ const char *s, *s2;
+ int rc = 0;
+
+ if (!string || !ascii_strcasecmp (string, "default")) {
+ if (opt.def_preference_list)
+ string=opt.def_preference_list;
+ else if ( !check_cipher_algo(CIPHER_ALGO_IDEA) )
+ string = "S7 S3 S2 S1 H2 H3 Z2 Z1";
+ else
+ string = "S7 S3 S2 H2 H3 Z2 Z1";
+
+ /* 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
+ PGP2 anyway -dms */
+ }
+ else if (!ascii_strcasecmp (string, "none"))
+ string = "";
+
+ for (s=string; *s; s = s2) {
+ if ((*s=='s' || *s == 'S') && isdigit(s[1]) ) {
+ val = strtoul (++s, (char**)&s2, 10);
+ if (set_one_pref (val, 'S', check_cipher_algo, sym, &nsym))
+ rc = -1;
+ }
+ else if ((*s=='h' || *s == 'H') && isdigit(s[1]) ) {
+ val = strtoul (++s, (char**)&s2, 10);
+ if (set_one_pref (val, 'H', check_digest_algo, hash, &nhash))
+ rc = -1;
+ }
+ else if ((*s=='z' || *s == 'Z') && isdigit(s[1]) ) {
+ val = strtoul (++s, (char**)&s2, 10);
+ if (set_one_pref (val, 'Z', check_compress_algo, zip, &nzip))
+ rc = -1;
+ }
+ else if (ascii_strcasecmp(s,"mdc")==0) {
+ mdc=1;
+ s2=s+3;
+ }
+ else if (ascii_strcasecmp(s,"no-mdc")==0) {
+ mdc=0;
+ s2=s+6;
+ }
+ else if (isspace (*s))
+ s2 = s+1;
+ else {
+ log_info (_("invalid character in preference string\n"));
+ return -1;
+ }
+ }
+
+ if (!rc)
+ {
+ 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;
+ prefs_initialized = 1;
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+ * Return a printable list of preferences. Caller must free.
+ */
+char *
+keygen_get_std_prefs ()
+{
+ char *buf;
+ int i;
+
+ if (!prefs_initialized)
+ keygen_set_std_prefs (NULL,0);
+
+ buf = m_alloc ( MAX_PREFS*3*5 + 5 + 1);
+ *buf = 0;
+ for (i=0; i < nsym_prefs; i++ )
+ sprintf (buf+strlen(buf), "S%d ", sym_prefs[i]);
+ for (i=0; i < nhash_prefs; i++ )
+ sprintf (buf+strlen(buf), "H%d ", hash_prefs[i]);
+ for (i=0; i < nzip_prefs; i++ )
+ sprintf (buf+strlen(buf), "Z%d ", zip_prefs[i]);
+
+ if(mdc_available)
+ sprintf(buf+strlen(buf),"[mdc]");
+ else if (*buf) /* trim the trailing space */
+ buf[strlen(buf)-1] = 0;
+
+ return buf;
+}
+
+
+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);
+}
+
+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);
+
+ return 0;
+}
+
/****************
* Add preference to the self signature packet.
* This is only called for packets with version > 3.
+
*/
int
keygen_add_std_prefs( PKT_signature *sig, void *opaque )
{
+ PKT_public_key *pk = opaque;
byte buf[8];
+ do_add_key_flags (sig, pk->pubkey_usage);
keygen_add_key_expire( sig, opaque );
-
- buf[0] = GCRY_CIPHER_RIJNDAEL;
- buf[1] = GCRY_CIPHER_TWOFISH;
- buf[2] = GCRY_CIPHER_CAST5;
- buf[3] = GCRY_CIPHER_BLOWFISH;
- build_sig_subpkt( sig, SIGSUBPKT_PREF_SYM, buf, 4 );
-
- buf[0] = GCRY_MD_RMD160;
- buf[1] = GCRY_MD_SHA1;
- build_sig_subpkt( sig, SIGSUBPKT_PREF_HASH, buf, 2 );
-
- buf[0] = 2;
- buf[1] = 1;
- build_sig_subpkt( sig, SIGSUBPKT_PREF_COMPR, buf, 2 );
-
- buf[0] = 1; /* supports MDC packets (15 + 16) */
- build_sig_subpkt( sig, SIGSUBPKT_FEATURES, buf, 1 );
+ keygen_upd_std_prefs (sig, opaque);
buf[0] = 0x80; /* no modify - It is reasonable that a key holder
* has the possibility to reject signatures from users
@@ -163,10 +488,69 @@ keygen_add_std_prefs( PKT_signature *sig, void *opaque )
return 0;
}
+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);
+ /* 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;
+}
static int
-write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
+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 )
{
PACKET *pkt;
PKT_signature *sig;
@@ -188,16 +572,20 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
if( !node )
BUG();
pk = node->pkt->pkt.public_key;
+ 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);
/* and make the signature */
- rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
- keygen_add_std_prefs, pk );
+ rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0, 0, 0,
+ keygen_add_std_prefs, pk );
if( rc ) {
- log_error("make_keysig_packet failed: %s\n", gpg_errstr(rc) );
+ log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
}
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
add_kbnode( root, new_kbnode( pkt ) );
@@ -205,13 +593,15 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
}
static int
-write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
+write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk,
+ unsigned int use )
{
PACKET *pkt;
PKT_signature *sig;
int rc=0;
KBNODE node;
PKT_public_key *pk, *subpk;
+ struct opaque_data_usage_and_pk oduap;
if( opt.verbose )
log_info(_("writing key binding signature\n"));
@@ -221,6 +611,10 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
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);
+
/* find the last subkey */
subpk = NULL;
for(node=pub_root; node; node = node->next ) {
@@ -231,14 +625,16 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
BUG();
/* and make the signature */
- rc = make_keysig_packet( &sig, pk, NULL, subpk, sk, 0x18, 0,
- keygen_add_key_expire, subpk );
+ 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 );
if( rc ) {
- log_error("make_keysig_packet failed: %s\n", gpg_errstr(rc) );
+ log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
}
- pkt = gcry_xcalloc( 1, sizeof *pkt );
+ pkt = m_alloc_clear( sizeof *pkt );
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
add_kbnode( root, new_kbnode( pkt ) );
@@ -246,63 +642,17 @@ write_keybinding( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
}
-
-static int
-key_from_sexp( GCRY_MPI *array,
- GCRY_SEXP sexp, const char *topname, const char *elems )
-{
- GCRY_SEXP list, l2;
- const char *s;
- int i, idx;
-
- list = gcry_sexp_find_token( sexp, topname, 0 );
- if( !list )
- return GCRYERR_INV_OBJ;
- l2 = gcry_sexp_cadr( list );
- gcry_sexp_release ( list );
- list = l2;
- if( !list )
- return GCRYERR_NO_OBJ;
-
- idx = 0;
- for(s=elems; *s; s++, idx++ ) {
- l2 = gcry_sexp_find_token( list, s, 1 );
- if( !l2 ) {
- for(i=0; i<idx; i++) {
- gcry_free( array[i] );
- array[i] = NULL;
- }
- gcry_sexp_release ( list );
- return GCRYERR_NO_OBJ; /* required parameter not found */
- }
- array[idx] = gcry_sexp_nth_mpi( l2, 1, GCRYMPI_FMT_USG );
- gcry_sexp_release ( l2 );
- if( !array[idx] ) {
- for(i=0; i<idx; i++) {
- gcry_free( array[i] );
- array[i] = NULL;
- }
- gcry_sexp_release ( list );
- return GCRYERR_INV_OBJ; /* required parameter is invalid */
- }
- }
- gcry_sexp_release ( list );
-
- return 0;
-}
-
-
-
static int
gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
{
int rc;
+ int i;
PACKET *pkt;
PKT_secret_key *sk;
PKT_public_key *pk;
- GCRY_SEXP misc_key_info;
- GCRY_SEXP s_parms, s_key;
+ MPI skey[4];
+ MPI *factors;
assert( is_ELGAMAL(algo) );
@@ -316,46 +666,31 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
log_info(_("keysize rounded up to %u bits\n"), nbits );
}
- if ( gcry_sexp_build ( &s_parms, NULL,
- "(genkey(%s(nbits %d)))",
- algo == GCRY_PK_ELG_E ? "openpgp-elg" :
- algo == GCRY_PK_ELG ? "elg" : "x-oops" ,
- (int)nbits ) )
- BUG ();
- rc = gcry_pk_genkey( &s_key, s_parms );
- gcry_sexp_release( s_parms );
+ rc = pubkey_generate( algo, nbits, skey, &factors );
if( rc ) {
- log_error("pk_genkey failed: %s\n", gpg_errstr(rc) );
+ log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
return rc;
}
-
- sk = gcry_xcalloc( 1, sizeof *sk );
- pk = gcry_xcalloc( 1, sizeof *pk );
+ sk = m_alloc_clear( sizeof *sk );
+ pk = m_alloc_clear( sizeof *pk );
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;
-
- rc = key_from_sexp( pk->pkey, s_key, "public-key", "pgy" );
- if( rc ) {
- log_error("key_from_sexp failed: rc=%d\n", rc );
- return rc;
- }
- rc = key_from_sexp( sk->skey, s_key, "private-key", "pgyx" );
- if( rc ) {
- log_error("key_from_sexp failed: rc=%d\n", rc );
- return rc;
- }
- misc_key_info = gcry_sexp_find_token( s_key, "misc-key-info", 0 );
- gcry_sexp_release ( s_key );
-
+ 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];
sk->is_protected = 0;
sk->protect.algo = 0;
- sk->csum = checksum_mpi( sk->skey[3] );
+ sk->csum = checksum_mpi_counted_nbits( sk->skey[3] );
if( ret_sk ) /* not a subkey: return an unprotected version of the sk */
*ret_sk = copy_secret_key( NULL, sk );
@@ -364,39 +699,27 @@ gen_elg(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
sk->protect.s2k = *s2k;
rc = protect_secret_key( sk, dek );
if( rc ) {
- log_error("protect_secret_key failed: %s\n", gpg_errstr(rc) );
+ log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
free_public_key(pk);
free_secret_key(sk);
return rc;
}
}
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
pkt->pkt.public_key = pk;
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) */
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
pkt->pkt.secret_key = sk;
add_kbnode(sec_root, new_kbnode( pkt ));
- if ( misc_key_info ) {
- size_t n;
- char *buf;
-
- n = gcry_sexp_sprint ( misc_key_info, 0, NULL, 0 );
- buf = gcry_xmalloc ( n+4 );
- strcpy ( buf, "#::" );
- n = gcry_sexp_sprint ( misc_key_info, 0, buf+3, n );
- if ( n ) {
- n += 3;
- add_kbnode( sec_root, make_comment_node_from_buffer( buf, n ));
- }
- gcry_free ( buf );
- gcry_sexp_release (misc_key_info);
- }
+ for(i=0; factors[i]; i++ )
+ add_kbnode( sec_root,
+ make_mpi_comment_node("#:ELG_factor:", factors[i] ));
return 0;
}
@@ -410,11 +733,12 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
STRING2KEY *s2k, PKT_secret_key **ret_sk, u32 expireval )
{
int rc;
+ int i;
PACKET *pkt;
PKT_secret_key *sk;
PKT_public_key *pk;
- GCRY_SEXP misc_key_info;
- GCRY_SEXP s_parms, s_key;
+ MPI skey[5];
+ MPI *factors;
if( nbits > 1024 || nbits < 512 ) {
nbits = 1024;
@@ -426,44 +750,33 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
log_info(_("keysize rounded up to %u bits\n"), nbits );
}
- if ( gcry_sexp_build ( &s_parms, NULL,
- "(genkey(dsa(nbits %d)))", (int)nbits ) )
- BUG ();
-
- rc = gcry_pk_genkey( &s_key, s_parms );
- gcry_sexp_release( s_parms );
+ rc = pubkey_generate( PUBKEY_ALGO_DSA, nbits, skey, &factors );
if( rc ) {
- log_error("pk_genkey failed: %s\n", gpg_errstr(rc) );
+ log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
return rc;
}
-
- sk = gcry_xcalloc( 1, sizeof *sk );
- pk = gcry_xcalloc( 1, sizeof *pk );
+ sk = m_alloc_clear( sizeof *sk );
+ pk = m_alloc_clear( sizeof *pk );
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 = GCRY_PK_DSA;
-
- rc = key_from_sexp( pk->pkey, s_key, "public-key", "pqgy" );
- if( rc ) {
- log_error("key_from_sexp failed: rc=%d\n", rc );
- return rc;
- }
- rc = key_from_sexp( sk->skey, s_key, "private-key", "pqgyx" );
- if( rc ) {
- log_error("key_from_sexp failed: rc=%d\n", rc );
- return rc;
- }
- misc_key_info = gcry_sexp_find_token( s_key, "misc-key-info", 0 );
- gcry_sexp_release ( s_key );
-
+ 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];
sk->is_protected = 0;
sk->protect.algo = 0;
- sk->csum = checksum_mpi( sk->skey[4] );
+ sk->csum = checksum_mpi_counted_nbits( sk->skey[4] );
if( ret_sk ) /* not a subkey: return an unprotected version of the sk */
*ret_sk = copy_secret_key( NULL, sk );
@@ -472,47 +785,39 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
sk->protect.s2k = *s2k;
rc = protect_secret_key( sk, dek );
if( rc ) {
- log_error("protect_secret_key failed: %s\n", gpg_errstr(rc) );
+ log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
free_public_key(pk);
free_secret_key(sk);
- gcry_sexp_release (misc_key_info);
return rc;
}
}
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
pkt->pkt.public_key = pk;
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)
+ * p = 2 * q * f1 * f2 * ... * fn
+ * We store only f1 to f_n-1; fn can be calculated because p and q
+ * are known.
*/
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
pkt->pkt.secret_key = sk;
add_kbnode(sec_root, new_kbnode( pkt ));
- if ( misc_key_info ) {
- size_t n;
- char *buf;
-
- n = gcry_sexp_sprint ( misc_key_info, 0, NULL, 0 );
- buf = gcry_xmalloc ( n+4 );
- strcpy ( buf, "#::" );
- n = gcry_sexp_sprint ( misc_key_info, 0, buf+3, n );
- if ( n ) {
- n += 3;
- add_kbnode( sec_root, make_comment_node_from_buffer( buf, n ));
- }
- gcry_free ( buf );
- gcry_sexp_release (misc_key_info);
- }
- /* fixme: Merge this with the elg-generate function and release
- * some more stuff (memory-leak) */
+ for(i=1; factors[i]; i++ ) /* the first one is q */
+ add_kbnode( sec_root,
+ make_mpi_comment_node("#:DSA_factor:", factors[i] ));
+
return 0;
}
-#if 0
+
+/*
+ * Generate an RSA key.
+ */
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 )
@@ -521,7 +826,7 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
PACKET *pkt;
PKT_secret_key *sk;
PKT_public_key *pk;
- MPI skey[4];
+ MPI skey[6];
MPI *factors;
assert( is_RSA(algo) );
@@ -538,12 +843,12 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
rc = pubkey_generate( algo, nbits, skey, &factors );
if( rc ) {
- log_error("pubkey_generate failed: %s\n", gpg_errstr(rc) );
+ log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
return rc;
}
- sk = gcry_xcalloc( 1, sizeof *sk );
- pk = gcry_xcalloc( 1, sizeof *pk );
+ sk = m_alloc_clear( sizeof *sk );
+ pk = m_alloc_clear( sizeof *pk );
sk->timestamp = pk->timestamp = make_timestamp();
sk->version = pk->version = 4;
if( expireval ) {
@@ -573,26 +878,25 @@ gen_rsa(int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
sk->protect.s2k = *s2k;
rc = protect_secret_key( sk, dek );
if( rc ) {
- log_error("protect_secret_key failed: %s\n", gpg_errstr(rc) );
+ log_error("protect_secret_key failed: %s\n", g10_errstr(rc) );
free_public_key(pk);
free_secret_key(sk);
return rc;
}
}
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
pkt->pkt.public_key = pk;
add_kbnode(pub_root, new_kbnode( pkt ));
- pkt = gcry_xcalloc( 1,sizeof *pkt);
+ pkt = m_alloc_clear(sizeof *pkt);
pkt->pkttype = ret_sk ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
pkt->pkt.secret_key = sk;
add_kbnode(sec_root, new_kbnode( pkt ));
return 0;
}
-#endif
/****************
@@ -625,55 +929,69 @@ check_valid_days( const char *s )
/****************
* Returns: 0 to create both a DSA and a ElGamal key.
+ * and only if key flags are to be written the desired usage.
*/
static int
-ask_algo( int addmode )
+ask_algo (int addmode, unsigned int *r_usage)
{
char *answer;
int algo;
+ *r_usage = 0;
tty_printf(_("Please select what kind of key you want:\n"));
if( !addmode )
tty_printf(_(" (%d) DSA and ElGamal (default)\n"), 1 );
tty_printf( _(" (%d) DSA (sign only)\n"), 2 );
if( addmode )
tty_printf( _(" (%d) ElGamal (encrypt only)\n"), 3 );
- tty_printf( _(" (%d) ElGamal (sign and encrypt)\n"), 4 );
- #if 0
- tty_printf( _(" (%d) RSA (sign and encrypt)\n"), 5 );
- #endif
+ 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 );
for(;;) {
answer = cpr_get("keygen.algo",_("Your selection? "));
cpr_kill_prompt();
algo = *answer? atoi(answer): 1;
- gcry_free(answer);
+ m_free(answer);
if( algo == 1 && !addmode ) {
algo = 0; /* create both keys */
break;
}
- #if 0
+ else if( algo == 7 && opt.expert ) {
+ if (cpr_get_answer_is_yes ("keygen.algo.rsa_se",_(
+ "The use of this algorithm is deprecated - create anyway? "))){
+ algo = PUBKEY_ALGO_RSA;
+ *r_usage = PUBKEY_USAGE_ENC | PUBKEY_USAGE_SIG;
+ break;
+ }
+ }
+ else if( algo == 6 && addmode ) {
+ algo = PUBKEY_ALGO_RSA;
+ *r_usage = PUBKEY_USAGE_ENC;
+ break;
+ }
else if( algo == 5 ) {
- if( cpr_get_answer_is_yes("keygen.algo.rsa_se",_(
- "Do you really want to create a sign and encrypt key? "))) {
- algo = GCRY_PK_RSA;
- break;
- }
+ algo = PUBKEY_ALGO_RSA;
+ *r_usage = PUBKEY_USAGE_SIG;
+ break;
}
- #endif
- else if( algo == 4 ) {
+ else if( algo == 4 && opt.expert) {
if( cpr_get_answer_is_yes("keygen.algo.elg_se",_(
- "Do you really want to create a sign and encrypt key? "))) {
- algo = GCRY_PK_ELG;
+ "The use of this algorithm is deprecated - create anyway? "))){
+ algo = PUBKEY_ALGO_ELGAMAL;
break;
}
}
else if( algo == 3 && addmode ) {
- algo = GCRY_PK_ELG_E;
+ algo = PUBKEY_ALGO_ELGAMAL_E;
break;
}
else if( algo == 2 ) {
- algo = GCRY_PK_DSA;
+ algo = PUBKEY_ALGO_DSA;
break;
}
else
@@ -689,24 +1007,28 @@ ask_keysize( int algo )
char *answer;
unsigned nbits;
- 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"),
- gcry_pk_algo_name(algo) );
+ 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) );
+ }
+
for(;;) {
answer = cpr_get("keygen.size",
_("What keysize do you want? (1024) "));
cpr_kill_prompt();
nbits = *answer? atoi(answer): 1024;
- gcry_free(answer);
- if( algo == GCRY_PK_DSA && (nbits < 512 || nbits > 1024) )
+ m_free(answer);
+ if( algo == PUBKEY_ALGO_DSA && (nbits < 512 || nbits > 1024) )
tty_printf(_("DSA only allows keysizes from 512 to 1024\n"));
- else if( nbits < 768 )
- tty_printf(_("keysize too small; 768 is smallest value allowed.\n"));
- else if( algo == GCRY_PK_RSA && nbits < 1024 )
+ else if( algo == PUBKEY_ALGO_RSA && nbits < 1024 )
tty_printf(_("keysize too small;"
" 1024 is smallest value allowed for RSA.\n"));
+ else if( nbits < 768 )
+ tty_printf(_("keysize too small;"
+ " 768 is smallest value allowed.\n"));
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
@@ -731,16 +1053,11 @@ ask_keysize( int algo )
break;
}
}
- else if( nbits > 1536 && !cpr_enabled() && algo != GCRY_PK_RSA ) {
- if( cpr_get_answer_is_yes("keygen.size.large.okay",_(
- "Do you really need such a large keysize? ")) )
- break;
- }
else
break;
}
tty_printf(_("Requested keysize is %u bits\n"), nbits );
- if( algo == GCRY_PK_DSA && (nbits % 64) ) {
+ if( algo == PUBKEY_ALGO_DSA && (nbits % 64) ) {
nbits = ((nbits + 63) / 64) * 64;
tty_printf(_("rounded up to %u bits\n"), nbits );
}
@@ -786,20 +1103,38 @@ parse_expire_string( const char *string )
return valid_days;
}
-
-static u32
-ask_expire_interval(void)
+/* object == 0 for a key, and 1 for a sig */
+u32
+ask_expire_interval(int object)
{
char *answer;
int valid_days=0;
u32 interval = 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"));
+ 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();
+ }
+
/* Note: The elgamal subkey for DSA has no expiration date because
* it must be signed with the DSA key and this one has the expiration
* date */
@@ -808,8 +1143,11 @@ ask_expire_interval(void)
for(;;) {
u32 curtime=make_timestamp();
- gcry_free(answer);
- answer = cpr_get("keygen.valid",_("Key is valid for? (0) "));
+ 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) "));
cpr_kill_prompt();
trim_spaces(answer);
valid_days = parse_expire_string( answer );
@@ -819,14 +1157,18 @@ ask_expire_interval(void)
}
if( !valid_days ) {
- tty_printf(_("Key does not expire at all\n"));
+ tty_printf(_("%s does not expire at all\n"),
+ object==0?"Key":"Signature");
interval = 0;
}
else {
interval = valid_days * 86400L;
/* print the date when the key expires */
- tty_printf(_("Key expires at %s\n"),
+ tty_printf(_("%s expires at %s\n"),
+ object==0?"Key":"Signature",
asctimestamp((ulong)(curtime + interval) ) );
+ /* FIXME: This check yields warning on alhas:
+ write a configure check and to this check here only for 32 bit machines */
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"));
@@ -836,14 +1178,14 @@ ask_expire_interval(void)
_("Is this correct (y/n)? ")) )
break;
}
- gcry_free(answer);
+ m_free(answer);
return interval;
}
u32
ask_expiredate()
{
- u32 x = ask_expire_interval();
+ u32 x = ask_expire_interval(0);
return x? make_timestamp() + x : 0;
}
@@ -887,7 +1229,7 @@ ask_user_id( int mode )
if( !aname ) {
for(;;) {
- gcry_free(aname);
+ m_free(aname);
aname = cpr_get("keygen.name",_("Real name: "));
trim_spaces(aname);
cpr_kill_prompt();
@@ -907,7 +1249,7 @@ ask_user_id( int mode )
}
if( !amail ) {
for(;;) {
- gcry_free(amail);
+ m_free(amail);
amail = cpr_get("keygen.email",_("Email address: "));
trim_spaces(amail);
cpr_kill_prompt();
@@ -926,7 +1268,7 @@ ask_user_id( int mode )
}
if( !acomment ) {
for(;;) {
- gcry_free(acomment);
+ m_free(acomment);
acomment = cpr_get("keygen.comment",_("Comment: "));
trim_spaces(acomment);
cpr_kill_prompt();
@@ -940,8 +1282,8 @@ ask_user_id( int mode )
}
- gcry_free(uid);
- uid = p = gcry_xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10);
+ m_free(uid);
+ uid = p = m_alloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10);
p = stpcpy(p, aname );
if( *acomment )
p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")");
@@ -950,10 +1292,8 @@ ask_user_id( int mode )
/* append a warning if we do not have dev/random
* or it is switched into quick testmode */
- #if 0
if( quick_random_gen(-1) )
strcpy(p, " (INSECURE!)" );
- #endif
/* print a note in case that UTF8 mapping has to be done */
for(p=uid; *p; p++ ) {
@@ -973,12 +1313,12 @@ ask_user_id( int mode )
}
for(;;) {
- char *ansstr = _("NnCcEeOoQq");
+ const char *ansstr = _("NnCcEeOoQq");
if( strlen(ansstr) != 10 )
BUG();
if( cpr_enabled() ) {
- answer = gcry_xstrdup(ansstr+6);
+ answer = m_strdup(ansstr+6);
answer[1] = 0;
}
else {
@@ -990,15 +1330,15 @@ ask_user_id( int mode )
if( strlen(answer) > 1 )
;
else if( *answer == ansstr[0] || *answer == ansstr[1] ) {
- gcry_free(aname); aname = NULL;
+ m_free(aname); aname = NULL;
break;
}
else if( *answer == ansstr[2] || *answer == ansstr[3] ) {
- gcry_free(acomment); acomment = NULL;
+ m_free(acomment); acomment = NULL;
break;
}
else if( *answer == ansstr[4] || *answer == ansstr[5] ) {
- gcry_free(amail); amail = NULL;
+ m_free(amail); amail = NULL;
break;
}
else if( *answer == ansstr[6] || *answer == ansstr[7] ) {
@@ -1006,29 +1346,29 @@ ask_user_id( int mode )
tty_printf(_("Please correct the error first\n"));
}
else {
- gcry_free(aname); aname = NULL;
- gcry_free(acomment); acomment = NULL;
- gcry_free(amail); amail = NULL;
+ m_free(aname); aname = NULL;
+ m_free(acomment); acomment = NULL;
+ m_free(amail); amail = NULL;
break;
}
}
else if( *answer == ansstr[8] || *answer == ansstr[9] ) {
- gcry_free(aname); aname = NULL;
- gcry_free(acomment); acomment = NULL;
- gcry_free(amail); amail = NULL;
- gcry_free(uid); uid = NULL;
+ m_free(aname); aname = NULL;
+ m_free(acomment); acomment = NULL;
+ m_free(amail); amail = NULL;
+ m_free(uid); uid = NULL;
break;
}
- gcry_free(answer);
+ m_free(answer);
}
- gcry_free(answer);
+ m_free(answer);
if( !amail && !acomment && !amail )
break;
- gcry_free(uid); uid = NULL;
+ m_free(uid); uid = NULL;
}
if( uid ) {
char *p = native_to_utf8( uid );
- gcry_free( uid );
+ m_free( uid );
uid = p;
}
return uid;
@@ -1040,20 +1380,22 @@ ask_passphrase( STRING2KEY **ret_s2k )
{
DEK *dek = NULL;
STRING2KEY *s2k;
+ const char *errtext = NULL;
tty_printf(_("You need a Passphrase to protect your secret key.\n\n") );
- s2k = gcry_xmalloc_secure( sizeof *s2k );
+ s2k = m_alloc_secure( sizeof *s2k );
for(;;) {
s2k->mode = opt.s2k_mode;
s2k->hash_algo = opt.s2k_digest_algo;
- dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 );
+ dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k,2,errtext);
if( !dek ) {
- tty_printf(_("passphrase not correctly repeated; try again.\n"));
+ errtext = _("passphrase not correctly repeated; try again");
+ tty_printf(_("%s.\n"), errtext);
}
else if( !dek->keylen ) {
- gcry_free(dek); dek = NULL;
- gcry_free(s2k); s2k = NULL;
+ m_free(dek); dek = NULL;
+ m_free(s2k); s2k = NULL;
tty_printf(_(
"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"
@@ -1069,7 +1411,7 @@ ask_passphrase( STRING2KEY **ret_s2k )
static int
-do_create( int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root,
+do_create( int algo, unsigned int nbits, KBNODE pub_root, KBNODE sec_root,
DEK *dek, STRING2KEY *s2k, PKT_secret_key **sk, u32 expiredate )
{
int rc=0;
@@ -1081,14 +1423,12 @@ do_create( int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root,
"disks) during the prime generation; this gives the random number\n"
"generator a better chance to gain enough entropy.\n") );
- if( algo == GCRY_PK_ELG || algo == GCRY_PK_ELG_E )
+ if( algo == PUBKEY_ALGO_ELGAMAL || algo == PUBKEY_ALGO_ELGAMAL_E )
rc = gen_elg(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
- else if( algo == GCRY_PK_DSA )
+ else if( algo == PUBKEY_ALGO_DSA )
rc = gen_dsa(nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
- #if 0
- else if( algo == GCRY_PK_RSA )
+ else if( algo == PUBKEY_ALGO_RSA )
rc = gen_rsa(algo, nbits, pub_root, sec_root, dek, s2k, sk, expiredate);
- #endif
else
BUG();
@@ -1120,9 +1460,10 @@ generate_user_id()
if( !p )
return NULL;
n = strlen(p);
- uid = gcry_xcalloc( 1, sizeof *uid + n - 1 );
+ uid = m_alloc_clear( sizeof *uid + n - 1 );
uid->len = n;
strcpy(uid->name, p);
+ uid->ref = 1;
return uid;
}
@@ -1135,11 +1476,11 @@ release_parameter_list( struct para_data_s *r )
for( ; r ; r = r2 ) {
r2 = r->next;
if( r->key == pPASSPHRASE_DEK )
- gcry_free( r->u.dek );
+ m_free( r->u.dek );
else if( r->key == pPASSPHRASE_S2K )
- gcry_free( r->u.s2k );
+ m_free( r->u.s2k );
- gcry_free(r);
+ m_free(r);
}
}
@@ -1163,12 +1504,102 @@ get_parameter_value( struct para_data_s *para, enum para_name key )
static int
get_parameter_algo( struct para_data_s *para, enum para_name key )
{
+ int i;
struct para_data_s *r = get_parameter( para, key );
if( !r )
return -1;
if( isdigit( *r->u.value ) )
- return atoi( r->u.value );
- return gcry_pk_map_name( r->u.value );
+ 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 */
}
@@ -1181,6 +1612,8 @@ get_parameter_u32( struct para_data_s *para, enum para_name key )
return 0;
if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE )
return r->u.expire;
+ if( r->key == pKEYUSAGE || r->key == pSUBKEYUSAGE )
+ return r->u.usage;
return (unsigned int)strtoul( r->u.value, NULL, 10 );
}
@@ -1205,10 +1638,16 @@ get_parameter_s2k( struct para_data_s *para, enum para_name key )
return r? r->u.s2k : NULL;
}
+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;
+}
static int
proc_parameter_file( struct para_data_s *para, const char *fname,
- struct output_control_s *outctrl )
+ struct output_control_s *outctrl )
{
struct para_data_s *r;
const char *s1, *s2, *s3;
@@ -1219,18 +1658,24 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
/* check that we have all required parameters */
assert( get_parameter( para, pKEYTYPE ) );
i = get_parameter_algo( para, pKEYTYPE );
- if( i < 1 || openpgp_pk_test_algo( i, GCRY_PK_USAGE_SIGN ) ) {
+ if( i < 1 || check_pubkey_algo2( i, PUBKEY_USAGE_SIG ) ) {
r = get_parameter( para, pKEYTYPE );
log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
return -1;
}
+ if (parse_parameter_usage (fname, para, pKEYUSAGE))
+ return -1;
+
i = get_parameter_algo( para, pSUBKEYTYPE );
- if( i > 1 && openpgp_pk_test_algo( i, 0 ) ) {
+ if( i > 0 && check_pubkey_algo( i ) ) {
r = get_parameter( para, pSUBKEYTYPE );
log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
return -1;
}
+ if (i > 0 && parse_parameter_usage (fname, para, pSUBKEYUSAGE))
+ return -1;
+
if( !get_parameter_value( para, pUSERID ) ) {
/* create the formatted user ID */
@@ -1239,7 +1684,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
s3 = get_parameter_value( para, pNAMEEMAIL );
if( s1 || s2 || s3 ) {
n = (s1?strlen(s1):0) + (s2?strlen(s2):0) + (s3?strlen(s3):0);
- r = gcry_xcalloc( 1, sizeof *r + n + 20 );
+ r = m_alloc_clear( sizeof *r + n + 20 );
r->key = pUSERID;
p = r->u.value;
if( s1 )
@@ -1253,6 +1698,13 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
}
}
+ /* 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;
+
/* make DEK and S2K from the Passphrase */
r = get_parameter( para, pPASSPHRASE );
if( r && *r->u.value ) {
@@ -1262,21 +1714,21 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
STRING2KEY *s2k;
DEK *dek;
- s2k = gcry_xmalloc_secure( sizeof *s2k );
+ s2k = m_alloc_secure( sizeof *s2k );
s2k->mode = opt.s2k_mode;
s2k->hash_algo = opt.s2k_digest_algo;
set_next_passphrase( r->u.value );
- dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 );
+ dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2, NULL );
set_next_passphrase( NULL );
assert( dek );
memset( r->u.value, 0, strlen(r->u.value) );
- r = gcry_xcalloc( 1, sizeof *r );
+ r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_S2K;
r->u.s2k = s2k;
r->next = para;
para = r;
- r = gcry_xcalloc( 1, sizeof *r );
+ r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_DEK;
r->u.dek = dek;
r->next = para;
@@ -1294,7 +1746,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
r->u.expire = i * 86400L;
r->key = pKEYEXPIRE; /* change hat entry */
/* also set it for the subkey */
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pSUBKEYEXPIRE;
r->u.expire = i * 86400L;
r->next = para;
@@ -1324,13 +1776,17 @@ read_parameter_file( const char *fname )
} keywords[] = {
{ "Key-Type", pKEYTYPE},
{ "Key-Length", pKEYLENGTH },
+ { "Key-Usage", pKEYUSAGE },
{ "Subkey-Type", pSUBKEYTYPE },
{ "Subkey-Length", pSUBKEYLENGTH },
+ { "Subkey-Usage", pSUBKEYUSAGE },
{ "Name-Real", pNAMEREAL },
{ "Name-Email", pNAMEEMAIL },
{ "Name-Comment", pNAMECOMMENT },
{ "Expire-Date", pEXPIREDATE },
{ "Passphrase", pPASSPHRASE },
+ { "Preferences", pPREFERENCES },
+ { "Revoker", pREVOKER },
{ NULL, 0 }
};
FILE *fp;
@@ -1366,45 +1822,45 @@ read_parameter_file( const char *fname )
err = "line too long";
break;
}
- for( p = line; isspace(*p); p++ )
+ for( p = line; isspace(*(byte*)p); p++ )
;
if( !*p || *p == '#' )
continue;
keyword = p;
if( *keyword == '%' ) {
- for( ; !isspace(*p); p++ )
+ for( ; !isspace(*(byte*)p); p++ )
;
if( *p )
*p++ = 0;
- for( ; isspace(*p); p++ )
+ for( ; isspace(*(byte*)p); p++ )
;
value = p;
trim_trailing_ws( value, strlen(value) );
- if( !stricmp( keyword, "%echo" ) )
+ if( !ascii_strcasecmp( keyword, "%echo" ) )
log_info("%s\n", value );
- else if( !stricmp( keyword, "%dry-run" ) )
+ else if( !ascii_strcasecmp( keyword, "%dry-run" ) )
outctrl.dryrun = 1;
- else if( !stricmp( keyword, "%commit" ) ) {
+ else if( !ascii_strcasecmp( keyword, "%commit" ) ) {
outctrl.lnr = lnr;
proc_parameter_file( para, fname, &outctrl );
release_parameter_list( para );
para = NULL;
}
- else if( !stricmp( keyword, "%pubring" ) ) {
+ else if( !ascii_strcasecmp( keyword, "%pubring" ) ) {
if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) )
; /* still the same file - ignore it */
else {
- gcry_free( outctrl.pub.newfname );
- outctrl.pub.newfname = gcry_xstrdup( value );
+ m_free( outctrl.pub.newfname );
+ outctrl.pub.newfname = m_strdup( value );
outctrl.use_files = 1;
}
}
- else if( !stricmp( keyword, "%secring" ) ) {
+ else if( !ascii_strcasecmp( keyword, "%secring" ) ) {
if( outctrl.sec.fname && !strcmp( outctrl.sec.fname, value ) )
; /* still the same file - ignore it */
else {
- gcry_free( outctrl.sec.newfname );
- outctrl.sec.newfname = gcry_xstrdup( value );
+ m_free( outctrl.sec.newfname );
+ outctrl.sec.newfname = m_strdup( value );
outctrl.use_files = 1;
}
}
@@ -1422,7 +1878,7 @@ read_parameter_file( const char *fname )
}
if( *p )
*p++ = 0;
- for( ; isspace(*p); p++ )
+ for( ; isspace(*(byte*)p); p++ )
;
if( !*p ) {
err = "missing argument";
@@ -1432,7 +1888,7 @@ read_parameter_file( const char *fname )
trim_trailing_ws( value, strlen(value) );
for(i=0; keywords[i].name; i++ ) {
- if( !stricmp( keywords[i].name, keyword ) )
+ if( !ascii_strcasecmp( keywords[i].name, keyword ) )
break;
}
if( !keywords[i].name ) {
@@ -1460,7 +1916,7 @@ read_parameter_file( const char *fname )
break;
}
}
- r = gcry_xcalloc( 1, sizeof *r + strlen( value ) );
+ r = m_alloc_clear( sizeof *r + strlen( value ) );
r->lnr = lnr;
r->key = keywords[i].key;
strcpy( r->u.value, value );
@@ -1480,10 +1936,10 @@ read_parameter_file( const char *fname )
if( outctrl.use_files ) { /* close open streams */
iobuf_close( outctrl.pub.stream );
iobuf_close( outctrl.sec.stream );
- gcry_free( outctrl.pub.fname );
- gcry_free( outctrl.pub.newfname );
- gcry_free( outctrl.sec.fname );
- gcry_free( outctrl.sec.newfname );
+ m_free( outctrl.pub.fname );
+ m_free( outctrl.pub.newfname );
+ m_free( outctrl.sec.fname );
+ m_free( outctrl.sec.newfname );
}
release_parameter_list( para );
@@ -1504,6 +1960,7 @@ generate_keypair( const char *fname )
DEK *dek;
STRING2KEY *s2k;
int algo;
+ unsigned int use;
int both = 0;
u32 expire;
struct para_data_s *para = NULL;
@@ -1517,50 +1974,61 @@ generate_keypair( const char *fname )
return;
}
- algo = ask_algo( 0 );
+ algo = ask_algo( 0, &use );
if( !algo ) { /* default: DSA with ElG subkey of the specified size */
both = 1;
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
- sprintf( r->u.value, "%d", GCRY_PK_DSA );
+ sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
r->next = para;
para = r;
tty_printf(_("DSA keypair will have 1024 bits.\n"));
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYLENGTH;
strcpy( r->u.value, "1024" );
r->next = para;
para = r;
- algo = GCRY_PK_ELG_E;
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ algo = PUBKEY_ALGO_ELGAMAL_E;
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pSUBKEYTYPE;
sprintf( r->u.value, "%d", algo );
r->next = para;
para = r;
}
else {
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYTYPE;
sprintf( r->u.value, "%d", algo );
r->next = para;
para = r;
+
+ 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;
+ }
+
}
nbits = ask_keysize( algo );
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
sprintf( r->u.value, "%u", nbits);
r->next = para;
para = r;
- expire = ask_expire_interval();
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ expire = ask_expire_interval(0);
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYEXPIRE;
r->u.expire = expire;
r->next = para;
para = r;
- r = gcry_xcalloc( 1, sizeof *r + 20 );
+ r = m_alloc_clear( sizeof *r + 20 );
r->key = pSUBKEYEXPIRE;
r->u.expire = expire;
r->next = para;
@@ -1572,7 +2040,7 @@ generate_keypair( const char *fname )
release_parameter_list( para );
return;
}
- r = gcry_xcalloc( 1, sizeof *r + strlen(uid) );
+ r = m_alloc_clear( sizeof *r + strlen(uid) );
r->key = pUSERID;
strcpy( r->u.value, uid );
r->next = para;
@@ -1580,12 +2048,12 @@ generate_keypair( const char *fname )
dek = ask_passphrase( &s2k );
if( dek ) {
- r = gcry_xcalloc( 1, sizeof *r );
+ r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_DEK;
r->u.dek = dek;
r->next = para;
para = r;
- r = gcry_xcalloc( 1, sizeof *r );
+ r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_S2K;
r->u.s2k = s2k;
r->next = para;
@@ -1601,13 +2069,13 @@ static void
do_generate_keypair( struct para_data_s *para,
struct output_control_s *outctrl )
{
- char *pub_fname = NULL;
- char *sec_fname = NULL;
KBNODE pub_root = NULL;
KBNODE sec_root = NULL;
PKT_secret_key *sk = NULL;
const char *s;
+ struct revocation_key *revkey;
int rc;
+ int did_sub = 0;
if( outctrl->dryrun ) {
log_info("dry-run mode - key generation skipped\n");
@@ -1619,7 +2087,7 @@ do_generate_keypair( struct para_data_s *para,
if( outctrl->pub.newfname ) {
iobuf_close(outctrl->pub.stream);
outctrl->pub.stream = NULL;
- gcry_free( outctrl->pub.fname );
+ m_free( outctrl->pub.fname );
outctrl->pub.fname = outctrl->pub.newfname;
outctrl->pub.newfname = NULL;
@@ -1638,7 +2106,7 @@ do_generate_keypair( struct para_data_s *para,
if( outctrl->sec.newfname ) {
iobuf_close(outctrl->sec.stream);
outctrl->sec.stream = NULL;
- gcry_free( outctrl->sec.fname );
+ m_free( outctrl->sec.fname );
outctrl->sec.fname = outctrl->sec.newfname;
outctrl->sec.newfname = NULL;
@@ -1654,20 +2122,14 @@ do_generate_keypair( struct para_data_s *para,
&outctrl->sec.afx );
}
}
- pub_fname = outctrl->pub.fname; /* only for info output */
- sec_fname = outctrl->sec.fname; /* only for info output */
assert( outctrl->pub.stream );
assert( outctrl->sec.stream );
- }
- else {
- pub_fname = get_writable_keyblock_file( 0 );
- sec_fname = get_writable_keyblock_file( 1 );
+ 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 );
+ }
}
- if( opt.verbose ) {
- log_info(_("writing public key to `%s'\n"), pub_fname );
- log_info(_("writing secret key to `%s'\n"), sec_fname );
- }
/* we create the packets as a tree of kbnodes. Because the structure
* we create is known in advance we simply generate a linked list
@@ -1684,14 +2146,24 @@ do_generate_keypair( struct para_data_s *para,
get_parameter_s2k( para, pPASSPHRASE_S2K ),
&sk,
get_parameter_u32( para, pKEYEXPIRE ) );
+
+ 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);
+ }
+
if( !rc && (s=get_parameter_value(para, pUSERID)) ) {
write_uid(pub_root, s );
if( !rc )
write_uid(sec_root, s );
if( !rc )
- rc = write_selfsig(pub_root, pub_root, sk);
+ rc = write_selfsig(pub_root, pub_root, sk,
+ get_parameter_uint (para, pKEYUSAGE));
if( !rc )
- rc = write_selfsig(sec_root, pub_root, sk);
+ rc = write_selfsig(sec_root, pub_root, sk,
+ get_parameter_uint (para, pKEYUSAGE));
}
if( get_parameter( para, pSUBKEYTYPE ) ) {
@@ -1703,64 +2175,90 @@ do_generate_keypair( struct para_data_s *para,
NULL,
get_parameter_u32( para, pSUBKEYEXPIRE ) );
if( !rc )
- rc = write_keybinding(pub_root, pub_root, sk);
+ rc = write_keybinding(pub_root, pub_root, sk,
+ get_parameter_uint (para, pSUBKEYUSAGE));
if( !rc )
- rc = write_keybinding(sec_root, pub_root, sk);
+ rc = write_keybinding(sec_root, pub_root, sk,
+ get_parameter_uint (para, pSUBKEYUSAGE));
+ did_sub = 1;
}
if( !rc && outctrl->use_files ) { /* direct write to specified files */
rc = write_keyblock( outctrl->pub.stream, pub_root );
if( rc )
- log_error("can't write public key: %s\n", gpg_errstr(rc) );
+ log_error("can't write public key: %s\n", g10_errstr(rc) );
if( !rc ) {
rc = write_keyblock( outctrl->sec.stream, sec_root );
if( rc )
- log_error("can't write secret key: %s\n", gpg_errstr(rc) );
+ log_error("can't write secret key: %s\n", g10_errstr(rc) );
}
}
else if( !rc ) { /* write to the standard keyrings */
- KBPOS pub_kbpos;
- KBPOS sec_kbpos;
- int rc1 = -1;
- int rc2 = -1;
-
- /* we can now write the certificates */
- if( get_keyblock_handle( pub_fname, 0, &pub_kbpos ) ) {
- if( add_keyblock_resource( pub_fname, 1, 0 ) ) {
- log_error("can add keyblock file `%s'\n", pub_fname );
- rc = GPGERR_CREATE_FILE;
- }
- else if( get_keyblock_handle( pub_fname, 0, &pub_kbpos ) ) {
- log_error("can get keyblock handle for `%s'\n", pub_fname );
- rc = GPGERR_CREATE_FILE;
- }
- }
- if( rc )
- ;
- else if( get_keyblock_handle( sec_fname, 1, &sec_kbpos ) ) {
- if( add_keyblock_resource( sec_fname, 1, 1 ) ) {
- log_error("can add keyblock file `%s'\n", sec_fname );
- rc = GPGERR_CREATE_FILE;
- }
- else if( get_keyblock_handle( sec_fname, 1, &sec_kbpos ) ) {
- log_error("can get keyblock handle for `%s'\n", sec_fname );
- rc = GPGERR_CREATE_FILE;
- }
- }
+ 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);
+ }
+
- if( rc )
- ;
- else if( (rc=insert_keyblock( pub_root )) )
- log_error("can't write public key: %s\n", gpg_errstr(rc) );
- else if( (rc=insert_keyblock( sec_root )) )
- log_error("can't write secret key: %s\n", gpg_errstr(rc) );
- else {
- if( !opt.batch )
- tty_printf(_("public and secret key created and signed.\n") );
if( !opt.batch
- && get_parameter_algo( para, pKEYTYPE ) == GCRY_PK_DSA
+ && ( get_parameter_algo( para, pKEYTYPE ) == PUBKEY_ALGO_DSA
+ || no_enc_rsa )
&& !get_parameter( para, pSUBKEYTYPE ) )
{
tty_printf(_("Note that this key cannot be used for "
@@ -1769,23 +2267,21 @@ do_generate_keypair( struct para_data_s *para,
"secondary key for this purpose.\n") );
}
}
-
}
if( rc ) {
if( opt.batch )
- log_error("key generation failed: %s\n", gpg_errstr(rc) );
+ log_error("key generation failed: %s\n", g10_errstr(rc) );
else
- tty_printf(_("Key generation failed: %s\n"), gpg_errstr(rc) );
+ tty_printf(_("Key generation failed: %s\n"), g10_errstr(rc) );
+ }
+ else {
+ write_status_text (STATUS_KEY_CREATED, did_sub? "B":"P");
}
release_kbnode( pub_root );
release_kbnode( sec_root );
if( sk ) /* the unprotected secret key */
free_secret_key(sk);
- if( !outctrl->use_files ) {
- gcry_free(pub_fname);
- gcry_free(sec_fname);
- }
}
@@ -1800,6 +2296,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
KBNODE node;
PKT_secret_key *sk = NULL; /* this is the primary sk */
int algo;
+ unsigned int use;
u32 expire;
unsigned nbits;
char *passphrase = NULL;
@@ -1825,16 +2322,21 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
: _("key has been created %lu seconds "
"in future (time warp or clock problem)\n"), d );
if( !opt.ignore_time_conflict ) {
- rc = GPGERR_TIME_CONFLICT;
+ rc = G10ERR_TIME_CONFLICT;
goto leave;
}
}
+ if (sk->version < 4) {
+ log_info (_("NOTE: creating subkeys for v3 keys "
+ "is not OpenPGP compliant\n"));
+ goto leave;
+ }
/* unprotect to get the passphrase */
switch( is_secret_key_protected( sk ) ) {
case -1:
- rc = GPGERR_PUBKEY_ALGO;
+ rc = G10ERR_PUBKEY_ALGO;
break;
case 0:
tty_printf("This key is not protected.\n");
@@ -1850,37 +2352,39 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
goto leave;
- algo = ask_algo( 1 );
+ algo = ask_algo( 1, &use );
assert(algo);
nbits = ask_keysize( algo );
- expire = ask_expire_interval();
+ expire = ask_expire_interval(0);
if( !cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay",
_("Really create? ") ) )
goto leave;
if( passphrase ) {
- s2k = gcry_xmalloc_secure( sizeof *s2k );
+ s2k = m_alloc_secure( sizeof *s2k );
s2k->mode = opt.s2k_mode;
s2k->hash_algo = opt.s2k_digest_algo;
set_next_passphrase( passphrase );
- dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2 );
+ dek = passphrase_to_dek( NULL, 0, opt.s2k_cipher_algo, s2k, 2, NULL );
}
rc = do_create( algo, nbits, pub_keyblock, sec_keyblock,
dek, s2k, NULL, expire );
if( !rc )
- rc = write_keybinding(pub_keyblock, pub_keyblock, sk);
- if( !rc )
- rc = write_keybinding(sec_keyblock, pub_keyblock, sk);
+ rc = write_keybinding(pub_keyblock, pub_keyblock, sk, use);
if( !rc )
+ rc = write_keybinding(sec_keyblock, pub_keyblock, sk, use);
+ if( !rc ) {
okay = 1;
+ write_status_text (STATUS_KEY_CREATED, "S");
+ }
leave:
if( rc )
- log_error(_("Key generation failed: %s\n"), gpg_errstr(rc) );
- gcry_free( passphrase );
- gcry_free( dek );
- gcry_free( s2k );
+ log_error(_("Key generation failed: %s\n"), g10_errstr(rc) );
+ m_free( passphrase );
+ m_free( dek );
+ m_free( s2k );
if( sk ) /* release the copy of the (now unprotected) secret key */
free_secret_key(sk);
set_next_passphrase( NULL );
@@ -1897,10 +2401,9 @@ write_keyblock( IOBUF out, KBNODE node )
int rc = build_packet( out, node->pkt );
if( rc ) {
log_error("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, gpg_errstr(rc) );
- return GPGERR_WRITE_FILE;
+ node->pkt->pkttype, g10_errstr(rc) );
+ return G10ERR_WRITE_FILE;
}
}
return 0;
}
-