diff options
Diffstat (limited to 'g10/keygen.c')
-rw-r--r-- | g10/keygen.c | 1301 |
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; } - |