diff --git a/g10/keygen.c.~HEAD~ b/g10/keygen.c.~HEAD~ deleted file mode 100644 index a1f449e15..000000000 --- a/g10/keygen.c.~HEAD~ +++ /dev/null @@ -1,4835 +0,0 @@ -/* keygen.c - Generate a key pair - * Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc. - * Copyright (C) 2014, 2015 Werner Koch - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gpg.h" -#include "util.h" -#include "main.h" -#include "packet.h" -#include "ttyio.h" -#include "options.h" -#include "keydb.h" -#include "trustdb.h" -#include "status.h" -#include "i18n.h" -#include "keyserver-internal.h" -#include "call-agent.h" -#include "pkglue.h" -#include "../common/shareddefs.h" -#include "host2net.h" -#include "mbox-util.h" - - -/* The default algorithms. If you change them remember to change them - also in gpg.c:gpgconf_list. You should also check that the value - is inside the bounds enforced by ask_keysize and gen_xxx. */ -#define DEFAULT_STD_ALGO PUBKEY_ALGO_RSA -#define DEFAULT_STD_KEYSIZE 2048 -#define DEFAULT_STD_CURVE NULL -#define DEFAULT_STD_SUBALGO PUBKEY_ALGO_RSA -#define DEFAULT_STD_SUBKEYSIZE 2048 -#define DEFAULT_STD_SUBCURVE NULL - -/* Flag bits used during key generation. */ -#define KEYGEN_FLAG_NO_PROTECTION 1 -#define KEYGEN_FLAG_TRANSIENT_KEY 2 - -/* Maximum number of supported algorithm preferences. */ -#define MAX_PREFS 30 - -enum para_name { - pKEYTYPE, - pKEYLENGTH, - pKEYCURVE, - pKEYUSAGE, - pSUBKEYTYPE, - pSUBKEYLENGTH, - pSUBKEYCURVE, - pSUBKEYUSAGE, - pAUTHKEYTYPE, - pNAMEREAL, - pNAMEEMAIL, - pNAMECOMMENT, - pPREFERENCES, - pREVOKER, - pUSERID, - pCREATIONDATE, - pKEYCREATIONDATE, /* Same in seconds since epoch. */ - pEXPIREDATE, - pKEYEXPIRE, /* in n seconds */ - pSUBKEYEXPIRE, /* in n seconds */ - pPASSPHRASE, - pSERIALNO, - pCARDBACKUPKEY, - pHANDLE, - pKEYSERVER -}; - -struct para_data_s { - struct para_data_s *next; - int lnr; - enum para_name key; - union { - u32 expire; - u32 creation; - unsigned int usage; - struct revocation_key revkey; - char value[1]; - } u; -}; - -struct output_control_s -{ - int lnr; - int dryrun; - unsigned int keygen_flags; - int use_files; - struct { - char *fname; - char *newfname; - IOBUF stream; - armor_filter_context_t *afx; - } pub; -}; - - -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,ks_modify; - -static void do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, - struct output_control_s *outctrl, int card ); -static int write_keyblock (iobuf_t out, kbnode_t node); -static gpg_error_t gen_card_key (int algo, int keyno, int is_primary, - kbnode_t pub_root, - u32 *timestamp, u32 expireval); -static int gen_card_key_with_backup (int algo, int keyno, int is_primary, - kbnode_t pub_root, u32 timestamp, - u32 expireval, struct para_data_s *para); - - -static void -print_status_key_created (int letter, PKT_public_key *pk, const char *handle) -{ - byte array[MAX_FINGERPRINT_LEN], *s; - char *buf, *p; - size_t i, n; - - if (!handle) - handle = ""; - - buf = xmalloc (MAX_FINGERPRINT_LEN*2+31 + strlen (handle) + 1); - - p = buf; - if (letter || pk) - { - *p++ = letter; - *p++ = ' '; - fingerprint_from_pk (pk, array, &n); - s = array; - for (i=0; i < n ; i++, s++, p += 2) - sprintf (p, "%02X", *s); - } - if (*handle) - { - *p++ = ' '; - for (i=0; handle[i] && i < 100; i++) - *p++ = isspace ((unsigned int)handle[i])? '_':handle[i]; - } - *p = 0; - write_status_text ((letter || pk)?STATUS_KEY_CREATED:STATUS_KEY_NOT_CREATED, - buf); - xfree (buf); -} - -static void -print_status_key_not_created (const char *handle) -{ - print_status_key_created (0, NULL, handle); -} - - - -static void -write_uid( KBNODE root, const char *s ) -{ - PACKET *pkt = xmalloc_clear(sizeof *pkt ); - size_t n = strlen(s); - - pkt->pkttype = PKT_USER_ID; - pkt->pkt.user_id = xmalloc_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]; - - buf[0] = 0; - - /* The spec says that all primary keys MUST be able to certify. */ - if(sig->sig_class!=0x18) - buf[0] |= 0x01; - - if (use & PUBKEY_USAGE_SIG) - buf[0] |= 0x02; - if (use & PUBKEY_USAGE_ENC) - buf[0] |= 0x04 | 0x08; - if (use & PUBKEY_USAGE_AUTH) - buf[0] |= 0x20; - - build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1); -} - - -int -keygen_add_key_expire (PKT_signature *sig, void *opaque) -{ - PKT_public_key *pk = opaque; - byte buf[8]; - u32 u; - - if (pk->expiredate) - { - if (pk->expiredate > pk->timestamp) - u = pk->expiredate - pk->timestamp; - else - u = 1; - - buf[0] = (u >> 24) & 0xff; - buf[1] = (u >> 16) & 0xff; - buf[2] = (u >> 8) & 0xff; - buf[3] = u & 0xff; - build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4); - } - else - { - /* Make sure we don't leave a key expiration subpacket lying - around */ - delete_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE); - } - - 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 (int val, int type, const char *item, byte *buf, int *nbuf) -{ - int i; - - for (i=0; i < *nbuf; i++ ) - if (buf[i] == val) - { - log_info (_("preference '%s' duplicated\n"), item); - return -1; - } - - if (*nbuf >= MAX_PREFS) - { - if(type==1) - log_info(_("too many cipher preferences\n")); - else if(type==2) - log_info(_("too many digest preferences\n")); - else if(type==3) - log_info(_("too many compression preferences\n")); - else - BUG(); - - return -1; - } - - buf[(*nbuf)++] = val; - return 0; -} - -/* - * Parse the supplied string and use it to set the standard - * preferences. The string may be in a form like the one printed by - * "pref" (something like: "S10 S3 H3 H2 Z2 Z1") or the actual - * cipher/hash/compress names. Use NULL to set the default - * preferences. Returns: 0 = okay - */ -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, val, rc=0; - int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */ - char dummy_string[20*4+1]; /* Enough for 20 items. */ - - if (!string || !ascii_strcasecmp (string, "default")) - { - if (opt.def_preference_list) - string=opt.def_preference_list; - else - { - int any_compress = 0; - dummy_string[0]='\0'; - - /* The rationale why we use the order AES256,192,128 is - for compatibility reasons with PGP. If gpg would - define AES128 first, we would get the somewhat - confusing situation: - - gpg -r pgpkey -r gpgkey ---gives--> AES256 - gpg -r gpgkey -r pgpkey ---gives--> AES - - Note that by using --personal-cipher-preferences it is - possible to prefer AES128. - */ - - /* Make sure we do not add more than 15 items here, as we - could overflow the size of dummy_string. We currently - have at most 12. */ - if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES256) ) - strcat(dummy_string,"S9 "); - if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES192) ) - strcat(dummy_string,"S8 "); - if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES) ) - strcat(dummy_string,"S7 "); - strcat(dummy_string,"S2 "); /* 3DES */ - - /* The default hash algo order is: - SHA-256, SHA-384, SHA-512, SHA-224, SHA-1. - */ - if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) - strcat (dummy_string, "H8 "); - - if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) - strcat (dummy_string, "H9 "); - - if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512)) - strcat (dummy_string, "H10 "); - - if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224)) - strcat (dummy_string, "H11 "); - - strcat (dummy_string, "H2 "); /* SHA-1 */ - - if(!check_compress_algo(COMPRESS_ALGO_ZLIB)) - { - strcat(dummy_string,"Z2 "); - any_compress = 1; - } - - if(!check_compress_algo(COMPRESS_ALGO_BZIP2)) - { - strcat(dummy_string,"Z3 "); - any_compress = 1; - } - - if(!check_compress_algo(COMPRESS_ALGO_ZIP)) - { - strcat(dummy_string,"Z1 "); - any_compress = 1; - } - - /* In case we have no compress algo at all, declare that - we prefer no compresssion. */ - if (!any_compress) - strcat(dummy_string,"Z0 "); - - /* Remove the trailing space. */ - if (*dummy_string && dummy_string[strlen (dummy_string)-1] == ' ') - dummy_string[strlen (dummy_string)-1] = 0; - - string=dummy_string; - } - } - else if (!ascii_strcasecmp (string, "none")) - string = ""; - - if(strlen(string)) - { - char *tok,*prefstring; - - prefstring=xstrdup(string); /* need a writable string! */ - - while((tok=strsep(&prefstring," ,"))) - { - if((val=string_to_cipher_algo (tok))) - { - if(set_one_pref(val,1,tok,sym,&nsym)) - rc=-1; - } - else if((val=string_to_digest_algo (tok))) - { - if(set_one_pref(val,2,tok,hash,&nhash)) - rc=-1; - } - else if((val=string_to_compress_algo(tok))>-1) - { - if(set_one_pref(val,3,tok,zip,&nzip)) - rc=-1; - } - else if (ascii_strcasecmp(tok,"mdc")==0) - mdc=1; - else if (ascii_strcasecmp(tok,"no-mdc")==0) - mdc=0; - else if (ascii_strcasecmp(tok,"ks-modify")==0) - modify=1; - else if (ascii_strcasecmp(tok,"no-ks-modify")==0) - modify=0; - else - { - log_info (_("invalid item '%s' in preference string\n"),tok); - rc=-1; - } - } - - xfree(prefstring); - } - - if(!rc) - { - if(personal) - { - if(personal==PREFTYPE_SYM) - { - xfree(opt.personal_cipher_prefs); - - if(nsym==0) - opt.personal_cipher_prefs=NULL; - else - { - int i; - - opt.personal_cipher_prefs= - xmalloc(sizeof(prefitem_t *)*(nsym+1)); - - for (i=0; iref=1; - - uid->prefs=xmalloc((sizeof(prefitem_t *)* - (nsym_prefs+nhash_prefs+nzip_prefs+1))); - - for(i=0;iprefs[j].type=PREFTYPE_SYM; - uid->prefs[j].value=sym_prefs[i]; - } - - for(i=0;iprefs[j].type=PREFTYPE_HASH; - uid->prefs[j].value=hash_prefs[i]; - } - - for(i=0;iprefs[j].type=PREFTYPE_ZIP; - uid->prefs[j].value=zip_prefs[i]; - } - - uid->prefs[j].type=PREFTYPE_NONE; - uid->prefs[j].value=0; - - uid->flags.mdc=mdc_available; - uid->flags.ks_modify=ks_modify; - - return uid; -} - -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 = xmalloc_clear (n); - } - else { - buf = xmalloc (n); - memcpy (buf, s, n); - } - - if(enabled) - buf[0] |= 0x01; /* MDC feature */ - else - buf[0] &= ~0x01; - - /* Are there any bits set? */ - for(i=0;ihashed, SIGSUBPKT_FEATURES); - else - build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n); - - xfree (buf); -} - -static void -add_keyserver_modify (PKT_signature *sig,int enabled) -{ - const byte *s; - size_t n; - int i; - char *buf; - - /* The keyserver modify flag is a negative flag (i.e. no-modify) */ - enabled=!enabled; - - s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n ); - /* Already set or cleared */ - if (s && n && - ((enabled && (s[0] & 0x80)) || (!enabled && !(s[0] & 0x80)))) - return; - - if (!s || !n) { /* create a new one */ - n = 1; - buf = xmalloc_clear (n); - } - else { - buf = xmalloc (n); - memcpy (buf, s, n); - } - - if(enabled) - buf[0] |= 0x80; /* no-modify flag */ - else - buf[0] &= ~0x80; - - /* Are there any bits set? */ - for(i=0;ihashed, SIGSUBPKT_KS_FLAGS); - else - build_sig_subpkt (sig, SIGSUBPKT_KS_FLAGS, buf, n); - - xfree (buf); -} - - -int -keygen_upd_std_prefs (PKT_signature *sig, void *opaque) -{ - (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); - add_keyserver_modify (sig,ks_modify); - keygen_add_keyserver_url(sig,NULL); - - 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; - - do_add_key_flags (sig, pk->pubkey_usage); - keygen_add_key_expire (sig, opaque ); - keygen_upd_std_prefs (sig, opaque); - keygen_add_keyserver_url (sig,NULL); - - return 0; -} - -int -keygen_add_keyserver_url(PKT_signature *sig, void *opaque) -{ - const char *url=opaque; - - if(!url) - url=opt.def_keyserver_url; - - if(url) - build_sig_subpkt(sig,SIGSUBPKT_PREF_KS,url,strlen(url)); - else - delete_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS); - - return 0; -} - -int -keygen_add_notations(PKT_signature *sig,void *opaque) -{ - struct notation *notation; - - /* We always start clean */ - delete_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION); - delete_sig_subpkt(sig->unhashed,SIGSUBPKT_NOTATION); - sig->flags.notation=0; - - for(notation=opaque;notation;notation=notation->next) - if(!notation->flags.ignore) - { - unsigned char *buf; - unsigned int n1,n2; - - n1=strlen(notation->name); - if(notation->altvalue) - n2=strlen(notation->altvalue); - else if(notation->bdat) - n2=notation->blen; - else - n2=strlen(notation->value); - - buf = xmalloc( 8 + n1 + n2 ); - - /* human readable or not */ - buf[0] = notation->bdat?0:0x80; - buf[1] = buf[2] = buf[3] = 0; - buf[4] = n1 >> 8; - buf[5] = n1; - buf[6] = n2 >> 8; - buf[7] = n2; - memcpy(buf+8, notation->name, n1 ); - if(notation->altvalue) - memcpy(buf+8+n1, notation->altvalue, n2 ); - else if(notation->bdat) - memcpy(buf+8+n1, notation->bdat, n2 ); - else - memcpy(buf+8+n1, notation->value, n2 ); - build_sig_subpkt( sig, SIGSUBPKT_NOTATION | - (notation->flags.critical?SIGSUBPKT_FLAG_CRITICAL:0), - buf, 8+n1+n2 ); - xfree(buf); - } - - 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; -} - - - -/* Create a back-signature. If TIMESTAMP is not NULL, use it for the - signature creation time. */ -gpg_error_t -make_backsig (PKT_signature *sig, PKT_public_key *pk, - PKT_public_key *sub_pk, PKT_public_key *sub_psk, - u32 timestamp, const char *cache_nonce) -{ - gpg_error_t err; - PKT_signature *backsig; - - cache_public_key (sub_pk); - - err = make_keysig_packet (&backsig, pk, NULL, sub_pk, sub_psk, 0x19, - 0, timestamp, 0, NULL, NULL, cache_nonce); - if (err) - log_error ("make_keysig_packet failed for backsig: %s\n", - gpg_strerror (err)); - else - { - /* Get it into a binary packed form. */ - IOBUF backsig_out = iobuf_temp(); - PACKET backsig_pkt; - - init_packet (&backsig_pkt); - backsig_pkt.pkttype = PKT_SIGNATURE; - backsig_pkt.pkt.signature = backsig; - err = build_packet (backsig_out, &backsig_pkt); - free_packet (&backsig_pkt); - if (err) - log_error ("build_packet failed for backsig: %s\n", gpg_strerror (err)); - else - { - size_t pktlen = 0; - byte *buf = iobuf_get_temp_buffer (backsig_out); - - /* Remove the packet header. */ - if(buf[0]&0x40) - { - if (buf[1] < 192) - { - pktlen = buf[1]; - buf += 2; - } - else if(buf[1] < 224) - { - pktlen = (buf[1]-192)*256; - pktlen += buf[2]+192; - buf += 3; - } - else if (buf[1] == 255) - { - pktlen = buf32_to_size_t (buf+2); - buf += 6; - } - else - BUG (); - } - else - { - int mark = 1; - - switch (buf[0]&3) - { - case 3: - BUG (); - break; - - case 2: - pktlen = (size_t)buf[mark++] << 24; - pktlen |= buf[mark++] << 16; - - case 1: - pktlen |= buf[mark++] << 8; - - case 0: - pktlen |= buf[mark++]; - } - - buf += mark; - } - - /* Now make the binary blob into a subpacket. */ - build_sig_subpkt (sig, SIGSUBPKT_SIGNATURE, buf, pktlen); - - iobuf_close (backsig_out); - } - } - - return err; -} - - -/* Write a direct key signature to the first key in ROOT using the key - PSK. REVKEY is describes the direct key signature and TIMESTAMP is - the timestamp to set on the signature. */ -static gpg_error_t -write_direct_sig (KBNODE root, PKT_public_key *psk, - struct revocation_key *revkey, u32 timestamp, - const char *cache_nonce) -{ - gpg_error_t err; - PACKET *pkt; - PKT_signature *sig; - 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 (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); - - /* Make the signature. */ - err = make_keysig_packet (&sig, pk, NULL,NULL, psk, 0x1F, - 0, timestamp, 0, - keygen_add_revkey, revkey, cache_nonce); - if (err) - { - log_error ("make_keysig_packet failed: %s\n", gpg_strerror (err) ); - return err; - } - - pkt = xmalloc_clear (sizeof *pkt); - pkt->pkttype = PKT_SIGNATURE; - pkt->pkt.signature = sig; - add_kbnode (root, new_kbnode (pkt)); - return err; -} - - - -/* Write a self-signature to the first user id in ROOT using the key - PSK. USE and TIMESTAMP give the extra data we need for the - signature. */ -static gpg_error_t -write_selfsigs (KBNODE root, PKT_public_key *psk, - unsigned int use, u32 timestamp, const char *cache_nonce) -{ - gpg_error_t err; - PACKET *pkt; - PKT_signature *sig; - PKT_user_id *uid; - KBNODE node; - PKT_public_key *pk; - - if (opt.verbose) - log_info (_("writing self signature\n")); - - /* Get the uid packet from the list. */ - node = find_kbnode (root, PKT_USER_ID); - if (!node) - BUG(); /* No user id packet in tree. */ - uid = node->pkt->pkt.user_id; - - /* Get the pk packet from the pub_tree. */ - node = find_kbnode (root, PKT_PUBLIC_KEY); - if (!node) - BUG(); - pk = node->pkt->pkt.public_key; - - /* The usage has not yet been set - do it now. */ - 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); - - /* Make the signature. */ - err = make_keysig_packet (&sig, pk, uid, NULL, psk, 0x13, - 0, timestamp, 0, - keygen_add_std_prefs, pk, cache_nonce); - if (err) - { - log_error ("make_keysig_packet failed: %s\n", gpg_strerror (err)); - return err; - } - - pkt = xmalloc_clear (sizeof *pkt); - pkt->pkttype = PKT_SIGNATURE; - pkt->pkt.signature = sig; - add_kbnode (root, new_kbnode (pkt)); - - return err; -} - - -/* Write the key binding signature. If TIMESTAMP is not NULL use the - signature creation time. PRI_PSK is the key use for signing. - SUB_PSK is a key used to create a back-signature; that one is only - used if USE has the PUBKEY_USAGE_SIG capability. */ -static int -write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk, - unsigned int use, u32 timestamp, const char *cache_nonce) -{ - gpg_error_t err; - PACKET *pkt; - PKT_signature *sig; - KBNODE node; - PKT_public_key *pri_pk, *sub_pk; - struct opaque_data_usage_and_pk oduap; - - if (opt.verbose) - log_info(_("writing key binding signature\n")); - - /* Get the primary pk packet from the tree. */ - node = find_kbnode (root, PKT_PUBLIC_KEY); - if (!node) - BUG(); - pri_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 (pri_pk); - - /* Find the last subkey. */ - sub_pk = NULL; - for (node = root; node; node = node->next ) - { - if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) - sub_pk = node->pkt->pkt.public_key; - } - if (!sub_pk) - BUG(); - - /* Make the signature. */ - oduap.usage = use; - oduap.pk = sub_pk; - err = make_keysig_packet (&sig, pri_pk, NULL, sub_pk, pri_psk, 0x18, - 0, timestamp, 0, - keygen_add_key_flags_and_expire, &oduap, - cache_nonce); - if (err) - { - log_error ("make_keysig_packeto failed: %s\n", gpg_strerror (err)); - return err; - } - - /* Make a backsig. */ - if (use & PUBKEY_USAGE_SIG) - { - err = make_backsig (sig, pri_pk, sub_pk, sub_psk, timestamp, cache_nonce); - if (err) - return err; - } - - pkt = xmalloc_clear ( sizeof *pkt ); - pkt->pkttype = PKT_SIGNATURE; - pkt->pkt.signature = sig; - add_kbnode (root, new_kbnode (pkt) ); - return err; -} - - -static gpg_error_t -ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo) -{ - gpg_error_t err; - gcry_sexp_t list, l2; - char *curve; - int i; - const char *oidstr; - unsigned int nbits; - - array[0] = NULL; - array[1] = NULL; - array[2] = NULL; - - list = gcry_sexp_find_token (sexp, "public-key", 0); - if (!list) - return gpg_error (GPG_ERR_INV_OBJ); - l2 = gcry_sexp_cadr (list); - gcry_sexp_release (list); - list = l2; - if (!list) - return gpg_error (GPG_ERR_NO_OBJ); - - l2 = gcry_sexp_find_token (list, "curve", 0); - if (!l2) - { - err = gpg_error (GPG_ERR_NO_OBJ); - goto leave; - } - curve = gcry_sexp_nth_string (l2, 1); - if (!curve) - { - err = gpg_error (GPG_ERR_NO_OBJ); - goto leave; - } - gcry_sexp_release (l2); - oidstr = openpgp_curve_to_oid (curve, &nbits); - if (!oidstr) - { - /* That can't happen because we used one of the curves - gpg_curve_to_oid knows about. */ - err = gpg_error (GPG_ERR_INV_OBJ); - goto leave; - } - err = openpgp_oid_from_str (oidstr, &array[0]); - if (err) - goto leave; - - l2 = gcry_sexp_find_token (list, "q", 0); - if (!l2) - { - err = gpg_error (GPG_ERR_NO_OBJ); - goto leave; - } - array[1] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l2); - if (!array[1]) - { - err = gpg_error (GPG_ERR_INV_OBJ); - goto leave; - } - gcry_sexp_release (list); - - if (algo == PUBKEY_ALGO_ECDH) - { - array[2] = pk_ecdh_default_params (nbits); - if (!array[2]) - { - err = gpg_error_from_syserror (); - goto leave; - } - } - - leave: - if (err) - { - for (i=0; i < 3; i++) - { - gcry_mpi_release (array[i]); - array[i] = NULL; - } - } - return err; -} - - -/* Extract key parameters from SEXP and store them in ARRAY. ELEMS is - a string where each character denotes a parameter name. TOPNAME is - the name of the top element above the elements. */ -static int -key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, - const char *topname, const char *elems) -{ - gcry_sexp_t list, l2; - const char *s; - int i, idx; - int rc = 0; - - list = gcry_sexp_find_token (sexp, topname, 0); - if (!list) - return gpg_error (GPG_ERR_INV_OBJ); - l2 = gcry_sexp_cadr (list); - gcry_sexp_release (list); - list = l2; - if (!list) - return gpg_error (GPG_ERR_NO_OBJ); - - for (idx=0,s=elems; *s; s++, idx++) - { - l2 = gcry_sexp_find_token (list, s, 1); - if (!l2) - { - rc = gpg_error (GPG_ERR_NO_OBJ); /* required parameter not found */ - goto leave; - } - array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); - gcry_sexp_release (l2); - if (!array[idx]) - { - rc = gpg_error (GPG_ERR_INV_OBJ); /* required parameter invalid */ - goto leave; - } - } - gcry_sexp_release (list); - - leave: - if (rc) - { - for (i=0; itimestamp = timestamp; - pk->version = 4; - if (expireval) - pk->expiredate = pk->timestamp + expireval; - pk->pubkey_algo = algo; - - if (algo == PUBKEY_ALGO_ECDSA - || algo == PUBKEY_ALGO_EDDSA - || algo == PUBKEY_ALGO_ECDH ) - err = ecckey_from_sexp (pk->pkey, s_key, algo); - else - err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem); - if (err) - { - log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); - gcry_sexp_release (s_key); - free_public_key (pk); - return err; - } - gcry_sexp_release (s_key); - - pkt = xtrycalloc (1, sizeof *pkt); - if (!pkt) - { - err = gpg_error_from_syserror (); - free_public_key (pk); - return err; - } - - pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; - pkt->pkt.public_key = pk; - add_kbnode (pub_root, new_kbnode (pkt)); - - return 0; -} - - -/* Common code for the key generation function gen_xxx. */ -static int -common_gen (const char *keyparms, int algo, const char *algoelem, - kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey, - int keygen_flags, const char *passphrase, char **cache_nonce_addr) -{ - int err; - PACKET *pkt; - PKT_public_key *pk; - gcry_sexp_t s_key; - - err = agent_genkey (NULL, cache_nonce_addr, keyparms, - !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), - passphrase, - &s_key); - if (err) - { - log_error ("agent_genkey failed: %s\n", gpg_strerror (err) ); - return err; - } - - pk = xtrycalloc (1, sizeof *pk); - if (!pk) - { - err = gpg_error_from_syserror (); - gcry_sexp_release (s_key); - return err; - } - - pk->timestamp = timestamp; - pk->version = 4; - if (expireval) - pk->expiredate = pk->timestamp + expireval; - pk->pubkey_algo = algo; - - if (algo == PUBKEY_ALGO_ECDSA - || algo == PUBKEY_ALGO_EDDSA - || algo == PUBKEY_ALGO_ECDH ) - err = ecckey_from_sexp (pk->pkey, s_key, algo); - else - err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem); - if (err) - { - log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); - gcry_sexp_release (s_key); - free_public_key (pk); - return err; - } - gcry_sexp_release (s_key); - - pkt = xtrycalloc (1, sizeof *pkt); - if (!pkt) - { - err = gpg_error_from_syserror (); - free_public_key (pk); - return err; - } - - pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; - pkt->pkt.public_key = pk; - add_kbnode (pub_root, new_kbnode (pkt)); - - return 0; -} - - -/* - * Generate an Elgamal key. - */ -static int -gen_elg (int algo, unsigned int nbits, KBNODE pub_root, - u32 timestamp, u32 expireval, int is_subkey, - int keygen_flags, const char *passphrase, char **cache_nonce_addr) -{ - int err; - char *keyparms; - char nbitsstr[35]; - - assert (is_ELGAMAL (algo)); - - if (nbits < 1024) - { - nbits = 2048; - log_info (_("keysize invalid; using %u bits\n"), nbits ); - } - else if (nbits > 4096) - { - nbits = 4096; - log_info (_("keysize invalid; using %u bits\n"), nbits ); - } - - if ((nbits % 32)) - { - nbits = ((nbits + 31) / 32) * 32; - log_info (_("keysize rounded up to %u bits\n"), nbits ); - } - - /* Note that we use transient-key only if no-protection has also - been enabled. */ - snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); - keyparms = xtryasprintf ("(genkey(%s(nbits %zu:%s)%s))", - algo == GCRY_PK_ELG_E ? "openpgp-elg" : - algo == GCRY_PK_ELG ? "elg" : "x-oops" , - strlen (nbitsstr), nbitsstr, - ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) - && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? - "(transient-key)" : "" ); - if (!keyparms) - err = gpg_error_from_syserror (); - else - { - err = common_gen (keyparms, algo, "pgy", - pub_root, timestamp, expireval, is_subkey, - keygen_flags, passphrase, cache_nonce_addr); - xfree (keyparms); - } - - return err; -} - - -/* - * Generate an DSA key - */ -static gpg_error_t -gen_dsa (unsigned int nbits, KBNODE pub_root, - u32 timestamp, u32 expireval, int is_subkey, - int keygen_flags, const char *passphrase, char **cache_nonce_addr) -{ - int err; - unsigned int qbits; - char *keyparms; - char nbitsstr[35]; - char qbitsstr[35]; - - if (nbits < 768) - { - nbits = 2048; - log_info(_("keysize invalid; using %u bits\n"), nbits ); - } - else if ( nbits > 3072 ) - { - nbits = 3072; - log_info(_("keysize invalid; using %u bits\n"), nbits ); - } - - if( (nbits % 64) ) - { - nbits = ((nbits + 63) / 64) * 64; - log_info(_("keysize rounded up to %u bits\n"), nbits ); - } - - /* To comply with FIPS rules we round up to the next value unless in - expert mode. */ - if (!opt.expert && nbits > 1024 && (nbits % 1024)) - { - nbits = ((nbits + 1023) / 1024) * 1024; - log_info(_("keysize rounded up to %u bits\n"), nbits ); - } - - /* - Figure out a q size based on the key size. FIPS 180-3 says: - - L = 1024, N = 160 - L = 2048, N = 224 - L = 2048, N = 256 - L = 3072, N = 256 - - 2048/256 is an odd pair since there is also a 2048/224 and - 3072/256. Matching sizes is not a very exact science. - - We'll do 256 qbits for nbits over 2047, 224 for nbits over 1024 - but less than 2048, and 160 for 1024 (DSA1). - */ - - if (nbits > 2047) - qbits = 256; - else if ( nbits > 1024) - qbits = 224; - else - qbits = 160; - - if (qbits != 160 ) - log_info (_("WARNING: some OpenPGP programs can't" - " handle a DSA key with this digest size\n")); - - snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); - snprintf (qbitsstr, sizeof qbitsstr, "%u", qbits); - keyparms = xtryasprintf ("(genkey(dsa(nbits %zu:%s)(qbits %zu:%s)%s))", - strlen (nbitsstr), nbitsstr, - strlen (qbitsstr), qbitsstr, - ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) - && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? - "(transient-key)" : "" ); - if (!keyparms) - err = gpg_error_from_syserror (); - else - { - err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy", - pub_root, timestamp, expireval, is_subkey, - keygen_flags, passphrase, cache_nonce_addr); - xfree (keyparms); - } - - return err; -} - - - -/* - * Generate an ECC key - */ -static gpg_error_t -gen_ecc (int algo, const char *curve, kbnode_t pub_root, - u32 timestamp, u32 expireval, int is_subkey, - int keygen_flags, const char *passphrase, char **cache_nonce_addr) -{ - gpg_error_t err; - char *keyparms; - - assert (algo == PUBKEY_ALGO_ECDSA - || algo == PUBKEY_ALGO_EDDSA - || algo == PUBKEY_ALGO_ECDH); - - if (!curve || !*curve) - return gpg_error (GPG_ERR_UNKNOWN_CURVE); - - /* Note that we use the "comp" flag with EdDSA to request the use of - a 0x40 compression prefix octet. */ - if (algo == PUBKEY_ALGO_EDDSA) - keyparms = xtryasprintf - ("(genkey(ecc(curve %zu:%s)(flags eddsa comp%s)))", - strlen (curve), curve, - (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) - && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? - " transient-key" : "")); - else if (algo == PUBKEY_ALGO_ECDH && !strcmp (curve, "Curve25519")) - keyparms = xtryasprintf - ("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))", - strlen (curve), curve, - (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) - && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? - " transient-key" : "")); - else - keyparms = xtryasprintf - ("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))", - strlen (curve), curve, - (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) - && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? - " transient-key" : "")); - - if (!keyparms) - err = gpg_error_from_syserror (); - else - { - err = common_gen (keyparms, algo, "", - pub_root, timestamp, expireval, is_subkey, - keygen_flags, passphrase, cache_nonce_addr); - xfree (keyparms); - } - - return err; -} - - -/* - * Generate an RSA key. - */ -static int -gen_rsa (int algo, unsigned int nbits, KBNODE pub_root, - u32 timestamp, u32 expireval, int is_subkey, - int keygen_flags, const char *passphrase, char **cache_nonce_addr) -{ - int err; - char *keyparms; - char nbitsstr[35]; - const unsigned maxsize = (opt.flags.large_rsa ? 8192 : 4096); - - assert (is_RSA(algo)); - - if (!nbits) - nbits = DEFAULT_STD_KEYSIZE; - - if (nbits < 1024) - { - nbits = 2048; - log_info (_("keysize invalid; using %u bits\n"), nbits ); - } - else if (nbits > maxsize) - { - nbits = maxsize; - log_info (_("keysize invalid; using %u bits\n"), nbits ); - } - - if ((nbits % 32)) - { - nbits = ((nbits + 31) / 32) * 32; - log_info (_("keysize rounded up to %u bits\n"), nbits ); - } - - snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); - keyparms = xtryasprintf ("(genkey(rsa(nbits %zu:%s)%s))", - strlen (nbitsstr), nbitsstr, - ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) - && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? - "(transient-key)" : "" ); - if (!keyparms) - err = gpg_error_from_syserror (); - else - { - err = common_gen (keyparms, algo, "ne", - pub_root, timestamp, expireval, is_subkey, - keygen_flags, passphrase, cache_nonce_addr); - xfree (keyparms); - } - - return err; -} - - -/**************** - * check valid days: - * return 0 on error or the multiplier - */ -static int -check_valid_days( const char *s ) -{ - if( !digitp(s) ) - return 0; - for( s++; *s; s++) - if( !digitp(s) ) - break; - if( !*s ) - return 1; - if( s[1] ) - return 0; /* e.g. "2323wc" */ - if( *s == 'd' || *s == 'D' ) - return 1; - if( *s == 'w' || *s == 'W' ) - return 7; - if( *s == 'm' || *s == 'M' ) - return 30; - if( *s == 'y' || *s == 'Y' ) - return 365; - return 0; -} - - -static void -print_key_flags(int flags) -{ - if(flags&PUBKEY_USAGE_SIG) - tty_printf("%s ",_("Sign")); - - if(flags&PUBKEY_USAGE_CERT) - tty_printf("%s ",_("Certify")); - - if(flags&PUBKEY_USAGE_ENC) - tty_printf("%s ",_("Encrypt")); - - if(flags&PUBKEY_USAGE_AUTH) - tty_printf("%s ",_("Authenticate")); -} - - -/* Returns the key flags */ -static unsigned int -ask_key_flags(int algo,int subkey) -{ - /* TRANSLATORS: Please use only plain ASCII characters for the - translation. If this is not possible use single digits. The - string needs to 8 bytes long. Here is a description of the - functions: - - s = Toggle signing capability - e = Toggle encryption capability - a = Toggle authentication capability - q = Finish - */ - const char *togglers=_("SsEeAaQq"); - char *answer=NULL; - const char *s; - unsigned int current=0; - unsigned int possible=openpgp_pk_algo_usage(algo); - - if ( strlen(togglers) != 8 ) - { - tty_printf ("NOTE: Bad translation at %s:%d. " - "Please report.\n", __FILE__, __LINE__); - togglers = "11223300"; - } - - /* Only primary keys may certify. */ - if(subkey) - possible&=~PUBKEY_USAGE_CERT; - - /* Preload the current set with the possible set, minus - authentication, since nobody really uses auth yet. */ - current=possible&~PUBKEY_USAGE_AUTH; - - for(;;) - { - tty_printf("\n"); - tty_printf(_("Possible actions for a %s key: "), - openpgp_pk_algo_name (algo)); - print_key_flags(possible); - tty_printf("\n"); - tty_printf(_("Current allowed actions: ")); - print_key_flags(current); - tty_printf("\n\n"); - - if(possible&PUBKEY_USAGE_SIG) - tty_printf(_(" (%c) Toggle the sign capability\n"), - togglers[0]); - if(possible&PUBKEY_USAGE_ENC) - tty_printf(_(" (%c) Toggle the encrypt capability\n"), - togglers[2]); - if(possible&PUBKEY_USAGE_AUTH) - tty_printf(_(" (%c) Toggle the authenticate capability\n"), - togglers[4]); - - tty_printf(_(" (%c) Finished\n"),togglers[6]); - tty_printf("\n"); - - xfree(answer); - answer = cpr_get("keygen.flags",_("Your selection? ")); - cpr_kill_prompt(); - - if (*answer == '=') - { - /* Hack to allow direct entry of the capabilities. */ - current = 0; - for (s=answer+1; *s; s++) - { - if ((*s == 's' || *s == 'S') && (possible&PUBKEY_USAGE_SIG)) - current |= PUBKEY_USAGE_SIG; - else if ((*s == 'e' || *s == 'E') && (possible&PUBKEY_USAGE_ENC)) - current |= PUBKEY_USAGE_ENC; - else if ((*s == 'a' || *s == 'A') && (possible&PUBKEY_USAGE_AUTH)) - current |= PUBKEY_USAGE_AUTH; - else if (!subkey && *s == 'c') - { - /* Accept 'c' for the primary key because USAGE_CERT - will will be set anyway. This is for folks who - want to experiment with a cert-only primary key. */ - current |= PUBKEY_USAGE_CERT; - } - } - break; - } - else if (strlen(answer)>1) - tty_printf(_("Invalid selection.\n")); - else if(*answer=='\0' || *answer==togglers[6] || *answer==togglers[7]) - break; - else if((*answer==togglers[0] || *answer==togglers[1]) - && possible&PUBKEY_USAGE_SIG) - { - if(current&PUBKEY_USAGE_SIG) - current&=~PUBKEY_USAGE_SIG; - else - current|=PUBKEY_USAGE_SIG; - } - else if((*answer==togglers[2] || *answer==togglers[3]) - && possible&PUBKEY_USAGE_ENC) - { - if(current&PUBKEY_USAGE_ENC) - current&=~PUBKEY_USAGE_ENC; - else - current|=PUBKEY_USAGE_ENC; - } - else if((*answer==togglers[4] || *answer==togglers[5]) - && possible&PUBKEY_USAGE_AUTH) - { - if(current&PUBKEY_USAGE_AUTH) - current&=~PUBKEY_USAGE_AUTH; - else - current|=PUBKEY_USAGE_AUTH; - } - else - tty_printf(_("Invalid selection.\n")); - } - - xfree(answer); - - return current; -} - - -/* Check whether we have a key for the key with HEXGRIP. Returns 0 if - there is no such key or the OpenPGP algo number for the key. */ -static int -check_keygrip (ctrl_t ctrl, const char *hexgrip) -{ - gpg_error_t err; - unsigned char *public; - size_t publiclen; - const char *algostr; - - if (hexgrip[0] == '&') - hexgrip++; - - err = agent_readkey (ctrl, 0, hexgrip, &public); - if (err) - return 0; - publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL); - - get_pk_algo_from_canon_sexp (public, publiclen, &algostr); - xfree (public); - - /* FIXME: Mapping of ECC algorithms is probably not correct. */ - if (!algostr) - return 0; - else if (!strcmp (algostr, "rsa")) - return PUBKEY_ALGO_RSA; - else if (!strcmp (algostr, "dsa")) - return PUBKEY_ALGO_DSA; - else if (!strcmp (algostr, "elg")) - return PUBKEY_ALGO_ELGAMAL_E; - else if (!strcmp (algostr, "ecc")) - return PUBKEY_ALGO_ECDH; - else if (!strcmp (algostr, "ecdsa")) - return PUBKEY_ALGO_ECDSA; - else if (!strcmp (algostr, "eddsa")) - return PUBKEY_ALGO_EDDSA; - else - return 0; -} - - - -/* Ask for an algorithm. The function returns the algorithm id to - * create. If ADDMODE is false the function won't show an option to - * create the primary and subkey combined and won't set R_USAGE - * either. If a combined algorithm has been selected, the subkey - * algorithm is stored at R_SUBKEY_ALGO. If R_KEYGRIP is given, the - * user has the choice to enter the keygrip of an existing key. That - * keygrip is then stored at this address. The caller needs to free - * it. */ -static int -ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, - char **r_keygrip) -{ - char *keygrip = NULL; - char *answer = NULL; - int algo; - int dummy_algo; - - if (!r_subkey_algo) - r_subkey_algo = &dummy_algo; - - tty_printf (_("Please select what kind of key you want:\n")); - -#if GPG_USE_RSA - if (!addmode) - tty_printf (_(" (%d) RSA and RSA (default)\n"), 1 ); -#endif - - if (!addmode) - tty_printf (_(" (%d) DSA and Elgamal\n"), 2 ); - - tty_printf (_(" (%d) DSA (sign only)\n"), 3 ); -#if GPG_USE_RSA - tty_printf (_(" (%d) RSA (sign only)\n"), 4 ); -#endif - - if (addmode) - { - tty_printf (_(" (%d) Elgamal (encrypt only)\n"), 5 ); -#if GPG_USE_RSA - tty_printf (_(" (%d) RSA (encrypt only)\n"), 6 ); -#endif - } - if (opt.expert) - { - tty_printf (_(" (%d) DSA (set your own capabilities)\n"), 7 ); -#if GPG_USE_RSA - tty_printf (_(" (%d) RSA (set your own capabilities)\n"), 8 ); -#endif - } - -#if GPG_USE_ECDSA || GPG_USE_ECDH || GPG_USE_EDDSA - if (opt.expert && !addmode) - tty_printf (_(" (%d) ECC and ECC\n"), 9 ); - if (opt.expert) - tty_printf (_(" (%d) ECC (sign only)\n"), 10 ); - if (opt.expert) - tty_printf (_(" (%d) ECC (set your own capabilities)\n"), 11 ); - if (opt.expert && addmode) - tty_printf (_(" (%d) ECC (encrypt only)\n"), 12 ); -#endif - - if (opt.expert && r_keygrip) - tty_printf (_(" (%d) Existing key\n"), 13 ); - - for (;;) - { - *r_usage = 0; - *r_subkey_algo = 0; - xfree (answer); - answer = cpr_get ("keygen.algo", _("Your selection? ")); - cpr_kill_prompt (); - algo = *answer? atoi (answer) : 1; - if ((algo == 1 || !strcmp (answer, "rsa+rsa")) && !addmode) - { - algo = PUBKEY_ALGO_RSA; - *r_subkey_algo = PUBKEY_ALGO_RSA; - break; - } - else if ((algo == 2 || !strcmp (answer, "dsa+elg")) && !addmode) - { - algo = PUBKEY_ALGO_DSA; - *r_subkey_algo = PUBKEY_ALGO_ELGAMAL_E; - break; - } - else if (algo == 3 || !strcmp (answer, "dsa")) - { - algo = PUBKEY_ALGO_DSA; - *r_usage = PUBKEY_USAGE_SIG; - break; - } - else if (algo == 4 || !strcmp (answer, "rsa/s")) - { - algo = PUBKEY_ALGO_RSA; - *r_usage = PUBKEY_USAGE_SIG; - break; - } - else if ((algo == 5 || !strcmp (answer, "elg")) && addmode) - { - algo = PUBKEY_ALGO_ELGAMAL_E; - *r_usage = PUBKEY_USAGE_ENC; - break; - } - else if ((algo == 6 || !strcmp (answer, "rsa/e")) && addmode) - { - algo = PUBKEY_ALGO_RSA; - *r_usage = PUBKEY_USAGE_ENC; - break; - } - else if ((algo == 7 || !strcmp (answer, "dsa/*")) && opt.expert) - { - algo = PUBKEY_ALGO_DSA; - *r_usage = ask_key_flags (algo, addmode); - break; - } - else if ((algo == 8 || !strcmp (answer, "rsa/*")) && opt.expert) - { - algo = PUBKEY_ALGO_RSA; - *r_usage = ask_key_flags (algo, addmode); - break; - } - else if ((algo == 9 || !strcmp (answer, "ecc+ecc")) - && opt.expert && !addmode) - { - algo = PUBKEY_ALGO_ECDSA; - *r_subkey_algo = PUBKEY_ALGO_ECDH; - break; - } - else if ((algo == 10 || !strcmp (answer, "ecc/s")) && opt.expert) - { - algo = PUBKEY_ALGO_ECDSA; - *r_usage = PUBKEY_USAGE_SIG; - break; - } - else if ((algo == 11 || !strcmp (answer, "ecc/*")) && opt.expert) - { - algo = PUBKEY_ALGO_ECDSA; - *r_usage = ask_key_flags (algo, addmode); - break; - } - else if ((algo == 12 || !strcmp (answer, "ecc/e")) - && opt.expert && addmode) - { - algo = PUBKEY_ALGO_ECDH; - *r_usage = PUBKEY_USAGE_ENC; - break; - } - else if ((algo == 13 || !strcmp (answer, "keygrip")) - && opt.expert && r_keygrip) - { - for (;;) - { - xfree (answer); - answer = tty_get (_("Enter the keygrip: ")); - tty_kill_prompt (); - trim_spaces (answer); - if (!*answer) - { - xfree (answer); - answer = NULL; - continue; - } - - if (strlen (answer) != 40 && - !(answer[0] == '&' && strlen (answer+1) == 40)) - tty_printf - (_("Not a valid keygrip (expecting 40 hex digits)\n")); - else if (!(algo = check_keygrip (ctrl, answer)) ) - tty_printf (_("No key with this keygrip\n")); - else - break; /* Okay. */ - } - xfree (keygrip); - keygrip = answer; - answer = NULL; - *r_usage = ask_key_flags (algo, addmode); - break; - } - else - tty_printf (_("Invalid selection.\n")); - - } - - xfree(answer); - if (r_keygrip) - *r_keygrip = keygrip; - return algo; -} - - -/* Ask for the key size. ALGO is the algorithm. If PRIMARY_KEYSIZE - is not 0, the function asks for the size of the encryption - subkey. */ -static unsigned -ask_keysize (int algo, unsigned int primary_keysize) -{ - unsigned int nbits, min, def = DEFAULT_STD_KEYSIZE, max=4096; - int for_subkey = !!primary_keysize; - int autocomp = 0; - - if(opt.expert) - min=512; - else - min=1024; - - if (primary_keysize && !opt.expert) - { - /* Deduce the subkey size from the primary key size. */ - if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072) - nbits = 3072; /* For performance reasons we don't support more - than 3072 bit DSA. However we won't see this - case anyway because DSA can't be used as an - encryption subkey ;-). */ - else - nbits = primary_keysize; - autocomp = 1; - goto leave; - } - - switch(algo) - { - case PUBKEY_ALGO_DSA: - def=2048; - max=3072; - break; - - case PUBKEY_ALGO_ECDSA: - case PUBKEY_ALGO_ECDH: - min=256; - def=256; - max=521; - break; - - case PUBKEY_ALGO_EDDSA: - min=255; - def=255; - max=441; - break; - - case PUBKEY_ALGO_RSA: - min=1024; - break; - } - - tty_printf(_("%s keys may be between %u and %u bits long.\n"), - openpgp_pk_algo_name (algo), min, max); - - for (;;) - { - char *prompt, *answer; - - if (for_subkey) - prompt = xasprintf (_("What keysize do you want " - "for the subkey? (%u) "), def); - else - prompt = xasprintf (_("What keysize do you want? (%u) "), def); - answer = cpr_get ("keygen.size", prompt); - cpr_kill_prompt (); - nbits = *answer? atoi (answer): def; - xfree(prompt); - xfree(answer); - - if(nbitsmax) - tty_printf(_("%s keysizes must be in the range %u-%u\n"), - openpgp_pk_algo_name (algo), min, max); - else - break; - } - - tty_printf (_("Requested keysize is %u bits\n"), nbits); - - leave: - if (algo == PUBKEY_ALGO_DSA && (nbits % 64)) - { - nbits = ((nbits + 63) / 64) * 64; - if (!autocomp) - tty_printf (_("rounded up to %u bits\n"), nbits); - } - else if (algo == PUBKEY_ALGO_EDDSA) - { - if (nbits != 255 && nbits != 441) - { - if (nbits < 256) - nbits = 255; - else - nbits = 441; - if (!autocomp) - tty_printf (_("rounded to %u bits\n"), nbits); - } - } - else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) - { - if (nbits != 256 && nbits != 384 && nbits != 521) - { - if (nbits < 256) - nbits = 256; - else if (nbits < 384) - nbits = 384; - else - nbits = 521; - if (!autocomp) - tty_printf (_("rounded to %u bits\n"), nbits); - } - } - else if ((nbits % 32)) - { - nbits = ((nbits + 31) / 32) * 32; - if (!autocomp) - tty_printf (_("rounded up to %u bits\n"), nbits ); - } - - return nbits; -} - - -/* Ask for the curve. ALGO is the selected algorithm which this - function may adjust. Returns a malloced string with the name of - the curve. BOTH tells that gpg creates a primary and subkey. */ -static char * -ask_curve (int *algo, int *subkey_algo) -{ - struct { - const char *name; - int available; - int expert_only; - int fix_curve; - const char *pretty_name; - } curves[] = { -#if GPG_USE_EDDSA - { "Curve25519", 0, 0, 1, "Curve 25519" }, -#endif -#if GPG_USE_ECDSA || GPG_USE_ECDH - { "NIST P-256", 0, 1, 0, }, - { "NIST P-384", 0, 0, 0, }, - { "NIST P-521", 0, 1, 0, }, - { "brainpoolP256r1", 0, 1, 0, "Brainpool P-256" }, - { "brainpoolP384r1", 0, 1, 0, "Brainpool P-384" }, - { "brainpoolP512r1", 0, 1, 0, "Brainpool P-512" }, - { "secp256k1", 0, 1, 0 }, -#endif - }; - int idx; - char *answer; - char *result = NULL; - gcry_sexp_t keyparms; - - tty_printf (_("Please select which elliptic curve you want:\n")); - - again: - keyparms = NULL; - for (idx=0; idx < DIM(curves); idx++) - { - int rc; - - curves[idx].available = 0; - if (!opt.expert && curves[idx].expert_only) - continue; - - /* FIXME: The strcmp below is a temporary hack during - development. It shall be removed as soon as we have proper - Curve25519 support in Libgcrypt. */ - gcry_sexp_release (keyparms); - rc = gcry_sexp_build (&keyparms, NULL, - "(public-key(ecc(curve %s)))", - (!strcmp (curves[idx].name, "Curve25519") - ? "Ed25519" : curves[idx].name)); - if (rc) - continue; - if (!gcry_pk_get_curve (keyparms, 0, NULL)) - continue; - if (subkey_algo && curves[idx].fix_curve) - { - /* Both Curve 25519 keys are to be created. Check that - Libgcrypt also supports the real Curve25519. */ - gcry_sexp_release (keyparms); - rc = gcry_sexp_build (&keyparms, NULL, - "(public-key(ecc(curve %s)))", - curves[idx].name); - if (rc) - continue; - if (!gcry_pk_get_curve (keyparms, 0, NULL)) - continue; - } - - curves[idx].available = 1; - tty_printf (" (%d) %s\n", idx + 1, - curves[idx].pretty_name? - curves[idx].pretty_name:curves[idx].name); - } - gcry_sexp_release (keyparms); - - - for (;;) - { - answer = cpr_get ("keygen.curve", _("Your selection? ")); - cpr_kill_prompt (); - idx = *answer? atoi (answer) : 1; - if (*answer && !idx) - { - /* See whether the user entered the name of the curve. */ - for (idx=0; idx < DIM(curves); idx++) - { - if (!opt.expert && curves[idx].expert_only) - continue; - if (!stricmp (curves[idx].name, answer) - || (curves[idx].pretty_name - && !stricmp (curves[idx].pretty_name, answer))) - break; - } - if (idx == DIM(curves)) - idx = -1; - } - else - idx--; - xfree(answer); - answer = NULL; - if (idx < 0 || idx >= DIM (curves) || !curves[idx].available) - tty_printf (_("Invalid selection.\n")); - else - { - if (curves[idx].fix_curve) - { - log_info ("WARNING: Curve25519 is not yet part of the" - " OpenPGP standard.\n"); - - if (!cpr_get_answer_is_yes("experimental_curve.override", - "Use this curve anyway? (y/N) ") ) - goto again; - } - - /* If the user selected a signing algorithm and Curve25519 - we need to update the algo and and the curve name. */ - if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA) - && curves[idx].fix_curve) - { - if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA) - { - *subkey_algo = PUBKEY_ALGO_EDDSA; - result = xstrdup ("Ed25519"); - } - *algo = PUBKEY_ALGO_EDDSA; - result = xstrdup ("Ed25519"); - } - else - result = xstrdup (curves[idx].name); - break; - } - } - - if (!result) - result = xstrdup (curves[0].name); - - return result; -} - - -/**************** - * Parse an expire string and return its value in seconds. - * Returns (u32)-1 on error. - * This isn't perfect since scan_isodatestr returns unix time, and - * OpenPGP actually allows a 32-bit time *plus* a 32-bit offset. - * Because of this, we only permit setting expirations up to 2106, but - * OpenPGP could theoretically allow up to 2242. I think we'll all - * just cope for the next few years until we get a 64-bit time_t or - * similar. - */ -u32 -parse_expire_string( const char *string ) -{ - int mult; - u32 seconds; - u32 abs_date = 0; - u32 curtime = make_timestamp (); - time_t tt; - - if (!*string) - seconds = 0; - else if (!strncmp (string, "seconds=", 8)) - seconds = atoi (string+8); - else if ((abs_date = scan_isodatestr(string)) - && (abs_date+86400/2) > curtime) - seconds = (abs_date+86400/2) - curtime; - else if ((tt = isotime2epoch (string)) != (time_t)(-1)) - seconds = (u32)tt - curtime; - else if ((mult = check_valid_days (string))) - seconds = atoi (string) * 86400L * mult; - else - seconds = (u32)(-1); - - return seconds; -} - -/* Parsean Creation-Date string which is either "1986-04-26" or - "19860426T042640". Returns 0 on error. */ -static u32 -parse_creation_string (const char *string) -{ - u32 seconds; - - if (!*string) - seconds = 0; - else if ( !strncmp (string, "seconds=", 8) ) - seconds = atoi (string+8); - else if ( !(seconds = scan_isodatestr (string))) - { - time_t tmp = isotime2epoch (string); - seconds = (tmp == (time_t)(-1))? 0 : tmp; - } - return seconds; -} - - -/* object == 0 for a key, and 1 for a sig */ -u32 -ask_expire_interval(int object,const char *def_expire) -{ - u32 interval; - char *answer; - - switch(object) - { - case 0: - if(def_expire) - BUG(); - tty_printf(_("Please specify how long the key should be valid.\n" - " 0 = key does not expire\n" - " = key expires in n days\n" - " w = key expires in n weeks\n" - " m = key expires in n months\n" - " y = key expires in n years\n")); - break; - - case 1: - if(!def_expire) - BUG(); - tty_printf(_("Please specify how long the signature should be valid.\n" - " 0 = signature does not expire\n" - " = signature expires in n days\n" - " w = signature expires in n weeks\n" - " m = signature expires in n months\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 */ - - answer = NULL; - for(;;) - { - u32 curtime; - - xfree(answer); - if(object==0) - answer = cpr_get("keygen.valid",_("Key is valid for? (0) ")); - else - { - char *prompt; - -#define PROMPTSTRING _("Signature is valid for? (%s) ") - /* This will actually end up larger than necessary because - of the 2 bytes for '%s' */ - prompt=xmalloc(strlen(PROMPTSTRING)+strlen(def_expire)+1); - sprintf(prompt,PROMPTSTRING,def_expire); -#undef PROMPTSTRING - - answer = cpr_get("siggen.valid",prompt); - xfree(prompt); - - if(*answer=='\0') - answer=xstrdup(def_expire); - } - cpr_kill_prompt(); - trim_spaces(answer); - curtime = make_timestamp (); - interval = parse_expire_string( answer ); - if( interval == (u32)-1 ) - { - tty_printf(_("invalid value\n")); - continue; - } - - if( !interval ) - { - tty_printf((object==0) - ? _("Key does not expire at all\n") - : _("Signature does not expire at all\n")); - } - else - { - tty_printf(object==0 - ? _("Key expires at %s\n") - : _("Signature expires at %s\n"), - asctimestamp((ulong)(curtime + interval) ) ); -#if SIZEOF_TIME_T <= 4 && !defined (HAVE_UNSIGNED_TIME_T) - 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")); - else -#endif /*SIZEOF_TIME_T*/ - if ( (time_t)((unsigned long)(curtime+interval)) < curtime ) - { - tty_printf (_("invalid value\n")); - continue; - } - } - - if( cpr_enabled() || cpr_get_answer_is_yes("keygen.valid.okay", - _("Is this correct? (y/N) ")) ) - break; - } - - xfree(answer); - return interval; -} - -u32 -ask_expiredate() -{ - u32 x = ask_expire_interval(0,NULL); - return x? make_timestamp() + x : 0; -} - - - -static PKT_user_id * -uid_from_string (const char *string) -{ - size_t n; - PKT_user_id *uid; - - n = strlen (string); - uid = xmalloc_clear (sizeof *uid + n); - uid->len = n; - strcpy (uid->name, string); - uid->ref = 1; - return uid; -} - - -/* Return true if the user id UID already exists in the keyblock. */ -static int -uid_already_in_keyblock (kbnode_t keyblock, const char *uid) -{ - PKT_user_id *uidpkt = uid_from_string (uid); - kbnode_t node; - int result = 0; - - for (node=keyblock; node && !result; node=node->next) - if (!is_deleted_kbnode (node) - && node->pkt->pkttype == PKT_USER_ID - && !cmp_user_ids (uidpkt, node->pkt->pkt.user_id)) - result = 1; - free_user_id (uidpkt); - return result; -} - - -/* Ask for a user ID. With a MODE of 1 an extra help prompt is - printed for use during a new key creation. If KEYBLOCK is not NULL - the function prevents the creation of an already existing user - ID. IF FULL is not set some prompts are not shown. */ -static char * -ask_user_id (int mode, int full, KBNODE keyblock) -{ - char *answer; - char *aname, *acomment, *amail, *uid; - - if ( !mode ) - { - /* TRANSLATORS: This is the new string telling the user what - gpg is now going to do (i.e. ask for the parts of the user - ID). Note that if you do not translate this string, a - different string will be used, which might still have - a correct translation. */ - const char *s1 = - N_("\n" - "GnuPG needs to construct a user ID to identify your key.\n" - "\n"); - const char *s2 = _(s1); - - if (!strcmp (s1, s2)) - { - /* There is no translation for the string thus we to use - the old info text. gettext has no way to tell whether - a translation is actually available, thus we need to - to compare again. */ - /* TRANSLATORS: This string is in general not anymore used - but you should keep your existing translation. In case - the new string is not translated this old string will - be used. */ - const char *s3 = N_("\n" -"You need a user ID to identify your key; " - "the software constructs the user ID\n" -"from the Real Name, Comment and Email Address in this form:\n" -" \"Heinrich Heine (Der Dichter) \"\n\n"); - const char *s4 = _(s3); - if (strcmp (s3, s4)) - s2 = s3; /* A translation exists - use it. */ - } - tty_printf ("%s", s2) ; - } - uid = aname = acomment = amail = NULL; - for(;;) { - char *p; - int fail=0; - - if( !aname ) { - for(;;) { - xfree(aname); - aname = cpr_get("keygen.name",_("Real name: ")); - trim_spaces(aname); - cpr_kill_prompt(); - - if( opt.allow_freeform_uid ) - break; - - if( strpbrk( aname, "<>" ) ) - { - tty_printf(_("Invalid character in name\n")); - tty_printf(_("The characters '%s' and '%s' may not " - "appear in name\n"), "<", ">"); - } - else if( digitp(aname) ) - tty_printf(_("Name may not start with a digit\n")); - else if( strlen(aname) < 5 ) - tty_printf(_("Name must be at least 5 characters long\n")); - else - break; - } - } - if( !amail ) { - for(;;) { - xfree(amail); - amail = cpr_get("keygen.email",_("Email address: ")); - trim_spaces(amail); - cpr_kill_prompt(); - if( !*amail || opt.allow_freeform_uid ) - break; /* no email address is okay */ - else if ( !is_valid_mailbox (amail) ) - tty_printf(_("Not a valid email address\n")); - else - break; - } - } - if (!acomment) { - if (full) { - for(;;) { - xfree(acomment); - acomment = cpr_get("keygen.comment",_("Comment: ")); - trim_spaces(acomment); - cpr_kill_prompt(); - if( !*acomment ) - break; /* no comment is okay */ - else if( strpbrk( acomment, "()" ) ) - tty_printf(_("Invalid character in comment\n")); - else - break; - } - } - else { - xfree (acomment); - acomment = xstrdup (""); - } - } - - - xfree(uid); - uid = p = xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10); - p = stpcpy(p, aname ); - if( *acomment ) - p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")"); - if( *amail ) - p = stpcpy(stpcpy(stpcpy(p," <"), amail),">"); - - /* Append a warning if the RNG is switched into fake mode. */ - if ( random_is_faked () ) - strcpy(p, " (insecure!)" ); - - /* print a note in case that UTF8 mapping has to be done */ - for(p=uid; *p; p++ ) { - if( *p & 0x80 ) { - tty_printf(_("You are using the '%s' character set.\n"), - get_native_charset() ); - break; - } - } - - tty_printf(_("You selected this USER-ID:\n \"%s\"\n\n"), uid); - - if( !*amail && !opt.allow_freeform_uid - && (strchr( aname, '@' ) || strchr( acomment, '@'))) { - fail = 1; - tty_printf(_("Please don't put the email address " - "into the real name or the comment\n") ); - } - - if (!fail && keyblock) - { - if (uid_already_in_keyblock (keyblock, uid)) - { - tty_printf (_("Such a user ID already exists on this key!\n")); - fail = 1; - } - } - - for(;;) { - /* TRANSLATORS: These are the allowed answers in - lower and uppercase. Below you will find the matching - string which should be translated accordingly and the - letter changed to match the one in the answer string. - - n = Change name - c = Change comment - e = Change email - o = Okay (ready, continue) - q = Quit - */ - const char *ansstr = _("NnCcEeOoQq"); - - if( strlen(ansstr) != 10 ) - BUG(); - if( cpr_enabled() ) { - answer = xstrdup (ansstr + (fail?8:6)); - answer[1] = 0; - } - else if (full) { - answer = cpr_get("keygen.userid.cmd", fail? - _("Change (N)ame, (C)omment, (E)mail or (Q)uit? ") : - _("Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? ")); - cpr_kill_prompt(); - } - else { - answer = cpr_get("keygen.userid.cmd", fail? - _("Change (N)ame, (E)mail, or (Q)uit? ") : - _("Change (N)ame, (E)mail, or (O)kay/(Q)uit? ")); - cpr_kill_prompt(); - } - if( strlen(answer) > 1 ) - ; - else if( *answer == ansstr[0] || *answer == ansstr[1] ) { - xfree(aname); aname = NULL; - break; - } - else if( *answer == ansstr[2] || *answer == ansstr[3] ) { - xfree(acomment); acomment = NULL; - break; - } - else if( *answer == ansstr[4] || *answer == ansstr[5] ) { - xfree(amail); amail = NULL; - break; - } - else if( *answer == ansstr[6] || *answer == ansstr[7] ) { - if( fail ) { - tty_printf(_("Please correct the error first\n")); - } - else { - xfree(aname); aname = NULL; - xfree(acomment); acomment = NULL; - xfree(amail); amail = NULL; - break; - } - } - else if( *answer == ansstr[8] || *answer == ansstr[9] ) { - xfree(aname); aname = NULL; - xfree(acomment); acomment = NULL; - xfree(amail); amail = NULL; - xfree(uid); uid = NULL; - break; - } - xfree(answer); - } - xfree(answer); - if (!amail && !acomment) - break; - xfree(uid); uid = NULL; - } - if( uid ) { - char *p = native_to_utf8( uid ); - xfree( uid ); - uid = p; - } - return uid; -} - - -/* MODE 0 - standard - 1 - Ask for passphrase of the card backup key. */ -#if 0 -static DEK * -do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled) -{ - DEK *dek = NULL; - STRING2KEY *s2k; - const char *errtext = NULL; - const char *custdesc = NULL; - - tty_printf(_("You need a Passphrase to protect your secret key.\n\n") ); - - if (mode == 1) - custdesc = _("Please enter a passphrase to protect the off-card " - "backup of the new encryption key."); - - s2k = xmalloc_secure( sizeof *s2k ); - for(;;) { - s2k->mode = opt.s2k_mode; - s2k->hash_algo = S2K_DIGEST_ALGO; - dek = passphrase_to_dek_ext (NULL, 0, opt.s2k_cipher_algo, s2k, 2, - errtext, custdesc, NULL, r_canceled); - if (!dek && *r_canceled) { - xfree(dek); dek = NULL; - xfree(s2k); s2k = NULL; - break; - } - else if( !dek ) { - errtext = N_("passphrase not correctly repeated; try again"); - tty_printf(_("%s.\n"), _(errtext)); - } - else if( !dek->keylen ) { - xfree(dek); dek = NULL; - xfree(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" - "using this program with the option \"--edit-key\".\n\n")); - break; - } - else - break; /* okay */ - } - *ret_s2k = s2k; - return dek; -} -#endif /* 0 */ - - -/* Basic key generation. Here we divert to the actual generation - routines based on the requested algorithm. */ -static int -do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root, - u32 timestamp, u32 expiredate, int is_subkey, - int keygen_flags, const char *passphrase, char **cache_nonce_addr) -{ - gpg_error_t err; - - /* Fixme: The entropy collecting message should be moved to a - libgcrypt progress handler. */ - if (!opt.batch) - tty_printf (_( -"We need to generate a lot of random bytes. It is a good idea to perform\n" -"some other action (type on the keyboard, move the mouse, utilize the\n" -"disks) during the prime generation; this gives the random number\n" -"generator a better chance to gain enough entropy.\n") ); - - if (algo == PUBKEY_ALGO_ELGAMAL_E) - err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey, - keygen_flags, passphrase, cache_nonce_addr); - else if (algo == PUBKEY_ALGO_DSA) - err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey, - keygen_flags, passphrase, cache_nonce_addr); - else if (algo == PUBKEY_ALGO_ECDSA - || algo == PUBKEY_ALGO_EDDSA - || algo == PUBKEY_ALGO_ECDH) - err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey, - keygen_flags, passphrase, cache_nonce_addr); - else if (algo == PUBKEY_ALGO_RSA) - err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey, - keygen_flags, passphrase, cache_nonce_addr); - else - BUG(); - - return err; -} - - -/* Generate a new user id packet or return NULL if canceled. If - KEYBLOCK is not NULL the function prevents the creation of an - already existing user ID. If UIDSTR is not NULL the user is not - asked but UIDSTR is used to create the user id packet; if the user - id already exists NULL is returned. UIDSTR is expected to be utf-8 - encoded and should have already been checked for a valid length - etc. */ -PKT_user_id * -generate_user_id (KBNODE keyblock, const char *uidstr) -{ - PKT_user_id *uid; - char *p; - - if (uidstr) - { - if (uid_already_in_keyblock (keyblock, uidstr)) - return NULL; /* Already exists. */ - uid = uid_from_string (uidstr); - } - else - { - p = ask_user_id (1, 1, keyblock); - if (!p) - return NULL; /* Canceled. */ - uid = uid_from_string (p); - xfree (p); - } - return uid; -} - - -/* Append R to the linked list PARA. */ -static void -append_to_parameter (struct para_data_s *para, struct para_data_s *r) -{ - assert (para); - while (para->next) - para = para->next; - para->next = r; -} - -/* Release the parameter list R. */ -static void -release_parameter_list (struct para_data_s *r) -{ - struct para_data_s *r2; - - for (; r ; r = r2) - { - r2 = r->next; - if (r->key == pPASSPHRASE && *r->u.value) - wipememory (r->u.value, strlen (r->u.value)); - xfree (r); - } -} - -static struct para_data_s * -get_parameter( struct para_data_s *para, enum para_name key ) -{ - struct para_data_s *r; - - for( r = para; r && r->key != key; r = r->next ) - ; - return r; -} - -static const char * -get_parameter_value( struct para_data_s *para, enum para_name key ) -{ - struct para_data_s *r = get_parameter( para, key ); - return (r && *r->u.value)? r->u.value : NULL; -} - - -/* This is similar to get_parameter_value but also returns the empty - string. This is required so that quick_generate_keypair can use an - empty Passphrase to specify no-protection. */ -static const char * -get_parameter_passphrase (struct para_data_s *para) -{ - struct para_data_s *r = get_parameter (para, pPASSPHRASE); - return r ? r->u.value : NULL; -} - - -static int -get_parameter_algo( struct para_data_s *para, enum para_name key, - int *r_default) -{ - int i; - struct para_data_s *r = get_parameter( para, key ); - - if (r_default) - *r_default = 0; - - if (!r) - return -1; - - /* Note that we need to handle the ECC algorithms specified as - strings directly because Libgcrypt folds them all to ECC. */ - if (!ascii_strcasecmp (r->u.value, "default")) - { - /* Note: If you change this default algo, remember to change it - also in gpg.c:gpgconf_list. */ - i = DEFAULT_STD_ALGO; - if (r_default) - *r_default = 1; - } - else if (digitp (r->u.value)) - i = atoi( r->u.value ); - else if (!strcmp (r->u.value, "ELG-E") - || !strcmp (r->u.value, "ELG")) - i = PUBKEY_ALGO_ELGAMAL_E; - else if (!ascii_strcasecmp (r->u.value, "EdDSA")) - i = PUBKEY_ALGO_EDDSA; - else if (!ascii_strcasecmp (r->u.value, "ECDSA")) - i = PUBKEY_ALGO_ECDSA; - else if (!ascii_strcasecmp (r->u.value, "ECDH")) - i = PUBKEY_ALGO_ECDH; - else - i = map_pk_gcry_to_openpgp (gcry_pk_map_name (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. Returns -1 on - * error, 0 for no usage given or 1 for usage available. - */ -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 if ( !ascii_strcasecmp (p, "auth") ) - use |= PUBKEY_USAGE_AUTH; - else { - log_error("%s:%d: invalid usage list\n", fname, r->lnr ); - return -1; /* error */ - } - } - r->u.usage = use; - return 1; -} - -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;iu.revkey,&revkey,sizeof(struct revocation_key)); - - return 0; - - fail: - log_error("%s:%d: invalid revocation key\n", fname, r->lnr ); - return -1; /* error */ -} - - -static u32 -get_parameter_u32( struct para_data_s *para, enum para_name key ) -{ - struct para_data_s *r = get_parameter( para, key ); - - if( !r ) - return 0; - if( r->key == pKEYCREATIONDATE ) - return r->u.creation; - 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 ); -} - -static unsigned int -get_parameter_uint( struct para_data_s *para, enum para_name key ) -{ - return get_parameter_u32( para, key ); -} - -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 (ctrl_t ctrl, struct para_data_s *para, const char *fname, - struct output_control_s *outctrl, int card ) -{ - struct para_data_s *r; - const char *s1, *s2, *s3; - size_t n; - char *p; - int is_default = 0; - int have_user_id = 0; - int err, algo; - - /* Check that we have all required parameters. */ - r = get_parameter( para, pKEYTYPE ); - if(r) - { - algo = get_parameter_algo (para, pKEYTYPE, &is_default); - if (openpgp_pk_test_algo2 (algo, PUBKEY_USAGE_SIG)) - { - log_error ("%s:%d: invalid algorithm\n", fname, r->lnr ); - return -1; - } - } - else - { - log_error ("%s: no Key-Type specified\n",fname); - return -1; - } - - err = parse_parameter_usage (fname, para, pKEYUSAGE); - if (!err) - { - /* Default to algo capabilities if key-usage is not provided and - no default algorithm has been requested. */ - r = xmalloc_clear(sizeof(*r)); - r->key = pKEYUSAGE; - r->u.usage = (is_default - ? (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG) - : openpgp_pk_algo_usage(algo)); - append_to_parameter (para, r); - } - else if (err == -1) - return -1; - else - { - r = get_parameter (para, pKEYUSAGE); - if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo))) - { - log_error ("%s:%d: specified Key-Usage not allowed for algo %d\n", - fname, r->lnr, algo); - return -1; - } - } - - is_default = 0; - r = get_parameter( para, pSUBKEYTYPE ); - if(r) - { - algo = get_parameter_algo (para, pSUBKEYTYPE, &is_default); - if (openpgp_pk_test_algo (algo)) - { - log_error ("%s:%d: invalid algorithm\n", fname, r->lnr ); - return -1; - } - - err = parse_parameter_usage (fname, para, pSUBKEYUSAGE); - if (!err) - { - /* Default to algo capabilities if subkey-usage is not - provided */ - r = xmalloc_clear (sizeof(*r)); - r->key = pSUBKEYUSAGE; - r->u.usage = (is_default - ? PUBKEY_USAGE_ENC - : openpgp_pk_algo_usage (algo)); - append_to_parameter (para, r); - } - else if (err == -1) - return -1; - else - { - r = get_parameter (para, pSUBKEYUSAGE); - if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo))) - { - log_error ("%s:%d: specified Subkey-Usage not allowed" - " for algo %d\n", fname, r->lnr, algo); - return -1; - } - } - } - - - if( get_parameter_value( para, pUSERID ) ) - have_user_id=1; - else - { - /* create the formatted user ID */ - s1 = get_parameter_value( para, pNAMEREAL ); - s2 = get_parameter_value( para, pNAMECOMMENT ); - s3 = get_parameter_value( para, pNAMEEMAIL ); - if( s1 || s2 || s3 ) - { - n = (s1?strlen(s1):0) + (s2?strlen(s2):0) + (s3?strlen(s3):0); - r = xmalloc_clear( sizeof *r + n + 20 ); - r->key = pUSERID; - p = r->u.value; - if( s1 ) - p = stpcpy(p, s1 ); - if( s2 ) - p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")"); - if( s3 ) - p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">"); - append_to_parameter (para, r); - have_user_id=1; - } - } - - if(!have_user_id) - { - log_error("%s: no User-ID specified\n",fname); - return -1; - } - - /* Set preferences, if any. */ - keygen_set_std_prefs(get_parameter_value( para, pPREFERENCES ), 0); - - /* Set keyserver, if any. */ - s1=get_parameter_value( para, pKEYSERVER ); - if(s1) - { - struct keyserver_spec *spec; - - spec = parse_keyserver_uri (s1, 1); - if(spec) - { - free_keyserver_spec(spec); - opt.def_keyserver_url=s1; - } - else - { - log_error("%s:%d: invalid keyserver url\n", fname, r->lnr ); - return -1; - } - } - - /* Set revoker, if any. */ - if (parse_revocation_key (fname, para, pREVOKER)) - return -1; - - - /* Make KEYCREATIONDATE from Creation-Date. */ - r = get_parameter (para, pCREATIONDATE); - if (r && *r->u.value) - { - u32 seconds; - - seconds = parse_creation_string (r->u.value); - if (!seconds) - { - log_error ("%s:%d: invalid creation date\n", fname, r->lnr ); - return -1; - } - r->u.creation = seconds; - r->key = pKEYCREATIONDATE; /* Change that entry. */ - } - - /* Make KEYEXPIRE from Expire-Date. */ - r = get_parameter( para, pEXPIREDATE ); - if( r && *r->u.value ) - { - u32 seconds; - - seconds = parse_expire_string( r->u.value ); - if( seconds == (u32)-1 ) - { - log_error("%s:%d: invalid expire date\n", fname, r->lnr ); - return -1; - } - r->u.expire = seconds; - r->key = pKEYEXPIRE; /* change hat entry */ - /* also set it for the subkey */ - r = xmalloc_clear( sizeof *r + 20 ); - r->key = pSUBKEYEXPIRE; - r->u.expire = seconds; - append_to_parameter (para, r); - } - - do_generate_keypair (ctrl, para, outctrl, card ); - return 0; -} - - -/**************** - * Kludge to allow non interactive key generation controlled - * by a parameter file. - * Note, that string parameters are expected to be in UTF-8 - */ -static void -read_parameter_file (ctrl_t ctrl, const char *fname ) -{ - static struct { const char *name; - enum para_name key; - } keywords[] = { - { "Key-Type", pKEYTYPE}, - { "Key-Length", pKEYLENGTH }, - { "Key-Curve", pKEYCURVE }, - { "Key-Usage", pKEYUSAGE }, - { "Subkey-Type", pSUBKEYTYPE }, - { "Subkey-Length", pSUBKEYLENGTH }, - { "Subkey-Curve", pSUBKEYCURVE }, - { "Subkey-Usage", pSUBKEYUSAGE }, - { "Name-Real", pNAMEREAL }, - { "Name-Email", pNAMEEMAIL }, - { "Name-Comment", pNAMECOMMENT }, - { "Expire-Date", pEXPIREDATE }, - { "Creation-Date", pCREATIONDATE }, - { "Passphrase", pPASSPHRASE }, - { "Preferences", pPREFERENCES }, - { "Revoker", pREVOKER }, - { "Handle", pHANDLE }, - { "Keyserver", pKEYSERVER }, - { NULL, 0 } - }; - IOBUF fp; - byte *line; - unsigned int maxlen, nline; - char *p; - int lnr; - const char *err = NULL; - struct para_data_s *para, *r; - int i; - struct output_control_s outctrl; - - memset( &outctrl, 0, sizeof( outctrl ) ); - outctrl.pub.afx = new_armor_context (); - - if( !fname || !*fname) - fname = "-"; - - fp = iobuf_open (fname); - if (fp && is_secured_file (iobuf_get_fd (fp))) - { - iobuf_close (fp); - fp = NULL; - gpg_err_set_errno (EPERM); - } - if (!fp) { - log_error (_("can't open '%s': %s\n"), fname, strerror(errno) ); - return; - } - iobuf_ioctl (fp, IOBUF_IOCTL_NO_CACHE, 1, NULL); - - lnr = 0; - err = NULL; - para = NULL; - maxlen = 1024; - line = NULL; - while ( iobuf_read_line (fp, &line, &nline, &maxlen) ) { - char *keyword, *value; - - lnr++; - if( !maxlen ) { - err = "line too long"; - break; - } - for( p = line; isspace(*(byte*)p); p++ ) - ; - if( !*p || *p == '#' ) - continue; - keyword = p; - if( *keyword == '%' ) { - for( ; !isspace(*(byte*)p); p++ ) - ; - if( *p ) - *p++ = 0; - for( ; isspace(*(byte*)p); p++ ) - ; - value = p; - trim_trailing_ws( value, strlen(value) ); - if( !ascii_strcasecmp( keyword, "%echo" ) ) - log_info("%s\n", value ); - else if( !ascii_strcasecmp( keyword, "%dry-run" ) ) - outctrl.dryrun = 1; - else if( !ascii_strcasecmp( keyword, "%ask-passphrase" ) ) - ; /* Dummy for backward compatibility. */ - else if( !ascii_strcasecmp( keyword, "%no-ask-passphrase" ) ) - ; /* Dummy for backward compatibility. */ - else if( !ascii_strcasecmp( keyword, "%no-protection" ) ) - outctrl.keygen_flags |= KEYGEN_FLAG_NO_PROTECTION; - else if( !ascii_strcasecmp( keyword, "%transient-key" ) ) - outctrl.keygen_flags |= KEYGEN_FLAG_TRANSIENT_KEY; - else if( !ascii_strcasecmp( keyword, "%commit" ) ) { - outctrl.lnr = lnr; - if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 )) - print_status_key_not_created - (get_parameter_value (para, pHANDLE)); - release_parameter_list( para ); - para = NULL; - } - else if( !ascii_strcasecmp( keyword, "%pubring" ) ) { - if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) ) - ; /* still the same file - ignore it */ - else { - xfree( outctrl.pub.newfname ); - outctrl.pub.newfname = xstrdup( value ); - outctrl.use_files = 1; - } - } - else if( !ascii_strcasecmp( keyword, "%secring" ) ) { - /* Ignore this command. */ - } - else - log_info("skipping control '%s' (%s)\n", keyword, value ); - - - continue; - } - - - if( !(p = strchr( p, ':' )) || p == keyword ) { - err = "missing colon"; - break; - } - if( *p ) - *p++ = 0; - for( ; isspace(*(byte*)p); p++ ) - ; - if( !*p ) { - err = "missing argument"; - break; - } - value = p; - trim_trailing_ws( value, strlen(value) ); - - for(i=0; keywords[i].name; i++ ) { - if( !ascii_strcasecmp( keywords[i].name, keyword ) ) - break; - } - if( !keywords[i].name ) { - err = "unknown keyword"; - break; - } - if( keywords[i].key != pKEYTYPE && !para ) { - err = "parameter block does not start with \"Key-Type\""; - break; - } - - if( keywords[i].key == pKEYTYPE && para ) { - outctrl.lnr = lnr; - if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 )) - print_status_key_not_created - (get_parameter_value (para, pHANDLE)); - release_parameter_list( para ); - para = NULL; - } - else { - for( r = para; r; r = r->next ) { - if( r->key == keywords[i].key ) - break; - } - if( r ) { - err = "duplicate keyword"; - break; - } - } - r = xmalloc_clear( sizeof *r + strlen( value ) ); - r->lnr = lnr; - r->key = keywords[i].key; - strcpy( r->u.value, value ); - r->next = para; - para = r; - } - if( err ) - log_error("%s:%d: %s\n", fname, lnr, err ); - else if( iobuf_error (fp) ) { - log_error("%s:%d: read error\n", fname, lnr); - } - else if( para ) { - outctrl.lnr = lnr; - if (proc_parameter_file (ctrl, para, fname, &outctrl, 0 )) - print_status_key_not_created (get_parameter_value (para, pHANDLE)); - } - - if( outctrl.use_files ) { /* close open streams */ - iobuf_close( outctrl.pub.stream ); - - /* Must invalidate that ugly cache to actually close it. */ - if (outctrl.pub.fname) - iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, - 0, (char*)outctrl.pub.fname); - - xfree( outctrl.pub.fname ); - xfree( outctrl.pub.newfname ); - } - - release_parameter_list( para ); - iobuf_close (fp); - release_armor_context (outctrl.pub.afx); -} - - -/* Helper for quick_generate_keypair. */ -static struct para_data_s * -quickgen_set_para (struct para_data_s *para, int for_subkey, - int algo, int nbits, const char *curve) -{ - struct para_data_s *r; - - r = xmalloc_clear (sizeof *r + 20); - r->key = for_subkey? pSUBKEYUSAGE : pKEYUSAGE; - strcpy (r->u.value, for_subkey ? "encrypt" : "sign"); - r->next = para; - para = r; - r = xmalloc_clear (sizeof *r + 20); - r->key = for_subkey? pSUBKEYTYPE : pKEYTYPE; - sprintf (r->u.value, "%d", algo); - r->next = para; - para = r; - - if (curve) - { - r = xmalloc_clear (sizeof *r + strlen (curve)); - r->key = for_subkey? pSUBKEYCURVE : pKEYCURVE; - strcpy (r->u.value, curve); - r->next = para; - para = r; - } - else - { - r = xmalloc_clear (sizeof *r + 20); - r->key = for_subkey? pSUBKEYLENGTH : pKEYLENGTH; - sprintf (r->u.value, "%u", nbits); - r->next = para; - para = r; - } - - return para; -} - - -/* - * Unattended generation of a standard key. - */ -void -quick_generate_keypair (ctrl_t ctrl, const char *uid) -{ - gpg_error_t err; - struct para_data_s *para = NULL; - struct para_data_s *r; - struct output_control_s outctrl; - int use_tty; - - memset (&outctrl, 0, sizeof outctrl); - - use_tty = (!opt.batch && !opt.answer_yes - && !cpr_enabled () - && gnupg_isatty (fileno (stdin)) - && gnupg_isatty (fileno (stdout)) - && gnupg_isatty (fileno (stderr))); - - r = xmalloc_clear (sizeof *r + strlen (uid)); - r->key = pUSERID; - strcpy (r->u.value, uid); - r->next = para; - para = r; - - uid = trim_spaces (r->u.value); - if (!*uid || (!opt.allow_freeform_uid && !is_valid_user_id (uid))) - { - log_error (_("Key generation failed: %s\n"), - gpg_strerror (GPG_ERR_INV_USER_ID)); - goto leave; - } - - /* If gpg is directly used on the console ask whether a key with the - given user id shall really be created. */ - if (use_tty) - { - tty_printf (_("About to create a key for:\n \"%s\"\n\n"), uid); - if (!cpr_get_answer_is_yes_def ("quick_keygen.okay", - _("Continue? (Y/n) "), 1)) - goto leave; - } - - /* Check whether such a user ID already exists. */ - { - KEYDB_HANDLE kdbhd; - KEYDB_SEARCH_DESC desc; - - memset (&desc, 0, sizeof desc); - desc.mode = KEYDB_SEARCH_MODE_EXACT; - desc.u.name = uid; - - kdbhd = keydb_new (); - if (!kdbhd) - goto leave; - - err = keydb_search (kdbhd, &desc, 1, NULL); - keydb_release (kdbhd); - if (gpg_err_code (err) != GPG_ERR_NOT_FOUND) - { - log_info (_("A key for \"%s\" already exists\n"), uid); - if (opt.answer_yes) - ; - else if (!use_tty - || !cpr_get_answer_is_yes_def ("quick_keygen.force", - _("Create anyway? (y/N) "), 0)) - { - log_inc_errorcount (); /* we used log_info */ - goto leave; - } - log_info (_("creating anyway\n")); - } - } - - para = quickgen_set_para (para, 0, - DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE, - DEFAULT_STD_CURVE); - para = quickgen_set_para (para, 1, - DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE, - DEFAULT_STD_SUBCURVE); - - /* If the pinentry loopback mode is not and we have a static - passphrase (i.e. set with --passphrase{,-fd,-file} while in batch - mode), we use that passphrase for the new key. */ - if (opt.pinentry_mode != PINENTRY_MODE_LOOPBACK - && have_static_passphrase ()) - { - const char *s = get_static_passphrase (); - - r = xmalloc_clear (sizeof *r + strlen (s)); - r->key = pPASSPHRASE; - strcpy (r->u.value, s); - r->next = para; - para = r; - } - - proc_parameter_file (ctrl, para, "[internal]", &outctrl, 0); - leave: - release_parameter_list (para); -} - - -/* - * Generate a keypair (fname is only used in batch mode) If - * CARD_SERIALNO is not NULL the function will create the keys on an - * OpenPGP Card. If CARD_BACKUP_KEY has been set and CARD_SERIALNO is - * NOT NULL, the encryption key for the card is generated on the host, - * imported to the card and a backup file created by gpg-agent. If - * FULL is not set only the basic prompts are used (except for batch - * mode). - */ -void -generate_keypair (ctrl_t ctrl, int full, const char *fname, - const char *card_serialno, int card_backup_key) -{ - unsigned int nbits; - char *uid = NULL; - int algo; - unsigned int use; - int both = 0; - u32 expire; - struct para_data_s *para = NULL; - struct para_data_s *r; - struct output_control_s outctrl; - -#ifndef ENABLE_CARD_SUPPORT - (void)card_backup_key; -#endif - - memset( &outctrl, 0, sizeof( outctrl ) ); - - if (opt.batch && card_serialno) - { - /* We don't yet support unattended key generation. */ - log_error (_("can't do this in batch mode\n")); - return; - } - - if (opt.batch) - { - read_parameter_file (ctrl, fname); - return; - } - - if (card_serialno) - { -#ifdef ENABLE_CARD_SUPPORT - r = xcalloc (1, sizeof *r + strlen (card_serialno) ); - r->key = pSERIALNO; - strcpy( r->u.value, card_serialno); - r->next = para; - para = r; - - algo = PUBKEY_ALGO_RSA; - - r = xcalloc (1, sizeof *r + 20 ); - r->key = pKEYTYPE; - sprintf( r->u.value, "%d", algo ); - r->next = para; - para = r; - r = xcalloc (1, sizeof *r + 20 ); - r->key = pKEYUSAGE; - strcpy (r->u.value, "sign"); - r->next = para; - para = r; - - r = xcalloc (1, sizeof *r + 20 ); - r->key = pSUBKEYTYPE; - sprintf( r->u.value, "%d", algo ); - r->next = para; - para = r; - r = xcalloc (1, sizeof *r + 20 ); - r->key = pSUBKEYUSAGE; - strcpy (r->u.value, "encrypt"); - r->next = para; - para = r; - - r = xcalloc (1, sizeof *r + 20 ); - r->key = pAUTHKEYTYPE; - sprintf( r->u.value, "%d", algo ); - r->next = para; - para = r; - - if (card_backup_key) - { - r = xcalloc (1, sizeof *r + 1); - r->key = pCARDBACKUPKEY; - strcpy (r->u.value, "1"); - r->next = para; - para = r; - } -#endif /*ENABLE_CARD_SUPPORT*/ - } - else if (full) /* Full featured key generation. */ - { - int subkey_algo; - char *curve = NULL; - - /* Fixme: To support creating a primary key by keygrip we better - also define the keyword for the parameter file. Note that - the subkey case will never be asserted if a keygrip has been - given. */ - algo = ask_algo (ctrl, 0, &subkey_algo, &use, NULL); - if (subkey_algo) - { - /* Create primary and subkey at once. */ - both = 1; - if (algo == PUBKEY_ALGO_ECDSA - || algo == PUBKEY_ALGO_EDDSA - || algo == PUBKEY_ALGO_ECDH) - { - curve = ask_curve (&algo, &subkey_algo); - r = xmalloc_clear( sizeof *r + 20 ); - r->key = pKEYTYPE; - sprintf( r->u.value, "%d", algo); - r->next = para; - para = r; - nbits = 0; - r = xmalloc_clear (sizeof *r + strlen (curve)); - r->key = pKEYCURVE; - strcpy (r->u.value, curve); - r->next = para; - para = r; - } - else - { - r = xmalloc_clear( sizeof *r + 20 ); - r->key = pKEYTYPE; - sprintf( r->u.value, "%d", algo); - r->next = para; - para = r; - nbits = ask_keysize (algo, 0); - r = xmalloc_clear( sizeof *r + 20 ); - r->key = pKEYLENGTH; - sprintf( r->u.value, "%u", nbits); - r->next = para; - para = r; - } - r = xmalloc_clear( sizeof *r + 20 ); - r->key = pKEYUSAGE; - strcpy( r->u.value, "sign" ); - r->next = para; - para = r; - - r = xmalloc_clear( sizeof *r + 20 ); - r->key = pSUBKEYTYPE; - sprintf( r->u.value, "%d", subkey_algo); - r->next = para; - para = r; - r = xmalloc_clear( sizeof *r + 20 ); - r->key = pSUBKEYUSAGE; - strcpy( r->u.value, "encrypt" ); - r->next = para; - para = r; - - if (algo == PUBKEY_ALGO_ECDSA - || algo == PUBKEY_ALGO_EDDSA - || algo == PUBKEY_ALGO_ECDH) - { - if (algo == PUBKEY_ALGO_EDDSA - && subkey_algo == PUBKEY_ALGO_ECDH) - { - /* Need to switch to a different curve for the - encryption key. */ - xfree (curve); - curve = xstrdup ("Curve25519"); - } - r = xmalloc_clear (sizeof *r + strlen (curve)); - r->key = pSUBKEYCURVE; - strcpy (r->u.value, curve); - r->next = para; - para = r; - } - } - else /* Create only a single key. */ - { - /* For ECC we need to ask for the curve before storing the - algo because ask_curve may change the algo. */ - if (algo == PUBKEY_ALGO_ECDSA - || algo == PUBKEY_ALGO_EDDSA - || algo == PUBKEY_ALGO_ECDH) - { - curve = ask_curve (&algo, NULL); - nbits = 0; - r = xmalloc_clear (sizeof *r + strlen (curve)); - r->key = pKEYCURVE; - strcpy (r->u.value, curve); - r->next = para; - para = r; - } - - r = xmalloc_clear( sizeof *r + 20 ); - r->key = pKEYTYPE; - sprintf( r->u.value, "%d", algo ); - r->next = para; - para = r; - - if (use) - { - r = xmalloc_clear( sizeof *r + 25 ); - r->key = pKEYUSAGE; - sprintf( r->u.value, "%s%s%s", - (use & PUBKEY_USAGE_SIG)? "sign ":"", - (use & PUBKEY_USAGE_ENC)? "encrypt ":"", - (use & PUBKEY_USAGE_AUTH)? "auth":"" ); - r->next = para; - para = r; - } - nbits = 0; - } - - if (algo == PUBKEY_ALGO_ECDSA - || algo == PUBKEY_ALGO_EDDSA - || algo == PUBKEY_ALGO_ECDH) - { - /* The curve has already been set. */ - } - else - { - nbits = ask_keysize (both? subkey_algo : algo, nbits); - r = xmalloc_clear( sizeof *r + 20 ); - r->key = both? pSUBKEYLENGTH : pKEYLENGTH; - sprintf( r->u.value, "%u", nbits); - r->next = para; - para = r; - } - - xfree (curve); - } - else /* Default key generation. */ - { - tty_printf ( _("Note: Use \"%s %s\"" - " for a full featured key generation dialog.\n"), - NAME_OF_INSTALLED_GPG, "--full-gen-key" ); - para = quickgen_set_para (para, 0, - DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE, - DEFAULT_STD_CURVE); - para = quickgen_set_para (para, 1, - DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE, - DEFAULT_STD_SUBCURVE); - } - - - expire = full? ask_expire_interval (0, NULL) : 0; - r = xcalloc (1, sizeof *r + 20); - r->key = pKEYEXPIRE; - r->u.expire = expire; - r->next = para; - para = r; - r = xcalloc (1, sizeof *r + 20); - r->key = pSUBKEYEXPIRE; - r->u.expire = expire; - r->next = para; - para = r; - - uid = ask_user_id (0, full, NULL); - if (!uid) - { - log_error(_("Key generation canceled.\n")); - release_parameter_list( para ); - return; - } - r = xcalloc (1, sizeof *r + strlen (uid)); - r->key = pUSERID; - strcpy (r->u.value, uid); - r->next = para; - para = r; - - proc_parameter_file (ctrl, para, "[internal]", &outctrl, !!card_serialno); - release_parameter_list (para); -} - - -#if 0 /* not required */ -/* Generate a raw key and return it as a secret key packet. The - function will ask for the passphrase and return a protected as well - as an unprotected copy of a new secret key packet. 0 is returned - on success and the caller must then free the returned values. */ -static int -generate_raw_key (int algo, unsigned int nbits, u32 created_at, - PKT_secret_key **r_sk_unprotected, - PKT_secret_key **r_sk_protected) -{ - int rc; - DEK *dek = NULL; - STRING2KEY *s2k = NULL; - PKT_secret_key *sk = NULL; - int i; - size_t nskey, npkey; - gcry_sexp_t s_parms, s_key; - int canceled; - - npkey = pubkey_get_npkey (algo); - nskey = pubkey_get_nskey (algo); - assert (nskey <= PUBKEY_MAX_NSKEY && npkey < nskey); - - if (nbits < 512) - { - nbits = 512; - log_info (_("keysize invalid; using %u bits\n"), nbits ); - } - - if ((nbits % 32)) - { - nbits = ((nbits + 31) / 32) * 32; - log_info(_("keysize rounded up to %u bits\n"), nbits ); - } - - dek = do_ask_passphrase (&s2k, 1, &canceled); - if (canceled) - { - rc = gpg_error (GPG_ERR_CANCELED); - goto leave; - } - - sk = xmalloc_clear (sizeof *sk); - sk->timestamp = created_at; - sk->version = 4; - sk->pubkey_algo = algo; - - if ( !is_RSA (algo) ) - { - log_error ("only RSA is supported for offline generated keys\n"); - rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); - goto leave; - } - rc = gcry_sexp_build (&s_parms, NULL, - "(genkey(rsa(nbits %d)))", - (int)nbits); - if (rc) - log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc)); - rc = gcry_pk_genkey (&s_key, s_parms); - gcry_sexp_release (s_parms); - if (rc) - { - log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) ); - goto leave; - } - rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu"); - gcry_sexp_release (s_key); - if (rc) - { - log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) ); - goto leave; - } - - for (i=npkey; i < nskey; i++) - sk->csum += checksum_mpi (sk->skey[i]); - - if (r_sk_unprotected) - *r_sk_unprotected = copy_secret_key (NULL, sk); - - rc = genhelp_protect (dek, s2k, sk); - if (rc) - goto leave; - - if (r_sk_protected) - { - *r_sk_protected = sk; - sk = NULL; - } - - leave: - if (sk) - free_secret_key (sk); - xfree (dek); - xfree (s2k); - return rc; -} -#endif /* ENABLE_CARD_SUPPORT */ - -/* Create and delete a dummy packet to start off a list of kbnodes. */ -static void -start_tree(KBNODE *tree) -{ - PACKET *pkt; - - pkt=xmalloc_clear(sizeof(*pkt)); - pkt->pkttype=PKT_NONE; - *tree=new_kbnode(pkt); - delete_kbnode(*tree); -} - - -static void -do_generate_keypair (ctrl_t ctrl, struct para_data_s *para, - struct output_control_s *outctrl, int card) -{ - gpg_error_t err; - KBNODE pub_root = NULL; - const char *s; - PKT_public_key *pri_psk = NULL; - PKT_public_key *sub_psk = NULL; - struct revocation_key *revkey; - int did_sub = 0; - u32 timestamp; - char *cache_nonce = NULL; - - if (outctrl->dryrun) - { - log_info("dry-run mode - key generation skipped\n"); - return; - } - - if ( outctrl->use_files ) - { - if ( outctrl->pub.newfname ) - { - iobuf_close(outctrl->pub.stream); - outctrl->pub.stream = NULL; - if (outctrl->pub.fname) - iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, - 0, (char*)outctrl->pub.fname); - xfree( outctrl->pub.fname ); - outctrl->pub.fname = outctrl->pub.newfname; - outctrl->pub.newfname = NULL; - - if (is_secured_filename (outctrl->pub.fname) ) - { - outctrl->pub.stream = NULL; - gpg_err_set_errno (EPERM); - } - else - outctrl->pub.stream = iobuf_create (outctrl->pub.fname, 0); - if (!outctrl->pub.stream) - { - log_error(_("can't create '%s': %s\n"), outctrl->pub.newfname, - strerror(errno) ); - return; - } - if (opt.armor) - { - outctrl->pub.afx->what = 1; - push_armor_filter (outctrl->pub.afx, outctrl->pub.stream); - } - } - assert( outctrl->pub.stream ); - if (opt.verbose) - log_info (_("writing public key to '%s'\n"), outctrl->pub.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. The first packet is a dummy packet which we flag as - deleted. The very first packet must always be a KEY packet. */ - - start_tree (&pub_root); - - timestamp = get_parameter_u32 (para, pKEYCREATIONDATE); - if (!timestamp) - timestamp = make_timestamp (); - - /* Note that, depending on the backend (i.e. the used scdaemon - version), the card key generation may update TIMESTAMP for each - key. Thus we need to pass TIMESTAMP to all signing function to - make sure that the binding signature is done using the timestamp - of the corresponding (sub)key and not that of the primary key. - An alternative implementation could tell the signing function the - node of the subkey but that is more work than just to pass the - current timestamp. */ - - if (!card) - err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ), - get_parameter_uint( para, pKEYLENGTH ), - get_parameter_value (para, pKEYCURVE), - pub_root, - timestamp, - get_parameter_u32( para, pKEYEXPIRE ), 0, - outctrl->keygen_flags, - get_parameter_passphrase (para), - &cache_nonce); - else - err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, - ×tamp, - get_parameter_u32 (para, pKEYEXPIRE)); - - /* Get the pointer to the generated public key packet. */ - if (!err) - { - pri_psk = pub_root->next->pkt->pkt.public_key; - assert (pri_psk); - } - - if (!err && (revkey = get_parameter_revkey (para, pREVOKER))) - err = write_direct_sig (pub_root, pri_psk, revkey, timestamp, cache_nonce); - - if (!err && (s = get_parameter_value (para, pUSERID))) - { - write_uid (pub_root, s ); - err = write_selfsigs (pub_root, pri_psk, - get_parameter_uint (para, pKEYUSAGE), timestamp, - cache_nonce); - } - - /* Write the auth key to the card before the encryption key. This - is a partial workaround for a PGP bug (as of this writing, all - versions including 8.1), that causes it to try and encrypt to - the most recent subkey regardless of whether that subkey is - actually an encryption type. In this case, the auth key is an - RSA key so it succeeds. */ - - if (!err && card && get_parameter (para, pAUTHKEYTYPE)) - { - err = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, - ×tamp, - get_parameter_u32 (para, pKEYEXPIRE)); - if (!err) - err = write_keybinding (pub_root, pri_psk, NULL, - PUBKEY_USAGE_AUTH, timestamp, cache_nonce); - } - - if (!err && get_parameter (para, pSUBKEYTYPE)) - { - sub_psk = NULL; - if (!card) - { - err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL), - get_parameter_uint (para, pSUBKEYLENGTH), - get_parameter_value (para, pSUBKEYCURVE), - pub_root, - timestamp, - get_parameter_u32 (para, pSUBKEYEXPIRE), 1, - outctrl->keygen_flags, - get_parameter_passphrase (para), - &cache_nonce); - /* Get the pointer to the generated public subkey packet. */ - if (!err) - { - kbnode_t node; - - for (node = pub_root; node; node = node->next) - if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) - sub_psk = node->pkt->pkt.public_key; - assert (sub_psk); - } - } - else - { - if ((s = get_parameter_value (para, pCARDBACKUPKEY))) - { - /* A backup of the encryption key has been requested. - Generate the key in software and import it then to - the card. Write a backup file. */ - err = gen_card_key_with_backup - (PUBKEY_ALGO_RSA, 2, 0, pub_root, timestamp, - get_parameter_u32 (para, pKEYEXPIRE), para); - } - else - { - err = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, - ×tamp, - get_parameter_u32 (para, pKEYEXPIRE)); - } - } - - if (!err) - err = write_keybinding (pub_root, pri_psk, sub_psk, - get_parameter_uint (para, pSUBKEYUSAGE), - timestamp, cache_nonce); - did_sub = 1; - } - - if (!err && outctrl->use_files) /* Direct write to specified files. */ - { - err = write_keyblock (outctrl->pub.stream, pub_root); - if (err) - log_error ("can't write public key: %s\n", gpg_strerror (err)); - } - else if (!err) /* Write to the standard keyrings. */ - { - KEYDB_HANDLE pub_hd; - - pub_hd = keydb_new (); - if (!pub_hd) - err = gpg_error_from_syserror (); - else - { - err = keydb_locate_writable (pub_hd); - if (err) - log_error (_("no writable public keyring found: %s\n"), - gpg_strerror (err)); - } - - if (!err && opt.verbose) - { - log_info (_("writing public key to '%s'\n"), - keydb_get_resource_name (pub_hd)); - } - - if (!err) - { - err = keydb_insert_keyblock (pub_hd, pub_root); - if (err) - log_error (_("error writing public keyring '%s': %s\n"), - keydb_get_resource_name (pub_hd), gpg_strerror (err)); - } - - keydb_release (pub_hd); - - if (!err) - { - int no_enc_rsa; - PKT_public_key *pk; - - no_enc_rsa = ((get_parameter_algo (para, pKEYTYPE, NULL) - == PUBKEY_ALGO_RSA) - && get_parameter_uint (para, pKEYUSAGE) - && !((get_parameter_uint (para, pKEYUSAGE) - & PUBKEY_USAGE_ENC)) ); - - pk = find_kbnode (pub_root, PKT_PUBLIC_KEY)->pkt->pkt.public_key; - - keyid_from_pk (pk, pk->main_keyid); - register_trusted_keyid (pk->main_keyid); - - update_ownertrust (pk, ((get_ownertrust (pk) & ~TRUST_MASK) - | TRUST_ULTIMATE )); - - gen_standard_revoke (pk, cache_nonce); - - if (!opt.batch) - { - tty_printf (_("public and secret key created and signed.\n") ); - tty_printf ("\n"); - list_keyblock_direct (ctrl, pub_root, 0, 1, 1); - } - - - if (!opt.batch - && (get_parameter_algo (para, pKEYTYPE, NULL) == PUBKEY_ALGO_DSA - || no_enc_rsa ) - && !get_parameter (para, pSUBKEYTYPE) ) - { - tty_printf(_("Note that this key cannot be used for " - "encryption. You may want to use\n" - "the command \"--edit-key\" to generate a " - "subkey for this purpose.\n") ); - } - } - } - - if (err) - { - if (opt.batch) - log_error ("key generation failed: %s\n", gpg_strerror (err) ); - else - tty_printf (_("Key generation failed: %s\n"), gpg_strerror (err) ); - write_status_error (card? "card_key_generate":"key_generate", err); - print_status_key_not_created ( get_parameter_value (para, pHANDLE) ); - } - else - { - PKT_public_key *pk = find_kbnode (pub_root, - PKT_PUBLIC_KEY)->pkt->pkt.public_key; - print_status_key_created (did_sub? 'B':'P', pk, - get_parameter_value (para, pHANDLE)); - } - - release_kbnode (pub_root); - xfree (cache_nonce); -} - - -/* Add a new subkey to an existing key. Returns 0 if a new key has - been generated and put into the keyblocks. */ -gpg_error_t -generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock) -{ - gpg_error_t err = 0; - kbnode_t node; - PKT_public_key *pri_psk = NULL; - PKT_public_key *sub_psk = NULL; - int algo; - unsigned int use; - u32 expire; - unsigned int nbits = 0; - char *curve = NULL; - u32 cur_time; - char *hexgrip = NULL; - char *serialno = NULL; - - /* Break out the primary key. */ - node = find_kbnode (keyblock, PKT_PUBLIC_KEY); - if (!node) - { - log_error ("Oops; primary key missing in keyblock!\n"); - err = gpg_error (GPG_ERR_BUG); - goto leave; - } - pri_psk = node->pkt->pkt.public_key; - - cur_time = make_timestamp (); - - if (pri_psk->timestamp > cur_time) - { - ulong d = pri_psk->timestamp - cur_time; - log_info ( d==1 ? _("key has been created %lu second " - "in future (time warp or clock problem)\n") - : _("key has been created %lu seconds " - "in future (time warp or clock problem)\n"), d ); - if (!opt.ignore_time_conflict) - { - err = gpg_error (GPG_ERR_TIME_CONFLICT); - goto leave; - } - } - - if (pri_psk->version < 4) - { - log_info (_("Note: creating subkeys for v3 keys " - "is not OpenPGP compliant\n")); - err = gpg_error (GPG_ERR_CONFLICT); - goto leave; - } - - err = hexkeygrip_from_pk (pri_psk, &hexgrip); - if (err) - goto leave; - if (agent_get_keyinfo (NULL, hexgrip, &serialno)) - { - tty_printf (_("Secret parts of primary key are not available.\n")); - goto leave; - } - if (serialno) - tty_printf (_("Secret parts of primary key are stored on-card.\n")); - - xfree (hexgrip); - hexgrip = NULL; - algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip); - assert (algo); - - if (hexgrip) - nbits = 0; - else if (algo == PUBKEY_ALGO_ECDSA - || algo == PUBKEY_ALGO_EDDSA - || algo == PUBKEY_ALGO_ECDH) - curve = ask_curve (&algo, NULL); - else - nbits = ask_keysize (algo, 0); - - expire = ask_expire_interval (0, NULL); - if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay", - _("Really create? (y/N) "))) - { - err = gpg_error (GPG_ERR_CANCELED); - goto leave; - } - - if (hexgrip) - err = do_create_from_keygrip (ctrl, algo, hexgrip, - keyblock, cur_time, expire, 1); - else - err = do_create (algo, nbits, curve, - keyblock, cur_time, expire, 1, 0, NULL, NULL); - if (err) - goto leave; - - /* Get the pointer to the generated public subkey packet. */ - for (node = keyblock; node; node = node->next) - if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) - sub_psk = node->pkt->pkt.public_key; - - /* Write the binding signature. */ - err = write_keybinding (keyblock, pri_psk, sub_psk, use, cur_time, NULL); - if (err) - goto leave; - - write_status_text (STATUS_KEY_CREATED, "S"); - - leave: - xfree (curve); - xfree (hexgrip); - xfree (serialno); - if (err) - log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); - return err; -} - - -#ifdef ENABLE_CARD_SUPPORT -/* Generate a subkey on a card. */ -gpg_error_t -generate_card_subkeypair (kbnode_t pub_keyblock, - int keyno, const char *serialno) -{ - gpg_error_t err = 0; - kbnode_t node; - PKT_public_key *pri_pk = NULL; - int algo; - unsigned int use; - u32 expire; - u32 cur_time; - struct para_data_s *para = NULL; - - assert (keyno >= 1 && keyno <= 3); - - para = xtrycalloc (1, sizeof *para + strlen (serialno) ); - if (!para) - { - err = gpg_error_from_syserror (); - goto leave; - } - para->key = pSERIALNO; - strcpy (para->u.value, serialno); - - /* Break out the primary secret key */ - node = find_kbnode (pub_keyblock, PKT_PUBLIC_KEY); - if (!node) - { - log_error ("Oops; publkic key lost!\n"); - err = gpg_error (GPG_ERR_INTERNAL); - goto leave; - } - pri_pk = node->pkt->pkt.public_key; - - cur_time = make_timestamp(); - if (pri_pk->timestamp > cur_time) - { - ulong d = pri_pk->timestamp - cur_time; - log_info (d==1 ? _("key has been created %lu second " - "in future (time warp or clock problem)\n") - : _("key has been created %lu seconds " - "in future (time warp or clock problem)\n"), d ); - if (!opt.ignore_time_conflict) - { - err = gpg_error (GPG_ERR_TIME_CONFLICT); - goto leave; - } - } - - if (pri_pk->version < 4) - { - log_info (_("Note: creating subkeys for v3 keys " - "is not OpenPGP compliant\n")); - err = gpg_error (GPG_ERR_NOT_SUPPORTED); - goto leave; - } - - algo = PUBKEY_ALGO_RSA; - expire = ask_expire_interval (0, NULL); - if (keyno == 1) - use = PUBKEY_USAGE_SIG; - else if (keyno == 2) - use = PUBKEY_USAGE_ENC; - else - use = PUBKEY_USAGE_AUTH; - if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.cardsub.okay", - _("Really create? (y/N) "))) - { - err = gpg_error (GPG_ERR_CANCELED); - goto leave; - } - - /* Note, that depending on the backend, the card key generation may - update CUR_TIME. */ - err = gen_card_key (algo, keyno, 0, pub_keyblock, &cur_time, expire); - /* Get the pointer to the generated public subkey packet. */ - if (!err) - { - PKT_public_key *sub_pk = NULL; - - for (node = pub_keyblock; node; node = node->next) - if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) - sub_pk = node->pkt->pkt.public_key; - assert (sub_pk); - err = write_keybinding (pub_keyblock, pri_pk, sub_pk, - use, cur_time, NULL); - } - - leave: - if (err) - log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); - else - write_status_text (STATUS_KEY_CREATED, "S"); - release_parameter_list (para); - return err; -} -#endif /* !ENABLE_CARD_SUPPORT */ - -/* - * Write a keyblock to an output stream - */ -static int -write_keyblock( IOBUF out, KBNODE node ) -{ - for( ; node ; node = node->next ) - { - if(!is_deleted_kbnode(node)) - { - int rc = build_packet( out, node->pkt ); - if( rc ) - { - log_error("build_packet(%d) failed: %s\n", - node->pkt->pkttype, gpg_strerror (rc) ); - return rc; - } - } - } - - return 0; -} - - -/* Note that timestamp is an in/out arg. */ -static gpg_error_t -gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root, - u32 *timestamp, u32 expireval) -{ -#ifdef ENABLE_CARD_SUPPORT - gpg_error_t err; - struct agent_card_genkey_s info; - PACKET *pkt; - PKT_public_key *pk; - - if (algo != PUBKEY_ALGO_RSA) - return gpg_error (GPG_ERR_PUBKEY_ALGO); - - pk = xtrycalloc (1, sizeof *pk ); - if (!pk) - return gpg_error_from_syserror (); - pkt = xtrycalloc (1, sizeof *pkt); - if (!pkt) - { - xfree (pk); - return gpg_error_from_syserror (); - } - - /* Note: SCD knows the serialnumber, thus there is no point in passing it. */ - err = agent_scd_genkey (&info, keyno, 1, NULL, *timestamp); - /* The code below is not used because we force creation of - * the a card key (3rd arg). - * if (gpg_err_code (rc) == GPG_ERR_EEXIST) - * { - * tty_printf ("\n"); - * log_error ("WARNING: key does already exists!\n"); - * tty_printf ("\n"); - * if ( cpr_get_answer_is_yes( "keygen.card.replace_key", - * _("Replace existing key? "))) - * rc = agent_scd_genkey (&info, keyno, 1); - * } - */ - if (!err && (!info.n || !info.e)) - { - log_error ("communication error with SCD\n"); - gcry_mpi_release (info.n); - gcry_mpi_release (info.e); - err = gpg_error (GPG_ERR_GENERAL); - } - if (err) - { - log_error ("key generation failed: %s\n", gpg_strerror (err)); - xfree (pkt); - xfree (pk); - return err; - } - - /* Send the learn command so that the agent creates a shadow key for - card key. We need to do that now so that we are able to create - the self-signatures. */ - err = agent_scd_learn (NULL, 0); - if (err) - { - /* Oops: Card removed during generation. */ - log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err)); - xfree (pkt); - xfree (pk); - return err; - } - - if (*timestamp != info.created_at) - log_info ("NOTE: the key does not use the suggested creation date\n"); - *timestamp = info.created_at; - - pk->timestamp = info.created_at; - pk->version = 4; - if (expireval) - pk->expiredate = pk->timestamp + expireval; - pk->pubkey_algo = algo; - pk->pkey[0] = info.n; - pk->pkey[1] = info.e; - - pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY; - pkt->pkt.public_key = pk; - add_kbnode (pub_root, new_kbnode (pkt)); - - return 0; -#else - (void)algo; - (void)keyno; - (void)is_primary; - (void)pub_root; - (void)timestamp; - (void)expireval; - return gpg_error (GPG_ERR_NOT_SUPPORTED); -#endif /*!ENABLE_CARD_SUPPORT*/ -} - - - -static int -gen_card_key_with_backup (int algo, int keyno, int is_primary, - KBNODE pub_root, u32 timestamp, - u32 expireval, struct para_data_s *para) -{ -#if ENABLE_CARD_SUPPORT && 0 - /* FIXME: Move this to gpg-agent. */ - int rc; - const char *s; - PACKET *pkt; - PKT_secret_key *sk, *sk_unprotected = NULL, *sk_protected = NULL; - PKT_public_key *pk; - size_t n; - int i; - unsigned int nbits; - - /* Get the size of the key directly from the card. */ - { - struct agent_card_info_s info; - - memset (&info, 0, sizeof info); - if (!agent_scd_getattr ("KEY-ATTR", &info) - && info.key_attr[1].algo) - nbits = info.key_attr[1].nbits; - else - nbits = 1024; /* All pre-v2.0 cards. */ - agent_release_card_info (&info); - } - - /* Create a key of this size in memory. */ - rc = generate_raw_key (algo, nbits, timestamp, - &sk_unprotected, &sk_protected); - if (rc) - return rc; - - /* Store the key to the card. */ - rc = save_unprotected_key_to_card (sk_unprotected, keyno); - if (rc) - { - log_error (_("storing key onto card failed: %s\n"), gpg_strerror (rc)); - free_secret_key (sk_unprotected); - free_secret_key (sk_protected); - write_status_errcode ("save_key_to_card", rc); - return rc; - } - - /* Get rid of the secret key parameters and store the serial numer. */ - sk = sk_unprotected; - n = pubkey_get_nskey (sk->pubkey_algo); - for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++) - { - gcry_mpi_release (sk->skey[i]); - sk->skey[i] = NULL; - } - i = pubkey_get_npkey (sk->pubkey_algo); - sk->skey[i] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8); - sk->is_protected = 1; - sk->protect.s2k.mode = 1002; - s = get_parameter_value (para, pSERIALNO); - assert (s); - for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1]; - sk->protect.ivlen++, s += 2) - sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s); - - /* Now write the *protected* secret key to the file. */ - { - char name_buffer[50]; - char *fname; - IOBUF fp; - mode_t oldmask; - - keyid_from_sk (sk, NULL); - snprintf (name_buffer, sizeof name_buffer, "sk_%08lX%08lX.gpg", - (ulong)sk->keyid[0], (ulong)sk->keyid[1]); - - fname = make_filename (backup_dir, name_buffer, NULL); - /* Note that the umask call is not anymore needed because - iobuf_create now takes care of it. However, it does not harm - and thus we keep it. */ - oldmask = umask (077); - if (is_secured_filename (fname)) - { - fp = NULL; - gpg_err_set_errno (EPERM); - } - else - fp = iobuf_create (fname, 1); - umask (oldmask); - if (!fp) - { - rc = gpg_error_from_syserror (); - log_error (_("can't create backup file '%s': %s\n"), - fname, strerror(errno) ); - xfree (fname); - free_secret_key (sk_unprotected); - free_secret_key (sk_protected); - return rc; - } - - pkt = xcalloc (1, sizeof *pkt); - pkt->pkttype = PKT_SECRET_KEY; - pkt->pkt.secret_key = sk_protected; - sk_protected = NULL; - - rc = build_packet (fp, pkt); - if (rc) - { - log_error("build packet failed: %s\n", gpg_strerror (rc)); - iobuf_cancel (fp); - } - else - { - unsigned char array[MAX_FINGERPRINT_LEN]; - char *fprbuf, *p; - - iobuf_close (fp); - iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname); - log_info (_("Note: backup of card key saved to '%s'\n"), fname); - - fingerprint_from_sk (sk, array, &n); - p = fprbuf = xmalloc (MAX_FINGERPRINT_LEN*2 + 1 + 1); - for (i=0; i < n ; i++, p += 2) - sprintf (p, "%02X", array[i]); - *p++ = ' '; - *p = 0; - - write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED, - fprbuf, - fname, strlen (fname), - 0); - xfree (fprbuf); - } - free_packet (pkt); - xfree (pkt); - xfree (fname); - if (rc) - { - free_secret_key (sk_unprotected); - return rc; - } - } - - /* Create the public key from the secret key. */ - pk = xcalloc (1, sizeof *pk ); - pk->timestamp = sk->timestamp; - pk->version = sk->version; - if (expireval) - pk->expiredate = sk->expiredate = sk->timestamp + expireval; - pk->pubkey_algo = sk->pubkey_algo; - n = pubkey_get_npkey (sk->pubkey_algo); - for (i=0; i < n; i++) - pk->pkey[i] = mpi_copy (sk->skey[i]); - - /* Build packets and add them to the node lists. */ - pkt = xcalloc (1,sizeof *pkt); - pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY; - pkt->pkt.public_key = pk; - add_kbnode(pub_root, new_kbnode( pkt )); - - pkt = xcalloc (1,sizeof *pkt); - pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY; - pkt->pkt.secret_key = sk; - add_kbnode(sec_root, new_kbnode( pkt )); - - return 0; -#else -# if __GCC__ && ENABLE_CARD_SUPPORT -# warning Card support still missing -# endif - (void)algo; - (void)keyno; - (void)is_primary; - (void)pub_root; - (void)timestamp; - (void)expireval; - (void)para; - return gpg_error (GPG_ERR_NOT_SUPPORTED); -#endif /*!ENABLE_CARD_SUPPORT*/ -} - - -#if 0 -int -save_unprotected_key_to_card (PKT_public_key *sk, int keyno) -{ - int rc; - unsigned char *rsa_n = NULL; - unsigned char *rsa_e = NULL; - unsigned char *rsa_p = NULL; - unsigned char *rsa_q = NULL; - size_t rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len; - unsigned char *sexp = NULL; - unsigned char *p; - char numbuf[55], numbuf2[50]; - - assert (is_RSA (sk->pubkey_algo)); - assert (!sk->is_protected); - - /* Copy the parameters into straight buffers. */ - gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_n, &rsa_n_len, sk->skey[0]); - gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_e, &rsa_e_len, sk->skey[1]); - gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_p, &rsa_p_len, sk->skey[3]); - gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_q, &rsa_q_len, sk->skey[4]); - if (!rsa_n || !rsa_e || !rsa_p || !rsa_q) - { - rc = GPG_ERR_INV_ARG; - goto leave; - } - - /* Put the key into an S-expression. */ - sexp = p = xmalloc_secure (30 - + rsa_n_len + rsa_e_len + rsa_p_len + rsa_q_len - + 4*sizeof (numbuf) + 25 + sizeof(numbuf) + 20); - - p = stpcpy (p,"(11:private-key(3:rsa(1:n"); - sprintf (numbuf, "%u:", (unsigned int)rsa_n_len); - p = stpcpy (p, numbuf); - memcpy (p, rsa_n, rsa_n_len); - p += rsa_n_len; - - sprintf (numbuf, ")(1:e%u:", (unsigned int)rsa_e_len); - p = stpcpy (p, numbuf); - memcpy (p, rsa_e, rsa_e_len); - p += rsa_e_len; - - sprintf (numbuf, ")(1:p%u:", (unsigned int)rsa_p_len); - p = stpcpy (p, numbuf); - memcpy (p, rsa_p, rsa_p_len); - p += rsa_p_len; - - sprintf (numbuf, ")(1:q%u:", (unsigned int)rsa_q_len); - p = stpcpy (p, numbuf); - memcpy (p, rsa_q, rsa_q_len); - p += rsa_q_len; - - p = stpcpy (p,"))(10:created-at"); - sprintf (numbuf2, "%lu", (unsigned long)sk->timestamp); - sprintf (numbuf, "%lu:", (unsigned long)strlen (numbuf2)); - p = stpcpy (stpcpy (stpcpy (p, numbuf), numbuf2), "))"); - - /* Fixme: Unfortunately we don't have the serialnumber available - - thus we can't pass it down to the agent. */ - rc = agent_scd_writekey (keyno, NULL, sexp, p - sexp); - - leave: - xfree (sexp); - xfree (rsa_n); - xfree (rsa_e); - xfree (rsa_p); - xfree (rsa_q); - return rc; -} -#endif /*ENABLE_CARD_SUPPORT*/